blob: abb695d6c7be9c105a2feeca269188f41b85a81f [file] [log] [blame]
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -08001/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
David Collins8885f792017-01-26 14:36:34 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define pr_fmt(fmt) "flashv2: %s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/delay.h>
20#include <linux/slab.h>
21#include <linux/of.h>
22#include <linux/of_irq.h>
23#include <linux/of_gpio.h>
24#include <linux/gpio.h>
25#include <linux/regmap.h>
26#include <linux/power_supply.h>
27#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/regulator/consumer.h>
30#include <linux/leds-qpnp-flash.h>
31#include <linux/leds-qpnp-flash-v2.h>
32#include <linux/qpnp/qpnp-revid.h>
33#include <linux/log2.h>
34#include "leds.h"
35
36#define FLASH_LED_REG_LED_STATUS1(base) (base + 0x08)
37#define FLASH_LED_REG_LED_STATUS2(base) (base + 0x09)
38#define FLASH_LED_REG_INT_RT_STS(base) (base + 0x10)
39#define FLASH_LED_REG_SAFETY_TMR(base) (base + 0x40)
40#define FLASH_LED_REG_TGR_CURRENT(base) (base + 0x43)
41#define FLASH_LED_REG_MOD_CTRL(base) (base + 0x46)
42#define FLASH_LED_REG_IRES(base) (base + 0x47)
43#define FLASH_LED_REG_STROBE_CFG(base) (base + 0x48)
44#define FLASH_LED_REG_STROBE_CTRL(base) (base + 0x49)
45#define FLASH_LED_EN_LED_CTRL(base) (base + 0x4C)
46#define FLASH_LED_REG_HDRM_PRGM(base) (base + 0x4D)
47#define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50)
48#define FLASH_LED_REG_WARMUP_DELAY(base) (base + 0x51)
49#define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52)
50#define FLASH_LED_REG_THERMAL_RMP_DN_RATE(base) (base + 0x55)
51#define FLASH_LED_REG_THERMAL_THRSH1(base) (base + 0x56)
52#define FLASH_LED_REG_THERMAL_THRSH2(base) (base + 0x57)
53#define FLASH_LED_REG_THERMAL_THRSH3(base) (base + 0x58)
54#define FLASH_LED_REG_THERMAL_HYSTERESIS(base) (base + 0x59)
55#define FLASH_LED_REG_THERMAL_DEBOUNCE(base) (base + 0x5A)
56#define FLASH_LED_REG_VPH_DROOP_THRESHOLD(base) (base + 0x61)
57#define FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base) (base + 0x62)
58#define FLASH_LED_REG_ILED_GRT_THRSH(base) (base + 0x67)
59#define FLASH_LED_REG_LED1N2_ICLAMP_LOW(base) (base + 0x68)
60#define FLASH_LED_REG_LED1N2_ICLAMP_MID(base) (base + 0x69)
61#define FLASH_LED_REG_LED3_ICLAMP_LOW(base) (base + 0x6A)
62#define FLASH_LED_REG_LED3_ICLAMP_MID(base) (base + 0x6B)
63#define FLASH_LED_REG_MITIGATION_SEL(base) (base + 0x6E)
64#define FLASH_LED_REG_MITIGATION_SW(base) (base + 0x6F)
65#define FLASH_LED_REG_LMH_LEVEL(base) (base + 0x70)
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -070066#define FLASH_LED_REG_MULTI_STROBE_CTRL(base) (base + 0x71)
67#define FLASH_LED_REG_LPG_INPUT_CTRL(base) (base + 0x72)
David Collins8885f792017-01-26 14:36:34 -080068#define FLASH_LED_REG_CURRENT_DERATE_EN(base) (base + 0x76)
69
70#define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4)
71#define FLASH_LED_CURRENT_MASK GENMASK(6, 0)
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -070072#define FLASH_LED_STROBE_MASK GENMASK(1, 0)
David Collins8885f792017-01-26 14:36:34 -080073#define FLASH_HW_STROBE_MASK GENMASK(2, 0)
74#define FLASH_LED_ISC_WARMUP_DELAY_MASK GENMASK(1, 0)
75#define FLASH_LED_CURRENT_DERATE_EN_MASK GENMASK(2, 0)
76#define FLASH_LED_VPH_DROOP_DEBOUNCE_MASK GENMASK(1, 0)
77#define FLASH_LED_CHGR_MITIGATION_SEL_MASK GENMASK(5, 4)
78#define FLASH_LED_LMH_MITIGATION_SEL_MASK GENMASK(1, 0)
79#define FLASH_LED_ILED_GRT_THRSH_MASK GENMASK(5, 0)
80#define FLASH_LED_LMH_LEVEL_MASK GENMASK(1, 0)
81#define FLASH_LED_VPH_DROOP_HYSTERESIS_MASK GENMASK(5, 4)
82#define FLASH_LED_VPH_DROOP_THRESHOLD_MASK GENMASK(2, 0)
83#define FLASH_LED_THERMAL_HYSTERESIS_MASK GENMASK(1, 0)
84#define FLASH_LED_THERMAL_DEBOUNCE_MASK GENMASK(1, 0)
85#define FLASH_LED_THERMAL_THRSH_MASK GENMASK(2, 0)
86#define FLASH_LED_MOD_CTRL_MASK BIT(7)
87#define FLASH_LED_HW_SW_STROBE_SEL_BIT BIT(2)
88#define FLASH_LED_VPH_DROOP_FAULT_MASK BIT(4)
89#define FLASH_LED_LMH_MITIGATION_EN_MASK BIT(0)
90#define FLASH_LED_CHGR_MITIGATION_EN_MASK BIT(4)
91#define THERMAL_OTST1_RAMP_CTRL_MASK BIT(7)
92#define THERMAL_OTST1_RAMP_CTRL_SHIFT 7
93#define THERMAL_DERATE_SLOW_SHIFT 4
94#define THERMAL_DERATE_SLOW_MASK GENMASK(6, 4)
95#define THERMAL_DERATE_FAST_MASK GENMASK(2, 0)
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -070096#define LED1N2_FLASH_ONCE_ONLY_BIT BIT(0)
97#define LED3_FLASH_ONCE_ONLY_BIT BIT(1)
98#define LPG_INPUT_SEL_BIT BIT(0)
David Collins8885f792017-01-26 14:36:34 -080099
100#define VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us) (val_us / 8)
101#define VPH_DROOP_HYST_MV_TO_VAL(val_mv) (val_mv / 25)
David Collins8885f792017-01-26 14:36:34 -0800102#define VPH_DROOP_THRESH_VAL_TO_UV(val) ((val + 25) * 100000)
103#define MITIGATION_THRSH_MA_TO_VAL(val_ma) (val_ma / 100)
David Collins8885f792017-01-26 14:36:34 -0800104#define THERMAL_HYST_TEMP_TO_VAL(val, divisor) (val / divisor)
105
106#define FLASH_LED_ISC_WARMUP_DELAY_SHIFT 6
107#define FLASH_LED_WARMUP_DELAY_DEFAULT 2
108#define FLASH_LED_ISC_DELAY_DEFAULT 3
109#define FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT 2
110#define FLASH_LED_VPH_DROOP_HYST_SHIFT 4
111#define FLASH_LED_VPH_DROOP_HYST_DEFAULT 2
112#define FLASH_LED_VPH_DROOP_THRESH_DEFAULT 5
113#define FLASH_LED_DEBOUNCE_MAX 3
114#define FLASH_LED_HYSTERESIS_MAX 3
115#define FLASH_LED_VPH_DROOP_THRESH_MAX 7
116#define THERMAL_DERATE_SLOW_MAX 314592
117#define THERMAL_DERATE_FAST_MAX 512
118#define THERMAL_DEBOUNCE_TIME_MAX 64
119#define THERMAL_DERATE_HYSTERESIS_MAX 3
120#define FLASH_LED_THERMAL_THRSH_MIN 3
121#define FLASH_LED_THERMAL_THRSH_MAX 7
122#define FLASH_LED_THERMAL_OTST_LEVELS 3
123#define FLASH_LED_VLED_MAX_DEFAULT_UV 3500000
124#define FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA 4500000
125#define FLASH_LED_RPARA_DEFAULT_UOHM 0
126#define FLASH_LED_SAFETY_TMR_ENABLE BIT(7)
127#define FLASH_LED_LMH_LEVEL_DEFAULT 0
128#define FLASH_LED_LMH_MITIGATION_ENABLE 1
129#define FLASH_LED_LMH_MITIGATION_DISABLE 0
130#define FLASH_LED_CHGR_MITIGATION_ENABLE BIT(4)
131#define FLASH_LED_CHGR_MITIGATION_DISABLE 0
Ankit Sharmaa7153c32017-03-22 19:04:52 +0530132#define FLASH_LED_LMH_MITIGATION_SEL_DEFAULT 2
David Collins8885f792017-01-26 14:36:34 -0800133#define FLASH_LED_MITIGATION_SEL_MAX 2
134#define FLASH_LED_CHGR_MITIGATION_SEL_SHIFT 4
Ankit Sharmaa7153c32017-03-22 19:04:52 +0530135#define FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT 0xA
136#define FLASH_LED_CHGR_MITIGATION_THRSH_MAX 0x1F
David Collins8885f792017-01-26 14:36:34 -0800137#define FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV 3700000
138#define FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM 400000
139#define FLASH_LED_IRES_BASE 3
140#define FLASH_LED_IRES_DIVISOR 2500
141#define FLASH_LED_IRES_MIN_UA 5000
142#define FLASH_LED_IRES_DEFAULT_UA 12500
143#define FLASH_LED_IRES_DEFAULT_VAL 0x00
144#define FLASH_LED_HDRM_VOL_SHIFT 4
145#define FLASH_LED_HDRM_VOL_DEFAULT_MV 0x80
146#define FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV 0x04
147#define FLASH_LED_HDRM_VOL_BASE_MV 125
148#define FLASH_LED_HDRM_VOL_STEP_MV 25
149#define FLASH_LED_STROBE_CFG_DEFAULT 0x00
150#define FLASH_LED_HW_STROBE_OPTION_1 0x00
151#define FLASH_LED_HW_STROBE_OPTION_2 0x01
152#define FLASH_LED_HW_STROBE_OPTION_3 0x02
153#define FLASH_LED_ENABLE BIT(0)
154#define FLASH_LED_MOD_ENABLE BIT(7)
155#define FLASH_LED_DISABLE 0x00
156#define FLASH_LED_SAFETY_TMR_DISABLED 0x13
David Collins8885f792017-01-26 14:36:34 -0800157#define FLASH_LED_MAX_TOTAL_CURRENT_MA 3750
Kiran Gunda5cadca72017-07-26 14:37:52 +0530158#define FLASH_LED_IRES5P0_MAX_CURR_MA 640
159#define FLASH_LED_IRES7P5_MAX_CURR_MA 960
160#define FLASH_LED_IRES10P0_MAX_CURR_MA 1280
161#define FLASH_LED_IRES12P5_MAX_CURR_MA 1600
162#define MAX_IRES_LEVELS 4
David Collins8885f792017-01-26 14:36:34 -0800163
164/* notifier call chain for flash-led irqs */
165static ATOMIC_NOTIFIER_HEAD(irq_notifier_list);
166
Ankit Sharmaa7153c32017-03-22 19:04:52 +0530167enum flash_charger_mitigation {
168 FLASH_DISABLE_CHARGER_MITIGATION,
169 FLASH_HW_CHARGER_MITIGATION_BY_ILED_THRSHLD,
170 FLASH_SW_CHARGER_MITIGATION,
171};
172
David Collins8885f792017-01-26 14:36:34 -0800173enum flash_led_type {
Subbaraman Narayanamurthyd737fd52018-01-17 19:58:52 -0800174 FLASH_LED_TYPE_UNKNOWN,
David Collins8885f792017-01-26 14:36:34 -0800175 FLASH_LED_TYPE_FLASH,
176 FLASH_LED_TYPE_TORCH,
177};
178
179enum {
180 LED1 = 0,
181 LED2,
182 LED3,
183};
184
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -0700185enum strobe_type {
186 SW_STROBE = 0,
187 HW_STROBE,
188 LPG_STROBE,
189};
190
David Collins8885f792017-01-26 14:36:34 -0800191/*
192 * Configurations for each individual LED
193 */
194struct flash_node_data {
195 struct platform_device *pdev;
196 struct led_classdev cdev;
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -0700197 struct pinctrl *strobe_pinctrl;
David Collins8885f792017-01-26 14:36:34 -0800198 struct pinctrl_state *hw_strobe_state_active;
199 struct pinctrl_state *hw_strobe_state_suspend;
200 int hw_strobe_gpio;
201 int ires_ua;
Kiran Gunda5cadca72017-07-26 14:37:52 +0530202 int default_ires_ua;
David Collins8885f792017-01-26 14:36:34 -0800203 int max_current;
204 int current_ma;
Ankit Sharmaa7153c32017-03-22 19:04:52 +0530205 int prev_current_ma;
David Collins8885f792017-01-26 14:36:34 -0800206 u8 duration;
207 u8 id;
Kiran Gunda5cadca72017-07-26 14:37:52 +0530208 u8 ires_idx;
209 u8 default_ires_idx;
David Collins8885f792017-01-26 14:36:34 -0800210 u8 hdrm_val;
211 u8 current_reg_val;
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -0700212 u8 strobe_ctrl;
213 u8 strobe_sel;
Subbaraman Narayanamurthyd737fd52018-01-17 19:58:52 -0800214 enum flash_led_type type;
David Collins8885f792017-01-26 14:36:34 -0800215 bool led_on;
216};
217
218
219struct flash_switch_data {
220 struct platform_device *pdev;
221 struct regulator *vreg;
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -0700222 struct pinctrl *led_en_pinctrl;
223 struct pinctrl_state *gpio_state_active;
224 struct pinctrl_state *gpio_state_suspend;
David Collins8885f792017-01-26 14:36:34 -0800225 struct led_classdev cdev;
226 int led_mask;
227 bool regulator_on;
228 bool enabled;
Subbaraman Narayanamurthyd737fd52018-01-17 19:58:52 -0800229 bool symmetry_en;
David Collins8885f792017-01-26 14:36:34 -0800230};
231
232/*
233 * Flash LED configuration read from device tree
234 */
235struct flash_led_platform_data {
236 struct pmic_revid_data *pmic_rev_id;
237 int *thermal_derate_current;
238 int all_ramp_up_done_irq;
239 int all_ramp_down_done_irq;
240 int led_fault_irq;
241 int ibatt_ocp_threshold_ua;
242 int vled_max_uv;
243 int rpara_uohm;
244 int lmh_rbatt_threshold_uohm;
245 int lmh_ocv_threshold_uv;
246 int thermal_derate_slow;
247 int thermal_derate_fast;
248 int thermal_hysteresis;
249 int thermal_debounce;
250 int thermal_thrsh1;
251 int thermal_thrsh2;
252 int thermal_thrsh3;
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -0700253 int hw_strobe_option;
David Collins8885f792017-01-26 14:36:34 -0800254 u32 led1n2_iclamp_low_ma;
255 u32 led1n2_iclamp_mid_ma;
256 u32 led3_iclamp_low_ma;
257 u32 led3_iclamp_mid_ma;
258 u8 isc_delay;
259 u8 warmup_delay;
260 u8 current_derate_en_cfg;
261 u8 vph_droop_threshold;
262 u8 vph_droop_hysteresis;
263 u8 vph_droop_debounce;
264 u8 lmh_mitigation_sel;
265 u8 chgr_mitigation_sel;
266 u8 lmh_level;
267 u8 iled_thrsh_val;
David Collins8885f792017-01-26 14:36:34 -0800268 bool hdrm_auto_mode_en;
269 bool thermal_derate_en;
270 bool otst_ramp_bkup_en;
271};
272
273/*
274 * Flash LED data structure containing flash LED attributes
275 */
276struct qpnp_flash_led {
277 struct flash_led_platform_data *pdata;
278 struct platform_device *pdev;
279 struct regmap *regmap;
280 struct flash_node_data *fnode;
281 struct flash_switch_data *snode;
282 struct power_supply *bms_psy;
283 struct notifier_block nb;
284 spinlock_t lock;
285 int num_fnodes;
286 int num_snodes;
287 int enable;
Ankit Sharmaa7153c32017-03-22 19:04:52 +0530288 int total_current_ma;
David Collins8885f792017-01-26 14:36:34 -0800289 u16 base;
290 bool trigger_lmh;
291 bool trigger_chgr;
292};
293
294static int thermal_derate_slow_table[] = {
295 128, 256, 512, 1024, 2048, 4096, 8192, 314592,
296};
297
298static int thermal_derate_fast_table[] = {
299 32, 64, 96, 128, 256, 384, 512,
300};
301
302static int otst1_threshold_table[] = {
303 85, 79, 73, 67, 109, 103, 97, 91,
304};
305
306static int otst2_threshold_table[] = {
307 110, 104, 98, 92, 134, 128, 122, 116,
308};
309
310static int otst3_threshold_table[] = {
311 125, 119, 113, 107, 149, 143, 137, 131,
312};
313
Kiran Gunda5cadca72017-07-26 14:37:52 +0530314static int max_ires_curr_ma_table[MAX_IRES_LEVELS] = {
315 FLASH_LED_IRES12P5_MAX_CURR_MA, FLASH_LED_IRES10P0_MAX_CURR_MA,
316 FLASH_LED_IRES7P5_MAX_CURR_MA, FLASH_LED_IRES5P0_MAX_CURR_MA
317};
318
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -0800319static inline int get_current_reg_code(int target_curr_ma, int ires_ua)
320{
321 if (!ires_ua || !target_curr_ma || (target_curr_ma < (ires_ua / 1000)))
322 return 0;
323
324 return DIV_ROUND_UP(target_curr_ma * 1000, ires_ua) - 1;
325}
326
David Collins8885f792017-01-26 14:36:34 -0800327static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data)
328{
329 int rc;
330 uint val;
331
332 rc = regmap_read(led->regmap, addr, &val);
333 if (rc < 0) {
334 pr_err("Unable to read from 0x%04X rc = %d\n", addr, rc);
335 return rc;
336 }
337
338 pr_debug("Read 0x%02X from addr 0x%04X\n", val, addr);
339 *data = (u8)val;
340 return 0;
341}
342
343static int qpnp_flash_led_write(struct qpnp_flash_led *led, u16 addr, u8 data)
344{
345 int rc;
346
347 rc = regmap_write(led->regmap, addr, data);
348 if (rc < 0) {
349 pr_err("Unable to write to 0x%04X rc = %d\n", addr, rc);
350 return rc;
351 }
352
353 pr_debug("Wrote 0x%02X to addr 0x%04X\n", data, addr);
354 return 0;
355}
356
357static int
358qpnp_flash_led_masked_read(struct qpnp_flash_led *led, u16 addr, u8 mask,
359 u8 *val)
360{
361 int rc;
362
363 rc = qpnp_flash_led_read(led, addr, val);
364 if (rc < 0)
365 return rc;
366
367 *val &= mask;
368 return rc;
369}
370
371static int
372qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask,
373 u8 val)
374{
375 int rc;
376
377 rc = regmap_update_bits(led->regmap, addr, mask, val);
378 if (rc < 0)
379 pr_err("Unable to update bits from 0x%04X, rc = %d\n", addr,
380 rc);
381 else
382 pr_debug("Wrote 0x%02X to addr 0x%04X\n", val, addr);
383
384 return rc;
385}
386
387static enum
388led_brightness qpnp_flash_led_brightness_get(struct led_classdev *led_cdev)
389{
390 return led_cdev->brightness;
391}
392
393static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
394{
395 int rc, i, addr_offset;
396 u8 val = 0, mask;
397
398 for (i = 0; i < led->num_fnodes; i++) {
399 addr_offset = led->fnode[i].id;
400 rc = qpnp_flash_led_write(led,
401 FLASH_LED_REG_HDRM_PRGM(led->base + addr_offset),
402 led->fnode[i].hdrm_val);
403 if (rc < 0)
404 return rc;
405
406 val |= 0x1 << led->fnode[i].id;
407 }
408
409 rc = qpnp_flash_led_write(led,
410 FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(led->base),
411 val);
412 if (rc < 0)
413 return rc;
414
415 rc = qpnp_flash_led_masked_write(led,
416 FLASH_LED_REG_ISC_DELAY(led->base),
417 FLASH_LED_ISC_WARMUP_DELAY_MASK,
418 led->pdata->isc_delay);
419 if (rc < 0)
420 return rc;
421
422 rc = qpnp_flash_led_masked_write(led,
423 FLASH_LED_REG_WARMUP_DELAY(led->base),
424 FLASH_LED_ISC_WARMUP_DELAY_MASK,
425 led->pdata->warmup_delay);
426 if (rc < 0)
427 return rc;
428
429 rc = qpnp_flash_led_masked_write(led,
430 FLASH_LED_REG_CURRENT_DERATE_EN(led->base),
431 FLASH_LED_CURRENT_DERATE_EN_MASK,
432 led->pdata->current_derate_en_cfg);
433 if (rc < 0)
434 return rc;
435
436 val = (led->pdata->otst_ramp_bkup_en << THERMAL_OTST1_RAMP_CTRL_SHIFT);
437 mask = THERMAL_OTST1_RAMP_CTRL_MASK;
438 if (led->pdata->thermal_derate_slow >= 0) {
439 val |= (led->pdata->thermal_derate_slow <<
440 THERMAL_DERATE_SLOW_SHIFT);
441 mask |= THERMAL_DERATE_SLOW_MASK;
442 }
443
444 if (led->pdata->thermal_derate_fast >= 0) {
445 val |= led->pdata->thermal_derate_fast;
446 mask |= THERMAL_DERATE_FAST_MASK;
447 }
448
449 rc = qpnp_flash_led_masked_write(led,
450 FLASH_LED_REG_THERMAL_RMP_DN_RATE(led->base),
451 mask, val);
452 if (rc < 0)
453 return rc;
454
455 if (led->pdata->thermal_debounce >= 0) {
456 rc = qpnp_flash_led_masked_write(led,
457 FLASH_LED_REG_THERMAL_DEBOUNCE(led->base),
458 FLASH_LED_THERMAL_DEBOUNCE_MASK,
459 led->pdata->thermal_debounce);
460 if (rc < 0)
461 return rc;
462 }
463
464 if (led->pdata->thermal_hysteresis >= 0) {
465 rc = qpnp_flash_led_masked_write(led,
466 FLASH_LED_REG_THERMAL_HYSTERESIS(led->base),
467 FLASH_LED_THERMAL_HYSTERESIS_MASK,
468 led->pdata->thermal_hysteresis);
469 if (rc < 0)
470 return rc;
471 }
472
473 if (led->pdata->thermal_thrsh1 >= 0) {
474 rc = qpnp_flash_led_masked_write(led,
475 FLASH_LED_REG_THERMAL_THRSH1(led->base),
476 FLASH_LED_THERMAL_THRSH_MASK,
477 led->pdata->thermal_thrsh1);
478 if (rc < 0)
479 return rc;
480 }
481
482 if (led->pdata->thermal_thrsh2 >= 0) {
483 rc = qpnp_flash_led_masked_write(led,
484 FLASH_LED_REG_THERMAL_THRSH2(led->base),
485 FLASH_LED_THERMAL_THRSH_MASK,
486 led->pdata->thermal_thrsh2);
487 if (rc < 0)
488 return rc;
489 }
490
491 if (led->pdata->thermal_thrsh3 >= 0) {
492 rc = qpnp_flash_led_masked_write(led,
493 FLASH_LED_REG_THERMAL_THRSH3(led->base),
494 FLASH_LED_THERMAL_THRSH_MASK,
495 led->pdata->thermal_thrsh3);
496 if (rc < 0)
497 return rc;
498 }
499
500 rc = qpnp_flash_led_masked_write(led,
501 FLASH_LED_REG_VPH_DROOP_DEBOUNCE(led->base),
502 FLASH_LED_VPH_DROOP_DEBOUNCE_MASK,
503 led->pdata->vph_droop_debounce);
504 if (rc < 0)
505 return rc;
506
507 rc = qpnp_flash_led_masked_write(led,
508 FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
509 FLASH_LED_VPH_DROOP_THRESHOLD_MASK,
510 led->pdata->vph_droop_threshold);
511 if (rc < 0)
512 return rc;
513
514 rc = qpnp_flash_led_masked_write(led,
515 FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
516 FLASH_LED_VPH_DROOP_HYSTERESIS_MASK,
517 led->pdata->vph_droop_hysteresis);
518 if (rc < 0)
519 return rc;
520
521 rc = qpnp_flash_led_masked_write(led,
522 FLASH_LED_REG_MITIGATION_SEL(led->base),
523 FLASH_LED_LMH_MITIGATION_SEL_MASK,
524 led->pdata->lmh_mitigation_sel);
525 if (rc < 0)
526 return rc;
527
Ankit Sharmaa7153c32017-03-22 19:04:52 +0530528 val = led->pdata->chgr_mitigation_sel
529 << FLASH_LED_CHGR_MITIGATION_SEL_SHIFT;
David Collins8885f792017-01-26 14:36:34 -0800530 rc = qpnp_flash_led_masked_write(led,
531 FLASH_LED_REG_MITIGATION_SEL(led->base),
532 FLASH_LED_CHGR_MITIGATION_SEL_MASK,
Ankit Sharmaa7153c32017-03-22 19:04:52 +0530533 val);
David Collins8885f792017-01-26 14:36:34 -0800534 if (rc < 0)
535 return rc;
536
537 rc = qpnp_flash_led_masked_write(led,
538 FLASH_LED_REG_LMH_LEVEL(led->base),
539 FLASH_LED_LMH_LEVEL_MASK,
540 led->pdata->lmh_level);
541 if (rc < 0)
542 return rc;
543
544 rc = qpnp_flash_led_masked_write(led,
545 FLASH_LED_REG_ILED_GRT_THRSH(led->base),
546 FLASH_LED_ILED_GRT_THRSH_MASK,
547 led->pdata->iled_thrsh_val);
548 if (rc < 0)
549 return rc;
550
551 if (led->pdata->led1n2_iclamp_low_ma) {
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -0800552 val = get_current_reg_code(led->pdata->led1n2_iclamp_low_ma,
Subbaraman Narayanamurthy01c99612017-04-03 12:26:06 -0700553 led->fnode[LED1].ires_ua);
David Collins8885f792017-01-26 14:36:34 -0800554 rc = qpnp_flash_led_masked_write(led,
555 FLASH_LED_REG_LED1N2_ICLAMP_LOW(led->base),
556 FLASH_LED_CURRENT_MASK, val);
557 if (rc < 0)
558 return rc;
559 }
560
561 if (led->pdata->led1n2_iclamp_mid_ma) {
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -0800562 val = get_current_reg_code(led->pdata->led1n2_iclamp_mid_ma,
Subbaraman Narayanamurthy01c99612017-04-03 12:26:06 -0700563 led->fnode[LED1].ires_ua);
David Collins8885f792017-01-26 14:36:34 -0800564 rc = qpnp_flash_led_masked_write(led,
565 FLASH_LED_REG_LED1N2_ICLAMP_MID(led->base),
566 FLASH_LED_CURRENT_MASK, val);
567 if (rc < 0)
568 return rc;
569 }
570
571 if (led->pdata->led3_iclamp_low_ma) {
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -0800572 val = get_current_reg_code(led->pdata->led3_iclamp_low_ma,
Subbaraman Narayanamurthy01c99612017-04-03 12:26:06 -0700573 led->fnode[LED3].ires_ua);
David Collins8885f792017-01-26 14:36:34 -0800574 rc = qpnp_flash_led_masked_write(led,
575 FLASH_LED_REG_LED3_ICLAMP_LOW(led->base),
576 FLASH_LED_CURRENT_MASK, val);
577 if (rc < 0)
578 return rc;
579 }
580
581 if (led->pdata->led3_iclamp_mid_ma) {
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -0800582 val = get_current_reg_code(led->pdata->led3_iclamp_mid_ma,
Subbaraman Narayanamurthy01c99612017-04-03 12:26:06 -0700583 led->fnode[LED3].ires_ua);
David Collins8885f792017-01-26 14:36:34 -0800584 rc = qpnp_flash_led_masked_write(led,
585 FLASH_LED_REG_LED3_ICLAMP_MID(led->base),
586 FLASH_LED_CURRENT_MASK, val);
587 if (rc < 0)
588 return rc;
589 }
590
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -0700591 if (led->pdata->hw_strobe_option > 0) {
592 rc = qpnp_flash_led_masked_write(led,
593 FLASH_LED_REG_STROBE_CFG(led->base),
594 FLASH_LED_STROBE_MASK,
595 led->pdata->hw_strobe_option);
596 if (rc < 0)
597 return rc;
598 }
599
600 if (led->fnode[LED3].strobe_sel == LPG_STROBE) {
601 rc = qpnp_flash_led_masked_write(led,
602 FLASH_LED_REG_MULTI_STROBE_CTRL(led->base),
603 LED3_FLASH_ONCE_ONLY_BIT, 0);
604 if (rc < 0)
605 return rc;
606
607 rc = qpnp_flash_led_masked_write(led,
608 FLASH_LED_REG_LPG_INPUT_CTRL(led->base),
609 LPG_INPUT_SEL_BIT, LPG_INPUT_SEL_BIT);
610 if (rc < 0)
611 return rc;
612 }
David Collins8885f792017-01-26 14:36:34 -0800613 return 0;
614}
615
616static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode,
617 int hw_strobe_option, bool on)
618{
619 int rc = 0;
620
621 /*
622 * If the LED controlled by this fnode is not GPIO controlled
623 * for the given strobe_option, return.
624 */
625 if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_1)
626 return 0;
627 else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_2
628 && fnode->id != LED3)
629 return 0;
630 else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_3
631 && fnode->id == LED1)
632 return 0;
633
634 if (gpio_is_valid(fnode->hw_strobe_gpio)) {
635 gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0);
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -0700636 } else if (fnode->strobe_pinctrl && fnode->hw_strobe_state_active &&
David Collins8885f792017-01-26 14:36:34 -0800637 fnode->hw_strobe_state_suspend) {
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -0700638 rc = pinctrl_select_state(fnode->strobe_pinctrl,
David Collins8885f792017-01-26 14:36:34 -0800639 on ? fnode->hw_strobe_state_active :
640 fnode->hw_strobe_state_suspend);
641 if (rc < 0) {
642 pr_err("failed to change hw strobe pin state\n");
643 return rc;
644 }
645 }
646
647 return rc;
648}
649
650static int qpnp_flash_led_regulator_enable(struct qpnp_flash_led *led,
651 struct flash_switch_data *snode, bool on)
652{
653 int rc = 0;
654
655 if (!snode || !snode->vreg)
656 return 0;
657
658 if (snode->regulator_on == on)
659 return 0;
660
661 if (on)
662 rc = regulator_enable(snode->vreg);
663 else
664 rc = regulator_disable(snode->vreg);
665
666 if (rc < 0) {
667 pr_err("regulator_%s failed, rc=%d\n",
668 on ? "enable" : "disable", rc);
669 return rc;
670 }
671
672 snode->regulator_on = on ? true : false;
673 return 0;
674}
675
676static int get_property_from_fg(struct qpnp_flash_led *led,
677 enum power_supply_property prop, int *val)
678{
679 int rc;
680 union power_supply_propval pval = {0, };
681
682 if (!led->bms_psy) {
683 pr_err("no bms psy found\n");
684 return -EINVAL;
685 }
686
687 rc = power_supply_get_property(led->bms_psy, prop, &pval);
688 if (rc) {
689 pr_err("bms psy doesn't support reading prop %d rc = %d\n",
690 prop, rc);
691 return rc;
692 }
693
694 *val = pval.intval;
695 return rc;
696}
697
698#define VOLTAGE_HDRM_DEFAULT_MV 350
699static int qpnp_flash_led_get_voltage_headroom(struct qpnp_flash_led *led)
700{
701 int i, voltage_hdrm_mv = 0, voltage_hdrm_max = 0;
702
703 for (i = 0; i < led->num_fnodes; i++) {
704 if (led->fnode[i].led_on) {
705 if (led->fnode[i].id < 2) {
706 if (led->fnode[i].current_ma < 750)
707 voltage_hdrm_mv = 125;
708 else if (led->fnode[i].current_ma < 1000)
709 voltage_hdrm_mv = 175;
710 else if (led->fnode[i].current_ma < 1250)
711 voltage_hdrm_mv = 250;
712 else
713 voltage_hdrm_mv = 350;
714 } else {
715 if (led->fnode[i].current_ma < 375)
716 voltage_hdrm_mv = 125;
717 else if (led->fnode[i].current_ma < 500)
718 voltage_hdrm_mv = 175;
719 else if (led->fnode[i].current_ma < 625)
720 voltage_hdrm_mv = 250;
721 else
722 voltage_hdrm_mv = 350;
723 }
724
725 voltage_hdrm_max = max(voltage_hdrm_max,
726 voltage_hdrm_mv);
727 }
728 }
729
730 if (!voltage_hdrm_max)
731 return VOLTAGE_HDRM_DEFAULT_MV;
732
733 return voltage_hdrm_max;
734}
735
736#define UCONV 1000000LL
737#define MCONV 1000LL
738#define FLASH_VDIP_MARGIN 50000
739#define BOB_EFFICIENCY 900LL
740#define VIN_FLASH_MIN_UV 3300000LL
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800741static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led,
742 int *max_current)
David Collins8885f792017-01-26 14:36:34 -0800743{
Kyle Yan74fdd732017-03-22 13:37:08 -0700744 int ocv_uv, ibat_now, voltage_hdrm_mv, rc;
745 int rbatt_uohm = 0;
David Collins8885f792017-01-26 14:36:34 -0800746 int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw;
747 int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv, vph_flash_vdip;
748
749 /* RESISTANCE = esr_uohm + rslow_uohm */
750 rc = get_property_from_fg(led, POWER_SUPPLY_PROP_RESISTANCE,
751 &rbatt_uohm);
752 if (rc < 0) {
753 pr_err("bms psy does not support resistance, rc=%d\n", rc);
754 return rc;
755 }
756
757 /* If no battery is connected, return max possible flash current */
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800758 if (!rbatt_uohm) {
759 *max_current = FLASH_LED_MAX_TOTAL_CURRENT_MA;
760 return 0;
761 }
David Collins8885f792017-01-26 14:36:34 -0800762
763 rc = get_property_from_fg(led, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ocv_uv);
764 if (rc < 0) {
765 pr_err("bms psy does not support OCV, rc=%d\n", rc);
766 return rc;
767 }
768
769 rc = get_property_from_fg(led, POWER_SUPPLY_PROP_CURRENT_NOW,
770 &ibat_now);
771 if (rc < 0) {
772 pr_err("bms psy does not support current, rc=%d\n", rc);
773 return rc;
774 }
775
776 rbatt_uohm += led->pdata->rpara_uohm;
777 voltage_hdrm_mv = qpnp_flash_led_get_voltage_headroom(led);
778 vph_flash_vdip =
779 VPH_DROOP_THRESH_VAL_TO_UV(led->pdata->vph_droop_threshold)
780 + FLASH_VDIP_MARGIN;
781
782 /* Check if LMH_MITIGATION needs to be triggered */
783 if (!led->trigger_lmh && (ocv_uv < led->pdata->lmh_ocv_threshold_uv ||
784 rbatt_uohm > led->pdata->lmh_rbatt_threshold_uohm)) {
785 led->trigger_lmh = true;
786 rc = qpnp_flash_led_masked_write(led,
787 FLASH_LED_REG_MITIGATION_SW(led->base),
788 FLASH_LED_LMH_MITIGATION_EN_MASK,
789 FLASH_LED_LMH_MITIGATION_ENABLE);
790 if (rc < 0) {
791 pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
792 return rc;
793 }
794
795 /* Wait for LMH mitigation to take effect */
796 udelay(100);
797
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800798 return qpnp_flash_led_calc_max_current(led, max_current);
David Collins8885f792017-01-26 14:36:34 -0800799 }
800
801 /*
802 * Calculate the maximum current that can pulled out of the battery
803 * before the battery voltage dips below a safe threshold.
804 */
805 ibat_safe_ua = div_s64((ocv_uv - vph_flash_vdip) * UCONV,
806 rbatt_uohm);
807
808 if (ibat_safe_ua <= led->pdata->ibatt_ocp_threshold_ua) {
809 /*
810 * If the calculated current is below the OCP threshold, then
811 * use it as the possible flash current.
812 */
813 ibat_flash_ua = ibat_safe_ua - ibat_now;
814 vph_flash_uv = vph_flash_vdip;
815 } else {
816 /*
817 * If the calculated current is above the OCP threshold, then
818 * use the ocp threshold instead.
819 *
820 * Any higher current will be tripping the battery OCP.
821 */
822 ibat_flash_ua = led->pdata->ibatt_ocp_threshold_ua - ibat_now;
823 vph_flash_uv = ocv_uv - div64_s64((int64_t)rbatt_uohm
824 * led->pdata->ibatt_ocp_threshold_ua, UCONV);
825 }
826 /* Calculate the input voltage of the flash module. */
827 vin_flash_uv = max((led->pdata->vled_max_uv +
828 (voltage_hdrm_mv * MCONV)), VIN_FLASH_MIN_UV);
829 /* Calculate the available power for the flash module. */
830 avail_flash_power_fw = BOB_EFFICIENCY * vph_flash_uv * ibat_flash_ua;
831 /*
832 * Calculate the available amount of current the flash module can draw
833 * before collapsing the battery. (available power/ flash input voltage)
834 */
835 avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV);
836 pr_debug("avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d\n",
837 avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, led->trigger_lmh);
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800838 *max_current = min(FLASH_LED_MAX_TOTAL_CURRENT_MA,
David Collins8885f792017-01-26 14:36:34 -0800839 (int)(div64_s64(avail_flash_ua, MCONV)));
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800840 return 0;
David Collins8885f792017-01-26 14:36:34 -0800841}
842
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800843static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led,
844 int *thermal_current_lim)
David Collins8885f792017-01-26 14:36:34 -0800845{
David Collins8885f792017-01-26 14:36:34 -0800846 int rc;
847 u8 thermal_thrsh1, thermal_thrsh2, thermal_thrsh3, otst_status;
848
849 /* Store THERMAL_THRSHx register values */
850 rc = qpnp_flash_led_masked_read(led,
851 FLASH_LED_REG_THERMAL_THRSH1(led->base),
852 FLASH_LED_THERMAL_THRSH_MASK,
853 &thermal_thrsh1);
854 if (rc < 0)
855 return rc;
856
857 rc = qpnp_flash_led_masked_read(led,
858 FLASH_LED_REG_THERMAL_THRSH2(led->base),
859 FLASH_LED_THERMAL_THRSH_MASK,
860 &thermal_thrsh2);
861 if (rc < 0)
862 return rc;
863
864 rc = qpnp_flash_led_masked_read(led,
865 FLASH_LED_REG_THERMAL_THRSH3(led->base),
866 FLASH_LED_THERMAL_THRSH_MASK,
867 &thermal_thrsh3);
868 if (rc < 0)
869 return rc;
870
871 /* Lower THERMAL_THRSHx thresholds to minimum */
872 rc = qpnp_flash_led_masked_write(led,
873 FLASH_LED_REG_THERMAL_THRSH1(led->base),
874 FLASH_LED_THERMAL_THRSH_MASK,
875 FLASH_LED_THERMAL_THRSH_MIN);
876 if (rc < 0)
877 return rc;
878
879 rc = qpnp_flash_led_masked_write(led,
880 FLASH_LED_REG_THERMAL_THRSH2(led->base),
881 FLASH_LED_THERMAL_THRSH_MASK,
882 FLASH_LED_THERMAL_THRSH_MIN);
883 if (rc < 0)
884 return rc;
885
886 rc = qpnp_flash_led_masked_write(led,
887 FLASH_LED_REG_THERMAL_THRSH3(led->base),
888 FLASH_LED_THERMAL_THRSH_MASK,
889 FLASH_LED_THERMAL_THRSH_MIN);
890 if (rc < 0)
891 return rc;
892
893 /* Check THERMAL_OTST status */
894 rc = qpnp_flash_led_read(led,
895 FLASH_LED_REG_LED_STATUS2(led->base),
896 &otst_status);
897 if (rc < 0)
898 return rc;
899
900 /* Look up current limit based on THERMAL_OTST status */
901 if (otst_status)
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800902 *thermal_current_lim =
David Collins8885f792017-01-26 14:36:34 -0800903 led->pdata->thermal_derate_current[otst_status >> 1];
904
905 /* Restore THERMAL_THRESHx registers to original values */
906 rc = qpnp_flash_led_masked_write(led,
907 FLASH_LED_REG_THERMAL_THRSH1(led->base),
908 FLASH_LED_THERMAL_THRSH_MASK,
909 thermal_thrsh1);
910 if (rc < 0)
911 return rc;
912
913 rc = qpnp_flash_led_masked_write(led,
914 FLASH_LED_REG_THERMAL_THRSH2(led->base),
915 FLASH_LED_THERMAL_THRSH_MASK,
916 thermal_thrsh2);
917 if (rc < 0)
918 return rc;
919
920 rc = qpnp_flash_led_masked_write(led,
921 FLASH_LED_REG_THERMAL_THRSH3(led->base),
922 FLASH_LED_THERMAL_THRSH_MASK,
923 thermal_thrsh3);
924 if (rc < 0)
925 return rc;
926
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800927 return 0;
David Collins8885f792017-01-26 14:36:34 -0800928}
929
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800930static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led,
931 int *max_avail_current)
David Collins8885f792017-01-26 14:36:34 -0800932{
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800933 int thermal_current_lim = 0, rc;
David Collins8885f792017-01-26 14:36:34 -0800934
935 led->trigger_lmh = false;
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800936 rc = qpnp_flash_led_calc_max_current(led, max_avail_current);
937 if (rc < 0) {
938 pr_err("Couldn't calculate max_avail_current, rc=%d\n", rc);
939 return rc;
940 }
941
942 if (led->pdata->thermal_derate_en) {
943 rc = qpnp_flash_led_calc_thermal_current_lim(led,
944 &thermal_current_lim);
945 if (rc < 0) {
946 pr_err("Couldn't calculate thermal_current_lim, rc=%d\n",
947 rc);
948 return rc;
949 }
950 }
David Collins8885f792017-01-26 14:36:34 -0800951
952 if (thermal_current_lim)
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800953 *max_avail_current = min(*max_avail_current,
954 thermal_current_lim);
David Collins8885f792017-01-26 14:36:34 -0800955
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -0800956 return 0;
David Collins8885f792017-01-26 14:36:34 -0800957}
958
Ankit Sharmaa7153c32017-03-22 19:04:52 +0530959static void qpnp_flash_led_aggregate_max_current(struct flash_node_data *fnode)
960{
961 struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
962
963 if (fnode->current_ma)
964 led->total_current_ma += fnode->current_ma
965 - fnode->prev_current_ma;
966 else
967 led->total_current_ma -= fnode->prev_current_ma;
968
969 fnode->prev_current_ma = fnode->current_ma;
970}
971
David Collins8885f792017-01-26 14:36:34 -0800972static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
973{
Kiran Gunda5cadca72017-07-26 14:37:52 +0530974 int i = 0;
David Collins8885f792017-01-26 14:36:34 -0800975 int prgm_current_ma = value;
Ankit Sharma8798ab12017-04-06 15:44:09 +0530976 int min_ma = fnode->ires_ua / 1000;
Ankit Sharmaa7153c32017-03-22 19:04:52 +0530977 struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
David Collins8885f792017-01-26 14:36:34 -0800978
979 if (value <= 0)
980 prgm_current_ma = 0;
Ankit Sharma8798ab12017-04-06 15:44:09 +0530981 else if (value < min_ma)
982 prgm_current_ma = min_ma;
David Collins8885f792017-01-26 14:36:34 -0800983
Kiran Gunda5cadca72017-07-26 14:37:52 +0530984 fnode->ires_idx = fnode->default_ires_idx;
985 fnode->ires_ua = fnode->default_ires_ua;
986
David Collins8885f792017-01-26 14:36:34 -0800987 prgm_current_ma = min(prgm_current_ma, fnode->max_current);
Kiran Gunda5cadca72017-07-26 14:37:52 +0530988 if (prgm_current_ma > max_ires_curr_ma_table[fnode->ires_idx]) {
989 /* find the matching ires */
990 for (i = MAX_IRES_LEVELS - 1; i >= 0; i--) {
991 if (prgm_current_ma <= max_ires_curr_ma_table[i]) {
992 fnode->ires_idx = i;
993 fnode->ires_ua = FLASH_LED_IRES_MIN_UA +
994 (FLASH_LED_IRES_BASE - fnode->ires_idx) *
995 FLASH_LED_IRES_DIVISOR;
996 break;
997 }
998 }
999 }
David Collins8885f792017-01-26 14:36:34 -08001000 fnode->current_ma = prgm_current_ma;
1001 fnode->cdev.brightness = prgm_current_ma;
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -08001002 fnode->current_reg_val = get_current_reg_code(prgm_current_ma,
David Collins8885f792017-01-26 14:36:34 -08001003 fnode->ires_ua);
1004 fnode->led_on = prgm_current_ma != 0;
Ankit Sharmaa7153c32017-03-22 19:04:52 +05301005
1006 if (led->pdata->chgr_mitigation_sel == FLASH_SW_CHARGER_MITIGATION) {
1007 qpnp_flash_led_aggregate_max_current(fnode);
1008 led->trigger_chgr = false;
1009 if (led->total_current_ma >= 1000)
1010 led->trigger_chgr = true;
1011 }
David Collins8885f792017-01-26 14:36:34 -08001012}
1013
1014static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
1015{
1016 struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
1017 int i, rc, addr_offset;
1018
1019 rc = qpnp_flash_led_masked_write(led,
1020 FLASH_LED_EN_LED_CTRL(led->base),
1021 snode->led_mask, FLASH_LED_DISABLE);
1022 if (rc < 0)
1023 return rc;
1024
1025 if (led->trigger_lmh) {
1026 rc = qpnp_flash_led_masked_write(led,
1027 FLASH_LED_REG_MITIGATION_SW(led->base),
1028 FLASH_LED_LMH_MITIGATION_EN_MASK,
1029 FLASH_LED_LMH_MITIGATION_DISABLE);
1030 if (rc < 0) {
1031 pr_err("disable lmh mitigation failed, rc=%d\n", rc);
1032 return rc;
1033 }
1034 }
1035
1036 if (!led->trigger_chgr) {
1037 rc = qpnp_flash_led_masked_write(led,
1038 FLASH_LED_REG_MITIGATION_SW(led->base),
1039 FLASH_LED_CHGR_MITIGATION_EN_MASK,
1040 FLASH_LED_CHGR_MITIGATION_DISABLE);
1041 if (rc < 0) {
1042 pr_err("disable chgr mitigation failed, rc=%d\n", rc);
1043 return rc;
1044 }
1045 }
1046
1047 led->enable--;
1048 if (led->enable == 0) {
1049 rc = qpnp_flash_led_masked_write(led,
1050 FLASH_LED_REG_MOD_CTRL(led->base),
1051 FLASH_LED_MOD_CTRL_MASK, FLASH_LED_DISABLE);
1052 if (rc < 0)
1053 return rc;
1054 }
1055
1056 for (i = 0; i < led->num_fnodes; i++) {
1057 if (!led->fnode[i].led_on ||
1058 !(snode->led_mask & BIT(led->fnode[i].id)))
1059 continue;
1060
1061 addr_offset = led->fnode[i].id;
1062 rc = qpnp_flash_led_masked_write(led,
1063 FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
1064 FLASH_LED_CURRENT_MASK, 0);
1065 if (rc < 0)
1066 return rc;
1067
1068 led->fnode[i].led_on = false;
1069
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001070 if (led->fnode[i].strobe_sel == HW_STROBE) {
David Collins8885f792017-01-26 14:36:34 -08001071 rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
1072 led->pdata->hw_strobe_option, false);
1073 if (rc < 0) {
1074 pr_err("Unable to disable hw strobe, rc=%d\n",
1075 rc);
1076 return rc;
1077 }
1078 }
1079 }
1080
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -07001081 if (snode->led_en_pinctrl) {
1082 pr_debug("Selecting suspend state for %s\n", snode->cdev.name);
1083 rc = pinctrl_select_state(snode->led_en_pinctrl,
1084 snode->gpio_state_suspend);
1085 if (rc < 0) {
1086 pr_err("failed to select pinctrl suspend state rc=%d\n",
1087 rc);
1088 return rc;
1089 }
1090 }
1091
David Collins8885f792017-01-26 14:36:34 -08001092 snode->enabled = false;
1093 return 0;
1094}
1095
Subbaraman Narayanamurthyd737fd52018-01-17 19:58:52 -08001096static int qpnp_flash_led_symmetry_config(struct flash_switch_data *snode)
1097{
1098 struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
1099 int i, total_curr_ma = 0, num_leds = 0, prgm_current_ma;
1100 enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN;
1101
1102 for (i = 0; i < led->num_fnodes; i++) {
1103 if (snode->led_mask & BIT(led->fnode[i].id)) {
1104 if (led->fnode[i].type == FLASH_LED_TYPE_FLASH &&
1105 led->fnode[i].led_on)
1106 type = FLASH_LED_TYPE_FLASH;
1107
1108 if (led->fnode[i].type == FLASH_LED_TYPE_TORCH &&
1109 led->fnode[i].led_on)
1110 type = FLASH_LED_TYPE_TORCH;
1111 }
1112 }
1113
1114 if (type == FLASH_LED_TYPE_UNKNOWN) {
1115 pr_err("Incorrect type possibly because of no active LEDs\n");
1116 return -EINVAL;
1117 }
1118
1119 for (i = 0; i < led->num_fnodes; i++) {
1120 if ((snode->led_mask & BIT(led->fnode[i].id)) &&
1121 (led->fnode[i].type == type)) {
1122 total_curr_ma += led->fnode[i].current_ma;
1123 num_leds++;
1124 }
1125 }
1126
1127 if (num_leds > 0 && total_curr_ma > 0) {
1128 prgm_current_ma = total_curr_ma / num_leds;
1129 } else {
1130 pr_err("Incorrect configuration, num_leds: %d total_curr_ma: %d\n",
1131 num_leds, total_curr_ma);
1132 return -EINVAL;
1133 }
1134
1135 if (prgm_current_ma == 0) {
1136 pr_warn("prgm_curr_ma cannot be 0\n");
1137 return 0;
1138 }
1139
1140 pr_debug("num_leds: %d total: %d prgm_curr_ma: %d\n", num_leds,
1141 total_curr_ma, prgm_current_ma);
1142
1143 for (i = 0; i < led->num_fnodes; i++) {
1144 if (snode->led_mask & BIT(led->fnode[i].id) &&
1145 led->fnode[i].current_ma != prgm_current_ma &&
1146 led->fnode[i].type == type) {
1147 qpnp_flash_led_node_set(&led->fnode[i],
1148 prgm_current_ma);
1149 pr_debug("%s LED %d current: %d code: %d ires_ua: %d\n",
1150 (type == FLASH_LED_TYPE_FLASH) ?
1151 "flash" : "torch",
1152 led->fnode[i].id, prgm_current_ma,
1153 led->fnode[i].current_reg_val,
1154 led->fnode[i].ires_ua);
1155 }
1156 }
1157
1158 return 0;
1159}
1160
David Collins8885f792017-01-26 14:36:34 -08001161static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
1162{
1163 struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
1164 int rc, i, addr_offset;
1165 u8 val, mask;
1166
1167 if (snode->enabled == on) {
1168 pr_debug("Switch node is already %s!\n",
1169 on ? "enabled" : "disabled");
1170 return 0;
1171 }
1172
1173 if (!on) {
1174 rc = qpnp_flash_led_switch_disable(snode);
1175 return rc;
1176 }
1177
Subbaraman Narayanamurthy411699a2018-01-15 12:40:49 -08001178 /* Iterate over all active leds for this switch node */
Subbaraman Narayanamurthyd737fd52018-01-17 19:58:52 -08001179 if (snode->symmetry_en) {
1180 rc = qpnp_flash_led_symmetry_config(snode);
1181 if (rc < 0) {
1182 pr_err("Failed to configure current symmetrically, rc=%d\n",
1183 rc);
1184 return rc;
1185 }
1186 }
1187
David Collins8885f792017-01-26 14:36:34 -08001188 val = 0;
1189 for (i = 0; i < led->num_fnodes; i++)
Subbaraman Narayanamurthy411699a2018-01-15 12:40:49 -08001190 if (led->fnode[i].led_on &&
1191 snode->led_mask & BIT(led->fnode[i].id))
Kiran Gunda5cadca72017-07-26 14:37:52 +05301192 val |= led->fnode[i].ires_idx << (led->fnode[i].id * 2);
David Collins8885f792017-01-26 14:36:34 -08001193
1194 rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_IRES(led->base),
1195 FLASH_LED_CURRENT_MASK, val);
1196 if (rc < 0)
1197 return rc;
1198
David Collins8885f792017-01-26 14:36:34 -08001199 val = 0;
1200 for (i = 0; i < led->num_fnodes; i++) {
1201 if (!led->fnode[i].led_on ||
1202 !(snode->led_mask & BIT(led->fnode[i].id)))
1203 continue;
1204
1205 addr_offset = led->fnode[i].id;
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001206 if (led->fnode[i].strobe_sel == SW_STROBE)
David Collins8885f792017-01-26 14:36:34 -08001207 mask = FLASH_LED_HW_SW_STROBE_SEL_BIT;
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001208 else
1209 mask = FLASH_HW_STROBE_MASK;
David Collins8885f792017-01-26 14:36:34 -08001210 rc = qpnp_flash_led_masked_write(led,
1211 FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset),
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001212 mask, led->fnode[i].strobe_ctrl);
David Collins8885f792017-01-26 14:36:34 -08001213 if (rc < 0)
1214 return rc;
1215
1216 rc = qpnp_flash_led_masked_write(led,
1217 FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
1218 FLASH_LED_CURRENT_MASK, led->fnode[i].current_reg_val);
1219 if (rc < 0)
1220 return rc;
1221
1222 rc = qpnp_flash_led_write(led,
1223 FLASH_LED_REG_SAFETY_TMR(led->base + addr_offset),
1224 led->fnode[i].duration);
1225 if (rc < 0)
1226 return rc;
1227
1228 val |= FLASH_LED_ENABLE << led->fnode[i].id;
1229
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001230 if (led->fnode[i].strobe_sel == HW_STROBE) {
David Collins8885f792017-01-26 14:36:34 -08001231 rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
1232 led->pdata->hw_strobe_option, true);
1233 if (rc < 0) {
1234 pr_err("Unable to enable hw strobe rc=%d\n",
1235 rc);
1236 return rc;
1237 }
1238 }
1239 }
1240
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -07001241 if (snode->led_en_pinctrl) {
1242 pr_debug("Selecting active state for %s\n", snode->cdev.name);
1243 rc = pinctrl_select_state(snode->led_en_pinctrl,
1244 snode->gpio_state_active);
1245 if (rc < 0) {
1246 pr_err("failed to select pinctrl active state rc=%d\n",
1247 rc);
1248 return rc;
1249 }
1250 }
1251
David Collins8885f792017-01-26 14:36:34 -08001252 if (led->enable == 0) {
1253 rc = qpnp_flash_led_masked_write(led,
1254 FLASH_LED_REG_MOD_CTRL(led->base),
1255 FLASH_LED_MOD_CTRL_MASK, FLASH_LED_MOD_ENABLE);
1256 if (rc < 0)
1257 return rc;
1258 }
1259 led->enable++;
1260
1261 if (led->trigger_lmh) {
1262 rc = qpnp_flash_led_masked_write(led,
1263 FLASH_LED_REG_MITIGATION_SW(led->base),
1264 FLASH_LED_LMH_MITIGATION_EN_MASK,
1265 FLASH_LED_LMH_MITIGATION_ENABLE);
1266 if (rc < 0) {
1267 pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
1268 return rc;
1269 }
Subbaraman Narayanamurthyd02fbc92017-02-02 16:39:41 -08001270 /* Wait for LMH mitigation to take effect */
1271 udelay(500);
David Collins8885f792017-01-26 14:36:34 -08001272 }
1273
1274 if (led->trigger_chgr) {
1275 rc = qpnp_flash_led_masked_write(led,
1276 FLASH_LED_REG_MITIGATION_SW(led->base),
1277 FLASH_LED_CHGR_MITIGATION_EN_MASK,
1278 FLASH_LED_CHGR_MITIGATION_ENABLE);
1279 if (rc < 0) {
1280 pr_err("trigger chgr mitigation failed, rc=%d\n", rc);
1281 return rc;
1282 }
1283 }
1284
1285 rc = qpnp_flash_led_masked_write(led,
1286 FLASH_LED_EN_LED_CTRL(led->base),
1287 snode->led_mask, val);
1288 if (rc < 0)
1289 return rc;
1290
1291 snode->enabled = true;
1292 return 0;
1293}
1294
Kiran Gundabf1e6c02018-01-17 17:50:20 +05301295static int qpnp_flash_led_prepare_v2(struct led_trigger *trig, int options,
David Collins8885f792017-01-26 14:36:34 -08001296 int *max_current)
1297{
1298 struct led_classdev *led_cdev;
1299 struct flash_switch_data *snode;
1300 struct qpnp_flash_led *led;
1301 int rc;
1302
1303 if (!trig) {
1304 pr_err("Invalid led_trigger provided\n");
1305 return -EINVAL;
1306 }
1307
1308 led_cdev = trigger_to_lcdev(trig);
1309 if (!led_cdev) {
1310 pr_err("Invalid led_cdev in trigger %s\n", trig->name);
1311 return -EINVAL;
1312 }
1313
1314 snode = container_of(led_cdev, struct flash_switch_data, cdev);
1315 led = dev_get_drvdata(&snode->pdev->dev);
1316
1317 if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) {
1318 pr_err("Invalid options %d\n", options);
1319 return -EINVAL;
1320 }
1321
1322 if (options & ENABLE_REGULATOR) {
1323 rc = qpnp_flash_led_regulator_enable(led, snode, true);
1324 if (rc < 0) {
1325 pr_err("enable regulator failed, rc=%d\n", rc);
1326 return rc;
1327 }
1328 }
1329
1330 if (options & DISABLE_REGULATOR) {
1331 rc = qpnp_flash_led_regulator_enable(led, snode, false);
1332 if (rc < 0) {
1333 pr_err("disable regulator failed, rc=%d\n", rc);
1334 return rc;
1335 }
1336 }
1337
1338 if (options & QUERY_MAX_CURRENT) {
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -08001339 rc = qpnp_flash_led_get_max_avail_current(led, max_current);
David Collins8885f792017-01-26 14:36:34 -08001340 if (rc < 0) {
1341 pr_err("query max current failed, rc=%d\n", rc);
1342 return rc;
1343 }
David Collins8885f792017-01-26 14:36:34 -08001344 }
1345
David Collins8885f792017-01-26 14:36:34 -08001346 return 0;
1347}
1348
1349static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
1350 enum led_brightness value)
1351{
1352 struct flash_node_data *fnode = NULL;
1353 struct flash_switch_data *snode = NULL;
1354 struct qpnp_flash_led *led = NULL;
1355 int rc;
1356
1357 /*
1358 * strncmp() must be used here since a prefix comparison is required
1359 * in order to support names like led:switch_0 and led:flash_1.
1360 */
1361 if (!strncmp(led_cdev->name, "led:switch", strlen("led:switch"))) {
1362 snode = container_of(led_cdev, struct flash_switch_data, cdev);
1363 led = dev_get_drvdata(&snode->pdev->dev);
1364 } else if (!strncmp(led_cdev->name, "led:flash", strlen("led:flash")) ||
1365 !strncmp(led_cdev->name, "led:torch",
1366 strlen("led:torch"))) {
1367 fnode = container_of(led_cdev, struct flash_node_data, cdev);
1368 led = dev_get_drvdata(&fnode->pdev->dev);
1369 }
1370
1371 if (!led) {
1372 pr_err("Failed to get flash driver data\n");
1373 return;
1374 }
1375
1376 spin_lock(&led->lock);
1377 if (snode) {
1378 rc = qpnp_flash_led_switch_set(snode, value > 0);
1379 if (rc < 0)
1380 pr_err("Failed to set flash LED switch rc=%d\n", rc);
1381 } else if (fnode) {
1382 qpnp_flash_led_node_set(fnode, value);
1383 }
1384
1385 spin_unlock(&led->lock);
1386}
1387
1388/* sysfs show function for flash_max_current */
1389static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
1390 struct device_attribute *attr, char *buf)
1391{
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -08001392 int rc, max_current = 0;
David Collins8885f792017-01-26 14:36:34 -08001393 struct flash_switch_data *snode;
1394 struct qpnp_flash_led *led;
1395 struct led_classdev *led_cdev = dev_get_drvdata(dev);
1396
1397 snode = container_of(led_cdev, struct flash_switch_data, cdev);
1398 led = dev_get_drvdata(&snode->pdev->dev);
1399
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -08001400 rc = qpnp_flash_led_get_max_avail_current(led, &max_current);
David Collins8885f792017-01-26 14:36:34 -08001401 if (rc < 0)
1402 pr_err("query max current failed, rc=%d\n", rc);
1403
Subbaraman Narayanamurthyd94945e2017-11-28 19:54:09 -08001404 return snprintf(buf, PAGE_SIZE, "%d\n", max_current);
David Collins8885f792017-01-26 14:36:34 -08001405}
1406
1407/* sysfs attributes exported by flash_led */
1408static struct device_attribute qpnp_flash_led_attrs[] = {
1409 __ATTR(max_current, 0664, qpnp_flash_led_max_current_show, NULL),
1410};
1411
1412static int flash_led_psy_notifier_call(struct notifier_block *nb,
1413 unsigned long ev, void *v)
1414{
1415 struct power_supply *psy = v;
1416 struct qpnp_flash_led *led =
1417 container_of(nb, struct qpnp_flash_led, nb);
1418
1419 if (ev != PSY_EVENT_PROP_CHANGED)
1420 return NOTIFY_OK;
1421
1422 if (!strcmp(psy->desc->name, "bms")) {
1423 led->bms_psy = power_supply_get_by_name("bms");
1424 if (!led->bms_psy)
1425 pr_err("Failed to get bms power_supply\n");
1426 else
1427 power_supply_unreg_notifier(&led->nb);
1428 }
1429
1430 return NOTIFY_OK;
1431}
1432
1433static int flash_led_psy_register_notifier(struct qpnp_flash_led *led)
1434{
1435 int rc;
1436
1437 led->nb.notifier_call = flash_led_psy_notifier_call;
1438 rc = power_supply_reg_notifier(&led->nb);
1439 if (rc < 0) {
1440 pr_err("Couldn't register psy notifier, rc = %d\n", rc);
1441 return rc;
1442 }
1443
1444 return 0;
1445}
1446
1447/* irq handler */
1448static irqreturn_t qpnp_flash_led_irq_handler(int irq, void *_led)
1449{
1450 struct qpnp_flash_led *led = _led;
1451 enum flash_led_irq_type irq_type = INVALID_IRQ;
1452 int rc;
1453 u8 irq_status, led_status1, led_status2;
1454
1455 pr_debug("irq received, irq=%d\n", irq);
1456
1457 rc = qpnp_flash_led_read(led,
1458 FLASH_LED_REG_INT_RT_STS(led->base), &irq_status);
1459 if (rc < 0) {
1460 pr_err("Failed to read interrupt status reg, rc=%d\n", rc);
1461 goto exit;
1462 }
1463
1464 if (irq == led->pdata->all_ramp_up_done_irq)
1465 irq_type = ALL_RAMP_UP_DONE_IRQ;
1466 else if (irq == led->pdata->all_ramp_down_done_irq)
1467 irq_type = ALL_RAMP_DOWN_DONE_IRQ;
1468 else if (irq == led->pdata->led_fault_irq)
1469 irq_type = LED_FAULT_IRQ;
1470
1471 if (irq_type == ALL_RAMP_UP_DONE_IRQ)
1472 atomic_notifier_call_chain(&irq_notifier_list,
1473 irq_type, NULL);
1474
1475 if (irq_type == LED_FAULT_IRQ) {
1476 rc = qpnp_flash_led_read(led,
1477 FLASH_LED_REG_LED_STATUS1(led->base), &led_status1);
1478 if (rc < 0) {
1479 pr_err("Failed to read led_status1 reg, rc=%d\n", rc);
1480 goto exit;
1481 }
1482
1483 rc = qpnp_flash_led_read(led,
1484 FLASH_LED_REG_LED_STATUS2(led->base), &led_status2);
1485 if (rc < 0) {
1486 pr_err("Failed to read led_status2 reg, rc=%d\n", rc);
1487 goto exit;
1488 }
1489
1490 if (led_status1)
1491 pr_emerg("led short/open fault detected! led_status1=%x\n",
1492 led_status1);
1493
1494 if (led_status2 & FLASH_LED_VPH_DROOP_FAULT_MASK)
1495 pr_emerg("led vph_droop fault detected!\n");
1496 }
1497
1498 pr_debug("irq handled, irq_type=%x, irq_status=%x\n", irq_type,
1499 irq_status);
1500
1501exit:
1502 return IRQ_HANDLED;
1503}
1504
1505int qpnp_flash_led_register_irq_notifier(struct notifier_block *nb)
1506{
1507 return atomic_notifier_chain_register(&irq_notifier_list, nb);
1508}
1509
1510int qpnp_flash_led_unregister_irq_notifier(struct notifier_block *nb)
1511{
1512 return atomic_notifier_chain_unregister(&irq_notifier_list, nb);
1513}
1514
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -08001515static inline u8 get_safety_timer_code(u32 duration_ms)
1516{
1517 if (!duration_ms)
1518 return 0;
1519
1520 return (duration_ms / 10) - 1;
1521}
1522
1523static inline u8 get_vph_droop_thresh_code(u32 val_mv)
1524{
1525 if (!val_mv)
1526 return 0;
1527
1528 return (val_mv / 100) - 25;
1529}
1530
David Collins8885f792017-01-26 14:36:34 -08001531static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
1532 struct flash_node_data *fnode, struct device_node *node)
1533{
1534 const char *temp_string;
Ankit Sharma8798ab12017-04-06 15:44:09 +05301535 int rc, min_ma;
David Collins8885f792017-01-26 14:36:34 -08001536 u32 val;
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001537 bool hw_strobe = 0, edge_trigger = 0, active_high = 0;
David Collins8885f792017-01-26 14:36:34 -08001538
1539 fnode->pdev = led->pdev;
1540 fnode->cdev.brightness_set = qpnp_flash_led_brightness_set;
1541 fnode->cdev.brightness_get = qpnp_flash_led_brightness_get;
1542
1543 rc = of_property_read_string(node, "qcom,led-name", &fnode->cdev.name);
1544 if (rc < 0) {
1545 pr_err("Unable to read flash LED names\n");
1546 return rc;
1547 }
1548
1549 rc = of_property_read_string(node, "label", &temp_string);
1550 if (!rc) {
1551 if (!strcmp(temp_string, "flash")) {
1552 fnode->type = FLASH_LED_TYPE_FLASH;
1553 } else if (!strcmp(temp_string, "torch")) {
1554 fnode->type = FLASH_LED_TYPE_TORCH;
1555 } else {
1556 pr_err("Wrong flash LED type\n");
1557 return rc;
1558 }
1559 } else {
1560 pr_err("Unable to read flash LED label\n");
1561 return rc;
1562 }
1563
1564 rc = of_property_read_u32(node, "qcom,id", &val);
1565 if (!rc) {
1566 fnode->id = (u8)val;
1567 } else {
1568 pr_err("Unable to read flash LED ID\n");
1569 return rc;
1570 }
1571
1572 rc = of_property_read_string(node, "qcom,default-led-trigger",
1573 &fnode->cdev.default_trigger);
1574 if (rc < 0) {
1575 pr_err("Unable to read trigger name\n");
1576 return rc;
1577 }
1578
Kiran Gunda5cadca72017-07-26 14:37:52 +05301579 fnode->default_ires_ua = fnode->ires_ua = FLASH_LED_IRES_DEFAULT_UA;
1580 fnode->default_ires_idx = fnode->ires_idx = FLASH_LED_IRES_DEFAULT_VAL;
David Collins8885f792017-01-26 14:36:34 -08001581 rc = of_property_read_u32(node, "qcom,ires-ua", &val);
1582 if (!rc) {
Kiran Gunda5cadca72017-07-26 14:37:52 +05301583 fnode->default_ires_ua = fnode->ires_ua = val;
1584 fnode->default_ires_idx = fnode->ires_idx =
1585 FLASH_LED_IRES_BASE - (val - FLASH_LED_IRES_MIN_UA) /
1586 FLASH_LED_IRES_DIVISOR;
David Collins8885f792017-01-26 14:36:34 -08001587 } else if (rc != -EINVAL) {
1588 pr_err("Unable to read current resolution rc=%d\n", rc);
1589 return rc;
1590 }
1591
Ankit Sharma8798ab12017-04-06 15:44:09 +05301592 min_ma = fnode->ires_ua / 1000;
David Collins8885f792017-01-26 14:36:34 -08001593 rc = of_property_read_u32(node, "qcom,max-current", &val);
1594 if (!rc) {
Ankit Sharma8798ab12017-04-06 15:44:09 +05301595 if (val < min_ma)
1596 val = min_ma;
David Collins8885f792017-01-26 14:36:34 -08001597 fnode->max_current = val;
1598 fnode->cdev.max_brightness = val;
1599 } else {
1600 pr_err("Unable to read max current, rc=%d\n", rc);
1601 return rc;
1602 }
1603
1604 rc = of_property_read_u32(node, "qcom,current-ma", &val);
1605 if (!rc) {
Ankit Sharma8798ab12017-04-06 15:44:09 +05301606 if (val < min_ma || val > fnode->max_current)
David Collins8885f792017-01-26 14:36:34 -08001607 pr_warn("Invalid operational current specified, capping it\n");
Ankit Sharma8798ab12017-04-06 15:44:09 +05301608 if (val < min_ma)
1609 val = min_ma;
David Collins8885f792017-01-26 14:36:34 -08001610 if (val > fnode->max_current)
1611 val = fnode->max_current;
1612 fnode->current_ma = val;
1613 fnode->cdev.brightness = val;
1614 } else if (rc != -EINVAL) {
1615 pr_err("Unable to read operational current, rc=%d\n", rc);
1616 return rc;
1617 }
1618
1619 fnode->duration = FLASH_LED_SAFETY_TMR_DISABLED;
1620 rc = of_property_read_u32(node, "qcom,duration-ms", &val);
1621 if (!rc) {
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -08001622 fnode->duration = get_safety_timer_code(val);
1623 if (fnode->duration)
1624 fnode->duration |= FLASH_LED_SAFETY_TMR_ENABLE;
David Collins8885f792017-01-26 14:36:34 -08001625 } else if (rc == -EINVAL) {
1626 if (fnode->type == FLASH_LED_TYPE_FLASH) {
1627 pr_err("Timer duration is required for flash LED\n");
1628 return rc;
1629 }
1630 } else {
1631 pr_err("Unable to read timer duration\n");
1632 return rc;
1633 }
1634
1635 fnode->hdrm_val = FLASH_LED_HDRM_VOL_DEFAULT_MV;
1636 rc = of_property_read_u32(node, "qcom,hdrm-voltage-mv", &val);
1637 if (!rc) {
1638 val = (val - FLASH_LED_HDRM_VOL_BASE_MV) /
1639 FLASH_LED_HDRM_VOL_STEP_MV;
1640 fnode->hdrm_val = (val << FLASH_LED_HDRM_VOL_SHIFT) &
1641 FLASH_LED_HDRM_VOL_MASK;
1642 } else if (rc != -EINVAL) {
1643 pr_err("Unable to read headroom voltage\n");
1644 return rc;
1645 }
1646
1647 rc = of_property_read_u32(node, "qcom,hdrm-vol-hi-lo-win-mv", &val);
1648 if (!rc) {
1649 fnode->hdrm_val |= (val / FLASH_LED_HDRM_VOL_STEP_MV) &
1650 ~FLASH_LED_HDRM_VOL_MASK;
1651 } else if (rc == -EINVAL) {
1652 fnode->hdrm_val |= FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV;
1653 } else {
1654 pr_err("Unable to read hdrm hi-lo window voltage\n");
1655 return rc;
1656 }
1657
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001658 fnode->strobe_sel = SW_STROBE;
1659 rc = of_property_read_u32(node, "qcom,strobe-sel", &val);
1660 if (rc < 0) {
1661 if (rc != -EINVAL) {
1662 pr_err("Unable to read qcom,strobe-sel property\n");
1663 return rc;
1664 }
1665 } else {
1666 if (val < SW_STROBE || val > LPG_STROBE) {
1667 pr_err("Incorrect strobe selection specified %d\n",
1668 val);
1669 return -EINVAL;
1670 }
1671 fnode->strobe_sel = (u8)val;
1672 }
1673
1674 /*
1675 * LPG strobe is allowed only for LED3 and HW strobe option should be
1676 * option 2 or 3.
1677 */
1678 if (fnode->strobe_sel == LPG_STROBE) {
1679 if (led->pdata->hw_strobe_option ==
1680 FLASH_LED_HW_STROBE_OPTION_1) {
1681 pr_err("Incorrect strobe option for LPG strobe\n");
1682 return -EINVAL;
1683 }
1684 if (fnode->id != LED3) {
1685 pr_err("Incorrect LED chosen for LPG strobe\n");
1686 return -EINVAL;
1687 }
1688 }
1689
1690 if (fnode->strobe_sel == HW_STROBE) {
David Collins8885f792017-01-26 14:36:34 -08001691 edge_trigger = of_property_read_bool(node,
1692 "qcom,hw-strobe-edge-trigger");
1693 active_high = !of_property_read_bool(node,
1694 "qcom,hw-strobe-active-low");
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001695 hw_strobe = 1;
1696 } else if (fnode->strobe_sel == LPG_STROBE) {
1697 /* LPG strobe requires level trigger and active high */
1698 edge_trigger = 0;
1699 active_high = 1;
1700 hw_strobe = 1;
David Collins8885f792017-01-26 14:36:34 -08001701 }
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001702 fnode->strobe_ctrl = (hw_strobe << 2) | (edge_trigger << 1) |
1703 active_high;
David Collins8885f792017-01-26 14:36:34 -08001704
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -07001705 rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
1706 if (rc < 0) {
1707 pr_err("Unable to register led node %d\n", fnode->id);
1708 return rc;
1709 }
1710
1711 fnode->cdev.dev->of_node = node;
1712 fnode->strobe_pinctrl = devm_pinctrl_get(fnode->cdev.dev);
1713 if (IS_ERR_OR_NULL(fnode->strobe_pinctrl)) {
1714 pr_debug("No pinctrl defined for %s, err=%ld\n",
1715 fnode->cdev.name, PTR_ERR(fnode->strobe_pinctrl));
1716 fnode->strobe_pinctrl = NULL;
1717 }
1718
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07001719 if (fnode->strobe_sel == HW_STROBE) {
David Collins8885f792017-01-26 14:36:34 -08001720 if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
1721 fnode->hw_strobe_gpio = of_get_named_gpio(node,
1722 "qcom,hw-strobe-gpio", 0);
1723 if (fnode->hw_strobe_gpio < 0) {
1724 pr_err("Invalid gpio specified\n");
1725 return fnode->hw_strobe_gpio;
1726 }
1727 gpio_direction_output(fnode->hw_strobe_gpio, 0);
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -07001728 } else if (fnode->strobe_pinctrl) {
David Collins8885f792017-01-26 14:36:34 -08001729 fnode->hw_strobe_gpio = -1;
1730 fnode->hw_strobe_state_active =
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -07001731 pinctrl_lookup_state(fnode->strobe_pinctrl,
1732 "strobe_enable");
David Collins8885f792017-01-26 14:36:34 -08001733 if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) {
1734 pr_err("No active pin for hardware strobe, rc=%ld\n",
1735 PTR_ERR(fnode->hw_strobe_state_active));
1736 fnode->hw_strobe_state_active = NULL;
1737 }
1738
1739 fnode->hw_strobe_state_suspend =
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -07001740 pinctrl_lookup_state(fnode->strobe_pinctrl,
1741 "strobe_disable");
David Collins8885f792017-01-26 14:36:34 -08001742 if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) {
1743 pr_err("No suspend pin for hardware strobe, rc=%ld\n",
1744 PTR_ERR(fnode->hw_strobe_state_suspend)
1745 );
1746 fnode->hw_strobe_state_suspend = NULL;
1747 }
1748 }
1749 }
1750
David Collins8885f792017-01-26 14:36:34 -08001751 return 0;
1752}
1753
1754static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led,
1755 struct flash_switch_data *snode,
1756 struct device_node *node)
1757{
1758 int rc = 0, num;
1759 char reg_name[16], reg_sup_name[16];
1760
1761 rc = of_property_read_string(node, "qcom,led-name", &snode->cdev.name);
1762 if (rc < 0) {
1763 pr_err("Failed to read switch node name, rc=%d\n", rc);
1764 return rc;
1765 }
1766
1767 rc = sscanf(snode->cdev.name, "led:switch_%d", &num);
1768 if (!rc) {
1769 pr_err("No number for switch device?\n");
1770 return -EINVAL;
1771 }
1772
1773 rc = of_property_read_string(node, "qcom,default-led-trigger",
1774 &snode->cdev.default_trigger);
1775 if (rc < 0) {
1776 pr_err("Unable to read trigger name, rc=%d\n", rc);
1777 return rc;
1778 }
1779
1780 rc = of_property_read_u32(node, "qcom,led-mask", &snode->led_mask);
1781 if (rc < 0) {
1782 pr_err("Unable to read led mask rc=%d\n", rc);
1783 return rc;
1784 }
1785
Subbaraman Narayanamurthyd737fd52018-01-17 19:58:52 -08001786 snode->symmetry_en = of_property_read_bool(node, "qcom,symmetry-en");
1787
David Collins8885f792017-01-26 14:36:34 -08001788 if (snode->led_mask < 1 || snode->led_mask > 7) {
1789 pr_err("Invalid value for led-mask\n");
1790 return -EINVAL;
1791 }
1792
1793 scnprintf(reg_name, sizeof(reg_name), "switch%d-supply", num);
1794 if (of_find_property(led->pdev->dev.of_node, reg_name, NULL)) {
1795 scnprintf(reg_sup_name, sizeof(reg_sup_name), "switch%d", num);
1796 snode->vreg = devm_regulator_get(&led->pdev->dev, reg_sup_name);
1797 if (IS_ERR_OR_NULL(snode->vreg)) {
1798 rc = PTR_ERR(snode->vreg);
1799 if (rc != -EPROBE_DEFER)
1800 pr_err("Failed to get regulator, rc=%d\n", rc);
1801 snode->vreg = NULL;
1802 return rc;
1803 }
1804 }
1805
1806 snode->pdev = led->pdev;
1807 snode->cdev.brightness_set = qpnp_flash_led_brightness_set;
1808 snode->cdev.brightness_get = qpnp_flash_led_brightness_get;
1809 snode->cdev.flags |= LED_KEEP_TRIGGER;
1810 rc = led_classdev_register(&led->pdev->dev, &snode->cdev);
1811 if (rc < 0) {
1812 pr_err("Unable to register led switch node\n");
1813 return rc;
1814 }
1815
1816 snode->cdev.dev->of_node = node;
Subbaraman Narayanamurthy58377f02017-03-21 20:38:43 -07001817
1818 snode->led_en_pinctrl = devm_pinctrl_get(snode->cdev.dev);
1819 if (IS_ERR_OR_NULL(snode->led_en_pinctrl)) {
1820 pr_debug("No pinctrl defined for %s, err=%ld\n",
1821 snode->cdev.name, PTR_ERR(snode->led_en_pinctrl));
1822 snode->led_en_pinctrl = NULL;
1823 }
1824
1825 if (snode->led_en_pinctrl) {
1826 snode->gpio_state_active =
1827 pinctrl_lookup_state(snode->led_en_pinctrl,
1828 "led_enable");
1829 if (IS_ERR_OR_NULL(snode->gpio_state_active)) {
1830 pr_err("Cannot lookup LED active state\n");
1831 devm_pinctrl_put(snode->led_en_pinctrl);
1832 snode->led_en_pinctrl = NULL;
1833 return PTR_ERR(snode->gpio_state_active);
1834 }
1835
1836 snode->gpio_state_suspend =
1837 pinctrl_lookup_state(snode->led_en_pinctrl,
1838 "led_disable");
1839 if (IS_ERR_OR_NULL(snode->gpio_state_suspend)) {
1840 pr_err("Cannot lookup LED disable state\n");
1841 devm_pinctrl_put(snode->led_en_pinctrl);
1842 snode->led_en_pinctrl = NULL;
1843 return PTR_ERR(snode->gpio_state_suspend);
1844 }
1845 }
1846
David Collins8885f792017-01-26 14:36:34 -08001847 return 0;
1848}
1849
1850static int get_code_from_table(int *table, int len, int value)
1851{
1852 int i;
1853
1854 for (i = 0; i < len; i++) {
1855 if (value == table[i])
1856 break;
1857 }
1858
1859 if (i == len) {
1860 pr_err("Couldn't find %d from table\n", value);
1861 return -ENODATA;
1862 }
1863
1864 return i;
1865}
1866
1867static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
1868 struct device_node *node)
1869{
1870 struct device_node *revid_node;
1871 int rc;
1872 u32 val;
1873 bool short_circuit_det, open_circuit_det, vph_droop_det;
1874
1875 revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
1876 if (!revid_node) {
1877 pr_err("Missing qcom,pmic-revid property - driver failed\n");
1878 return -EINVAL;
1879 }
1880
1881 led->pdata->pmic_rev_id = get_revid_data(revid_node);
1882 if (IS_ERR_OR_NULL(led->pdata->pmic_rev_id)) {
1883 pr_err("Unable to get pmic_revid rc=%ld\n",
1884 PTR_ERR(led->pdata->pmic_rev_id));
1885 /*
1886 * the revid peripheral must be registered, any failure
1887 * here only indicates that the rev-id module has not
1888 * probed yet.
1889 */
1890 return -EPROBE_DEFER;
1891 }
1892
1893 pr_debug("PMIC subtype %d Digital major %d\n",
1894 led->pdata->pmic_rev_id->pmic_subtype,
1895 led->pdata->pmic_rev_id->rev4);
1896
1897 led->pdata->hdrm_auto_mode_en = of_property_read_bool(node,
1898 "qcom,hdrm-auto-mode");
1899
1900 led->pdata->isc_delay = FLASH_LED_ISC_DELAY_DEFAULT;
1901 rc = of_property_read_u32(node, "qcom,isc-delay-us", &val);
1902 if (!rc) {
1903 led->pdata->isc_delay =
1904 val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
1905 } else if (rc != -EINVAL) {
1906 pr_err("Unable to read ISC delay, rc=%d\n", rc);
1907 return rc;
1908 }
1909
1910 led->pdata->warmup_delay = FLASH_LED_WARMUP_DELAY_DEFAULT;
1911 rc = of_property_read_u32(node, "qcom,warmup-delay-us", &val);
1912 if (!rc) {
1913 led->pdata->warmup_delay =
1914 val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
1915 } else if (rc != -EINVAL) {
1916 pr_err("Unable to read WARMUP delay, rc=%d\n", rc);
1917 return rc;
1918 }
1919
1920 short_circuit_det =
1921 of_property_read_bool(node, "qcom,short-circuit-det");
1922 open_circuit_det = of_property_read_bool(node, "qcom,open-circuit-det");
1923 vph_droop_det = of_property_read_bool(node, "qcom,vph-droop-det");
1924 led->pdata->current_derate_en_cfg = (vph_droop_det << 2) |
1925 (open_circuit_det << 1) | short_circuit_det;
1926
1927 led->pdata->thermal_derate_en =
1928 of_property_read_bool(node, "qcom,thermal-derate-en");
1929
1930 if (led->pdata->thermal_derate_en) {
1931 led->pdata->thermal_derate_current =
1932 devm_kcalloc(&led->pdev->dev,
1933 FLASH_LED_THERMAL_OTST_LEVELS,
1934 sizeof(int), GFP_KERNEL);
1935 if (!led->pdata->thermal_derate_current)
1936 return -ENOMEM;
1937
1938 rc = of_property_read_u32_array(node,
1939 "qcom,thermal-derate-current",
1940 led->pdata->thermal_derate_current,
1941 FLASH_LED_THERMAL_OTST_LEVELS);
1942 if (rc < 0) {
1943 pr_err("Unable to read thermal current limits, rc=%d\n",
1944 rc);
1945 return rc;
1946 }
1947 }
1948
1949 led->pdata->otst_ramp_bkup_en =
1950 !of_property_read_bool(node, "qcom,otst-ramp-back-up-dis");
1951
1952 led->pdata->thermal_derate_slow = -EINVAL;
1953 rc = of_property_read_u32(node, "qcom,thermal-derate-slow", &val);
1954 if (!rc) {
1955 if (val < 0 || val > THERMAL_DERATE_SLOW_MAX) {
1956 pr_err("Invalid thermal_derate_slow %d\n", val);
1957 return -EINVAL;
1958 }
1959
1960 led->pdata->thermal_derate_slow =
1961 get_code_from_table(thermal_derate_slow_table,
1962 ARRAY_SIZE(thermal_derate_slow_table), val);
1963 } else if (rc != -EINVAL) {
1964 pr_err("Unable to read thermal derate slow, rc=%d\n", rc);
1965 return rc;
1966 }
1967
1968 led->pdata->thermal_derate_fast = -EINVAL;
1969 rc = of_property_read_u32(node, "qcom,thermal-derate-fast", &val);
1970 if (!rc) {
1971 if (val < 0 || val > THERMAL_DERATE_FAST_MAX) {
1972 pr_err("Invalid thermal_derate_fast %d\n", val);
1973 return -EINVAL;
1974 }
1975
1976 led->pdata->thermal_derate_fast =
1977 get_code_from_table(thermal_derate_fast_table,
1978 ARRAY_SIZE(thermal_derate_fast_table), val);
1979 } else if (rc != -EINVAL) {
1980 pr_err("Unable to read thermal derate fast, rc=%d\n", rc);
1981 return rc;
1982 }
1983
1984 led->pdata->thermal_debounce = -EINVAL;
1985 rc = of_property_read_u32(node, "qcom,thermal-debounce", &val);
1986 if (!rc) {
1987 if (val < 0 || val > THERMAL_DEBOUNCE_TIME_MAX) {
1988 pr_err("Invalid thermal_debounce %d\n", val);
1989 return -EINVAL;
1990 }
1991
1992 if (val >= 0 && val < 16)
1993 led->pdata->thermal_debounce = 0;
1994 else
1995 led->pdata->thermal_debounce = ilog2(val) - 3;
1996 } else if (rc != -EINVAL) {
1997 pr_err("Unable to read thermal debounce, rc=%d\n", rc);
1998 return rc;
1999 }
2000
2001 led->pdata->thermal_hysteresis = -EINVAL;
2002 rc = of_property_read_u32(node, "qcom,thermal-hysteresis", &val);
2003 if (!rc) {
2004 if (led->pdata->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
2005 val = THERMAL_HYST_TEMP_TO_VAL(val, 20);
2006 else
2007 val = THERMAL_HYST_TEMP_TO_VAL(val, 15);
2008
2009 if (val < 0 || val > THERMAL_DERATE_HYSTERESIS_MAX) {
2010 pr_err("Invalid thermal_derate_hysteresis %d\n", val);
2011 return -EINVAL;
2012 }
2013
2014 led->pdata->thermal_hysteresis = val;
2015 } else if (rc != -EINVAL) {
2016 pr_err("Unable to read thermal hysteresis, rc=%d\n", rc);
2017 return rc;
2018 }
2019
2020 led->pdata->thermal_thrsh1 = -EINVAL;
2021 rc = of_property_read_u32(node, "qcom,thermal-thrsh1", &val);
2022 if (!rc) {
2023 led->pdata->thermal_thrsh1 =
2024 get_code_from_table(otst1_threshold_table,
2025 ARRAY_SIZE(otst1_threshold_table), val);
2026 } else if (rc != -EINVAL) {
2027 pr_err("Unable to read thermal thrsh1, rc=%d\n", rc);
2028 return rc;
2029 }
2030
2031 led->pdata->thermal_thrsh2 = -EINVAL;
2032 rc = of_property_read_u32(node, "qcom,thermal-thrsh2", &val);
2033 if (!rc) {
2034 led->pdata->thermal_thrsh2 =
2035 get_code_from_table(otst2_threshold_table,
2036 ARRAY_SIZE(otst2_threshold_table), val);
2037 } else if (rc != -EINVAL) {
2038 pr_err("Unable to read thermal thrsh2, rc=%d\n", rc);
2039 return rc;
2040 }
2041
2042 led->pdata->thermal_thrsh3 = -EINVAL;
2043 rc = of_property_read_u32(node, "qcom,thermal-thrsh3", &val);
2044 if (!rc) {
2045 led->pdata->thermal_thrsh3 =
2046 get_code_from_table(otst3_threshold_table,
2047 ARRAY_SIZE(otst3_threshold_table), val);
2048 } else if (rc != -EINVAL) {
2049 pr_err("Unable to read thermal thrsh3, rc=%d\n", rc);
2050 return rc;
2051 }
2052
2053 led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT;
2054 rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val);
2055 if (!rc) {
2056 led->pdata->vph_droop_debounce =
2057 VPH_DROOP_DEBOUNCE_US_TO_VAL(val);
2058 } else if (rc != -EINVAL) {
2059 pr_err("Unable to read VPH droop debounce, rc=%d\n", rc);
2060 return rc;
2061 }
2062
2063 if (led->pdata->vph_droop_debounce > FLASH_LED_DEBOUNCE_MAX) {
2064 pr_err("Invalid VPH droop debounce specified\n");
2065 return -EINVAL;
2066 }
2067
2068 led->pdata->vph_droop_threshold = FLASH_LED_VPH_DROOP_THRESH_DEFAULT;
2069 rc = of_property_read_u32(node, "qcom,vph-droop-threshold-mv", &val);
2070 if (!rc) {
2071 led->pdata->vph_droop_threshold =
Subbaraman Narayanamurthyaf8dcb42018-01-17 20:23:47 -08002072 get_vph_droop_thresh_code(val);
David Collins8885f792017-01-26 14:36:34 -08002073 } else if (rc != -EINVAL) {
2074 pr_err("Unable to read VPH droop threshold, rc=%d\n", rc);
2075 return rc;
2076 }
2077
2078 if (led->pdata->vph_droop_threshold > FLASH_LED_VPH_DROOP_THRESH_MAX) {
2079 pr_err("Invalid VPH droop threshold specified\n");
2080 return -EINVAL;
2081 }
2082
2083 led->pdata->vph_droop_hysteresis =
2084 FLASH_LED_VPH_DROOP_HYST_DEFAULT;
2085 rc = of_property_read_u32(node, "qcom,vph-droop-hysteresis-mv", &val);
2086 if (!rc) {
2087 led->pdata->vph_droop_hysteresis =
2088 VPH_DROOP_HYST_MV_TO_VAL(val);
2089 } else if (rc != -EINVAL) {
2090 pr_err("Unable to read VPH droop hysteresis, rc=%d\n", rc);
2091 return rc;
2092 }
2093
2094 if (led->pdata->vph_droop_hysteresis > FLASH_LED_HYSTERESIS_MAX) {
2095 pr_err("Invalid VPH droop hysteresis specified\n");
2096 return -EINVAL;
2097 }
2098
2099 led->pdata->vph_droop_hysteresis <<= FLASH_LED_VPH_DROOP_HYST_SHIFT;
2100
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07002101 led->pdata->hw_strobe_option = -EINVAL;
David Collins8885f792017-01-26 14:36:34 -08002102 rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val);
2103 if (!rc) {
Subbaraman Narayanamurthy3f684b22017-03-21 20:49:54 -07002104 led->pdata->hw_strobe_option = val;
David Collins8885f792017-01-26 14:36:34 -08002105 } else if (rc != -EINVAL) {
2106 pr_err("Unable to parse hw strobe option, rc=%d\n", rc);
2107 return rc;
2108 }
2109
2110 rc = of_property_read_u32(node, "qcom,led1n2-iclamp-low-ma", &val);
2111 if (!rc) {
2112 led->pdata->led1n2_iclamp_low_ma = val;
2113 } else if (rc != -EINVAL) {
2114 pr_err("Unable to read led1n2_iclamp_low current, rc=%d\n", rc);
2115 return rc;
2116 }
2117
2118 rc = of_property_read_u32(node, "qcom,led1n2-iclamp-mid-ma", &val);
2119 if (!rc) {
2120 led->pdata->led1n2_iclamp_mid_ma = val;
2121 } else if (rc != -EINVAL) {
2122 pr_err("Unable to read led1n2_iclamp_mid current, rc=%d\n", rc);
2123 return rc;
2124 }
2125
2126 rc = of_property_read_u32(node, "qcom,led3-iclamp-low-ma", &val);
2127 if (!rc) {
2128 led->pdata->led3_iclamp_low_ma = val;
2129 } else if (rc != -EINVAL) {
2130 pr_err("Unable to read led3_iclamp_low current, rc=%d\n", rc);
2131 return rc;
2132 }
2133
2134 rc = of_property_read_u32(node, "qcom,led3-iclamp-mid-ma", &val);
2135 if (!rc) {
2136 led->pdata->led3_iclamp_mid_ma = val;
2137 } else if (rc != -EINVAL) {
2138 pr_err("Unable to read led3_iclamp_mid current, rc=%d\n", rc);
2139 return rc;
2140 }
2141
2142 led->pdata->vled_max_uv = FLASH_LED_VLED_MAX_DEFAULT_UV;
2143 rc = of_property_read_u32(node, "qcom,vled-max-uv", &val);
2144 if (!rc) {
2145 led->pdata->vled_max_uv = val;
2146 } else if (rc != -EINVAL) {
2147 pr_err("Unable to parse vled_max voltage, rc=%d\n", rc);
2148 return rc;
2149 }
2150
2151 led->pdata->ibatt_ocp_threshold_ua =
2152 FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA;
2153 rc = of_property_read_u32(node, "qcom,ibatt-ocp-threshold-ua", &val);
2154 if (!rc) {
2155 led->pdata->ibatt_ocp_threshold_ua = val;
2156 } else if (rc != -EINVAL) {
2157 pr_err("Unable to parse ibatt_ocp threshold, rc=%d\n", rc);
2158 return rc;
2159 }
2160
2161 led->pdata->rpara_uohm = FLASH_LED_RPARA_DEFAULT_UOHM;
2162 rc = of_property_read_u32(node, "qcom,rparasitic-uohm", &val);
2163 if (!rc) {
2164 led->pdata->rpara_uohm = val;
2165 } else if (rc != -EINVAL) {
2166 pr_err("Unable to parse rparasitic, rc=%d\n", rc);
2167 return rc;
2168 }
2169
2170 led->pdata->lmh_ocv_threshold_uv =
2171 FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV;
2172 rc = of_property_read_u32(node, "qcom,lmh-ocv-threshold-uv", &val);
2173 if (!rc) {
2174 led->pdata->lmh_ocv_threshold_uv = val;
2175 } else if (rc != -EINVAL) {
2176 pr_err("Unable to parse lmh ocv threshold, rc=%d\n", rc);
2177 return rc;
2178 }
2179
2180 led->pdata->lmh_rbatt_threshold_uohm =
2181 FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM;
2182 rc = of_property_read_u32(node, "qcom,lmh-rbatt-threshold-uohm", &val);
2183 if (!rc) {
2184 led->pdata->lmh_rbatt_threshold_uohm = val;
2185 } else if (rc != -EINVAL) {
2186 pr_err("Unable to parse lmh rbatt threshold, rc=%d\n", rc);
2187 return rc;
2188 }
2189
2190 led->pdata->lmh_level = FLASH_LED_LMH_LEVEL_DEFAULT;
2191 rc = of_property_read_u32(node, "qcom,lmh-level", &val);
2192 if (!rc) {
2193 led->pdata->lmh_level = val;
2194 } else if (rc != -EINVAL) {
2195 pr_err("Unable to parse lmh_level, rc=%d\n", rc);
2196 return rc;
2197 }
2198
Ankit Sharmaa7153c32017-03-22 19:04:52 +05302199 led->pdata->lmh_mitigation_sel = FLASH_LED_LMH_MITIGATION_SEL_DEFAULT;
David Collins8885f792017-01-26 14:36:34 -08002200 rc = of_property_read_u32(node, "qcom,lmh-mitigation-sel", &val);
2201 if (!rc) {
2202 led->pdata->lmh_mitigation_sel = val;
2203 } else if (rc != -EINVAL) {
2204 pr_err("Unable to parse lmh_mitigation_sel, rc=%d\n", rc);
2205 return rc;
2206 }
2207
2208 if (led->pdata->lmh_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) {
2209 pr_err("Invalid lmh_mitigation_sel specified\n");
2210 return -EINVAL;
2211 }
2212
Ankit Sharmaa7153c32017-03-22 19:04:52 +05302213 led->pdata->chgr_mitigation_sel = FLASH_SW_CHARGER_MITIGATION;
David Collins8885f792017-01-26 14:36:34 -08002214 rc = of_property_read_u32(node, "qcom,chgr-mitigation-sel", &val);
2215 if (!rc) {
2216 led->pdata->chgr_mitigation_sel = val;
2217 } else if (rc != -EINVAL) {
2218 pr_err("Unable to parse chgr_mitigation_sel, rc=%d\n", rc);
2219 return rc;
2220 }
2221
2222 if (led->pdata->chgr_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) {
2223 pr_err("Invalid chgr_mitigation_sel specified\n");
2224 return -EINVAL;
2225 }
2226
Ankit Sharmaa7153c32017-03-22 19:04:52 +05302227 led->pdata->iled_thrsh_val = FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT;
David Collins8885f792017-01-26 14:36:34 -08002228 rc = of_property_read_u32(node, "qcom,iled-thrsh-ma", &val);
2229 if (!rc) {
2230 led->pdata->iled_thrsh_val = MITIGATION_THRSH_MA_TO_VAL(val);
2231 } else if (rc != -EINVAL) {
2232 pr_err("Unable to parse iled_thrsh_val, rc=%d\n", rc);
2233 return rc;
2234 }
2235
Ankit Sharmaa7153c32017-03-22 19:04:52 +05302236 if (led->pdata->iled_thrsh_val > FLASH_LED_CHGR_MITIGATION_THRSH_MAX) {
David Collins8885f792017-01-26 14:36:34 -08002237 pr_err("Invalid iled_thrsh_val specified\n");
2238 return -EINVAL;
2239 }
2240
2241 led->pdata->all_ramp_up_done_irq =
2242 of_irq_get_byname(node, "all-ramp-up-done-irq");
2243 if (led->pdata->all_ramp_up_done_irq < 0)
2244 pr_debug("all-ramp-up-done-irq not used\n");
2245
2246 led->pdata->all_ramp_down_done_irq =
2247 of_irq_get_byname(node, "all-ramp-down-done-irq");
2248 if (led->pdata->all_ramp_down_done_irq < 0)
2249 pr_debug("all-ramp-down-done-irq not used\n");
2250
2251 led->pdata->led_fault_irq =
2252 of_irq_get_byname(node, "led-fault-irq");
2253 if (led->pdata->led_fault_irq < 0)
2254 pr_debug("led-fault-irq not used\n");
2255
2256 return 0;
2257}
2258
2259static int qpnp_flash_led_probe(struct platform_device *pdev)
2260{
2261 struct qpnp_flash_led *led;
2262 struct device_node *node, *temp;
2263 const char *temp_string;
2264 unsigned int base;
2265 int rc, i = 0, j = 0;
2266
2267 node = pdev->dev.of_node;
2268 if (!node) {
2269 pr_err("No flash LED nodes defined\n");
2270 return -ENODEV;
2271 }
2272
2273 rc = of_property_read_u32(node, "reg", &base);
2274 if (rc < 0) {
2275 pr_err("Couldn't find reg in node %s, rc = %d\n",
2276 node->full_name, rc);
2277 return rc;
2278 }
2279
2280 led = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_flash_led),
2281 GFP_KERNEL);
2282 if (!led)
2283 return -ENOMEM;
2284
2285 led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
2286 if (!led->regmap) {
2287 pr_err("Couldn't get parent's regmap\n");
2288 return -EINVAL;
2289 }
2290
2291 led->base = base;
2292 led->pdev = pdev;
2293 led->pdata = devm_kzalloc(&pdev->dev,
2294 sizeof(struct flash_led_platform_data), GFP_KERNEL);
2295 if (!led->pdata)
2296 return -ENOMEM;
2297
Kiran Gundabf1e6c02018-01-17 17:50:20 +05302298 qpnp_flash_led_prepare = qpnp_flash_led_prepare_v2;
David Collins8885f792017-01-26 14:36:34 -08002299 rc = qpnp_flash_led_parse_common_dt(led, node);
2300 if (rc < 0) {
2301 pr_err("Failed to parse common flash LED device tree\n");
2302 return rc;
2303 }
2304
2305 for_each_available_child_of_node(node, temp) {
2306 rc = of_property_read_string(temp, "label", &temp_string);
2307 if (rc < 0) {
2308 pr_err("Failed to parse label, rc=%d\n", rc);
2309 return rc;
2310 }
2311
2312 if (!strcmp("switch", temp_string)) {
2313 led->num_snodes++;
2314 } else if (!strcmp("flash", temp_string) ||
2315 !strcmp("torch", temp_string)) {
2316 led->num_fnodes++;
2317 } else {
2318 pr_err("Invalid label for led node\n");
2319 return -EINVAL;
2320 }
2321 }
2322
2323 if (!led->num_fnodes) {
2324 pr_err("No LED nodes defined\n");
2325 return -ECHILD;
2326 }
2327
2328 led->fnode = devm_kcalloc(&pdev->dev, led->num_fnodes,
2329 sizeof(*led->fnode),
2330 GFP_KERNEL);
2331 if (!led->fnode)
2332 return -ENOMEM;
2333
2334 led->snode = devm_kcalloc(&pdev->dev, led->num_snodes,
2335 sizeof(*led->snode),
2336 GFP_KERNEL);
2337 if (!led->snode)
2338 return -ENOMEM;
2339
2340 temp = NULL;
2341 i = 0;
2342 j = 0;
2343 for_each_available_child_of_node(node, temp) {
2344 rc = of_property_read_string(temp, "label", &temp_string);
2345 if (rc < 0) {
2346 pr_err("Failed to parse label, rc=%d\n", rc);
2347 return rc;
2348 }
2349
2350 if (!strcmp("flash", temp_string) ||
2351 !strcmp("torch", temp_string)) {
2352 rc = qpnp_flash_led_parse_each_led_dt(led,
Subbaraman Narayanamurthy01c99612017-04-03 12:26:06 -07002353 &led->fnode[i], temp);
David Collins8885f792017-01-26 14:36:34 -08002354 if (rc < 0) {
2355 pr_err("Unable to parse flash node %d rc=%d\n",
2356 i, rc);
2357 goto error_led_register;
2358 }
Subbaraman Narayanamurthy01c99612017-04-03 12:26:06 -07002359 i++;
David Collins8885f792017-01-26 14:36:34 -08002360 }
2361
2362 if (!strcmp("switch", temp_string)) {
2363 rc = qpnp_flash_led_parse_and_register_switch(led,
Subbaraman Narayanamurthy01c99612017-04-03 12:26:06 -07002364 &led->snode[j], temp);
David Collins8885f792017-01-26 14:36:34 -08002365 if (rc < 0) {
2366 pr_err("Unable to parse and register switch node, rc=%d\n",
2367 rc);
2368 goto error_switch_register;
2369 }
Subbaraman Narayanamurthy01c99612017-04-03 12:26:06 -07002370 j++;
David Collins8885f792017-01-26 14:36:34 -08002371 }
2372 }
2373
2374 /* setup irqs */
2375 if (led->pdata->all_ramp_up_done_irq >= 0) {
2376 rc = devm_request_threaded_irq(&led->pdev->dev,
2377 led->pdata->all_ramp_up_done_irq,
2378 NULL, qpnp_flash_led_irq_handler,
2379 IRQF_ONESHOT,
2380 "qpnp_flash_led_all_ramp_up_done_irq", led);
2381 if (rc < 0) {
2382 pr_err("Unable to request all_ramp_up_done(%d) IRQ(err:%d)\n",
2383 led->pdata->all_ramp_up_done_irq, rc);
2384 goto error_switch_register;
2385 }
2386 }
2387
2388 if (led->pdata->all_ramp_down_done_irq >= 0) {
2389 rc = devm_request_threaded_irq(&led->pdev->dev,
2390 led->pdata->all_ramp_down_done_irq,
2391 NULL, qpnp_flash_led_irq_handler,
2392 IRQF_ONESHOT,
2393 "qpnp_flash_led_all_ramp_down_done_irq", led);
2394 if (rc < 0) {
2395 pr_err("Unable to request all_ramp_down_done(%d) IRQ(err:%d)\n",
2396 led->pdata->all_ramp_down_done_irq, rc);
2397 goto error_switch_register;
2398 }
2399 }
2400
2401 if (led->pdata->led_fault_irq >= 0) {
2402 rc = devm_request_threaded_irq(&led->pdev->dev,
2403 led->pdata->led_fault_irq,
2404 NULL, qpnp_flash_led_irq_handler,
2405 IRQF_ONESHOT,
2406 "qpnp_flash_led_fault_irq", led);
2407 if (rc < 0) {
2408 pr_err("Unable to request led_fault(%d) IRQ(err:%d)\n",
2409 led->pdata->led_fault_irq, rc);
2410 goto error_switch_register;
2411 }
2412 }
2413
2414 led->bms_psy = power_supply_get_by_name("bms");
2415 if (!led->bms_psy) {
2416 rc = flash_led_psy_register_notifier(led);
2417 if (rc < 0) {
2418 pr_err("Couldn't register psy notifier, rc = %d\n", rc);
2419 goto error_switch_register;
2420 }
2421 }
2422
2423 rc = qpnp_flash_led_init_settings(led);
2424 if (rc < 0) {
2425 pr_err("Failed to initialize flash LED, rc=%d\n", rc);
2426 goto unreg_notifier;
2427 }
2428
2429 for (i = 0; i < led->num_snodes; i++) {
2430 for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) {
2431 rc = sysfs_create_file(&led->snode[i].cdev.dev->kobj,
2432 &qpnp_flash_led_attrs[j].attr);
2433 if (rc < 0) {
2434 pr_err("sysfs creation failed, rc=%d\n", rc);
2435 goto sysfs_fail;
2436 }
2437 }
2438 }
2439
2440 spin_lock_init(&led->lock);
2441
2442 dev_set_drvdata(&pdev->dev, led);
2443
2444 return 0;
2445
2446sysfs_fail:
2447 for (--j; j >= 0; j--)
2448 sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
2449 &qpnp_flash_led_attrs[j].attr);
2450
2451 for (--i; i >= 0; i--) {
2452 for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
2453 sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
2454 &qpnp_flash_led_attrs[j].attr);
2455 }
2456
2457 i = led->num_snodes;
2458unreg_notifier:
2459 power_supply_unreg_notifier(&led->nb);
2460error_switch_register:
2461 while (i > 0)
2462 led_classdev_unregister(&led->snode[--i].cdev);
2463 i = led->num_fnodes;
2464error_led_register:
2465 while (i > 0)
2466 led_classdev_unregister(&led->fnode[--i].cdev);
2467
2468 return rc;
2469}
2470
2471static int qpnp_flash_led_remove(struct platform_device *pdev)
2472{
2473 struct qpnp_flash_led *led = dev_get_drvdata(&pdev->dev);
2474 int i, j;
2475
2476 for (i = 0; i < led->num_snodes; i++) {
2477 for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
2478 sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
2479 &qpnp_flash_led_attrs[j].attr);
2480
2481 if (led->snode[i].regulator_on)
2482 qpnp_flash_led_regulator_enable(led,
2483 &led->snode[i], false);
2484 }
2485
2486 while (i > 0)
2487 led_classdev_unregister(&led->snode[--i].cdev);
2488
2489 i = led->num_fnodes;
2490 while (i > 0)
2491 led_classdev_unregister(&led->fnode[--i].cdev);
2492
2493 power_supply_unreg_notifier(&led->nb);
2494 return 0;
2495}
2496
2497const struct of_device_id qpnp_flash_led_match_table[] = {
2498 { .compatible = "qcom,qpnp-flash-led-v2",},
2499 { },
2500};
2501
2502static struct platform_driver qpnp_flash_led_driver = {
2503 .driver = {
2504 .name = "qcom,qpnp-flash-led-v2",
2505 .of_match_table = qpnp_flash_led_match_table,
2506 },
2507 .probe = qpnp_flash_led_probe,
2508 .remove = qpnp_flash_led_remove,
2509};
2510
2511static int __init qpnp_flash_led_init(void)
2512{
2513 return platform_driver_register(&qpnp_flash_led_driver);
2514}
2515late_initcall(qpnp_flash_led_init);
2516
2517static void __exit qpnp_flash_led_exit(void)
2518{
2519 platform_driver_unregister(&qpnp_flash_led_driver);
2520}
2521module_exit(qpnp_flash_led_exit);
2522
2523MODULE_DESCRIPTION("QPNP Flash LED driver v2");
2524MODULE_LICENSE("GPL v2");
2525MODULE_ALIAS("leds:leds-qpnp-flash-v2");