xref: /openbmc/linux/drivers/leds/leds-aw200xx.c (revision bd4d5b6f)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Awinic AW20036/AW20054/AW20072 LED driver
4  *
5  * Copyright (c) 2023, SberDevices. All Rights Reserved.
6  *
7  * Author: Martin Kurbanov <mmkurbanov@sberdevices.ru>
8  */
9 
10 #include <linux/bitfield.h>
11 #include <linux/bits.h>
12 #include <linux/container_of.h>
13 #include <linux/i2c.h>
14 #include <linux/leds.h>
15 #include <linux/mod_devicetable.h>
16 #include <linux/module.h>
17 #include <linux/mutex.h>
18 #include <linux/regmap.h>
19 #include <linux/time.h>
20 #include <linux/units.h>
21 
22 #define AW200XX_DIM_MAX                  (BIT(6) - 1)
23 #define AW200XX_FADE_MAX                 (BIT(8) - 1)
24 #define AW200XX_IMAX_DEFAULT_uA          60000
25 #define AW200XX_IMAX_MAX_uA              160000
26 #define AW200XX_IMAX_MIN_uA              3300
27 
28 /* Page 0 */
29 #define AW200XX_REG_PAGE0_BASE 0xc000
30 
31 /* Select page register */
32 #define AW200XX_REG_PAGE       0xF0
33 #define AW200XX_PAGE_MASK      (GENMASK(7, 6) | GENMASK(2, 0))
34 #define AW200XX_PAGE_SHIFT     0
35 #define AW200XX_NUM_PAGES      6
36 #define AW200XX_PAGE_SIZE      256
37 #define AW200XX_REG(page, reg) \
38 	(AW200XX_REG_PAGE0_BASE + (page) * AW200XX_PAGE_SIZE + (reg))
39 #define AW200XX_REG_MAX \
40 	AW200XX_REG(AW200XX_NUM_PAGES - 1, AW200XX_PAGE_SIZE - 1)
41 #define AW200XX_PAGE0 0
42 #define AW200XX_PAGE1 1
43 #define AW200XX_PAGE2 2
44 #define AW200XX_PAGE3 3
45 #define AW200XX_PAGE4 4
46 #define AW200XX_PAGE5 5
47 
48 /* Chip ID register */
49 #define AW200XX_REG_IDR       AW200XX_REG(AW200XX_PAGE0, 0x00)
50 #define AW200XX_IDR_CHIPID    0x18
51 
52 /* Sleep mode register */
53 #define AW200XX_REG_SLPCR     AW200XX_REG(AW200XX_PAGE0, 0x01)
54 #define AW200XX_SLPCR_ACTIVE  0x00
55 
56 /* Reset register */
57 #define AW200XX_REG_RSTR      AW200XX_REG(AW200XX_PAGE0, 0x02)
58 #define AW200XX_RSTR_RESET    0x01
59 
60 /* Global current configuration register */
61 #define AW200XX_REG_GCCR        AW200XX_REG(AW200XX_PAGE0, 0x03)
62 #define AW200XX_GCCR_IMAX_MASK  GENMASK(7, 4)
63 #define AW200XX_GCCR_IMAX(x)    ((x) << 4)
64 #define AW200XX_GCCR_ALLON      BIT(3)
65 
66 /* Fast clear display control register */
67 #define AW200XX_REG_FCD       AW200XX_REG(AW200XX_PAGE0, 0x04)
68 #define AW200XX_FCD_CLEAR     0x01
69 
70 /* Display size configuration */
71 #define AW200XX_REG_DSIZE          AW200XX_REG(AW200XX_PAGE0, 0x80)
72 #define AW200XX_DSIZE_COLUMNS_MAX  12
73 
74 #define AW200XX_LED2REG(x, columns) \
75 	((x) + (((x) / (columns)) * (AW200XX_DSIZE_COLUMNS_MAX - (columns))))
76 
77 /* DIM current configuration register on page 1 */
78 #define AW200XX_REG_DIM_PAGE1(x, columns) \
79 	AW200XX_REG(AW200XX_PAGE1, AW200XX_LED2REG(x, columns))
80 
81 /*
82  * DIM current configuration register (page 4).
83  * The even address for current DIM configuration.
84  * The odd address for current FADE configuration
85  */
86 #define AW200XX_REG_DIM(x, columns) \
87 	AW200XX_REG(AW200XX_PAGE4, AW200XX_LED2REG(x, columns) * 2)
88 #define AW200XX_REG_DIM2FADE(x) ((x) + 1)
89 
90 /*
91  * Duty ratio of display scan (see p.15 of datasheet for formula):
92  *   duty = (592us / 600.5us) * (1 / (display_rows + 1))
93  *
94  * Multiply to 1000 (MILLI) to improve the accuracy of calculations.
95  */
96 #define AW200XX_DUTY_RATIO(rows) \
97 	(((592UL * USEC_PER_SEC) / 600500UL) * (MILLI / (rows)) / MILLI)
98 
99 struct aw200xx_chipdef {
100 	u32 channels;
101 	u32 display_size_rows_max;
102 	u32 display_size_columns;
103 };
104 
105 struct aw200xx_led {
106 	struct led_classdev cdev;
107 	struct aw200xx *chip;
108 	int dim;
109 	u32 num;
110 };
111 
112 struct aw200xx {
113 	const struct aw200xx_chipdef *cdef;
114 	struct i2c_client *client;
115 	struct regmap *regmap;
116 	struct mutex mutex;
117 	u32 num_leds;
118 	u32 display_rows;
119 	struct aw200xx_led leds[];
120 };
121 
dim_show(struct device * dev,struct device_attribute * devattr,char * buf)122 static ssize_t dim_show(struct device *dev, struct device_attribute *devattr,
123 			char *buf)
124 {
125 	struct led_classdev *cdev = dev_get_drvdata(dev);
126 	struct aw200xx_led *led = container_of(cdev, struct aw200xx_led, cdev);
127 	int dim = led->dim;
128 
129 	if (dim < 0)
130 		return sysfs_emit(buf, "auto\n");
131 
132 	return sysfs_emit(buf, "%d\n", dim);
133 }
134 
dim_store(struct device * dev,struct device_attribute * devattr,const char * buf,size_t count)135 static ssize_t dim_store(struct device *dev, struct device_attribute *devattr,
136 			 const char *buf, size_t count)
137 {
138 	struct led_classdev *cdev = dev_get_drvdata(dev);
139 	struct aw200xx_led *led = container_of(cdev, struct aw200xx_led, cdev);
140 	struct aw200xx *chip = led->chip;
141 	u32 columns = chip->cdef->display_size_columns;
142 	int dim;
143 	ssize_t ret;
144 
145 	if (sysfs_streq(buf, "auto")) {
146 		dim = -1;
147 	} else {
148 		ret = kstrtoint(buf, 0, &dim);
149 		if (ret)
150 			return ret;
151 
152 		if (dim > AW200XX_DIM_MAX)
153 			return -EINVAL;
154 	}
155 
156 	mutex_lock(&chip->mutex);
157 
158 	if (dim >= 0) {
159 		ret = regmap_write(chip->regmap,
160 				   AW200XX_REG_DIM_PAGE1(led->num, columns),
161 				   dim);
162 		if (ret)
163 			goto out_unlock;
164 	}
165 
166 	led->dim = dim;
167 	ret = count;
168 
169 out_unlock:
170 	mutex_unlock(&chip->mutex);
171 	return ret;
172 }
173 static DEVICE_ATTR_RW(dim);
174 
175 static struct attribute *dim_attrs[] = {
176 	&dev_attr_dim.attr,
177 	NULL
178 };
179 ATTRIBUTE_GROUPS(dim);
180 
aw200xx_brightness_set(struct led_classdev * cdev,enum led_brightness brightness)181 static int aw200xx_brightness_set(struct led_classdev *cdev,
182 				  enum led_brightness brightness)
183 {
184 	struct aw200xx_led *led = container_of(cdev, struct aw200xx_led, cdev);
185 	struct aw200xx *chip = led->chip;
186 	int dim;
187 	u32 reg;
188 	int ret;
189 
190 	mutex_lock(&chip->mutex);
191 
192 	reg = AW200XX_REG_DIM(led->num, chip->cdef->display_size_columns);
193 
194 	dim = led->dim;
195 	if (dim < 0)
196 		dim = max_t(int,
197 			    brightness / (AW200XX_FADE_MAX / AW200XX_DIM_MAX),
198 			    1);
199 
200 	ret = regmap_write(chip->regmap, reg, dim);
201 	if (ret)
202 		goto out_unlock;
203 
204 	ret = regmap_write(chip->regmap,
205 			   AW200XX_REG_DIM2FADE(reg), brightness);
206 
207 out_unlock:
208 	mutex_unlock(&chip->mutex);
209 
210 	return ret;
211 }
212 
aw200xx_imax_from_global(const struct aw200xx * const chip,u32 global_imax_uA)213 static u32 aw200xx_imax_from_global(const struct aw200xx *const chip,
214 				    u32 global_imax_uA)
215 {
216 	u64 led_imax_uA;
217 
218 	/*
219 	 * The output current of each LED (see p.14 of datasheet for formula):
220 	 *   Iled = Imax * (dim / 63) * ((fade + 1) / 256) * duty
221 	 *
222 	 * The value of duty is determined by the following formula:
223 	 *   duty = (592us / 600.5us) * (1 / (display_rows + 1))
224 	 *
225 	 * Calculated for the maximum values of fade and dim.
226 	 * We divide by 1000 because we earlier multiplied by 1000 to improve
227 	 * accuracy when calculating the duty.
228 	 */
229 	led_imax_uA = global_imax_uA * AW200XX_DUTY_RATIO(chip->display_rows);
230 	do_div(led_imax_uA, MILLI);
231 
232 	return led_imax_uA;
233 }
234 
aw200xx_imax_to_global(const struct aw200xx * const chip,u32 led_imax_uA)235 static u32 aw200xx_imax_to_global(const struct aw200xx *const chip,
236 				  u32 led_imax_uA)
237 {
238 	u32 duty = AW200XX_DUTY_RATIO(chip->display_rows);
239 
240 	/* The output current of each LED (see p.14 of datasheet for formula) */
241 	return (led_imax_uA * 1000U) / duty;
242 }
243 
244 #define AW200XX_IMAX_MULTIPLIER1    10000
245 #define AW200XX_IMAX_MULTIPLIER2    3333
246 #define AW200XX_IMAX_BASE_VAL1      0
247 #define AW200XX_IMAX_BASE_VAL2      8
248 
249 /*
250  * The AW200XX has a 4-bit register (GCCR) to configure the global current,
251  * which ranges from 3.3mA to 160mA. The following table indicates the values
252  * of the global current, divided into two parts:
253  *
254  * +-----------+-----------------+-----------+-----------------+
255  * | reg value | global max (mA) | reg value | global max (mA) |
256  * +-----------+-----------------+-----------+-----------------+
257  * | 0         | 10              | 8         | 3.3             |
258  * | 1         | 20              | 9         | 6.7             |
259  * | 2         | 30              | 10        | 10              |
260  * | 3         | 40              | 11        | 13.3            |
261  * | 4         | 60              | 12        | 20              |
262  * | 5         | 80              | 13        | 26.7            |
263  * | 6         | 120             | 14        | 40              |
264  * | 7         | 160             | 15        | 53.3            |
265  * +-----------+-----------------+-----------+-----------------+
266  *
267  * The left part  with a multiplier of 10, and the right part  with a multiplier
268  * of 3.3.
269  * So we have two formulas to calculate the global current:
270  *   for the left part of the table:
271  *     imax = coefficient * 10
272  *
273  *   for the right part of the table:
274  *     imax = coefficient * 3.3
275  *
276  * The coefficient table consists of the following values:
277  *   1, 2, 3, 4, 6, 8, 12, 16.
278  */
aw200xx_set_imax(const struct aw200xx * const chip,u32 led_imax_uA)279 static int aw200xx_set_imax(const struct aw200xx *const chip,
280 			    u32 led_imax_uA)
281 {
282 	u32 g_imax_uA = aw200xx_imax_to_global(chip, led_imax_uA);
283 	u32 coeff_table[] = {1, 2, 3, 4, 6, 8, 12, 16};
284 	u32 gccr_imax = UINT_MAX;
285 	u32 cur_imax = 0;
286 	int i;
287 
288 	for (i = 0; i < ARRAY_SIZE(coeff_table); i++) {
289 		u32 imax;
290 
291 		/* select closest ones */
292 		imax = coeff_table[i] * AW200XX_IMAX_MULTIPLIER1;
293 		if (g_imax_uA >= imax && imax > cur_imax) {
294 			cur_imax = imax;
295 			gccr_imax = i + AW200XX_IMAX_BASE_VAL1;
296 		}
297 
298 		imax = coeff_table[i] * AW200XX_IMAX_MULTIPLIER2;
299 		imax = DIV_ROUND_CLOSEST(imax, 100) * 100;
300 		if (g_imax_uA >= imax && imax > cur_imax) {
301 			cur_imax = imax;
302 			gccr_imax = i + AW200XX_IMAX_BASE_VAL2;
303 		}
304 	}
305 
306 	if (gccr_imax == UINT_MAX)
307 		return -EINVAL;
308 
309 	return regmap_update_bits(chip->regmap, AW200XX_REG_GCCR,
310 				  AW200XX_GCCR_IMAX_MASK,
311 				  AW200XX_GCCR_IMAX(gccr_imax));
312 }
313 
aw200xx_chip_reset(const struct aw200xx * const chip)314 static int aw200xx_chip_reset(const struct aw200xx *const chip)
315 {
316 	int ret;
317 
318 	ret = regmap_write(chip->regmap, AW200XX_REG_RSTR, AW200XX_RSTR_RESET);
319 	if (ret)
320 		return ret;
321 
322 	regcache_mark_dirty(chip->regmap);
323 	return regmap_write(chip->regmap, AW200XX_REG_FCD, AW200XX_FCD_CLEAR);
324 }
325 
aw200xx_chip_init(const struct aw200xx * const chip)326 static int aw200xx_chip_init(const struct aw200xx *const chip)
327 {
328 	int ret;
329 
330 	ret = regmap_write(chip->regmap, AW200XX_REG_DSIZE,
331 			   chip->display_rows - 1);
332 	if (ret)
333 		return ret;
334 
335 	ret = regmap_write(chip->regmap, AW200XX_REG_SLPCR,
336 			   AW200XX_SLPCR_ACTIVE);
337 	if (ret)
338 		return ret;
339 
340 	return regmap_update_bits(chip->regmap, AW200XX_REG_GCCR,
341 				  AW200XX_GCCR_ALLON, AW200XX_GCCR_ALLON);
342 }
343 
aw200xx_chip_check(const struct aw200xx * const chip)344 static int aw200xx_chip_check(const struct aw200xx *const chip)
345 {
346 	struct device *dev = &chip->client->dev;
347 	u32 chipid;
348 	int ret;
349 
350 	ret = regmap_read(chip->regmap, AW200XX_REG_IDR, &chipid);
351 	if (ret)
352 		return dev_err_probe(dev, ret, "Failed to read chip ID\n");
353 
354 	if (chipid != AW200XX_IDR_CHIPID)
355 		return dev_err_probe(dev, -ENODEV,
356 				     "Chip reported wrong ID: %x\n", chipid);
357 
358 	return 0;
359 }
360 
aw200xx_probe_fw(struct device * dev,struct aw200xx * chip)361 static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip)
362 {
363 	struct fwnode_handle *child;
364 	u32 current_min, current_max, min_uA;
365 	int ret;
366 	int i;
367 
368 	ret = device_property_read_u32(dev, "awinic,display-rows",
369 				       &chip->display_rows);
370 	if (ret)
371 		return dev_err_probe(dev, ret,
372 				     "Failed to read 'display-rows' property\n");
373 
374 	if (!chip->display_rows ||
375 	    chip->display_rows > chip->cdef->display_size_rows_max) {
376 		return dev_err_probe(dev, -EINVAL,
377 				     "Invalid leds display size %u\n",
378 				     chip->display_rows);
379 	}
380 
381 	current_max = aw200xx_imax_from_global(chip, AW200XX_IMAX_MAX_uA);
382 	current_min = aw200xx_imax_from_global(chip, AW200XX_IMAX_MIN_uA);
383 	min_uA = UINT_MAX;
384 	i = 0;
385 
386 	device_for_each_child_node(dev, child) {
387 		struct led_init_data init_data = {};
388 		struct aw200xx_led *led;
389 		u32 source, imax;
390 
391 		ret = fwnode_property_read_u32(child, "reg", &source);
392 		if (ret) {
393 			dev_err(dev, "Missing reg property\n");
394 			chip->num_leds--;
395 			continue;
396 		}
397 
398 		if (source >= chip->cdef->channels) {
399 			dev_err(dev, "LED reg %u out of range (max %u)\n",
400 				source, chip->cdef->channels);
401 			chip->num_leds--;
402 			continue;
403 		}
404 
405 		ret = fwnode_property_read_u32(child, "led-max-microamp",
406 					       &imax);
407 		if (ret) {
408 			dev_info(&chip->client->dev,
409 				 "DT property led-max-microamp is missing\n");
410 		} else if (imax < current_min || imax > current_max) {
411 			dev_err(dev, "Invalid value %u for led-max-microamp\n",
412 				imax);
413 			chip->num_leds--;
414 			continue;
415 		} else {
416 			min_uA = min(min_uA, imax);
417 		}
418 
419 		led = &chip->leds[i];
420 		led->dim = -1;
421 		led->num = source;
422 		led->chip = chip;
423 		led->cdev.brightness_set_blocking = aw200xx_brightness_set;
424 		led->cdev.groups = dim_groups;
425 		init_data.fwnode = child;
426 
427 		ret = devm_led_classdev_register_ext(dev, &led->cdev,
428 						     &init_data);
429 		if (ret) {
430 			fwnode_handle_put(child);
431 			break;
432 		}
433 
434 		i++;
435 	}
436 
437 	if (!chip->num_leds)
438 		return -EINVAL;
439 
440 	if (min_uA == UINT_MAX) {
441 		min_uA = aw200xx_imax_from_global(chip,
442 						  AW200XX_IMAX_DEFAULT_uA);
443 	}
444 
445 	return aw200xx_set_imax(chip, min_uA);
446 }
447 
448 static const struct regmap_range_cfg aw200xx_ranges[] = {
449 	{
450 		.name = "aw200xx",
451 		.range_min = 0,
452 		.range_max = AW200XX_REG_MAX,
453 		.selector_reg = AW200XX_REG_PAGE,
454 		.selector_mask = AW200XX_PAGE_MASK,
455 		.selector_shift = AW200XX_PAGE_SHIFT,
456 		.window_start = 0,
457 		.window_len = AW200XX_PAGE_SIZE,
458 	},
459 };
460 
461 static const struct regmap_range aw200xx_writeonly_ranges[] = {
462 	regmap_reg_range(AW200XX_REG(AW200XX_PAGE1, 0x00), AW200XX_REG_MAX),
463 };
464 
465 static const struct regmap_access_table aw200xx_readable_table = {
466 	.no_ranges = aw200xx_writeonly_ranges,
467 	.n_no_ranges = ARRAY_SIZE(aw200xx_writeonly_ranges),
468 };
469 
470 static const struct regmap_range aw200xx_readonly_ranges[] = {
471 	regmap_reg_range(AW200XX_REG_IDR, AW200XX_REG_IDR),
472 };
473 
474 static const struct regmap_access_table aw200xx_writeable_table = {
475 	.no_ranges = aw200xx_readonly_ranges,
476 	.n_no_ranges = ARRAY_SIZE(aw200xx_readonly_ranges),
477 };
478 
479 static const struct regmap_config aw200xx_regmap_config = {
480 	.reg_bits = 8,
481 	.val_bits = 8,
482 	.max_register = AW200XX_REG_MAX,
483 	.ranges = aw200xx_ranges,
484 	.num_ranges = ARRAY_SIZE(aw200xx_ranges),
485 	.rd_table = &aw200xx_readable_table,
486 	.wr_table = &aw200xx_writeable_table,
487 	.cache_type = REGCACHE_RBTREE,
488 };
489 
aw200xx_probe(struct i2c_client * client)490 static int aw200xx_probe(struct i2c_client *client)
491 {
492 	const struct aw200xx_chipdef *cdef;
493 	struct aw200xx *chip;
494 	int count;
495 	int ret;
496 
497 	cdef = device_get_match_data(&client->dev);
498 	if (!cdef)
499 		return -ENODEV;
500 
501 	count = device_get_child_node_count(&client->dev);
502 	if (!count || count > cdef->channels)
503 		return dev_err_probe(&client->dev, -EINVAL,
504 				     "Incorrect number of leds (%d)", count);
505 
506 	chip = devm_kzalloc(&client->dev, struct_size(chip, leds, count),
507 			    GFP_KERNEL);
508 	if (!chip)
509 		return -ENOMEM;
510 
511 	chip->cdef = cdef;
512 	chip->num_leds = count;
513 	chip->client = client;
514 	i2c_set_clientdata(client, chip);
515 
516 	chip->regmap = devm_regmap_init_i2c(client, &aw200xx_regmap_config);
517 	if (IS_ERR(chip->regmap))
518 		return PTR_ERR(chip->regmap);
519 
520 	ret = aw200xx_chip_check(chip);
521 	if (ret)
522 		return ret;
523 
524 	mutex_init(&chip->mutex);
525 
526 	/* Need a lock now since after call aw200xx_probe_fw, sysfs nodes created */
527 	mutex_lock(&chip->mutex);
528 
529 	ret = aw200xx_chip_reset(chip);
530 	if (ret)
531 		goto out_unlock;
532 
533 	ret = aw200xx_probe_fw(&client->dev, chip);
534 	if (ret)
535 		goto out_unlock;
536 
537 	ret = aw200xx_chip_init(chip);
538 
539 out_unlock:
540 	mutex_unlock(&chip->mutex);
541 	return ret;
542 }
543 
aw200xx_remove(struct i2c_client * client)544 static void aw200xx_remove(struct i2c_client *client)
545 {
546 	struct aw200xx *chip = i2c_get_clientdata(client);
547 
548 	aw200xx_chip_reset(chip);
549 	mutex_destroy(&chip->mutex);
550 }
551 
552 static const struct aw200xx_chipdef aw20036_cdef = {
553 	.channels = 36,
554 	.display_size_rows_max = 3,
555 	.display_size_columns = 12,
556 };
557 
558 static const struct aw200xx_chipdef aw20054_cdef = {
559 	.channels = 54,
560 	.display_size_rows_max = 6,
561 	.display_size_columns = 9,
562 };
563 
564 static const struct aw200xx_chipdef aw20072_cdef = {
565 	.channels = 72,
566 	.display_size_rows_max = 6,
567 	.display_size_columns = 12,
568 };
569 
570 static const struct i2c_device_id aw200xx_id[] = {
571 	{ "aw20036" },
572 	{ "aw20054" },
573 	{ "aw20072" },
574 	{}
575 };
576 MODULE_DEVICE_TABLE(i2c, aw200xx_id);
577 
578 static const struct of_device_id aw200xx_match_table[] = {
579 	{ .compatible = "awinic,aw20036", .data = &aw20036_cdef, },
580 	{ .compatible = "awinic,aw20054", .data = &aw20054_cdef, },
581 	{ .compatible = "awinic,aw20072", .data = &aw20072_cdef, },
582 	{}
583 };
584 MODULE_DEVICE_TABLE(of, aw200xx_match_table);
585 
586 static struct i2c_driver aw200xx_driver = {
587 	.driver = {
588 		.name = "aw200xx",
589 		.of_match_table = aw200xx_match_table,
590 	},
591 	.probe = aw200xx_probe,
592 	.remove = aw200xx_remove,
593 	.id_table = aw200xx_id,
594 };
595 module_i2c_driver(aw200xx_driver);
596 
597 MODULE_AUTHOR("Martin Kurbanov <mmkurbanov@sberdevices.ru>");
598 MODULE_DESCRIPTION("AW200XX LED driver");
599 MODULE_LICENSE("GPL");
600