blob: c5cfd8e3f15f98e3cd43190cf8d0e7d95bc3494d [file] [log] [blame]
Dan Murphybc1b8492019-03-21 09:28:38 -05001// SPDX-License-Identifier: GPL-2.0
2// TI LM3532 LED driver
3// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
4
5#include <linux/i2c.h>
6#include <linux/leds.h>
7#include <linux/slab.h>
8#include <linux/regmap.h>
9#include <linux/types.h>
10#include <linux/regulator/consumer.h>
11#include <linux/module.h>
12#include <uapi/linux/uleds.h>
13#include <linux/gpio/consumer.h>
14
15#define LM3532_NAME "lm3532-led"
16#define LM3532_BL_MODE_MANUAL 0x00
17#define LM3532_BL_MODE_ALS 0x01
18
19#define LM3532_REG_OUTPUT_CFG 0x10
20#define LM3532_REG_STARTSHUT_RAMP 0x11
21#define LM3532_REG_RT_RAMP 0x12
22#define LM3532_REG_PWM_A_CFG 0x13
23#define LM3532_REG_PWM_B_CFG 0x14
24#define LM3532_REG_PWM_C_CFG 0x15
25#define LM3532_REG_ZONE_CFG_A 0x16
Dan Murphy4c905452019-08-20 14:53:04 -050026#define LM3532_REG_CTRL_A_FS_CURR 0x17
Dan Murphybc1b8492019-03-21 09:28:38 -050027#define LM3532_REG_ZONE_CFG_B 0x18
Dan Murphy4c905452019-08-20 14:53:04 -050028#define LM3532_REG_CTRL_B_FS_CURR 0x19
Dan Murphybc1b8492019-03-21 09:28:38 -050029#define LM3532_REG_ZONE_CFG_C 0x1a
Dan Murphy4c905452019-08-20 14:53:04 -050030#define LM3532_REG_CTRL_C_FS_CURR 0x1b
Dan Murphybc1b8492019-03-21 09:28:38 -050031#define LM3532_REG_ENABLE 0x1d
32#define LM3532_ALS_CONFIG 0x23
33#define LM3532_REG_ZN_0_HI 0x60
34#define LM3532_REG_ZN_0_LO 0x61
35#define LM3532_REG_ZN_1_HI 0x62
36#define LM3532_REG_ZN_1_LO 0x63
37#define LM3532_REG_ZN_2_HI 0x64
38#define LM3532_REG_ZN_2_LO 0x65
39#define LM3532_REG_ZN_3_HI 0x66
40#define LM3532_REG_ZN_3_LO 0x67
Dan Murphy13123942019-08-20 14:53:03 -050041#define LM3532_REG_ZONE_TRGT_A 0x70
42#define LM3532_REG_ZONE_TRGT_B 0x75
43#define LM3532_REG_ZONE_TRGT_C 0x7a
Dan Murphybc1b8492019-03-21 09:28:38 -050044#define LM3532_REG_MAX 0x7e
45
Dan Murphy6559ac32019-08-20 14:53:05 -050046/* Control Enable */
Dan Murphybc1b8492019-03-21 09:28:38 -050047#define LM3532_CTRL_A_ENABLE BIT(0)
48#define LM3532_CTRL_B_ENABLE BIT(1)
49#define LM3532_CTRL_C_ENABLE BIT(2)
50
51/* PWM Zone Control */
52#define LM3532_PWM_ZONE_MASK 0x7c
53#define LM3532_PWM_ZONE_0_EN BIT(2)
54#define LM3532_PWM_ZONE_1_EN BIT(3)
55#define LM3532_PWM_ZONE_2_EN BIT(4)
56#define LM3532_PWM_ZONE_3_EN BIT(5)
57#define LM3532_PWM_ZONE_4_EN BIT(6)
58
59/* Brightness Configuration */
60#define LM3532_I2C_CTRL BIT(0)
61#define LM3532_ALS_CTRL 0
62#define LM3532_LINEAR_MAP BIT(1)
63#define LM3532_ZONE_MASK (BIT(2) | BIT(3) | BIT(4))
64#define LM3532_ZONE_0 0
65#define LM3532_ZONE_1 BIT(2)
66#define LM3532_ZONE_2 BIT(3)
67#define LM3532_ZONE_3 (BIT(2) | BIT(3))
68#define LM3532_ZONE_4 BIT(4)
69
70#define LM3532_ENABLE_ALS BIT(3)
71#define LM3532_ALS_SEL_SHIFT 6
72
73/* Zone Boundary Register */
74#define LM3532_ALS_WINDOW_mV 2000
75#define LM3532_ALS_ZB_MAX 4
76#define LM3532_ALS_OFFSET_mV 2
77
78#define LM3532_CONTROL_A 0
79#define LM3532_CONTROL_B 1
80#define LM3532_CONTROL_C 2
81#define LM3532_MAX_CONTROL_BANKS 3
82#define LM3532_MAX_LED_STRINGS 3
83
84#define LM3532_OUTPUT_CFG_MASK 0x3
85#define LM3532_BRT_VAL_ADJUST 8
86#define LM3532_RAMP_DOWN_SHIFT 3
87
88#define LM3532_NUM_RAMP_VALS 8
89#define LM3532_NUM_AVG_VALS 8
90#define LM3532_NUM_IMP_VALS 32
91
Dan Murphy517ea492019-08-20 14:53:07 -050092#define LM3532_FS_CURR_MIN 5000
93#define LM3532_FS_CURR_MAX 29800
94#define LM3532_FS_CURR_STEP 800
95
Dan Murphybc1b8492019-03-21 09:28:38 -050096/*
97 * struct lm3532_als_data
98 * @config - value of ALS configuration register
99 * @als1_imp_sel - value of ALS1 resistor select register
100 * @als2_imp_sel - value of ALS2 resistor select register
101 * @als_avrg_time - ALS averaging time
102 * @als_input_mode - ALS input mode for brightness control
103 * @als_vmin - Minimum ALS voltage
104 * @als_vmax - Maximum ALS voltage
105 * @zone_lo - values of ALS lo ZB(Zone Boundary) registers
106 * @zone_hi - values of ALS hi ZB(Zone Boundary) registers
107 */
108struct lm3532_als_data {
109 u8 config;
110 u8 als1_imp_sel;
111 u8 als2_imp_sel;
112 u8 als_avrg_time;
113 u8 als_input_mode;
114 u32 als_vmin;
115 u32 als_vmax;
116 u8 zones_lo[LM3532_ALS_ZB_MAX];
117 u8 zones_hi[LM3532_ALS_ZB_MAX];
118};
119
120/**
121 * struct lm3532_led
122 * @led_dev: led class device
123 * @priv - Pointer the device data structure
124 * @control_bank - Control bank the LED is associated to
125 * @mode - Mode of the LED string
Dan Murphy13123942019-08-20 14:53:03 -0500126 * @ctrl_brt_pointer - Zone target register that controls the sink
Dan Murphybc1b8492019-03-21 09:28:38 -0500127 * @num_leds - Number of LED strings are supported in this array
Dan Murphy517ea492019-08-20 14:53:07 -0500128 * @full_scale_current - The full-scale current setting for the current sink.
Dan Murphybc1b8492019-03-21 09:28:38 -0500129 * @led_strings - The LED strings supported in this array
Tony Lindgren070a0ee2019-08-27 14:52:05 -0700130 * @enabled - Enabled status
Dan Murphybc1b8492019-03-21 09:28:38 -0500131 * @label - LED label
132 */
133struct lm3532_led {
134 struct led_classdev led_dev;
135 struct lm3532_data *priv;
136
137 int control_bank;
138 int mode;
Dan Murphy13123942019-08-20 14:53:03 -0500139 int ctrl_brt_pointer;
Dan Murphybc1b8492019-03-21 09:28:38 -0500140 int num_leds;
Dan Murphy517ea492019-08-20 14:53:07 -0500141 int full_scale_current;
Tony Lindgren070a0ee2019-08-27 14:52:05 -0700142 int enabled:1;
Dan Murphybc1b8492019-03-21 09:28:38 -0500143 u32 led_strings[LM3532_MAX_CONTROL_BANKS];
144 char label[LED_MAX_NAME_SIZE];
145};
146
147/**
148 * struct lm3532_data
149 * @enable_gpio - Hardware enable gpio
150 * @regulator: regulator
151 * @client: i2c client
152 * @regmap - Devices register map
153 * @dev - Pointer to the devices device struct
154 * @lock - Lock for reading/writing the device
155 * @als_data - Pointer to the als data struct
156 * @runtime_ramp_up - Runtime ramp up setting
157 * @runtime_ramp_down - Runtime ramp down setting
158 * @leds - Array of LED strings
159 */
160struct lm3532_data {
161 struct gpio_desc *enable_gpio;
162 struct regulator *regulator;
163 struct i2c_client *client;
164 struct regmap *regmap;
165 struct device *dev;
166 struct mutex lock;
167
168 struct lm3532_als_data *als_data;
169
170 u32 runtime_ramp_up;
171 u32 runtime_ramp_down;
172
173 struct lm3532_led leds[];
174};
175
176static const struct reg_default lm3532_reg_defs[] = {
177 {LM3532_REG_OUTPUT_CFG, 0xe4},
178 {LM3532_REG_STARTSHUT_RAMP, 0xc0},
179 {LM3532_REG_RT_RAMP, 0xc0},
180 {LM3532_REG_PWM_A_CFG, 0x82},
181 {LM3532_REG_PWM_B_CFG, 0x82},
182 {LM3532_REG_PWM_C_CFG, 0x82},
183 {LM3532_REG_ZONE_CFG_A, 0xf1},
Dan Murphy4c905452019-08-20 14:53:04 -0500184 {LM3532_REG_CTRL_A_FS_CURR, 0xf3},
Dan Murphybc1b8492019-03-21 09:28:38 -0500185 {LM3532_REG_ZONE_CFG_B, 0xf1},
Dan Murphy4c905452019-08-20 14:53:04 -0500186 {LM3532_REG_CTRL_B_FS_CURR, 0xf3},
Dan Murphybc1b8492019-03-21 09:28:38 -0500187 {LM3532_REG_ZONE_CFG_C, 0xf1},
Dan Murphy4c905452019-08-20 14:53:04 -0500188 {LM3532_REG_CTRL_C_FS_CURR, 0xf3},
Dan Murphybc1b8492019-03-21 09:28:38 -0500189 {LM3532_REG_ENABLE, 0xf8},
190 {LM3532_ALS_CONFIG, 0x44},
191 {LM3532_REG_ZN_0_HI, 0x35},
192 {LM3532_REG_ZN_0_LO, 0x33},
193 {LM3532_REG_ZN_1_HI, 0x6a},
194 {LM3532_REG_ZN_1_LO, 0x66},
195 {LM3532_REG_ZN_2_HI, 0xa1},
196 {LM3532_REG_ZN_2_LO, 0x99},
197 {LM3532_REG_ZN_3_HI, 0xdc},
198 {LM3532_REG_ZN_3_LO, 0xcc},
199};
200
201static const struct regmap_config lm3532_regmap_config = {
202 .reg_bits = 8,
203 .val_bits = 8,
204
205 .max_register = LM3532_REG_MAX,
206 .reg_defaults = lm3532_reg_defs,
207 .num_reg_defaults = ARRAY_SIZE(lm3532_reg_defs),
208 .cache_type = REGCACHE_FLAT,
209};
210
211const static int als_imp_table[LM3532_NUM_IMP_VALS] = {37000, 18500, 12330,
212 92500, 7400, 6170, 5290,
213 4630, 4110, 3700, 3360,
214 3080, 2850, 2640, 2440,
215 2310, 2180, 2060, 1950,
216 1850, 1760, 1680, 1610,
217 1540, 1480, 1420, 1370,
218 1320, 1280, 1230, 1190};
219static int lm3532_get_als_imp_index(int als_imped)
220{
221 int i;
222
223 if (als_imped > als_imp_table[1])
224 return 0;
225
226 if (als_imped < als_imp_table[LM3532_NUM_IMP_VALS - 1])
227 return LM3532_NUM_IMP_VALS - 1;
228
229 for (i = 1; i < LM3532_NUM_IMP_VALS; i++) {
230 if (als_imped == als_imp_table[i])
231 return i;
232
233 /* Find an approximate index by looking up the table */
234 if (als_imped < als_imp_table[i - 1] &&
235 als_imped > als_imp_table[i]) {
236 if (als_imped - als_imp_table[i - 1] <
237 als_imp_table[i] - als_imped)
238 return i + 1;
239 else
240 return i;
241 }
242 }
243
244 return -EINVAL;
245}
246
247static int lm3532_get_index(const int table[], int size, int value)
248{
249 int i;
250
251 for (i = 1; i < size; i++) {
252 if (value == table[i])
253 return i;
254
255 /* Find an approximate index by looking up the table */
256 if (value > table[i - 1] &&
257 value < table[i]) {
258 if (value - table[i - 1] < table[i] - value)
259 return i - 1;
260 else
261 return i;
262 }
263 }
264
265 return -EINVAL;
266}
267
268const static int als_avrg_table[LM3532_NUM_AVG_VALS] = {17920, 35840, 71680,
269 1433360, 286720, 573440,
270 1146880, 2293760};
271static int lm3532_get_als_avg_index(int avg_time)
272{
273 if (avg_time <= als_avrg_table[0])
274 return 0;
275
276 if (avg_time > als_avrg_table[LM3532_NUM_AVG_VALS - 1])
277 return LM3532_NUM_AVG_VALS - 1;
278
279 return lm3532_get_index(&als_avrg_table[0], LM3532_NUM_AVG_VALS,
280 avg_time);
281}
282
283const static int ramp_table[LM3532_NUM_RAMP_VALS] = { 8, 1024, 2048, 4096, 8192,
284 16384, 32768, 65536};
285static int lm3532_get_ramp_index(int ramp_time)
286{
287 if (ramp_time <= ramp_table[0])
288 return 0;
289
290 if (ramp_time > ramp_table[LM3532_NUM_RAMP_VALS - 1])
291 return LM3532_NUM_RAMP_VALS - 1;
292
293 return lm3532_get_index(&ramp_table[0], LM3532_NUM_RAMP_VALS,
294 ramp_time);
295}
296
Tony Lindgren070a0ee2019-08-27 14:52:05 -0700297/* Caller must take care of locking */
Dan Murphybc1b8492019-03-21 09:28:38 -0500298static int lm3532_led_enable(struct lm3532_led *led_data)
299{
300 int ctrl_en_val = BIT(led_data->control_bank);
301 int ret;
302
Tony Lindgren070a0ee2019-08-27 14:52:05 -0700303 if (led_data->enabled)
304 return 0;
305
Dan Murphybc1b8492019-03-21 09:28:38 -0500306 ret = regmap_update_bits(led_data->priv->regmap, LM3532_REG_ENABLE,
307 ctrl_en_val, ctrl_en_val);
308 if (ret) {
309 dev_err(led_data->priv->dev, "Failed to set ctrl:%d\n", ret);
310 return ret;
311 }
312
Tony Lindgren070a0ee2019-08-27 14:52:05 -0700313 ret = regulator_enable(led_data->priv->regulator);
314 if (ret < 0)
315 return ret;
316
317 led_data->enabled = 1;
318
319 return 0;
Dan Murphybc1b8492019-03-21 09:28:38 -0500320}
321
Tony Lindgren070a0ee2019-08-27 14:52:05 -0700322/* Caller must take care of locking */
Dan Murphybc1b8492019-03-21 09:28:38 -0500323static int lm3532_led_disable(struct lm3532_led *led_data)
324{
325 int ctrl_en_val = BIT(led_data->control_bank);
326 int ret;
327
Tony Lindgren070a0ee2019-08-27 14:52:05 -0700328 if (!led_data->enabled)
329 return 0;
330
Dan Murphybc1b8492019-03-21 09:28:38 -0500331 ret = regmap_update_bits(led_data->priv->regmap, LM3532_REG_ENABLE,
Dan Murphy6559ac32019-08-20 14:53:05 -0500332 ctrl_en_val, 0);
Dan Murphybc1b8492019-03-21 09:28:38 -0500333 if (ret) {
334 dev_err(led_data->priv->dev, "Failed to set ctrl:%d\n", ret);
335 return ret;
336 }
337
Tony Lindgren070a0ee2019-08-27 14:52:05 -0700338 ret = regulator_disable(led_data->priv->regulator);
339 if (ret < 0)
340 return ret;
341
342 led_data->enabled = 0;
343
344 return 0;
Dan Murphybc1b8492019-03-21 09:28:38 -0500345}
346
347static int lm3532_brightness_set(struct led_classdev *led_cdev,
348 enum led_brightness brt_val)
349{
350 struct lm3532_led *led =
351 container_of(led_cdev, struct lm3532_led, led_dev);
352 u8 brightness_reg;
353 int ret;
354
355 mutex_lock(&led->priv->lock);
356
Dan Murphy6559ac32019-08-20 14:53:05 -0500357 if (led->mode == LM3532_ALS_CTRL) {
Dan Murphybc1b8492019-03-21 09:28:38 -0500358 if (brt_val > LED_OFF)
359 ret = lm3532_led_enable(led);
360 else
361 ret = lm3532_led_disable(led);
362
363 goto unlock;
364 }
365
366 if (brt_val == LED_OFF) {
367 ret = lm3532_led_disable(led);
368 goto unlock;
369 }
370
371 ret = lm3532_led_enable(led);
372 if (ret)
373 goto unlock;
374
Dan Murphy13123942019-08-20 14:53:03 -0500375 brightness_reg = LM3532_REG_ZONE_TRGT_A + led->control_bank * 5 +
376 (led->ctrl_brt_pointer >> 2);
Dan Murphybc1b8492019-03-21 09:28:38 -0500377
378 ret = regmap_write(led->priv->regmap, brightness_reg, brt_val);
379
380unlock:
381 mutex_unlock(&led->priv->lock);
382 return ret;
383}
384
385static int lm3532_init_registers(struct lm3532_led *led)
386{
387 struct lm3532_data *drvdata = led->priv;
388 unsigned int runtime_ramp_val;
389 unsigned int output_cfg_val = 0;
390 unsigned int output_cfg_shift = 0;
391 unsigned int output_cfg_mask = 0;
Dan Murphy13123942019-08-20 14:53:03 -0500392 unsigned int brightness_config_reg;
393 unsigned int brightness_config_val;
Dan Murphy517ea492019-08-20 14:53:07 -0500394 int fs_current_reg;
395 int fs_current_val;
Dan Murphybc1b8492019-03-21 09:28:38 -0500396 int ret, i;
397
Dan Murphy13123942019-08-20 14:53:03 -0500398 if (drvdata->enable_gpio)
399 gpiod_direction_output(drvdata->enable_gpio, 1);
400
401 brightness_config_reg = LM3532_REG_ZONE_CFG_A + led->control_bank * 2;
402 /*
403 * This could be hard coded to the default value but the control
404 * brightness register may have changed during boot.
405 */
406 ret = regmap_read(drvdata->regmap, brightness_config_reg,
407 &led->ctrl_brt_pointer);
408 if (ret)
409 return ret;
410
411 led->ctrl_brt_pointer &= LM3532_ZONE_MASK;
412 brightness_config_val = led->ctrl_brt_pointer | led->mode;
413 ret = regmap_write(drvdata->regmap, brightness_config_reg,
414 brightness_config_val);
415 if (ret)
416 return ret;
417
Dan Murphy517ea492019-08-20 14:53:07 -0500418 if (led->full_scale_current) {
419 fs_current_reg = LM3532_REG_CTRL_A_FS_CURR + led->control_bank * 2;
420 fs_current_val = (led->full_scale_current - LM3532_FS_CURR_MIN) /
421 LM3532_FS_CURR_STEP;
422
423 ret = regmap_write(drvdata->regmap, fs_current_reg,
424 fs_current_val);
425 if (ret)
426 return ret;
427 }
428
Dan Murphybc1b8492019-03-21 09:28:38 -0500429 for (i = 0; i < led->num_leds; i++) {
430 output_cfg_shift = led->led_strings[i] * 2;
431 output_cfg_val |= (led->control_bank << output_cfg_shift);
432 output_cfg_mask |= LM3532_OUTPUT_CFG_MASK << output_cfg_shift;
433 }
434
435 ret = regmap_update_bits(drvdata->regmap, LM3532_REG_OUTPUT_CFG,
436 output_cfg_mask, output_cfg_val);
437 if (ret)
438 return ret;
439
440 runtime_ramp_val = drvdata->runtime_ramp_up |
441 (drvdata->runtime_ramp_down << LM3532_RAMP_DOWN_SHIFT);
442
443 return regmap_write(drvdata->regmap, LM3532_REG_RT_RAMP,
444 runtime_ramp_val);
445}
446
447static int lm3532_als_configure(struct lm3532_data *priv,
448 struct lm3532_led *led)
449{
450 struct lm3532_als_data *als = priv->als_data;
451 u32 als_vmin, als_vmax, als_vstep;
452 int zone_reg = LM3532_REG_ZN_0_HI;
Dan Murphybc1b8492019-03-21 09:28:38 -0500453 int ret;
454 int i;
455
456 als_vmin = als->als_vmin;
457 als_vmax = als->als_vmax;
458
459 als_vstep = (als_vmax - als_vmin) / ((LM3532_ALS_ZB_MAX + 1) * 2);
460
461 for (i = 0; i < LM3532_ALS_ZB_MAX; i++) {
462 als->zones_lo[i] = ((als_vmin + als_vstep + (i * als_vstep)) *
463 LED_FULL) / 1000;
464 als->zones_hi[i] = ((als_vmin + LM3532_ALS_OFFSET_mV +
465 als_vstep + (i * als_vstep)) * LED_FULL) / 1000;
466
467 zone_reg = LM3532_REG_ZN_0_HI + i * 2;
468 ret = regmap_write(priv->regmap, zone_reg, als->zones_lo[i]);
469 if (ret)
470 return ret;
471
472 zone_reg += 1;
473 ret = regmap_write(priv->regmap, zone_reg, als->zones_hi[i]);
474 if (ret)
475 return ret;
476 }
477
478 als->config = (als->als_avrg_time | (LM3532_ENABLE_ALS) |
479 (als->als_input_mode << LM3532_ALS_SEL_SHIFT));
480
Dan Murphy13123942019-08-20 14:53:03 -0500481 return regmap_write(priv->regmap, LM3532_ALS_CONFIG, als->config);
Dan Murphybc1b8492019-03-21 09:28:38 -0500482}
483
484static int lm3532_parse_als(struct lm3532_data *priv)
485{
486 struct lm3532_als_data *als;
487 int als_avg_time;
488 int als_impedance;
489 int ret;
490
491 als = devm_kzalloc(priv->dev, sizeof(*als), GFP_KERNEL);
492 if (als == NULL)
493 return -ENOMEM;
494
495 ret = device_property_read_u32(&priv->client->dev, "ti,als-vmin",
496 &als->als_vmin);
497 if (ret)
498 als->als_vmin = 0;
499
500 ret = device_property_read_u32(&priv->client->dev, "ti,als-vmax",
501 &als->als_vmax);
502 if (ret)
503 als->als_vmax = LM3532_ALS_WINDOW_mV;
504
505 if (als->als_vmax > LM3532_ALS_WINDOW_mV) {
506 ret = -EINVAL;
507 return ret;
508 }
509
510 ret = device_property_read_u32(&priv->client->dev, "ti,als1-imp-sel",
511 &als_impedance);
512 if (ret)
513 als->als1_imp_sel = 0;
514 else
515 als->als1_imp_sel = lm3532_get_als_imp_index(als_impedance);
516
517 ret = device_property_read_u32(&priv->client->dev, "ti,als2-imp-sel",
518 &als_impedance);
519 if (ret)
520 als->als2_imp_sel = 0;
521 else
522 als->als2_imp_sel = lm3532_get_als_imp_index(als_impedance);
523
524 ret = device_property_read_u32(&priv->client->dev, "ti,als-avrg-time-us",
525 &als_avg_time);
526 if (ret)
527 als->als_avrg_time = 0;
528 else
529 als->als_avrg_time = lm3532_get_als_avg_index(als_avg_time);
530
531 ret = device_property_read_u8(&priv->client->dev, "ti,als-input-mode",
532 &als->als_input_mode);
533 if (ret)
534 als->als_input_mode = 0;
535
536 if (als->als_input_mode > LM3532_BL_MODE_ALS) {
537 ret = -EINVAL;
538 return ret;
539 }
540
541 priv->als_data = als;
542
543 return ret;
544}
545
546static int lm3532_parse_node(struct lm3532_data *priv)
547{
548 struct fwnode_handle *child = NULL;
549 struct lm3532_led *led;
550 const char *name;
551 int control_bank;
552 u32 ramp_time;
553 size_t i = 0;
554 int ret;
555
556 priv->enable_gpio = devm_gpiod_get_optional(&priv->client->dev,
557 "enable", GPIOD_OUT_LOW);
558 if (IS_ERR(priv->enable_gpio))
559 priv->enable_gpio = NULL;
560
561 priv->regulator = devm_regulator_get(&priv->client->dev, "vin");
562 if (IS_ERR(priv->regulator))
563 priv->regulator = NULL;
564
565 ret = device_property_read_u32(&priv->client->dev, "ramp-up-us",
566 &ramp_time);
567 if (ret)
568 dev_info(&priv->client->dev, "ramp-up-ms property missing\n");
569 else
570 priv->runtime_ramp_up = lm3532_get_ramp_index(ramp_time);
571
572 ret = device_property_read_u32(&priv->client->dev, "ramp-down-us",
573 &ramp_time);
574 if (ret)
575 dev_info(&priv->client->dev, "ramp-down-ms property missing\n");
576 else
577 priv->runtime_ramp_down = lm3532_get_ramp_index(ramp_time);
578
579 device_for_each_child_node(priv->dev, child) {
580 led = &priv->leds[i];
581
582 ret = fwnode_property_read_u32(child, "reg", &control_bank);
583 if (ret) {
584 dev_err(&priv->client->dev, "reg property missing\n");
585 fwnode_handle_put(child);
586 goto child_out;
587 }
588
589 if (control_bank > LM3532_CONTROL_C) {
590 dev_err(&priv->client->dev, "Control bank invalid\n");
591 continue;
592 }
593
594 led->control_bank = control_bank;
595
596 ret = fwnode_property_read_u32(child, "ti,led-mode",
597 &led->mode);
598 if (ret) {
599 dev_err(&priv->client->dev, "ti,led-mode property missing\n");
600 fwnode_handle_put(child);
601 goto child_out;
602 }
603
Dan Murphy517ea492019-08-20 14:53:07 -0500604 ret = fwnode_property_read_u32(child, "led-max-microamp",
605 &led->full_scale_current);
606
607 if (led->full_scale_current > LM3532_FS_CURR_MAX)
608 led->full_scale_current = LM3532_FS_CURR_MAX;
609
Dan Murphybc1b8492019-03-21 09:28:38 -0500610 if (led->mode == LM3532_BL_MODE_ALS) {
Dan Murphy6559ac32019-08-20 14:53:05 -0500611 led->mode = LM3532_ALS_CTRL;
Dan Murphybc1b8492019-03-21 09:28:38 -0500612 ret = lm3532_parse_als(priv);
613 if (ret)
614 dev_err(&priv->client->dev, "Failed to parse als\n");
615 else
616 lm3532_als_configure(priv, led);
Dan Murphy6559ac32019-08-20 14:53:05 -0500617 } else {
618 led->mode = LM3532_I2C_CTRL;
Dan Murphybc1b8492019-03-21 09:28:38 -0500619 }
620
Andy Shevchenkocc93c862019-07-23 23:14:57 +0300621 led->num_leds = fwnode_property_count_u32(child, "led-sources");
Dan Murphybc1b8492019-03-21 09:28:38 -0500622 if (led->num_leds > LM3532_MAX_LED_STRINGS) {
623 dev_err(&priv->client->dev, "To many LED string defined\n");
624 continue;
625 }
626
627 ret = fwnode_property_read_u32_array(child, "led-sources",
628 led->led_strings,
629 led->num_leds);
630 if (ret) {
631 dev_err(&priv->client->dev, "led-sources property missing\n");
632 fwnode_handle_put(child);
633 goto child_out;
634 }
635
636 fwnode_property_read_string(child, "linux,default-trigger",
637 &led->led_dev.default_trigger);
638
639 ret = fwnode_property_read_string(child, "label", &name);
640 if (ret)
641 snprintf(led->label, sizeof(led->label),
642 "%s::", priv->client->name);
643 else
644 snprintf(led->label, sizeof(led->label),
645 "%s:%s", priv->client->name, name);
646
647 led->priv = priv;
648 led->led_dev.name = led->label;
649 led->led_dev.brightness_set_blocking = lm3532_brightness_set;
650
651 ret = devm_led_classdev_register(priv->dev, &led->led_dev);
652 if (ret) {
653 dev_err(&priv->client->dev, "led register err: %d\n",
654 ret);
655 fwnode_handle_put(child);
656 goto child_out;
657 }
658
Dan Murphy6559ac32019-08-20 14:53:05 -0500659 ret = lm3532_init_registers(led);
660 if (ret) {
661 dev_err(&priv->client->dev, "register init err: %d\n",
662 ret);
663 fwnode_handle_put(child);
664 goto child_out;
665 }
Dan Murphybc1b8492019-03-21 09:28:38 -0500666
667 i++;
668 }
669
670child_out:
671 return ret;
672}
673
674static int lm3532_probe(struct i2c_client *client,
675 const struct i2c_device_id *id)
676{
677 struct lm3532_data *drvdata;
678 int ret = 0;
679 int count;
680
681 count = device_get_child_node_count(&client->dev);
682 if (!count) {
683 dev_err(&client->dev, "LEDs are not defined in device tree!");
684 return -ENODEV;
685 }
686
687 drvdata = devm_kzalloc(&client->dev, struct_size(drvdata, leds, count),
688 GFP_KERNEL);
689 if (drvdata == NULL)
690 return -ENOMEM;
691
692 drvdata->client = client;
693 drvdata->dev = &client->dev;
694
695 drvdata->regmap = devm_regmap_init_i2c(client, &lm3532_regmap_config);
696 if (IS_ERR(drvdata->regmap)) {
697 ret = PTR_ERR(drvdata->regmap);
698 dev_err(&client->dev, "Failed to allocate register map: %d\n",
699 ret);
700 return ret;
701 }
702
703 mutex_init(&drvdata->lock);
704 i2c_set_clientdata(client, drvdata);
705
706 ret = lm3532_parse_node(drvdata);
707 if (ret) {
708 dev_err(&client->dev, "Failed to parse node\n");
709 return ret;
710 }
711
Dan Murphybc1b8492019-03-21 09:28:38 -0500712 return ret;
713}
714
715static int lm3532_remove(struct i2c_client *client)
716{
717 struct lm3532_data *drvdata = i2c_get_clientdata(client);
718
719 mutex_destroy(&drvdata->lock);
720
721 if (drvdata->enable_gpio)
722 gpiod_direction_output(drvdata->enable_gpio, 0);
723
724 return 0;
725}
726
727static const struct of_device_id of_lm3532_leds_match[] = {
728 { .compatible = "ti,lm3532", },
729 {},
730};
731MODULE_DEVICE_TABLE(of, of_lm3532_leds_match);
732
733static const struct i2c_device_id lm3532_id[] = {
734 {LM3532_NAME, 0},
735 {}
736};
737MODULE_DEVICE_TABLE(i2c, lm3532_id);
738
739static struct i2c_driver lm3532_i2c_driver = {
740 .probe = lm3532_probe,
741 .remove = lm3532_remove,
742 .id_table = lm3532_id,
743 .driver = {
744 .name = LM3532_NAME,
745 .of_match_table = of_lm3532_leds_match,
746 },
747};
748module_i2c_driver(lm3532_i2c_driver);
749
750MODULE_DESCRIPTION("Back Light driver for LM3532");
751MODULE_LICENSE("GPL v2");
752MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");