Lines Matching +full:default +full:- +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 */
141 /* Convert an led.brightness level (0..255) to a TCA6507 level (0..15) */
142 static inline int TO_LEVEL(int brightness) in TO_LEVEL() argument
144 return brightness >> 4; in TO_LEVEL()
148 static inline int TO_BRIGHT(int level) in TO_BRIGHT() argument
150 if (level) in TO_BRIGHT()
151 return (level << 4) | 0xf; in TO_BRIGHT()
163 int level; member
178 int bank; /* Bank used, or -1 */
179 int blink; /* Set if hardware-blinking */
198 * The second is to be used as a 'fade-on' or 'fade-off' time. in choose_times()
203 * -EINVAL, otherwise return the sum that was achieved, plus 1 in choose_times()
207 * change-time visible (i.e. it is softer). in choose_times()
231 d = abs(msec - tt); in choose_times()
254 return -EINVAL; in choose_times()
258 * Update the register file with the appropriate 3-bit state for the
267 int n = tca->reg_file[bit] & ~mask; in set_select()
270 if (tca->reg_file[bit] != n) { in set_select()
271 tca->reg_file[bit] = n; in set_select()
272 tca->reg_set |= (1 << bit); in set_select()
277 /* Update the register file with the appropriate 4-bit code for one
289 n = tca->reg_file[reg] & ~mask; in set_code()
291 if (tca->reg_file[reg] != n) { in set_code()
292 tca->reg_file[reg] = n; in set_code()
293 tca->reg_set |= 1 << reg; in set_code()
297 /* Update brightness level. */
298 static void set_level(struct tca6507_chip *tca, int bank, int level) in set_level() argument
303 set_code(tca, TCA6507_MAX_INTENSITY, bank, level); in set_level()
306 set_code(tca, TCA6507_MASTER_INTENSITY, 0, level); in set_level()
309 tca->bank[bank].level = level; in set_level()
318 result = choose_times(tca->bank[bank].ontime, &c1, &c2); in set_times()
321 dev_dbg(&tca->client->dev, in set_times()
324 c2, time_codes[c2], tca->bank[bank].ontime); in set_times()
327 tca->bank[bank].ontime = result; in set_times()
329 result = choose_times(tca->bank[bank].offtime, &c1, &c2); in set_times()
330 dev_dbg(&tca->client->dev, in set_times()
333 c2, time_codes[c2], tca->bank[bank].offtime); in set_times()
337 tca->bank[bank].offtime = result; in set_times()
348 struct i2c_client *cl = tca->client; in tca6507_work()
353 spin_lock_irq(&tca->lock); in tca6507_work()
354 set = tca->reg_set; in tca6507_work()
355 memcpy(file, tca->reg_file, TCA6507_REG_CNT); in tca6507_work()
356 tca->reg_set = 0; in tca6507_work()
357 spin_unlock_irq(&tca->lock); in tca6507_work()
367 struct tca6507_chip *tca = led->chip; in led_release()
368 if (led->bank >= 0) { in led_release()
369 struct bank *b = tca->bank + led->bank; in led_release()
370 if (led->blink) in led_release()
371 b->time_use--; in led_release()
372 b->level_use--; in led_release()
374 led->blink = 0; in led_release()
375 led->bank = -1; in led_release()
382 int level = TO_LEVEL(led->led_cdev.brightness); in led_prepare() local
383 struct tca6507_chip *tca = led->chip; in led_prepare()
389 led->led_cdev.brightness = TO_BRIGHT(level); in led_prepare()
390 if (level == 0) { in led_prepare()
391 set_select(tca, led->num, TCA6507_LS_LED_OFF); in led_prepare()
395 if (led->ontime == 0 || led->offtime == 0) { in led_prepare()
397 * Just set the brightness, choosing first usable in led_prepare()
402 int best = -1;/* full-on */ in led_prepare()
403 int diff = 15-level; in led_prepare()
405 if (level == 15) { in led_prepare()
406 set_select(tca, led->num, TCA6507_LS_LED_ON); in led_prepare()
410 for (i = MASTER; i >= BANK0; i--) { in led_prepare()
412 if (tca->bank[i].level == level || in led_prepare()
413 tca->bank[i].level_use == 0) { in led_prepare()
417 d = abs(level - tca->bank[i].level); in led_prepare()
423 if (best == -1) { in led_prepare()
424 /* Best brightness is full-on */ in led_prepare()
425 set_select(tca, led->num, TCA6507_LS_LED_ON); in led_prepare()
426 led->led_cdev.brightness = LED_FULL; in led_prepare()
430 if (!tca->bank[best].level_use) in led_prepare()
431 set_level(tca, best, level); in led_prepare()
433 tca->bank[best].level_use++; in led_prepare()
434 led->bank = best; in led_prepare()
435 set_select(tca, led->num, bank_source[best]); in led_prepare()
436 led->led_cdev.brightness = TO_BRIGHT(tca->bank[best].level); in led_prepare()
445 if (choose_times(led->ontime, &c1, &c2) < 0) in led_prepare()
446 return -EINVAL; in led_prepare()
447 if (choose_times(led->offtime, &c1, &c2) < 0) in led_prepare()
448 return -EINVAL; in led_prepare()
451 if (tca->bank[i].level_use == 0) in led_prepare()
452 /* not in use - it is ours! */ in led_prepare()
454 if (tca->bank[i].level != level) in led_prepare()
455 /* Incompatible level - skip */ in led_prepare()
461 if (tca->bank[i].time_use == 0) in led_prepare()
462 /* Timer not in use, and level matches - use it */ in led_prepare()
465 if (!(tca->bank[i].on_dflt || in led_prepare()
466 led->on_dflt || in led_prepare()
467 tca->bank[i].ontime == led->ontime)) in led_prepare()
471 if (!(tca->bank[i].off_dflt || in led_prepare()
472 led->off_dflt || in led_prepare()
473 tca->bank[i].offtime == led->offtime)) in led_prepare()
482 /* Nothing matches - how sad */ in led_prepare()
483 return -EINVAL; in led_prepare()
485 b = &tca->bank[i]; in led_prepare()
486 if (b->level_use == 0) in led_prepare()
487 set_level(tca, i, level); in led_prepare()
488 b->level_use++; in led_prepare()
489 led->bank = i; in led_prepare()
491 if (b->on_dflt || in led_prepare()
492 !led->on_dflt || in led_prepare()
493 b->time_use == 0) { in led_prepare()
494 b->ontime = led->ontime; in led_prepare()
495 b->on_dflt = led->on_dflt; in led_prepare()
499 if (b->off_dflt || in led_prepare()
500 !led->off_dflt || in led_prepare()
501 b->time_use == 0) { in led_prepare()
502 b->offtime = led->offtime; in led_prepare()
503 b->off_dflt = led->off_dflt; in led_prepare()
510 led->ontime = b->ontime; in led_prepare()
511 led->offtime = b->offtime; in led_prepare()
513 b->time_use++; in led_prepare()
514 led->blink = 1; in led_prepare()
515 led->led_cdev.brightness = TO_BRIGHT(b->level); in led_prepare()
516 set_select(tca, led->num, blink_source[i]); in led_prepare()
522 struct tca6507_chip *tca = led->chip; in led_assign()
526 spin_lock_irqsave(&tca->lock, flags); in led_assign()
532 * to re-establish as steady level. in led_assign()
534 led->ontime = 0; in led_assign()
535 led->offtime = 0; in led_assign()
538 spin_unlock_irqrestore(&tca->lock, flags); in led_assign()
540 if (tca->reg_set) in led_assign()
541 schedule_work(&tca->work); in led_assign()
546 enum led_brightness brightness) in tca6507_brightness_set() argument
550 led->led_cdev.brightness = brightness; in tca6507_brightness_set()
551 led->ontime = 0; in tca6507_brightness_set()
552 led->offtime = 0; in tca6507_brightness_set()
564 led->on_dflt = 1; in tca6507_blink_set()
565 else if (delay_on != &led_cdev->blink_delay_on) in tca6507_blink_set()
566 led->on_dflt = 0; in tca6507_blink_set()
567 led->ontime = *delay_on; in tca6507_blink_set()
570 led->off_dflt = 1; in tca6507_blink_set()
571 else if (delay_off != &led_cdev->blink_delay_off) in tca6507_blink_set()
572 led->off_dflt = 0; in tca6507_blink_set()
573 led->offtime = *delay_off; in tca6507_blink_set()
575 if (led->ontime == 0) in tca6507_blink_set()
576 led->ontime = 512; in tca6507_blink_set()
577 if (led->offtime == 0) in tca6507_blink_set()
578 led->offtime = 512; in tca6507_blink_set()
580 if (led->led_cdev.brightness == LED_OFF) in tca6507_blink_set()
581 led->led_cdev.brightness = LED_FULL; in tca6507_blink_set()
583 led->ontime = 0; in tca6507_blink_set()
584 led->offtime = 0; in tca6507_blink_set()
585 led->led_cdev.brightness = LED_OFF; in tca6507_blink_set()
586 return -EINVAL; in tca6507_blink_set()
588 *delay_on = led->ontime; in tca6507_blink_set()
589 *delay_off = led->offtime; in tca6507_blink_set()
600 spin_lock_irqsave(&tca->lock, flags); in tca6507_gpio_set_value()
605 set_select(tca, tca->gpio_map[offset], in tca6507_gpio_set_value()
607 spin_unlock_irqrestore(&tca->lock, flags); in tca6507_gpio_set_value()
608 if (tca->reg_set) in tca6507_gpio_set_value()
609 schedule_work(&tca->work); in tca6507_gpio_set_value()
628 if (pdata->leds.leds[i].name && pdata->leds.leds[i].flags) { in tca6507_probe_gpios()
630 tca->gpio_map[gpios] = i; in tca6507_probe_gpios()
637 tca->gpio.label = "gpio-tca6507"; in tca6507_probe_gpios()
638 tca->gpio.ngpio = gpios; in tca6507_probe_gpios()
639 tca->gpio.base = pdata->gpio_base; in tca6507_probe_gpios()
640 tca->gpio.owner = THIS_MODULE; in tca6507_probe_gpios()
641 tca->gpio.direction_output = tca6507_gpio_direction_output; in tca6507_probe_gpios()
642 tca->gpio.set = tca6507_gpio_set_value; in tca6507_probe_gpios()
643 tca->gpio.parent = dev; in tca6507_probe_gpios()
644 err = gpiochip_add_data(&tca->gpio, tca); in tca6507_probe_gpios()
646 tca->gpio.ngpio = 0; in tca6507_probe_gpios()
654 if (tca->gpio.ngpio) in tca6507_remove_gpio()
655 gpiochip_remove(&tca->gpio); in tca6507_remove_gpio()
679 return ERR_PTR(-ENODEV); in tca6507_led_dt_init()
684 return ERR_PTR(-ENOMEM); in tca6507_led_dt_init()
694 if (fwnode_property_read_string(child, "linux,default-trigger", in tca6507_led_dt_init()
705 return ERR_PTR(ret ? : -EINVAL); in tca6507_led_dt_init()
714 return ERR_PTR(-ENOMEM); in tca6507_led_dt_init()
716 pdata->leds.leds = tca_leds; in tca6507_led_dt_init()
717 pdata->leds.num_leds = NUM_LEDS; in tca6507_led_dt_init()
719 pdata->gpio_base = -1; in tca6507_led_dt_init()
733 struct device *dev = &client->dev; in tca6507_probe()
740 adapter = client->adapter; in tca6507_probe()
743 return -EIO; in tca6507_probe()
747 dev_err(dev, "Need %d entries in platform-data list\n", NUM_LEDS); in tca6507_probe()
752 return -ENOMEM; in tca6507_probe()
754 tca->client = client; in tca6507_probe()
755 INIT_WORK(&tca->work, tca6507_work); in tca6507_probe()
756 spin_lock_init(&tca->lock); in tca6507_probe()
760 struct tca6507_led *l = tca->leds + i; in tca6507_probe()
762 l->chip = tca; in tca6507_probe()
763 l->num = i; in tca6507_probe()
764 if (pdata->leds.leds[i].name && !pdata->leds.leds[i].flags) { in tca6507_probe()
765 l->led_cdev.name = pdata->leds.leds[i].name; in tca6507_probe()
766 l->led_cdev.default_trigger in tca6507_probe()
767 = pdata->leds.leds[i].default_trigger; in tca6507_probe()
768 l->led_cdev.brightness_set = tca6507_brightness_set; in tca6507_probe()
769 l->led_cdev.blink_set = tca6507_blink_set; in tca6507_probe()
770 l->bank = -1; in tca6507_probe()
771 err = led_classdev_register(dev, &l->led_cdev); in tca6507_probe()
779 /* set all registers to known state - zero */ in tca6507_probe()
780 tca->reg_set = 0x7f; in tca6507_probe()
781 schedule_work(&tca->work); in tca6507_probe()
785 while (i--) { in tca6507_probe()
786 if (tca->leds[i].led_cdev.name) in tca6507_probe()
787 led_classdev_unregister(&tca->leds[i].led_cdev); in tca6507_probe()
796 struct tca6507_led *tca_leds = tca->leds; in tca6507_remove()
803 cancel_work_sync(&tca->work); in tca6507_remove()
808 .name = "leds-tca6507",