Skip to content

Commit 92a8156

Browse files
Dan Murphypavelmachek
authored andcommitted
leds: lp55xx: Add multicolor framework support to lp55xx
Add multicolor framework support for the lp55xx family. Acked-by: Pavel Machek <[email protected]> Acked-by: Jacek Anaszewski <[email protected]> Signed-off-by: Dan Murphy <[email protected]> Signed-off-by: Pavel Machek <[email protected]>
1 parent c732eaf commit 92a8156

File tree

8 files changed

+212
-52
lines changed

8 files changed

+212
-52
lines changed

drivers/leds/Kconfig

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ config LEDS_LP3952
386386

387387
config LEDS_LP55XX_COMMON
388388
tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501"
389-
depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562 || LEDS_LP8501
389+
depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
390+
depends on OF
390391
select FW_LOADER
391392
select FW_LOADER_USER_HELPER
392393
help
@@ -396,7 +397,7 @@ config LEDS_LP55XX_COMMON
396397
config LEDS_LP5521
397398
tristate "LED Support for N.S. LP5521 LED driver chip"
398399
depends on LEDS_CLASS && I2C
399-
select LEDS_LP55XX_COMMON
400+
depends on LEDS_LP55XX_COMMON
400401
help
401402
If you say yes here you get support for the National Semiconductor
402403
LP5521 LED driver. It is 3 channel chip with programmable engines.
@@ -406,7 +407,7 @@ config LEDS_LP5521
406407
config LEDS_LP5523
407408
tristate "LED Support for TI/National LP5523/55231 LED driver chip"
408409
depends on LEDS_CLASS && I2C
409-
select LEDS_LP55XX_COMMON
410+
depends on LEDS_LP55XX_COMMON
410411
help
411412
If you say yes here you get support for TI/National Semiconductor
412413
LP5523/55231 LED driver.
@@ -417,7 +418,7 @@ config LEDS_LP5523
417418
config LEDS_LP5562
418419
tristate "LED Support for TI LP5562 LED driver chip"
419420
depends on LEDS_CLASS && I2C
420-
select LEDS_LP55XX_COMMON
421+
depends on LEDS_LP55XX_COMMON
421422
help
422423
If you say yes here you get support for TI LP5562 LED driver.
423424
It is 4 channels chip with programmable engines.
@@ -427,7 +428,7 @@ config LEDS_LP5562
427428
config LEDS_LP8501
428429
tristate "LED Support for TI LP8501 LED driver chip"
429430
depends on LEDS_CLASS && I2C
430-
select LEDS_LP55XX_COMMON
431+
depends on LEDS_LP55XX_COMMON
431432
help
432433
If you say yes here you get support for TI LP8501 LED driver.
433434
It is 9 channel chip with programmable engines.

