Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  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
102struct aw200xx_chipdef {
103	u32 channels;
104	u32 display_size_rows_max;
105	u32 display_size_columns;
106};
107
108struct aw200xx_led {
109	struct led_classdev cdev;
110	struct aw200xx *chip;
111	int dim;
112	u32 num;
113};
114
115struct 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
126static 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
139static 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
173out_unlock:
174	mutex_unlock(&chip->mutex);
175	return ret;
176}
177static DEVICE_ATTR_RW(dim);
178
179static struct attribute *dim_attrs[] = {
180	&dev_attr_dim.attr,
181	NULL
182};
183ATTRIBUTE_GROUPS(dim);
184
185static 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
209out_unlock:
210	mutex_unlock(&chip->mutex);
211
212	return ret;
213}
214
215static 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
237static 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 */
281static 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
316static 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
331static 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
349static 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
366static 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
380static void aw200xx_disable(const struct aw200xx *const chip)
381{
382	return gpiod_set_value_cansleep(chip->hwen, 0);
383}
384
385static 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
410static 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
487static 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
500static const struct regmap_range aw200xx_writeonly_ranges[] = {
501	regmap_reg_range(AW200XX_REG(AW200XX_PAGE1, 0x00), AW200XX_REG_MAX),
502};
503
504static 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
509static const struct regmap_range aw200xx_readonly_ranges[] = {
510	regmap_reg_range(AW200XX_REG_IDR, AW200XX_REG_IDR),
511};
512
513static 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
518static 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
530static void aw200xx_chip_reset_action(void *data)
531{
532	aw200xx_chip_reset(data);
533}
534
535static void aw200xx_disable_action(void *data)
536{
537	aw200xx_disable(data);
538}
539
540static 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
607out_unlock:
608	if (ret)
609		aw200xx_disable(chip);
610
611	mutex_unlock(&chip->mutex);
612	return ret;
613}
614
615static const struct aw200xx_chipdef aw20036_cdef = {
616	.channels = 36,
617	.display_size_rows_max = 3,
618	.display_size_columns = 12,
619};
620
621static const struct aw200xx_chipdef aw20054_cdef = {
622	.channels = 54,
623	.display_size_rows_max = 6,
624	.display_size_columns = 9,
625};
626
627static const struct aw200xx_chipdef aw20072_cdef = {
628	.channels = 72,
629	.display_size_rows_max = 6,
630	.display_size_columns = 12,
631};
632
633static const struct aw200xx_chipdef aw20108_cdef = {
634	.channels = 108,
635	.display_size_rows_max = 9,
636	.display_size_columns = 12,
637};
638
639static const struct i2c_device_id aw200xx_id[] = {
640	{ "aw20036" },
641	{ "aw20054" },
642	{ "aw20072" },
643	{ "aw20108" },
644	{}
645};
646MODULE_DEVICE_TABLE(i2c, aw200xx_id);
647
648static 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};
655MODULE_DEVICE_TABLE(of, aw200xx_match_table);
656
657static 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};
665module_i2c_driver(aw200xx_driver);
666
667MODULE_AUTHOR("Martin Kurbanov <mmkurbanov@sberdevices.ru>");
668MODULE_DESCRIPTION("AW200XX LED driver");
669MODULE_LICENSE("GPL");