Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers/leds/leds-lp5521.c: support led pattern data

The lp5521 has autonomous operation mode without external control.
Using lp5521_platform_data, various led patterns can be configurable.
For supporting this feature, new functions and device attribute are
added.

Structure of lp5521_led_pattern: 3 channels are supported - red, green
and blue. Pattern(s) of each channel and numbers of pattern(s) are
defined in the pla= tform data. Pattern data are hexa codes which
include pattern commands such like set pwm, wait, ramp up/down, branch
and so on.

Pattern mode functions:
* lp5521_clear_program_memory
Before running new led pattern, program memory should be cleared.
* lp5521_write_program_memory
Pattern data updated in the program memory via the i2c.
* lp5521_get_pattern
Get pattern from predefined in the platform data.
* lp5521_run_led_pattern
Stop current pattern or run new pattern.
Transition time is required between different operation mode.

Device attribute - 'led_pattern': To load specific led pattern, new device
attribute is added.

When the lp5521 driver is unloaded, stop current led pattern mode.

Documentation updated : description about how to define the led patterns
and example.

[akpm@linux-foundation.org: checkpatch fixes]
Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Cc: Arun MURTHY <arun.murthy@stericsson.com>
Cc: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Kim, Milo and committed by
Linus Torvalds
011af7bc 3b49aacd

