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