Lines Matching +full:leds +full:- +full:trigger +full:- +full:pattern
2 * leds-tca6507
7 * The modulation can be varied in a simple pattern to produce a
8 * blink or double-blink.
11 * out-only (pull-up resistor required) or as an LED with variable
12 * brightness and hardware-assisted blinking.
20 * with separate time for rise, on, fall, off and second-off. Thus if
21 * 3 or more different non-trivial rates are required, software must
24 * support double-blink so 'second-off' always matches 'off'.
41 * delays in the ranges: 56-72, 112-144, 168-216, 224-27504,
42 * 28560-36720.
46 * maximum - 768+768 in this case. Other pairings are not available.
48 * Access to the 3 levels and 2 blinks are on a first-come,
49 * first-served basis. Access can be shared by multiple leds if they
56 * non-zero brightness is used. As 'full' is always available, the
58 * Max at '2', then other leds will have to choose between '2' and
61 * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the
62 * brightness and LEDs using the blink. It can only be reprogrammed
69 * default. Defaults are permitted to be changed freely - they are
73 * An led-tca6507 device must be provided with platform data or
76 * The platform-data lists for each output: the name, default trigger,
86 * whether it is an LED or a GPIO. "linux,default-trigger" can set a
87 * default trigger.
92 #include <linux/leds.h>
97 #include <linux/leds-tca6507.h>
101 #define TCA6507_LS_LED_OFF 0x0 /* Output HI-Z (off) */
102 #define TCA6507_LS_LED_OFF1 0x1 /* Output HI-Z (off) - not used */
186 int bank; /* Bank used, or -1 */
187 int blink; /* Set if hardware-blinking */
188 } leds[NUM_LEDS]; member
207 * The second is to be used as a 'fade-on' or 'fade-off' time. in choose_times()
212 * -EINVAL, otherwise return the sum that was achieved, plus 1 in choose_times()
216 * change-time visible (i.e. it is softer). in choose_times()
240 d = abs(msec - tt); in choose_times()
265 return -EINVAL; in choose_times()
269 * Update the register file with the appropriate 3-bit state for the
278 int n = tca->reg_file[bit] & ~mask; in set_select()
281 if (tca->reg_file[bit] != n) { in set_select()
282 tca->reg_file[bit] = n; in set_select()
283 tca->reg_set |= (1 << bit); in set_select()
288 /* Update the register file with the appropriate 4-bit code for one
300 n = tca->reg_file[reg] & ~mask; in set_code()
302 if (tca->reg_file[reg] != n) { in set_code()
303 tca->reg_file[reg] = n; in set_code()
304 tca->reg_set |= 1 << reg; in set_code()
320 tca->bank[bank].level = level; in set_level()
329 result = choose_times(tca->bank[bank].ontime, &c1, &c2); in set_times()
332 dev_dbg(&tca->client->dev, in set_times()
335 c2, time_codes[c2], tca->bank[bank].ontime); in set_times()
338 tca->bank[bank].ontime = result; in set_times()
340 result = choose_times(tca->bank[bank].offtime, &c1, &c2); in set_times()
341 dev_dbg(&tca->client->dev, in set_times()
344 c2, time_codes[c2], tca->bank[bank].offtime); in set_times()
348 tca->bank[bank].offtime = result; in set_times()
359 struct i2c_client *cl = tca->client; in tca6507_work()
364 spin_lock_irq(&tca->lock); in tca6507_work()
365 set = tca->reg_set; in tca6507_work()
366 memcpy(file, tca->reg_file, TCA6507_REG_CNT); in tca6507_work()
367 tca->reg_set = 0; in tca6507_work()
368 spin_unlock_irq(&tca->lock); in tca6507_work()
378 struct tca6507_chip *tca = led->chip; in led_release()
379 if (led->bank >= 0) { in led_release()
380 struct bank *b = tca->bank + led->bank; in led_release()
381 if (led->blink) in led_release()
382 b->time_use--; in led_release()
383 b->level_use--; in led_release()
385 led->blink = 0; in led_release()
386 led->bank = -1; in led_release()
393 int level = TO_LEVEL(led->led_cdev.brightness); in led_prepare()
394 struct tca6507_chip *tca = led->chip; in led_prepare()
400 led->led_cdev.brightness = TO_BRIGHT(level); in led_prepare()
402 set_select(tca, led->num, TCA6507_LS_LED_OFF); in led_prepare()
406 if (led->ontime == 0 || led->offtime == 0) { in led_prepare()
413 int best = -1;/* full-on */ in led_prepare()
414 int diff = 15-level; in led_prepare()
417 set_select(tca, led->num, TCA6507_LS_LED_ON); in led_prepare()
421 for (i = MASTER; i >= BANK0; i--) { in led_prepare()
423 if (tca->bank[i].level == level || in led_prepare()
424 tca->bank[i].level_use == 0) { in led_prepare()
428 d = abs(level - tca->bank[i].level); in led_prepare()
434 if (best == -1) { in led_prepare()
435 /* Best brightness is full-on */ in led_prepare()
436 set_select(tca, led->num, TCA6507_LS_LED_ON); in led_prepare()
437 led->led_cdev.brightness = LED_FULL; in led_prepare()
441 if (!tca->bank[best].level_use) in led_prepare()
444 tca->bank[best].level_use++; in led_prepare()
445 led->bank = best; in led_prepare()
446 set_select(tca, led->num, bank_source[best]); in led_prepare()
447 led->led_cdev.brightness = TO_BRIGHT(tca->bank[best].level); in led_prepare()
456 if (choose_times(led->ontime, &c1, &c2) < 0) in led_prepare()
457 return -EINVAL; in led_prepare()
458 if (choose_times(led->offtime, &c1, &c2) < 0) in led_prepare()
459 return -EINVAL; in led_prepare()
462 if (tca->bank[i].level_use == 0) in led_prepare()
463 /* not in use - it is ours! */ in led_prepare()
465 if (tca->bank[i].level != level) in led_prepare()
466 /* Incompatible level - skip */ in led_prepare()
472 if (tca->bank[i].time_use == 0) in led_prepare()
473 /* Timer not in use, and level matches - use it */ in led_prepare()
476 if (!(tca->bank[i].on_dflt || in led_prepare()
477 led->on_dflt || in led_prepare()
478 tca->bank[i].ontime == led->ontime)) in led_prepare()
482 if (!(tca->bank[i].off_dflt || in led_prepare()
483 led->off_dflt || in led_prepare()
484 tca->bank[i].offtime == led->offtime)) in led_prepare()
493 /* Nothing matches - how sad */ in led_prepare()
494 return -EINVAL; in led_prepare()
496 b = &tca->bank[i]; in led_prepare()
497 if (b->level_use == 0) in led_prepare()
499 b->level_use++; in led_prepare()
500 led->bank = i; in led_prepare()
502 if (b->on_dflt || in led_prepare()
503 !led->on_dflt || in led_prepare()
504 b->time_use == 0) { in led_prepare()
505 b->ontime = led->ontime; in led_prepare()
506 b->on_dflt = led->on_dflt; in led_prepare()
510 if (b->off_dflt || in led_prepare()
511 !led->off_dflt || in led_prepare()
512 b->time_use == 0) { in led_prepare()
513 b->offtime = led->offtime; in led_prepare()
514 b->off_dflt = led->off_dflt; in led_prepare()
521 led->ontime = b->ontime; in led_prepare()
522 led->offtime = b->offtime; in led_prepare()
524 b->time_use++; in led_prepare()
525 led->blink = 1; in led_prepare()
526 led->led_cdev.brightness = TO_BRIGHT(b->level); in led_prepare()
527 set_select(tca, led->num, blink_source[i]); in led_prepare()
533 struct tca6507_chip *tca = led->chip; in led_assign()
537 spin_lock_irqsave(&tca->lock, flags); in led_assign()
543 * to re-establish as steady level. in led_assign()
545 led->ontime = 0; in led_assign()
546 led->offtime = 0; in led_assign()
549 spin_unlock_irqrestore(&tca->lock, flags); in led_assign()
551 if (tca->reg_set) in led_assign()
552 schedule_work(&tca->work); in led_assign()
561 led->led_cdev.brightness = brightness; in tca6507_brightness_set()
562 led->ontime = 0; in tca6507_brightness_set()
563 led->offtime = 0; in tca6507_brightness_set()
575 led->on_dflt = 1; in tca6507_blink_set()
576 else if (delay_on != &led_cdev->blink_delay_on) in tca6507_blink_set()
577 led->on_dflt = 0; in tca6507_blink_set()
578 led->ontime = *delay_on; in tca6507_blink_set()
581 led->off_dflt = 1; in tca6507_blink_set()
582 else if (delay_off != &led_cdev->blink_delay_off) in tca6507_blink_set()
583 led->off_dflt = 0; in tca6507_blink_set()
584 led->offtime = *delay_off; in tca6507_blink_set()
586 if (led->ontime == 0) in tca6507_blink_set()
587 led->ontime = 512; in tca6507_blink_set()
588 if (led->offtime == 0) in tca6507_blink_set()
589 led->offtime = 512; in tca6507_blink_set()
591 if (led->led_cdev.brightness == LED_OFF) in tca6507_blink_set()
592 led->led_cdev.brightness = LED_FULL; in tca6507_blink_set()
594 led->ontime = 0; in tca6507_blink_set()
595 led->offtime = 0; in tca6507_blink_set()
596 led->led_cdev.brightness = LED_OFF; in tca6507_blink_set()
597 return -EINVAL; in tca6507_blink_set()
599 *delay_on = led->ontime; in tca6507_blink_set()
600 *delay_off = led->offtime; in tca6507_blink_set()
611 spin_lock_irqsave(&tca->lock, flags); in tca6507_gpio_set_value()
616 set_select(tca, tca->gpio_map[offset], in tca6507_gpio_set_value()
618 spin_unlock_irqrestore(&tca->lock, flags); in tca6507_gpio_set_value()
619 if (tca->reg_set) in tca6507_gpio_set_value()
620 schedule_work(&tca->work); in tca6507_gpio_set_value()
639 if (pdata->leds.leds[i].name && pdata->leds.leds[i].flags) { in tca6507_probe_gpios()
641 tca->gpio_name[gpios] = pdata->leds.leds[i].name; in tca6507_probe_gpios()
642 tca->gpio_map[gpios] = i; in tca6507_probe_gpios()
649 tca->gpio.label = "gpio-tca6507"; in tca6507_probe_gpios()
650 tca->gpio.names = tca->gpio_name; in tca6507_probe_gpios()
651 tca->gpio.ngpio = gpios; in tca6507_probe_gpios()
652 tca->gpio.base = pdata->gpio_base; in tca6507_probe_gpios()
653 tca->gpio.owner = THIS_MODULE; in tca6507_probe_gpios()
654 tca->gpio.direction_output = tca6507_gpio_direction_output; in tca6507_probe_gpios()
655 tca->gpio.set = tca6507_gpio_set_value; in tca6507_probe_gpios()
656 tca->gpio.parent = &client->dev; in tca6507_probe_gpios()
658 tca->gpio.of_node = of_node_get(client->dev.of_node); in tca6507_probe_gpios()
660 err = gpiochip_add_data(&tca->gpio, tca); in tca6507_probe_gpios()
662 tca->gpio.ngpio = 0; in tca6507_probe_gpios()
665 if (pdata->setup) in tca6507_probe_gpios()
666 pdata->setup(tca->gpio.base, tca->gpio.ngpio); in tca6507_probe_gpios()
672 if (tca->gpio.ngpio) in tca6507_remove_gpio()
673 gpiochip_remove(&tca->gpio); in tca6507_remove_gpio()
691 struct device_node *np = client->dev.of_node, *child; in tca6507_led_dt_init()
698 return ERR_PTR(-ENODEV); in tca6507_led_dt_init()
700 tca_leds = devm_kcalloc(&client->dev, in tca6507_led_dt_init()
703 return ERR_PTR(-ENOMEM); in tca6507_led_dt_init()
711 of_get_property(child, "label", NULL) ? : child->name; in tca6507_led_dt_init()
713 of_get_property(child, "linux,default-trigger", NULL); in tca6507_led_dt_init()
723 pdata = devm_kzalloc(&client->dev, in tca6507_led_dt_init()
726 return ERR_PTR(-ENOMEM); in tca6507_led_dt_init()
728 pdata->leds.leds = tca_leds; in tca6507_led_dt_init()
729 pdata->leds.num_leds = NUM_LEDS; in tca6507_led_dt_init()
731 pdata->gpio_base = -1; in tca6507_led_dt_init()
746 return ERR_PTR(-ENODEV); in tca6507_led_dt_init()
760 adapter = to_i2c_adapter(client->dev.parent); in tca6507_probe()
761 pdata = dev_get_platdata(&client->dev); in tca6507_probe()
764 return -EIO; in tca6507_probe()
766 if (!pdata || pdata->leds.num_leds != NUM_LEDS) { in tca6507_probe()
769 dev_err(&client->dev, "Need %d entries in platform-data list\n", in tca6507_probe()
774 tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL); in tca6507_probe()
776 return -ENOMEM; in tca6507_probe()
778 tca->client = client; in tca6507_probe()
779 INIT_WORK(&tca->work, tca6507_work); in tca6507_probe()
780 spin_lock_init(&tca->lock); in tca6507_probe()
784 struct tca6507_led *l = tca->leds + i; in tca6507_probe()
786 l->chip = tca; in tca6507_probe()
787 l->num = i; in tca6507_probe()
788 if (pdata->leds.leds[i].name && !pdata->leds.leds[i].flags) { in tca6507_probe()
789 l->led_cdev.name = pdata->leds.leds[i].name; in tca6507_probe()
790 l->led_cdev.default_trigger in tca6507_probe()
791 = pdata->leds.leds[i].default_trigger; in tca6507_probe()
792 l->led_cdev.brightness_set = tca6507_brightness_set; in tca6507_probe()
793 l->led_cdev.blink_set = tca6507_blink_set; in tca6507_probe()
794 l->bank = -1; in tca6507_probe()
795 err = led_classdev_register(&client->dev, in tca6507_probe()
796 &l->led_cdev); in tca6507_probe()
804 /* set all registers to known state - zero */ in tca6507_probe()
805 tca->reg_set = 0x7f; in tca6507_probe()
806 schedule_work(&tca->work); in tca6507_probe()
810 while (i--) { in tca6507_probe()
811 if (tca->leds[i].led_cdev.name) in tca6507_probe()
812 led_classdev_unregister(&tca->leds[i].led_cdev); in tca6507_probe()
821 struct tca6507_led *tca_leds = tca->leds; in tca6507_remove()
828 cancel_work_sync(&tca->work); in tca6507_remove()
835 .name = "leds-tca6507",