+150 -1
+38
Documentation/leds/leds-lp5521.txt
··· 111 111 .clock_mode = LP5521_CLOCK_INT, 112 112 .update_config = LP5521_CONFIGS, 113 113 }; 114 + 115 + LED patterns : LP5521 has autonomous operation without external control. 116 + Pattern data can be defined in the platform data. 117 + 118 + example of led pattern data : 119 + 120 + /* RGB(50,5,0) 500ms on, 500ms off, infinite loop */ 121 + static u8 pattern_red[] = { 122 + 0x40, 0x32, 0x60, 0x00, 0x40, 0x00, 0x60, 0x00, 123 + }; 124 + 125 + static u8 pattern_green[] = { 126 + 0x40, 0x05, 0x60, 0x00, 0x40, 0x00, 0x60, 0x00, 127 + }; 128 + 129 + static struct lp5521_led_pattern board_led_patterns[] = { 130 + { 131 + .r = pattern_red, 132 + .g = pattern_green, 133 + .size_r = ARRAY_SIZE(pattern_red), 134 + .size_g = ARRAY_SIZE(pattern_green), 135 + }, 136 + }; 137 + 138 + static struct lp5521_platform_data lp5521_platform_data = { 139 + .led_config = lp5521_led_config, 140 + .num_channels = ARRAY_SIZE(lp5521_led_config), 141 + .clock_mode = LP5521_CLOCK_EXT, 142 + .patterns = board_led_patterns, 143 + .num_patterns = ARRAY_SIZE(board_led_patterns), 144 + }; 145 + 146 + Then predefined led pattern(s) can be executed via the sysfs. 147 + To start the pattern #1, 148 + # echo 1 > /sys/bus/i2c/devices/xxxx/led_pattern 149 + (xxxx : i2c bus & slave address) 150 + To end the pattern, 151 + # echo 0 > /sys/bus/i2c/devices/xxxx/led_pattern
+101 -1
drivers/leds/leds-lp5521.c
··· 88 88 /* default R channel current register value */ 89 89 #define LP5521_REG_R_CURR_DEFAULT 0xAF 90 90 91 + /* Pattern Mode */ 92 + #define PATTERN_OFF 0 93 + 91 94 struct lp5521_engine { 92 95 int id; 93 96 u8 mode; ··· 496 493 ssize_t ret; 497 494 unsigned long curr; 498 495 499 - if (strict_strtoul(buf, 0, &curr)) 496 + if (kstrtoul(buf, 0, &curr)) 500 497 return -EINVAL; 501 498 502 499 if (curr > led->max_current) ··· 528 525 return sprintf(buf, "%s\n", ret ? "FAIL" : "OK"); 529 526 } 530 527 528 + static void lp5521_clear_program_memory(struct i2c_client *cl) 529 + { 530 + int i; 531 + u8 rgb_mem[] = { 532 + LP5521_REG_R_PROG_MEM, 533 + LP5521_REG_G_PROG_MEM, 534 + LP5521_REG_B_PROG_MEM, 535 + }; 536 + 537 + for (i = 0; i < ARRAY_SIZE(rgb_mem); i++) { 538 + lp5521_write(cl, rgb_mem[i], 0); 539 + lp5521_write(cl, rgb_mem[i] + 1, 0); 540 + } 541 + } 542 + 543 + static void lp5521_write_program_memory(struct i2c_client *cl, 544 + u8 base, u8 *rgb, int size) 545 + { 546 + int i; 547 + 548 + if (!rgb || size <= 0) 549 + return; 550 + 551 + for (i = 0; i < size; i++) 552 + lp5521_write(cl, base + i, *(rgb + i)); 553 + 554 + lp5521_write(cl, base + i, 0); 555 + lp5521_write(cl, base + i + 1, 0); 556 + } 557 + 558 + static inline struct lp5521_led_pattern *lp5521_get_pattern 559 + (struct lp5521_chip *chip, u8 offset) 560 + { 561 + struct lp5521_led_pattern *ptn; 562 + ptn = chip->pdata->patterns + (offset - 1); 563 + return ptn; 564 + } 565 + 566 + static void lp5521_run_led_pattern(int mode, struct lp5521_chip *chip) 567 + { 568 + struct lp5521_led_pattern *ptn; 569 + struct i2c_client *cl = chip->client; 570 + int num_patterns = chip->pdata->num_patterns; 571 + 572 + if (mode > num_patterns || !(chip->pdata->patterns)) 573 + return; 574 + 575 + if (mode == PATTERN_OFF) { 576 + lp5521_write(cl, LP5521_REG_ENABLE, 577 + LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM); 578 + usleep_range(1000, 2000); 579 + lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); 580 + } else { 581 + ptn = lp5521_get_pattern(chip, mode); 582 + if (!ptn) 583 + return; 584 + 585 + lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_LOAD); 586 + usleep_range(1000, 2000); 587 + 588 + lp5521_clear_program_memory(cl); 589 + 590 + lp5521_write_program_memory(cl, LP5521_REG_R_PROG_MEM, 591 + ptn->r, ptn->size_r); 592 + lp5521_write_program_memory(cl, LP5521_REG_G_PROG_MEM, 593 + ptn->g, ptn->size_g); 594 + lp5521_write_program_memory(cl, LP5521_REG_B_PROG_MEM, 595 + ptn->b, ptn->size_b); 596 + 597 + lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_RUN); 598 + usleep_range(1000, 2000); 599 + lp5521_write(cl, LP5521_REG_ENABLE, 600 + LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM | 601 + LP5521_EXEC_RUN); 602 + } 603 + } 604 + 605 + static ssize_t store_led_pattern(struct device *dev, 606 + struct device_attribute *attr, 607 + const char *buf, size_t len) 608 + { 609 + struct lp5521_chip *chip = i2c_get_clientdata(to_i2c_client(dev)); 610 + unsigned long val; 611 + int ret; 612 + 613 + ret = strict_strtoul(buf, 16, &val); 614 + if (ret) 615 + return ret; 616 + 617 + lp5521_run_led_pattern(val, chip); 618 + 619 + return len; 620 + } 621 + 531 622 /* led class device attributes */ 532 623 static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current); 533 624 static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL); ··· 647 550 static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load); 648 551 static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load); 649 552 static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL); 553 + static DEVICE_ATTR(led_pattern, S_IWUSR, NULL, store_led_pattern); 650 554 651 555 static struct attribute *lp5521_attributes[] = { 652 556 &dev_attr_engine1_mode.attr, ··· 657 559 &dev_attr_engine1_load.attr, 658 560 &dev_attr_engine2_load.attr, 659 561 &dev_attr_engine3_load.attr, 562 + &dev_attr_led_pattern.attr, 660 563 NULL 661 564 }; 662 565 ··· 860 761 struct lp5521_chip *chip = i2c_get_clientdata(client); 861 762 int i; 862 763 764 + lp5521_run_led_pattern(PATTERN_OFF, chip); 863 765 lp5521_unregister_sysfs(client); 864 766 865 767 for (i = 0; i < chip->num_leds; i++) {
+11
include/linux/leds-lp5521.h
··· 32 32 u8 max_current; 33 33 }; 34 34 35 + struct lp5521_led_pattern { 36 + u8 *r; 37 + u8 *g; 38 + u8 *b; 39 + u8 size_r; 40 + u8 size_g; 41 + u8 size_b; 42 + }; 43 + 35 44 #define LP5521_CLOCK_AUTO 0 36 45 #define LP5521_CLOCK_INT 1 37 46 #define LP5521_CLOCK_EXT 2 ··· 66 57 void (*enable)(bool state); 67 58 const char *label; 68 59 u8 update_config; 60 + struct lp5521_led_pattern *patterns; 61 + int num_patterns; 69 62 }; 70 63 71 64 #endif /* __LINUX_LP5521_H */