Lines Matching +full:leds +full:- +full:trigger +full:- +full:pattern
1 // SPDX-License-Identifier: GPL-2.0-only
3 * leds-tca6507
8 * The modulation can be varied in a simple pattern to produce a
9 * blink or double-blink.
12 * out-only (pull-up resistor required) or as an LED with variable
13 * brightness and hardware-assisted blinking.
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
57 * non-zero brightness is used. As 'full' is always available, the
59 * Max at '2', then other leds will have to choose between '2' and
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
70 * default. Defaults are permitted to be changed freely - they are
76 #include <linux/leds.h>
84 #define TCA6507_LS_LED_OFF 0x0 /* Output HI-Z (off) */
85 #define TCA6507_LS_LED_OFF1 0x1 /* Output HI-Z (off) - not used */
94 struct led_platform_data leds; member
175 int bank; /* Bank used, or -1 */
176 int blink; /* Set if hardware-blinking */
177 } leds[NUM_LEDS]; member
195 * The second is to be used as a 'fade-on' or 'fade-off' time. in choose_times()
200 * -EINVAL, otherwise return the sum that was achieved, plus 1 in choose_times()
204 * change-time visible (i.e. it is softer). in choose_times()
228 d = abs(msec - tt); in choose_times()
251 return -EINVAL; in choose_times()
255 * Update the register file with the appropriate 3-bit state for the
264 int n = tca->reg_file[bit] & ~mask; in set_select()
267 if (tca->reg_file[bit] != n) { in set_select()
268 tca->reg_file[bit] = n; in set_select()
269 tca->reg_set |= (1 << bit); in set_select()
274 /* Update the register file with the appropriate 4-bit code for one
286 n = tca->reg_file[reg] & ~mask; in set_code()
288 if (tca->reg_file[reg] != n) { in set_code()
289 tca->reg_file[reg] = n; in set_code()
290 tca->reg_set |= 1 << reg; in set_code()
306 tca->bank[bank].level = level; in set_level()
315 result = choose_times(tca->bank[bank].ontime, &c1, &c2); in set_times()
318 dev_dbg(&tca->client->dev, in set_times()
321 c2, time_codes[c2], tca->bank[bank].ontime); in set_times()
324 tca->bank[bank].ontime = result; in set_times()
326 result = choose_times(tca->bank[bank].offtime, &c1, &c2); in set_times()
327 dev_dbg(&tca->client->dev, in set_times()
330 c2, time_codes[c2], tca->bank[bank].offtime); in set_times()
334 tca->bank[bank].offtime = result; in set_times()
345 struct i2c_client *cl = tca->client; in tca6507_work()
350 spin_lock_irq(&tca->lock); in tca6507_work()
351 set = tca->reg_set; in tca6507_work()
352 memcpy(file, tca->reg_file, TCA6507_REG_CNT); in tca6507_work()
353 tca->reg_set = 0; in tca6507_work()
354 spin_unlock_irq(&tca->lock); in tca6507_work()
364 struct tca6507_chip *tca = led->chip; in led_release()
365 if (led->bank >= 0) { in led_release()
366 struct bank *b = tca->bank + led->bank; in led_release()
367 if (led->blink) in led_release()
368 b->time_use--; in led_release()
369 b->level_use--; in led_release()
371 led->blink = 0; in led_release()
372 led->bank = -1; in led_release()
379 int level = TO_LEVEL(led->led_cdev.brightness); in led_prepare()
380 struct tca6507_chip *tca = led->chip; in led_prepare()
386 led->led_cdev.brightness = TO_BRIGHT(level); in led_prepare()
388 set_select(tca, led->num, TCA6507_LS_LED_OFF); in led_prepare()
392 if (led->ontime == 0 || led->offtime == 0) { in led_prepare()
399 int best = -1;/* full-on */ in led_prepare()
400 int diff = 15-level; in led_prepare()
403 set_select(tca, led->num, TCA6507_LS_LED_ON); in led_prepare()
407 for (i = MASTER; i >= BANK0; i--) { in led_prepare()
409 if (tca->bank[i].level == level || in led_prepare()
410 tca->bank[i].level_use == 0) { in led_prepare()
414 d = abs(level - tca->bank[i].level); in led_prepare()
420 if (best == -1) { in led_prepare()
421 /* Best brightness is full-on */ in led_prepare()
422 set_select(tca, led->num, TCA6507_LS_LED_ON); in led_prepare()
423 led->led_cdev.brightness = LED_FULL; in led_prepare()
427 if (!tca->bank[best].level_use) in led_prepare()
430 tca->bank[best].level_use++; in led_prepare()
431 led->bank = best; in led_prepare()
432 set_select(tca, led->num, bank_source[best]); in led_prepare()
433 led->led_cdev.brightness = TO_BRIGHT(tca->bank[best].level); in led_prepare()
442 if (choose_times(led->ontime, &c1, &c2) < 0) in led_prepare()
443 return -EINVAL; in led_prepare()
444 if (choose_times(led->offtime, &c1, &c2) < 0) in led_prepare()
445 return -EINVAL; in led_prepare()
448 if (tca->bank[i].level_use == 0) in led_prepare()
449 /* not in use - it is ours! */ in led_prepare()
451 if (tca->bank[i].level != level) in led_prepare()
452 /* Incompatible level - skip */ in led_prepare()
458 if (tca->bank[i].time_use == 0) in led_prepare()
459 /* Timer not in use, and level matches - use it */ in led_prepare()
462 if (!(tca->bank[i].on_dflt || in led_prepare()
463 led->on_dflt || in led_prepare()
464 tca->bank[i].ontime == led->ontime)) in led_prepare()
468 if (!(tca->bank[i].off_dflt || in led_prepare()
469 led->off_dflt || in led_prepare()
470 tca->bank[i].offtime == led->offtime)) in led_prepare()
479 /* Nothing matches - how sad */ in led_prepare()
480 return -EINVAL; in led_prepare()
482 b = &tca->bank[i]; in led_prepare()
483 if (b->level_use == 0) in led_prepare()
485 b->level_use++; in led_prepare()
486 led->bank = i; in led_prepare()
488 if (b->on_dflt || in led_prepare()
489 !led->on_dflt || in led_prepare()
490 b->time_use == 0) { in led_prepare()
491 b->ontime = led->ontime; in led_prepare()
492 b->on_dflt = led->on_dflt; in led_prepare()
496 if (b->off_dflt || in led_prepare()
497 !led->off_dflt || in led_prepare()
498 b->time_use == 0) { in led_prepare()
499 b->offtime = led->offtime; in led_prepare()
500 b->off_dflt = led->off_dflt; in led_prepare()
507 led->ontime = b->ontime; in led_prepare()
508 led->offtime = b->offtime; in led_prepare()
510 b->time_use++; in led_prepare()
511 led->blink = 1; in led_prepare()
512 led->led_cdev.brightness = TO_BRIGHT(b->level); in led_prepare()
513 set_select(tca, led->num, blink_source[i]); in led_prepare()
519 struct tca6507_chip *tca = led->chip; in led_assign()
523 spin_lock_irqsave(&tca->lock, flags); in led_assign()
529 * to re-establish as steady level. in led_assign()
531 led->ontime = 0; in led_assign()
532 led->offtime = 0; in led_assign()
535 spin_unlock_irqrestore(&tca->lock, flags); in led_assign()
537 if (tca->reg_set) in led_assign()
538 schedule_work(&tca->work); in led_assign()
547 led->led_cdev.brightness = brightness; in tca6507_brightness_set()
548 led->ontime = 0; in tca6507_brightness_set()
549 led->offtime = 0; in tca6507_brightness_set()
561 led->on_dflt = 1; in tca6507_blink_set()
562 else if (delay_on != &led_cdev->blink_delay_on) in tca6507_blink_set()
563 led->on_dflt = 0; in tca6507_blink_set()
564 led->ontime = *delay_on; in tca6507_blink_set()
567 led->off_dflt = 1; in tca6507_blink_set()
568 else if (delay_off != &led_cdev->blink_delay_off) in tca6507_blink_set()
569 led->off_dflt = 0; in tca6507_blink_set()
570 led->offtime = *delay_off; in tca6507_blink_set()
572 if (led->ontime == 0) in tca6507_blink_set()
573 led->ontime = 512; in tca6507_blink_set()
574 if (led->offtime == 0) in tca6507_blink_set()
575 led->offtime = 512; in tca6507_blink_set()
577 if (led->led_cdev.brightness == LED_OFF) in tca6507_blink_set()
578 led->led_cdev.brightness = LED_FULL; in tca6507_blink_set()
580 led->ontime = 0; in tca6507_blink_set()
581 led->offtime = 0; in tca6507_blink_set()
582 led->led_cdev.brightness = LED_OFF; in tca6507_blink_set()
583 return -EINVAL; in tca6507_blink_set()
585 *delay_on = led->ontime; in tca6507_blink_set()
586 *delay_off = led->offtime; in tca6507_blink_set()
597 spin_lock_irqsave(&tca->lock, flags); in tca6507_gpio_set_value()
602 set_select(tca, tca->gpio_map[offset], in tca6507_gpio_set_value()
604 spin_unlock_irqrestore(&tca->lock, flags); in tca6507_gpio_set_value()
605 if (tca->reg_set) in tca6507_gpio_set_value()
606 schedule_work(&tca->work); in tca6507_gpio_set_value()
625 if (pdata->leds.leds[i].name && pdata->leds.leds[i].flags) { in tca6507_probe_gpios()
627 tca->gpio_map[gpios] = i; in tca6507_probe_gpios()
634 tca->gpio.label = "gpio-tca6507"; in tca6507_probe_gpios()
635 tca->gpio.ngpio = gpios; in tca6507_probe_gpios()
636 tca->gpio.base = -1; in tca6507_probe_gpios()
637 tca->gpio.owner = THIS_MODULE; in tca6507_probe_gpios()
638 tca->gpio.direction_output = tca6507_gpio_direction_output; in tca6507_probe_gpios()
639 tca->gpio.set = tca6507_gpio_set_value; in tca6507_probe_gpios()
640 tca->gpio.parent = dev; in tca6507_probe_gpios()
641 err = devm_gpiochip_add_data(dev, &tca->gpio, tca); in tca6507_probe_gpios()
643 tca->gpio.ngpio = 0; in tca6507_probe_gpios()
666 return ERR_PTR(-ENODEV); in tca6507_led_dt_init()
671 return ERR_PTR(-ENOMEM); in tca6507_led_dt_init()
681 if (fwnode_property_read_string(child, "linux,default-trigger", in tca6507_led_dt_init()
691 return ERR_PTR(ret ? : -EINVAL); in tca6507_led_dt_init()
699 return ERR_PTR(-ENOMEM); in tca6507_led_dt_init()
701 pdata->leds.leds = tca_leds; in tca6507_led_dt_init()
702 pdata->leds.num_leds = NUM_LEDS; in tca6507_led_dt_init()
715 struct device *dev = &client->dev; in tca6507_probe()
722 adapter = client->adapter; in tca6507_probe()
725 return -EIO; in tca6507_probe()
729 dev_err(dev, "Need %d entries in platform-data list\n", NUM_LEDS); in tca6507_probe()
734 return -ENOMEM; in tca6507_probe()
736 tca->client = client; in tca6507_probe()
737 INIT_WORK(&tca->work, tca6507_work); in tca6507_probe()
738 spin_lock_init(&tca->lock); in tca6507_probe()
742 struct tca6507_led *l = tca->leds + i; in tca6507_probe()
744 l->chip = tca; in tca6507_probe()
745 l->num = i; in tca6507_probe()
746 if (pdata->leds.leds[i].name && !pdata->leds.leds[i].flags) { in tca6507_probe()
747 l->led_cdev.name = pdata->leds.leds[i].name; in tca6507_probe()
748 l->led_cdev.default_trigger in tca6507_probe()
749 = pdata->leds.leds[i].default_trigger; in tca6507_probe()
750 l->led_cdev.brightness_set = tca6507_brightness_set; in tca6507_probe()
751 l->led_cdev.blink_set = tca6507_blink_set; in tca6507_probe()
752 l->bank = -1; in tca6507_probe()
753 err = devm_led_classdev_register(dev, &l->led_cdev); in tca6507_probe()
761 /* set all registers to known state - zero */ in tca6507_probe()
762 tca->reg_set = 0x7f; in tca6507_probe()
763 schedule_work(&tca->work); in tca6507_probe()
772 cancel_work_sync(&tca->work); in tca6507_remove()
777 .name = "leds-tca6507",