xref: /linux/drivers/leds/leds-lm3530.c (revision 08b7174fb8d126e607e385e34b9e1da4f3be274f)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2011 ST-Ericsson SA.
4  * Copyright (C) 2009 Motorola, Inc.
5  *
6  * Simple driver for National Semiconductor LM3530 Backlight driver chip
7  *
8  * Author: Shreshtha Kumar SAHU <shreshthakumar.sahu@stericsson.com>
9  * based on leds-lm3530.c by Dan Murphy <D.Murphy@motorola.com>
10  */
11 
12 #include <linux/i2c.h>
13 #include <linux/leds.h>
14 #include <linux/slab.h>
15 #include <linux/platform_device.h>
16 #include <linux/input.h>
17 #include <linux/led-lm3530.h>
18 #include <linux/types.h>
19 #include <linux/regulator/consumer.h>
20 #include <linux/module.h>
21 
22 #define LM3530_LED_DEV "lcd-backlight"
23 #define LM3530_NAME "lm3530-led"
24 
25 #define LM3530_GEN_CONFIG		0x10
26 #define LM3530_ALS_CONFIG		0x20
27 #define LM3530_BRT_RAMP_RATE		0x30
28 #define LM3530_ALS_IMP_SELECT		0x41
29 #define LM3530_BRT_CTRL_REG		0xA0
30 #define LM3530_ALS_ZB0_REG		0x60
31 #define LM3530_ALS_ZB1_REG		0x61
32 #define LM3530_ALS_ZB2_REG		0x62
33 #define LM3530_ALS_ZB3_REG		0x63
34 #define LM3530_ALS_Z0T_REG		0x70
35 #define LM3530_ALS_Z1T_REG		0x71
36 #define LM3530_ALS_Z2T_REG		0x72
37 #define LM3530_ALS_Z3T_REG		0x73
38 #define LM3530_ALS_Z4T_REG		0x74
39 #define LM3530_REG_MAX			14
40 
41 /* General Control Register */
42 #define LM3530_EN_I2C_SHIFT		(0)
43 #define LM3530_RAMP_LAW_SHIFT		(1)
44 #define LM3530_MAX_CURR_SHIFT		(2)
45 #define LM3530_EN_PWM_SHIFT		(5)
46 #define LM3530_PWM_POL_SHIFT		(6)
47 #define LM3530_EN_PWM_SIMPLE_SHIFT	(7)
48 
49 #define LM3530_ENABLE_I2C		(1 << LM3530_EN_I2C_SHIFT)
50 #define LM3530_ENABLE_PWM		(1 << LM3530_EN_PWM_SHIFT)
51 #define LM3530_POL_LOW			(1 << LM3530_PWM_POL_SHIFT)
52 #define LM3530_ENABLE_PWM_SIMPLE	(1 << LM3530_EN_PWM_SIMPLE_SHIFT)
53 
54 /* ALS Config Register Options */
55 #define LM3530_ALS_AVG_TIME_SHIFT	(0)
56 #define LM3530_EN_ALS_SHIFT		(3)
57 #define LM3530_ALS_SEL_SHIFT		(5)
58 
59 #define LM3530_ENABLE_ALS		(3 << LM3530_EN_ALS_SHIFT)
60 
61 /* Brightness Ramp Rate Register */
62 #define LM3530_BRT_RAMP_FALL_SHIFT	(0)
63 #define LM3530_BRT_RAMP_RISE_SHIFT	(3)
64 
65 /* ALS Resistor Select */
66 #define LM3530_ALS1_IMP_SHIFT		(0)
67 #define LM3530_ALS2_IMP_SHIFT		(4)
68 
69 /* Zone Boundary Register defaults */
70 #define LM3530_ALS_ZB_MAX		(4)
71 #define LM3530_ALS_WINDOW_mV		(1000)
72 #define LM3530_ALS_OFFSET_mV		(4)
73 
74 /* Zone Target Register defaults */
75 #define LM3530_DEF_ZT_0			(0x7F)
76 #define LM3530_DEF_ZT_1			(0x66)
77 #define LM3530_DEF_ZT_2			(0x4C)
78 #define LM3530_DEF_ZT_3			(0x33)
79 #define LM3530_DEF_ZT_4			(0x19)
80 
81 /* 7 bits are used for the brightness : LM3530_BRT_CTRL_REG */
82 #define MAX_BRIGHTNESS			(127)
83 
84 struct lm3530_mode_map {
85 	const char *mode;
86 	enum lm3530_mode mode_val;
87 };
88 
89 static struct lm3530_mode_map mode_map[] = {
90 	{ "man", LM3530_BL_MODE_MANUAL },
91 	{ "als", LM3530_BL_MODE_ALS },
92 	{ "pwm", LM3530_BL_MODE_PWM },
93 };
94 
95 /**
96  * struct lm3530_data
97  * @led_dev: led class device
98  * @client: i2c client
99  * @pdata: LM3530 platform data
100  * @mode: mode of operation - manual, ALS, PWM
101  * @regulator: regulator
102  * @brightness: previous brightness value
103  * @enable: regulator is enabled
104  */
105 struct lm3530_data {
106 	struct led_classdev led_dev;
107 	struct i2c_client *client;
108 	struct lm3530_platform_data *pdata;
109 	enum lm3530_mode mode;
110 	struct regulator *regulator;
111 	enum led_brightness brightness;
112 	bool enable;
113 };
114 
115 /*
116  * struct lm3530_als_data
117  * @config  : value of ALS configuration register
118  * @imp_sel : value of ALS resistor select register
119  * @zone    : values of ALS ZB(Zone Boundary) registers
120  */
121 struct lm3530_als_data {
122 	u8 config;
123 	u8 imp_sel;
124 	u8 zones[LM3530_ALS_ZB_MAX];
125 };
126 
127 static const u8 lm3530_reg[LM3530_REG_MAX] = {
128 	LM3530_GEN_CONFIG,
129 	LM3530_ALS_CONFIG,
130 	LM3530_BRT_RAMP_RATE,
131 	LM3530_ALS_IMP_SELECT,
132 	LM3530_BRT_CTRL_REG,
133 	LM3530_ALS_ZB0_REG,
134 	LM3530_ALS_ZB1_REG,
135 	LM3530_ALS_ZB2_REG,
136 	LM3530_ALS_ZB3_REG,
137 	LM3530_ALS_Z0T_REG,
138 	LM3530_ALS_Z1T_REG,
139 	LM3530_ALS_Z2T_REG,
140 	LM3530_ALS_Z3T_REG,
141 	LM3530_ALS_Z4T_REG,
142 };
143 
144 static int lm3530_get_mode_from_str(const char *str)
145 {
146 	int i;
147 
148 	for (i = 0; i < ARRAY_SIZE(mode_map); i++)
149 		if (sysfs_streq(str, mode_map[i].mode))
150 			return mode_map[i].mode_val;
151 
152 	return -EINVAL;
153 }
154 
155 static void lm3530_als_configure(struct lm3530_platform_data *pdata,
156 				struct lm3530_als_data *als)
157 {
158 	int i;
159 	u32 als_vmin, als_vmax, als_vstep;
160 
161 	if (pdata->als_vmax == 0) {
162 		pdata->als_vmin = 0;
163 		pdata->als_vmax = LM3530_ALS_WINDOW_mV;
164 	}
165 
166 	als_vmin = pdata->als_vmin;
167 	als_vmax = pdata->als_vmax;
168 
169 	if ((als_vmax - als_vmin) > LM3530_ALS_WINDOW_mV)
170 		pdata->als_vmax = als_vmax = als_vmin + LM3530_ALS_WINDOW_mV;
171 
172 	/* n zone boundary makes n+1 zones */
173 	als_vstep = (als_vmax - als_vmin) / (LM3530_ALS_ZB_MAX + 1);
174 
175 	for (i = 0; i < LM3530_ALS_ZB_MAX; i++)
176 		als->zones[i] = (((als_vmin + LM3530_ALS_OFFSET_mV) +
177 			als_vstep + (i * als_vstep)) * LED_FULL) / 1000;
178 
179 	als->config =
180 		(pdata->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
181 		(LM3530_ENABLE_ALS) |
182 		(pdata->als_input_mode << LM3530_ALS_SEL_SHIFT);
183 
184 	als->imp_sel =
185 		(pdata->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
186 		(pdata->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
187 }
188 
189 static int lm3530_led_enable(struct lm3530_data *drvdata)
190 {
191 	int ret;
192 
193 	if (drvdata->enable)
194 		return 0;
195 
196 	ret = regulator_enable(drvdata->regulator);
197 	if (ret) {
198 		dev_err(drvdata->led_dev.dev, "Failed to enable vin:%d\n", ret);
199 		return ret;
200 	}
201 
202 	drvdata->enable = true;
203 	return 0;
204 }
205 
206 static void lm3530_led_disable(struct lm3530_data *drvdata)
207 {
208 	int ret;
209 
210 	if (!drvdata->enable)
211 		return;
212 
213 	ret = regulator_disable(drvdata->regulator);
214 	if (ret) {
215 		dev_err(drvdata->led_dev.dev, "Failed to disable vin:%d\n",
216 			ret);
217 		return;
218 	}
219 
220 	drvdata->enable = false;
221 }
222 
223 static int lm3530_init_registers(struct lm3530_data *drvdata)
224 {
225 	int ret = 0;
226 	int i;
227 	u8 gen_config;
228 	u8 brt_ramp;
229 	u8 brightness;
230 	u8 reg_val[LM3530_REG_MAX];
231 	struct lm3530_platform_data *pdata = drvdata->pdata;
232 	struct i2c_client *client = drvdata->client;
233 	struct lm3530_pwm_data *pwm = &pdata->pwm_data;
234 	struct lm3530_als_data als;
235 
236 	memset(&als, 0, sizeof(struct lm3530_als_data));
237 
238 	gen_config = (pdata->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
239 			((pdata->max_current & 7) << LM3530_MAX_CURR_SHIFT);
240 
241 	switch (drvdata->mode) {
242 	case LM3530_BL_MODE_MANUAL:
243 		gen_config |= LM3530_ENABLE_I2C;
244 		break;
245 	case LM3530_BL_MODE_ALS:
246 		gen_config |= LM3530_ENABLE_I2C;
247 		lm3530_als_configure(pdata, &als);
248 		break;
249 	case LM3530_BL_MODE_PWM:
250 		gen_config |= LM3530_ENABLE_PWM | LM3530_ENABLE_PWM_SIMPLE |
251 			      (pdata->pwm_pol_hi << LM3530_PWM_POL_SHIFT);
252 		break;
253 	}
254 
255 	brt_ramp = (pdata->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
256 			(pdata->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
257 
258 	if (drvdata->brightness)
259 		brightness = drvdata->brightness;
260 	else
261 		brightness = drvdata->brightness = pdata->brt_val;
262 
263 	if (brightness > drvdata->led_dev.max_brightness)
264 		brightness = drvdata->led_dev.max_brightness;
265 
266 	reg_val[0] = gen_config;	/* LM3530_GEN_CONFIG */
267 	reg_val[1] = als.config;	/* LM3530_ALS_CONFIG */
268 	reg_val[2] = brt_ramp;		/* LM3530_BRT_RAMP_RATE */
269 	reg_val[3] = als.imp_sel;	/* LM3530_ALS_IMP_SELECT */
270 	reg_val[4] = brightness;	/* LM3530_BRT_CTRL_REG */
271 	reg_val[5] = als.zones[0];	/* LM3530_ALS_ZB0_REG */
272 	reg_val[6] = als.zones[1];	/* LM3530_ALS_ZB1_REG */
273 	reg_val[7] = als.zones[2];	/* LM3530_ALS_ZB2_REG */
274 	reg_val[8] = als.zones[3];	/* LM3530_ALS_ZB3_REG */
275 	reg_val[9] = LM3530_DEF_ZT_0;	/* LM3530_ALS_Z0T_REG */
276 	reg_val[10] = LM3530_DEF_ZT_1;	/* LM3530_ALS_Z1T_REG */
277 	reg_val[11] = LM3530_DEF_ZT_2;	/* LM3530_ALS_Z2T_REG */
278 	reg_val[12] = LM3530_DEF_ZT_3;	/* LM3530_ALS_Z3T_REG */
279 	reg_val[13] = LM3530_DEF_ZT_4;	/* LM3530_ALS_Z4T_REG */
280 
281 	ret = lm3530_led_enable(drvdata);
282 	if (ret)
283 		return ret;
284 
285 	for (i = 0; i < LM3530_REG_MAX; i++) {
286 		/* do not update brightness register when pwm mode */
287 		if (lm3530_reg[i] == LM3530_BRT_CTRL_REG &&
288 		    drvdata->mode == LM3530_BL_MODE_PWM) {
289 			if (pwm->pwm_set_intensity)
290 				pwm->pwm_set_intensity(reg_val[i],
291 					drvdata->led_dev.max_brightness);
292 			continue;
293 		}
294 
295 		ret = i2c_smbus_write_byte_data(client,
296 				lm3530_reg[i], reg_val[i]);
297 		if (ret)
298 			break;
299 	}
300 
301 	return ret;
302 }
303 
304 static void lm3530_brightness_set(struct led_classdev *led_cdev,
305 				     enum led_brightness brt_val)
306 {
307 	int err;
308 	struct lm3530_data *drvdata =
309 	    container_of(led_cdev, struct lm3530_data, led_dev);
310 	struct lm3530_platform_data *pdata = drvdata->pdata;
311 	struct lm3530_pwm_data *pwm = &pdata->pwm_data;
312 	u8 max_brightness = led_cdev->max_brightness;
313 
314 	switch (drvdata->mode) {
315 	case LM3530_BL_MODE_MANUAL:
316 
317 		if (!drvdata->enable) {
318 			err = lm3530_init_registers(drvdata);
319 			if (err) {
320 				dev_err(&drvdata->client->dev,
321 					"Register Init failed: %d\n", err);
322 				break;
323 			}
324 		}
325 
326 		/* set the brightness in brightness control register*/
327 		err = i2c_smbus_write_byte_data(drvdata->client,
328 				LM3530_BRT_CTRL_REG, brt_val);
329 		if (err)
330 			dev_err(&drvdata->client->dev,
331 				"Unable to set brightness: %d\n", err);
332 		else
333 			drvdata->brightness = brt_val;
334 
335 		if (brt_val == 0)
336 			lm3530_led_disable(drvdata);
337 		break;
338 	case LM3530_BL_MODE_ALS:
339 		break;
340 	case LM3530_BL_MODE_PWM:
341 		if (pwm->pwm_set_intensity)
342 			pwm->pwm_set_intensity(brt_val, max_brightness);
343 		break;
344 	default:
345 		break;
346 	}
347 }
348 
349 static ssize_t mode_show(struct device *dev,
350 			 struct device_attribute *attr, char *buf)
351 {
352 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
353 	struct lm3530_data *drvdata;
354 	int i, len = 0;
355 
356 	drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
357 	for (i = 0; i < ARRAY_SIZE(mode_map); i++)
358 		if (drvdata->mode == mode_map[i].mode_val)
359 			len += sprintf(buf + len, "[%s] ", mode_map[i].mode);
360 		else
361 			len += sprintf(buf + len, "%s ", mode_map[i].mode);
362 
363 	len += sprintf(buf + len, "\n");
364 
365 	return len;
366 }
367 
368 static ssize_t mode_store(struct device *dev, struct device_attribute
369 			  *attr, const char *buf, size_t size)
370 {
371 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
372 	struct lm3530_data *drvdata;
373 	struct lm3530_pwm_data *pwm;
374 	u8 max_brightness;
375 	int mode, err;
376 
377 	drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
378 	pwm = &drvdata->pdata->pwm_data;
379 	max_brightness = led_cdev->max_brightness;
380 	mode = lm3530_get_mode_from_str(buf);
381 	if (mode < 0) {
382 		dev_err(dev, "Invalid mode\n");
383 		return mode;
384 	}
385 
386 	drvdata->mode = mode;
387 
388 	/* set pwm to low if unnecessary */
389 	if (mode != LM3530_BL_MODE_PWM && pwm->pwm_set_intensity)
390 		pwm->pwm_set_intensity(0, max_brightness);
391 
392 	err = lm3530_init_registers(drvdata);
393 	if (err) {
394 		dev_err(dev, "Setting %s Mode failed :%d\n", buf, err);
395 		return err;
396 	}
397 
398 	return sizeof(drvdata->mode);
399 }
400 static DEVICE_ATTR_RW(mode);
401 
402 static struct attribute *lm3530_attrs[] = {
403 	&dev_attr_mode.attr,
404 	NULL
405 };
406 ATTRIBUTE_GROUPS(lm3530);
407 
408 static int lm3530_probe(struct i2c_client *client)
409 {
410 	struct lm3530_platform_data *pdata = dev_get_platdata(&client->dev);
411 	struct lm3530_data *drvdata;
412 	int err = 0;
413 
414 	if (pdata == NULL) {
415 		dev_err(&client->dev, "platform data required\n");
416 		return -ENODEV;
417 	}
418 
419 	/* BL mode */
420 	if (pdata->mode > LM3530_BL_MODE_PWM) {
421 		dev_err(&client->dev, "Illegal Mode request\n");
422 		return -EINVAL;
423 	}
424 
425 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
426 		dev_err(&client->dev, "I2C_FUNC_I2C not supported\n");
427 		return -EIO;
428 	}
429 
430 	drvdata = devm_kzalloc(&client->dev, sizeof(struct lm3530_data),
431 				GFP_KERNEL);
432 	if (drvdata == NULL)
433 		return -ENOMEM;
434 
435 	drvdata->mode = pdata->mode;
436 	drvdata->client = client;
437 	drvdata->pdata = pdata;
438 	drvdata->brightness = LED_OFF;
439 	drvdata->enable = false;
440 	drvdata->led_dev.name = LM3530_LED_DEV;
441 	drvdata->led_dev.brightness_set = lm3530_brightness_set;
442 	drvdata->led_dev.max_brightness = MAX_BRIGHTNESS;
443 	drvdata->led_dev.groups = lm3530_groups;
444 
445 	i2c_set_clientdata(client, drvdata);
446 
447 	drvdata->regulator = devm_regulator_get(&client->dev, "vin");
448 	if (IS_ERR(drvdata->regulator)) {
449 		dev_err(&client->dev, "regulator get failed\n");
450 		err = PTR_ERR(drvdata->regulator);
451 		drvdata->regulator = NULL;
452 		return err;
453 	}
454 
455 	if (drvdata->pdata->brt_val) {
456 		err = lm3530_init_registers(drvdata);
457 		if (err < 0) {
458 			dev_err(&client->dev,
459 				"Register Init failed: %d\n", err);
460 			return err;
461 		}
462 	}
463 	err = led_classdev_register(&client->dev, &drvdata->led_dev);
464 	if (err < 0) {
465 		dev_err(&client->dev, "Register led class failed: %d\n", err);
466 		return err;
467 	}
468 
469 	return 0;
470 }
471 
472 static void lm3530_remove(struct i2c_client *client)
473 {
474 	struct lm3530_data *drvdata = i2c_get_clientdata(client);
475 
476 	lm3530_led_disable(drvdata);
477 	led_classdev_unregister(&drvdata->led_dev);
478 }
479 
480 static const struct i2c_device_id lm3530_id[] = {
481 	{LM3530_NAME, 0},
482 	{}
483 };
484 MODULE_DEVICE_TABLE(i2c, lm3530_id);
485 
486 static struct i2c_driver lm3530_i2c_driver = {
487 	.probe = lm3530_probe,
488 	.remove = lm3530_remove,
489 	.id_table = lm3530_id,
490 	.driver = {
491 		.name = LM3530_NAME,
492 	},
493 };
494 
495 module_i2c_driver(lm3530_i2c_driver);
496 
497 MODULE_DESCRIPTION("Back Light driver for LM3530");
498 MODULE_LICENSE("GPL v2");
499 MODULE_AUTHOR("Shreshtha Kumar SAHU <shreshthakumar.sahu@stericsson.com>");
500