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
99struct aw200xx_chipdef {
100	u32 channels;
101	u32 display_size_rows_max;
102	u32 display_size_columns;
103};
104
105struct aw200xx_led {
106	struct led_classdev cdev;
107	struct aw200xx *chip;
108	int dim;
109	u32 num;
110};
111
112struct 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
122static 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
135static 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
169out_unlock:
170	mutex_unlock(&chip->mutex);
171	return ret;
172}
173static DEVICE_ATTR_RW(dim);
174
175static struct attribute *dim_attrs[] = {
176	&dev_attr_dim.attr,
177	NULL
178};
179ATTRIBUTE_GROUPS(dim);
180
181static 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
207out_unlock:
208	mutex_unlock(&chip->mutex);
209
210	return ret;
211}
212
213static 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
235static 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 */
279static 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
314static 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
326static 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
344static 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
361static 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
448static 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
461static const struct regmap_range aw200xx_writeonly_ranges[] = {
462	regmap_reg_range(AW200XX_REG(AW200XX_PAGE1, 0x00), AW200XX_REG_MAX),
463};
464
465static 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
470static const struct regmap_range aw200xx_readonly_ranges[] = {
471	regmap_reg_range(AW200XX_REG_IDR, AW200XX_REG_IDR),
472};
473
474static 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
479static 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
490static 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
539out_unlock:
540	mutex_unlock(&chip->mutex);
541	return ret;
542}
543
544static 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
552static const struct aw200xx_chipdef aw20036_cdef = {
553	.channels = 36,
554	.display_size_rows_max = 3,
555	.display_size_columns = 12,
556};
557
558static const struct aw200xx_chipdef aw20054_cdef = {
559	.channels = 54,
560	.display_size_rows_max = 6,
561	.display_size_columns = 9,
562};
563
564static const struct aw200xx_chipdef aw20072_cdef = {
565	.channels = 72,
566	.display_size_rows_max = 6,
567	.display_size_columns = 12,
568};
569
570static const struct i2c_device_id aw200xx_id[] = {
571	{ "aw20036" },
572	{ "aw20054" },
573	{ "aw20072" },
574	{}
575};
576MODULE_DEVICE_TABLE(i2c, aw200xx_id);
577
578static 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};
584MODULE_DEVICE_TABLE(of, aw200xx_match_table);
585
586static 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};
595module_i2c_driver(aw200xx_driver);
596
597MODULE_AUTHOR("Martin Kurbanov <mmkurbanov@sberdevices.ru>");
598MODULE_DESCRIPTION("AW200XX LED driver");
599MODULE_LICENSE("GPL");
600