Lines Matching +full:brightness +full:- +full:level
1 // SPDX-License-Identifier: GPL-2.0-only
3 * leds-tca6507
9 * blink or double-blink.
12 * out-only (pull-up resistor required) or as an LED with variable
13 * brightness and hardware-assisted blinking.
15 * Apart from OFF and ON there are three programmable brightness
21 * with separate time for rise, on, fall, off and second-off. Thus if
22 * 3 or more different non-trivial rates are required, software must
25 * support double-blink so 'second-off' always matches 'off'.
42 * delays in the ranges: 56-72, 112-144, 168-216, 224-27504,
43 * 28560-36720.
47 * maximum - 768+768 in this case. Other pairings are not available.
49 * Access to the 3 levels and 2 blinks are on a first-come,
50 * first-served basis. Access can be shared by multiple leds if they
51 * have the same level and either same blink rates, or some don't
56 * the desired brightness cannot be allocated, the closest available
57 * non-zero brightness is used. As 'full' is always available, the
62 * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the
63 * brightness and LEDs using the blink. It can only be reprogrammed
64 * when the appropriate counter is zero. The MASTER level has a
70 * default. Defaults are permitted to be changed freely - they are
84 #define TCA6507_LS_LED_OFF 0x0 /* Output HI-Z (off) */
85 #define TCA6507_LS_LED_OFF1 0x1 /* Output HI-Z (off) - not used */
138 /* Convert an led.brightness level (0..255) to a TCA6507 level (0..15) */
139 static inline int TO_LEVEL(int brightness)
141 return brightness >> 4;
145 static inline int TO_BRIGHT(int level)
147 if (level)
148 return (level << 4) | 0xf;
160 int level;
175 int bank; /* Bank used, or -1 */
176 int blink; /* Set if hardware-blinking */
195 * The second is to be used as a 'fade-on' or 'fade-off' time.
200 * -EINVAL, otherwise return the sum that was achieved, plus 1
204 * change-time visible (i.e. it is softer).
228 d = abs(msec - tt);
251 return -EINVAL;
255 * Update the register file with the appropriate 3-bit state for the
264 int n = tca->reg_file[bit] & ~mask;
267 if (tca->reg_file[bit] != n) {
268 tca->reg_file[bit] = n;
269 tca->reg_set |= (1 << bit);
274 /* Update the register file with the appropriate 4-bit code for one
286 n = tca->reg_file[reg] & ~mask;
288 if (tca->reg_file[reg] != n) {
289 tca->reg_file[reg] = n;
290 tca->reg_set |= 1 << reg;
294 /* Update brightness level. */
295 static void set_level(struct tca6507_chip *tca, int bank, int level)
300 set_code(tca, TCA6507_MAX_INTENSITY, bank, level);
303 set_code(tca, TCA6507_MASTER_INTENSITY, 0, level);
306 tca->bank[bank].level = level;
315 result = choose_times(tca->bank[bank].ontime, &c1, &c2);
318 dev_dbg(&tca->client->dev,
321 c2, time_codes[c2], tca->bank[bank].ontime);
324 tca->bank[bank].ontime = result;
326 result = choose_times(tca->bank[bank].offtime, &c1, &c2);
327 dev_dbg(&tca->client->dev,
330 c2, time_codes[c2], tca->bank[bank].offtime);
334 tca->bank[bank].offtime = result;
345 struct i2c_client *cl = tca->client;
350 spin_lock_irq(&tca->lock);
351 set = tca->reg_set;
352 memcpy(file, tca->reg_file, TCA6507_REG_CNT);
353 tca->reg_set = 0;
354 spin_unlock_irq(&tca->lock);
364 struct tca6507_chip *tca = led->chip;
365 if (led->bank >= 0) {
366 struct bank *b = tca->bank + led->bank;
367 if (led->blink)
368 b->time_use--;
369 b->level_use--;
371 led->blink = 0;
372 led->bank = -1;
379 int level = TO_LEVEL(led->led_cdev.brightness);
380 struct tca6507_chip *tca = led->chip;
386 led->led_cdev.brightness = TO_BRIGHT(level);
387 if (level == 0) {
388 set_select(tca, led->num, TCA6507_LS_LED_OFF);
392 if (led->ontime == 0 || led->offtime == 0) {
394 * Just set the brightness, choosing first usable
399 int best = -1;/* full-on */
400 int diff = 15-level;
402 if (level == 15) {
403 set_select(tca, led->num, TCA6507_LS_LED_ON);
407 for (i = MASTER; i >= BANK0; i--) {
409 if (tca->bank[i].level == level ||
410 tca->bank[i].level_use == 0) {
414 d = abs(level - tca->bank[i].level);
420 if (best == -1) {
421 /* Best brightness is full-on */
422 set_select(tca, led->num, TCA6507_LS_LED_ON);
423 led->led_cdev.brightness = LED_FULL;
427 if (!tca->bank[best].level_use)
428 set_level(tca, best, level);
430 tca->bank[best].level_use++;
431 led->bank = best;
432 set_select(tca, led->num, bank_source[best]);
433 led->led_cdev.brightness = TO_BRIGHT(tca->bank[best].level);
442 if (choose_times(led->ontime, &c1, &c2) < 0)
443 return -EINVAL;
444 if (choose_times(led->offtime, &c1, &c2) < 0)
445 return -EINVAL;
448 if (tca->bank[i].level_use == 0)
449 /* not in use - it is ours! */
451 if (tca->bank[i].level != level)
452 /* Incompatible level - skip */
458 if (tca->bank[i].time_use == 0)
459 /* Timer not in use, and level matches - use it */
462 if (!(tca->bank[i].on_dflt ||
463 led->on_dflt ||
464 tca->bank[i].ontime == led->ontime))
468 if (!(tca->bank[i].off_dflt ||
469 led->off_dflt ||
470 tca->bank[i].offtime == led->offtime))
479 /* Nothing matches - how sad */
480 return -EINVAL;
482 b = &tca->bank[i];
483 if (b->level_use == 0)
484 set_level(tca, i, level);
485 b->level_use++;
486 led->bank = i;
488 if (b->on_dflt ||
489 !led->on_dflt ||
490 b->time_use == 0) {
491 b->ontime = led->ontime;
492 b->on_dflt = led->on_dflt;
496 if (b->off_dflt ||
497 !led->off_dflt ||
498 b->time_use == 0) {
499 b->offtime = led->offtime;
500 b->off_dflt = led->off_dflt;
507 led->ontime = b->ontime;
508 led->offtime = b->offtime;
510 b->time_use++;
511 led->blink = 1;
512 led->led_cdev.brightness = TO_BRIGHT(b->level);
513 set_select(tca, led->num, blink_source[i]);
519 struct tca6507_chip *tca = led->chip;
523 spin_lock_irqsave(&tca->lock, flags);
529 * to re-establish as steady level.
531 led->ontime = 0;
532 led->offtime = 0;
535 spin_unlock_irqrestore(&tca->lock, flags);
537 if (tca->reg_set)
538 schedule_work(&tca->work);
543 enum led_brightness brightness)
547 led->led_cdev.brightness = brightness;
548 led->ontime = 0;
549 led->offtime = 0;
561 led->on_dflt = 1;
562 else if (delay_on != &led_cdev->blink_delay_on)
563 led->on_dflt = 0;
564 led->ontime = *delay_on;
567 led->off_dflt = 1;
568 else if (delay_off != &led_cdev->blink_delay_off)
569 led->off_dflt = 0;
570 led->offtime = *delay_off;
572 if (led->ontime == 0)
573 led->ontime = 512;
574 if (led->offtime == 0)
575 led->offtime = 512;
577 if (led->led_cdev.brightness == LED_OFF)
578 led->led_cdev.brightness = LED_FULL;
580 led->ontime = 0;
581 led->offtime = 0;
582 led->led_cdev.brightness = LED_OFF;
583 return -EINVAL;
585 *delay_on = led->ontime;
586 *delay_off = led->offtime;
597 spin_lock_irqsave(&tca->lock, flags);
602 set_select(tca, tca->gpio_map[offset],
604 spin_unlock_irqrestore(&tca->lock, flags);
605 if (tca->reg_set)
606 schedule_work(&tca->work);
626 if (pdata->leds.leds[i].name && pdata->leds.leds[i].flags) {
628 tca->gpio_map[gpios] = i;
635 tca->gpio.label = "gpio-tca6507";
636 tca->gpio.ngpio = gpios;
637 tca->gpio.base = -1;
638 tca->gpio.owner = THIS_MODULE;
639 tca->gpio.direction_output = tca6507_gpio_direction_output;
640 tca->gpio.set_rv = tca6507_gpio_set_value;
641 tca->gpio.parent = dev;
642 err = devm_gpiochip_add_data(dev, &tca->gpio, tca);
644 tca->gpio.ngpio = 0;
667 return ERR_PTR(-ENODEV);
672 return ERR_PTR(-ENOMEM);
682 if (fwnode_property_read_string(child, "linux,default-trigger",
692 return ERR_PTR(ret ? : -EINVAL);
700 return ERR_PTR(-ENOMEM);
702 pdata->leds.leds = tca_leds;
703 pdata->leds.num_leds = NUM_LEDS;
716 struct device *dev = &client->dev;
723 adapter = client->adapter;
726 return -EIO;
730 dev_err(dev, "Need %d entries in platform-data list\n", NUM_LEDS);
735 return -ENOMEM;
737 tca->client = client;
738 INIT_WORK(&tca->work, tca6507_work);
739 spin_lock_init(&tca->lock);
743 struct tca6507_led *l = tca->leds + i;
745 l->chip = tca;
746 l->num = i;
747 if (pdata->leds.leds[i].name && !pdata->leds.leds[i].flags) {
748 l->led_cdev.name = pdata->leds.leds[i].name;
749 l->led_cdev.default_trigger
750 = pdata->leds.leds[i].default_trigger;
751 l->led_cdev.brightness_set = tca6507_brightness_set;
752 l->led_cdev.blink_set = tca6507_blink_set;
753 l->bank = -1;
754 err = devm_led_classdev_register(dev, &l->led_cdev);
762 /* set all registers to known state - zero */
763 tca->reg_set = 0x7f;
764 schedule_work(&tca->work);
773 cancel_work_sync(&tca->work);
778 .name = "leds-tca6507",