drivers/leds/leds-lp5521.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -505,9 +505,16 @@ static int lp5521_probe(struct i2c_client *client,
505505
struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
506506
struct device_node *np = client->dev.of_node;
507507

508+
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
509+
if (!chip)
510+
return -ENOMEM;
511+
512+
chip->cfg = &lp5521_cfg;
513+
508514
if (!pdata) {
509515
if (np) {
510-
pdata = lp55xx_of_populate_pdata(&client->dev, np);
516+
pdata = lp55xx_of_populate_pdata(&client->dev, np,
517+
chip);
511518
if (IS_ERR(pdata))
512519
return PTR_ERR(pdata);
513520
} else {
@@ -516,18 +523,13 @@ static int lp5521_probe(struct i2c_client *client,
516523
}
517524
}
518525

519-
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
520-
if (!chip)
521-
return -ENOMEM;
522-
523526
led = devm_kcalloc(&client->dev,
524527
pdata->num_channels, sizeof(*led), GFP_KERNEL);
525528
if (!led)
526529
return -ENOMEM;
527530

528531
chip->cl = client;
529532
chip->pdata = pdata;
530-
chip->cfg = &lp5521_cfg;
531533

532534
mutex_init(&chip->lock);
533535

drivers/leds/leds-lp5523.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -873,9 +873,16 @@ static int lp5523_probe(struct i2c_client *client,
873873
struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
874874
struct device_node *np = client->dev.of_node;
875875

876+
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
877+
if (!chip)
878+
return -ENOMEM;
879+
880+
chip->cfg = &lp5523_cfg;
881+
876882
if (!pdata) {
877883
if (np) {
878-
pdata = lp55xx_of_populate_pdata(&client->dev, np);
884+
pdata = lp55xx_of_populate_pdata(&client->dev, np,
885+
chip);
879886
if (IS_ERR(pdata))
880887
return PTR_ERR(pdata);
881888
} else {
@@ -884,18 +891,13 @@ static int lp5523_probe(struct i2c_client *client,
884891
}
885892
}
886893

887-
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
888-
if (!chip)
889-
return -ENOMEM;
890-
891894
led = devm_kcalloc(&client->dev,
892895
pdata->num_channels, sizeof(*led), GFP_KERNEL);
893896
if (!led)
894897
return -ENOMEM;
895898

896899
chip->cl = client;
897900
chip->pdata = pdata;
898-
chip->cfg = &lp5523_cfg;
899901

900902
mutex_init(&chip->lock);
901903

drivers/leds/leds-lp5562.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -520,9 +520,16 @@ static int lp5562_probe(struct i2c_client *client,
520520
struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
521521
struct device_node *np = client->dev.of_node;
522522

523+
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
524+
if (!chip)
525+
return -ENOMEM;
526+
527+
chip->cfg = &lp5562_cfg;
528+
523529
if (!pdata) {
524530
if (np) {
525-
pdata = lp55xx_of_populate_pdata(&client->dev, np);
531+
pdata = lp55xx_of_populate_pdata(&client->dev, np,
532+
chip);
526533
if (IS_ERR(pdata))
527534
return PTR_ERR(pdata);
528535
} else {
@@ -531,9 +538,6 @@ static int lp5562_probe(struct i2c_client *client,
531538
}
532539
}
533540

534-
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
535-
if (!chip)
536-
return -ENOMEM;
537541

538542
led = devm_kcalloc(&client->dev,
539543
pdata->num_channels, sizeof(*led), GFP_KERNEL);
@@ -542,7 +546,6 @@ static int lp5562_probe(struct i2c_client *client,
542546

543547
chip->cl = client;
544548
chip->pdata = pdata;
545-
chip->cfg = &lp5562_cfg;
546549

547550
mutex_init(&chip->lock);
548551

drivers/leds/leds-lp55xx-common.c

Lines changed: 155 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ static struct lp55xx_led *dev_to_lp55xx_led(struct device *dev)
3434
return cdev_to_lp55xx_led(dev_get_drvdata(dev));
3535
}
3636

37+
static struct lp55xx_led *mcled_cdev_to_led(struct led_classdev_mc *mc_cdev)
38+
{
39+
return container_of(mc_cdev, struct lp55xx_led, mc_cdev);
40+
}
41+
3742
static void lp55xx_reset_device(struct lp55xx_chip *chip)
3843
{
3944
struct lp55xx_device_config *cfg = chip->cfg;
@@ -129,6 +134,18 @@ static struct attribute *lp55xx_led_attrs[] = {
129134
};
130135
ATTRIBUTE_GROUPS(lp55xx_led);
131136

137+
static int lp55xx_set_mc_brightness(struct led_classdev *cdev,
138+
enum led_brightness brightness)
139+
{
140+
struct led_classdev_mc *mc_dev = lcdev_to_mccdev(cdev);
141+
struct lp55xx_led *led = mcled_cdev_to_led(mc_dev);
142+
struct lp55xx_device_config *cfg = led->chip->cfg;
143+
144+
led_mc_calc_color_components(&led->mc_cdev, brightness);
145+
return cfg->multicolor_brightness_fn(led);
146+
147+
}
148+
132149
static int lp55xx_set_brightness(struct led_classdev *cdev,
133150
enum led_brightness brightness)
134151
{
@@ -145,9 +162,12 @@ static int lp55xx_init_led(struct lp55xx_led *led,
145162
struct lp55xx_platform_data *pdata = chip->pdata;
146163
struct lp55xx_device_config *cfg = chip->cfg;
147164
struct device *dev = &chip->cl->dev;
165+
int max_channel = cfg->max_channel;
166+
struct mc_subled *mc_led_info;
167+
struct led_classdev *led_cdev;
148168
char name[32];
169+
int i, j = 0;
149170
int ret;
150-
int max_channel = cfg->max_channel;
151171

152172
if (chan >= max_channel) {
153173
dev_err(dev, "invalid channel: %d / %d\n", chan, max_channel);
@@ -157,29 +177,55 @@ static int lp55xx_init_led(struct lp55xx_led *led,
157177
if (pdata->led_config[chan].led_current == 0)
158178
return 0;
159179

180+
if (pdata->led_config[chan].name) {
181+
led->cdev.name = pdata->led_config[chan].name;
182+
} else {
183+
snprintf(name, sizeof(name), "%s:channel%d",
184+
pdata->label ? : chip->cl->name, chan);
185+
led->cdev.name = name;
186+
}
187+
188+
if (pdata->led_config[chan].num_colors > 1) {
189+
mc_led_info = devm_kcalloc(dev,
190+
pdata->led_config[chan].num_colors,
191+
sizeof(*mc_led_info), GFP_KERNEL);
192+
if (!mc_led_info)
193+
return -ENOMEM;
194+
195+
led_cdev = &led->mc_cdev.led_cdev;
196+
led_cdev->name = led->cdev.name;
197+
led_cdev->brightness_set_blocking = lp55xx_set_mc_brightness;
198+
led->mc_cdev.num_colors = pdata->led_config[chan].num_colors;
199+
for (i = 0; i < led->mc_cdev.num_colors; i++) {
200+
mc_led_info[i].color_index =
201+
pdata->led_config[chan].color_id[i];
202+
mc_led_info[i].channel =
203+
pdata->led_config[chan].output_num[i];
204+
j++;
205+
}
206+
207+
led->mc_cdev.subled_info = mc_led_info;
208+
} else {
209+
led->cdev.brightness_set_blocking = lp55xx_set_brightness;
210+
}
211+
212+
led->cdev.groups = lp55xx_led_groups;
213+
led->cdev.default_trigger = pdata->led_config[chan].default_trigger;
160214
led->led_current = pdata->led_config[chan].led_current;
161215
led->max_current = pdata->led_config[chan].max_current;
162216
led->chan_nr = pdata->led_config[chan].chan_nr;
163-
led->cdev.default_trigger = pdata->led_config[chan].default_trigger;
164217

165218
if (led->chan_nr >= max_channel) {
166219
dev_err(dev, "Use channel numbers between 0 and %d\n",
167220
max_channel - 1);
168221
return -EINVAL;
169222
}
170223

171-
led->cdev.brightness_set_blocking = lp55xx_set_brightness;
172-
led->cdev.groups = lp55xx_led_groups;
173-
174-
if (pdata->led_config[chan].name) {
175-
led->cdev.name = pdata->led_config[chan].name;
176-
} else {
177-
snprintf(name, sizeof(name), "%s:channel%d",
178-
pdata->label ? : chip->cl->name, chan);
179-
led->cdev.name = name;
180-
}
224+
if (pdata->led_config[chan].num_colors > 1)
225+
ret = devm_led_classdev_multicolor_register(dev, &led->mc_cdev);
226+
else
227+
ret = devm_led_classdev_register(dev, &led->cdev);
181228

182-
ret = devm_led_classdev_register(dev, &led->cdev);
183229
if (ret) {
184230
dev_err(dev, "led register err: %d\n", ret);
185231
return ret;
@@ -515,14 +561,105 @@ void lp55xx_unregister_sysfs(struct lp55xx_chip *chip)
515561
}
516562
EXPORT_SYMBOL_GPL(lp55xx_unregister_sysfs);
517563

564+
static int lp55xx_parse_common_child(struct device_node *np,
565+
struct lp55xx_led_config *cfg,
566+
int led_number, int *chan_nr)
567+
{
568+
int ret;
569+
570+
of_property_read_string(np, "chan-name",
571+
&cfg[led_number].name);
572+
of_property_read_u8(np, "led-cur",
573+
&cfg[led_number].led_current);
574+
of_property_read_u8(np, "max-cur",
575+
&cfg[led_number].max_current);
576+
577+
ret = of_property_read_u32(np, "reg", chan_nr);
578+
if (ret)
579+
return ret;
580+
581+
if (*chan_nr < 0 || *chan_nr > cfg->max_channel)
582+
return -EINVAL;
583+
584+
return 0;
585+
}
586+
587+
static int lp55xx_parse_multi_led_child(struct device_node *child,
588+
struct lp55xx_led_config *cfg,
589+
int child_number, int color_number)
590+
{
591+
int chan_nr, color_id, ret;
592+
593+
ret = lp55xx_parse_common_child(child, cfg, child_number, &chan_nr);
594+
if (ret)
595+
return ret;
596+
597+
ret = of_property_read_u32(child, "color", &color_id);
598+
if (ret)
599+
return ret;
600+
601+
cfg[child_number].color_id[color_number] = color_id;
602+
cfg[child_number].output_num[color_number] = chan_nr;
603+
604+
return 0;
605+
}
606+
607+
static int lp55xx_parse_multi_led(struct device_node *np,
608+
struct lp55xx_led_config *cfg,
609+
int child_number)
610+
{
611+
struct device_node *child;
612+
int num_colors = 0, ret;
613+
614+
for_each_child_of_node(np, child) {
615+
ret = lp55xx_parse_multi_led_child(child, cfg, child_number,
616+
num_colors);
617+
if (ret)
618+
return ret;
619+
num_colors++;
620+
}
621+
622+
cfg[child_number].num_colors = num_colors;
623+
624+
return 0;
625+
}
626+
627+
static int lp55xx_parse_logical_led(struct device_node *np,
628+
struct lp55xx_led_config *cfg,
629+
int child_number)
630+
{
631+
int led_color, ret;
632+
int chan_nr = 0;
633+
634+
cfg[child_number].default_trigger =
635+
of_get_property(np, "linux,default-trigger", NULL);
636+
637+
ret = of_property_read_u32(np, "color", &led_color);
638+
if (ret)
639+
return ret;
640+
641+
if (led_color == LED_COLOR_ID_MULTI)
642+
return lp55xx_parse_multi_led(np, cfg, child_number);
643+
644+
ret = lp55xx_parse_common_child(np, cfg, child_number, &chan_nr);
645+
if (ret < 0)
646+
return ret;
647+
648+
cfg[child_number].chan_nr = chan_nr;
649+
650+
return ret;
651+
}
652+
518653
struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev,
519-
struct device_node *np)
654+
struct device_node *np,
655+
struct lp55xx_chip *chip)
520656
{
521657
struct device_node *child;
522658
struct lp55xx_platform_data *pdata;
523659
struct lp55xx_led_config *cfg;
524660
int num_channels;
525661
int i = 0;
662+
int ret;
526663

527664
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
528665
if (!pdata)
@@ -540,16 +677,12 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev,
540677

541678
pdata->led_config = &cfg[0];
542679
pdata->num_channels = num_channels;
680+
cfg->max_channel = chip->cfg->max_channel;
543681

544682
for_each_child_of_node(np, child) {
545-
cfg[i].chan_nr = i;
546-
547-
of_property_read_string(child, "chan-name", &cfg[i].name);
548-
of_property_read_u8(child, "led-cur", &cfg[i].led_current);
549-
of_property_read_u8(child, "max-cur", &cfg[i].max_current);
550-
cfg[i].default_trigger =
551-
of_get_property(child, "linux,default-trigger", NULL);
552-
683+
ret = lp55xx_parse_logical_led(child, cfg, i);
684+
if (ret)
685+
return ERR_PTR(-EINVAL);
553686
i++;
554687
}
555688

0 commit comments

Comments
 (0)