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