8
8
#include <linux/device.h>
9
9
#include <linux/hid.h>
10
10
#include <linux/leds.h>
11
+ #include <linux/led-class-multicolor.h>
11
12
#include <linux/module.h>
12
13
#include <linux/random.h>
13
14
#include <linux/sched.h>
14
15
#include <linux/usb.h>
15
16
#include <linux/wait.h>
17
+ #include <dt-bindings/leds/common.h>
16
18
17
19
#include "hid-ids.h"
18
20
@@ -44,9 +46,13 @@ enum lg_g15_led_type {
44
46
};
45
47
46
48
struct lg_g15_led {
47
- struct led_classdev cdev ;
49
+ union {
50
+ struct led_classdev cdev ;
51
+ struct led_classdev_mc mcdev ;
52
+ };
48
53
enum led_brightness brightness ;
49
54
enum lg_g15_led_type led ;
55
+ /* Used to store initial color intensities before subled_info is allocated */
50
56
u8 red , green , blue ;
51
57
};
52
58
@@ -229,15 +235,15 @@ static int lg_g510_kbd_led_write(struct lg_g15_data *g15,
229
235
struct lg_g15_led * g15_led ,
230
236
enum led_brightness brightness )
231
237
{
238
+ struct mc_subled * subleds = g15_led -> mcdev .subled_info ;
232
239
int ret ;
233
240
241
+ led_mc_calc_color_components (& g15_led -> mcdev , brightness );
242
+
234
243
g15 -> transfer_buf [0 ] = 5 + g15_led -> led ;
235
- g15 -> transfer_buf [1 ] =
236
- DIV_ROUND_CLOSEST (g15_led -> red * brightness , 255 );
237
- g15 -> transfer_buf [2 ] =
238
- DIV_ROUND_CLOSEST (g15_led -> green * brightness , 255 );
239
- g15 -> transfer_buf [3 ] =
240
- DIV_ROUND_CLOSEST (g15_led -> blue * brightness , 255 );
244
+ g15 -> transfer_buf [1 ] = subleds [0 ].brightness ;
245
+ g15 -> transfer_buf [2 ] = subleds [1 ].brightness ;
246
+ g15 -> transfer_buf [3 ] = subleds [2 ].brightness ;
241
247
242
248
ret = hid_hw_raw_request (g15 -> hdev ,
243
249
LG_G510_FEATURE_BACKLIGHT_RGB + g15_led -> led ,
@@ -258,8 +264,9 @@ static int lg_g510_kbd_led_write(struct lg_g15_data *g15,
258
264
static int lg_g510_kbd_led_set (struct led_classdev * led_cdev ,
259
265
enum led_brightness brightness )
260
266
{
267
+ struct led_classdev_mc * mc = lcdev_to_mccdev (led_cdev );
261
268
struct lg_g15_led * g15_led =
262
- container_of (led_cdev , struct lg_g15_led , cdev );
269
+ container_of (mc , struct lg_g15_led , mcdev );
263
270
struct lg_g15_data * g15 = dev_get_drvdata (led_cdev -> dev -> parent );
264
271
int ret ;
265
272
@@ -276,82 +283,20 @@ static int lg_g510_kbd_led_set(struct led_classdev *led_cdev,
276
283
277
284
static enum led_brightness lg_g510_kbd_led_get (struct led_classdev * led_cdev )
278
285
{
286
+ struct led_classdev_mc * mc = lcdev_to_mccdev (led_cdev );
279
287
struct lg_g15_led * g15_led =
280
- container_of (led_cdev , struct lg_g15_led , cdev );
288
+ container_of (mc , struct lg_g15_led , mcdev );
281
289
282
290
return g15_led -> brightness ;
283
291
}
284
292
285
- static ssize_t color_store (struct device * dev , struct device_attribute * attr ,
286
- const char * buf , size_t count )
287
- {
288
- struct led_classdev * led_cdev = dev_get_drvdata (dev );
289
- struct lg_g15_led * g15_led =
290
- container_of (led_cdev , struct lg_g15_led , cdev );
291
- struct lg_g15_data * g15 = dev_get_drvdata (led_cdev -> dev -> parent );
292
- unsigned long value ;
293
- int ret ;
294
-
295
- if (count < 7 || (count == 8 && buf [7 ] != '\n' ) || count > 8 )
296
- return - EINVAL ;
297
-
298
- if (buf [0 ] != '#' )
299
- return - EINVAL ;
300
-
301
- ret = kstrtoul (buf + 1 , 16 , & value );
302
- if (ret )
303
- return ret ;
304
-
305
- mutex_lock (& g15 -> mutex );
306
- g15_led -> red = (value & 0xff0000 ) >> 16 ;
307
- g15_led -> green = (value & 0x00ff00 ) >> 8 ;
308
- g15_led -> blue = (value & 0x0000ff );
309
- ret = lg_g510_kbd_led_write (g15 , g15_led , g15_led -> brightness );
310
- mutex_unlock (& g15 -> mutex );
311
-
312
- return (ret < 0 ) ? ret : count ;
313
- }
314
-
315
- static ssize_t color_show (struct device * dev , struct device_attribute * attr ,
316
- char * buf )
317
- {
318
- struct led_classdev * led_cdev = dev_get_drvdata (dev );
319
- struct lg_g15_led * g15_led =
320
- container_of (led_cdev , struct lg_g15_led , cdev );
321
- struct lg_g15_data * g15 = dev_get_drvdata (led_cdev -> dev -> parent );
322
- ssize_t ret ;
323
-
324
- mutex_lock (& g15 -> mutex );
325
- ret = sprintf (buf , "#%02x%02x%02x\n" ,
326
- g15_led -> red , g15_led -> green , g15_led -> blue );
327
- mutex_unlock (& g15 -> mutex );
328
-
329
- return ret ;
330
- }
331
-
332
- static DEVICE_ATTR_RW (color );
333
-
334
- static struct attribute * lg_g510_kbd_led_attrs [] = {
335
- & dev_attr_color .attr ,
336
- NULL ,
337
- };
338
-
339
- static const struct attribute_group lg_g510_kbd_led_group = {
340
- .attrs = lg_g510_kbd_led_attrs ,
341
- };
342
-
343
- static const struct attribute_group * lg_g510_kbd_led_groups [] = {
344
- & lg_g510_kbd_led_group ,
345
- NULL ,
346
- };
347
-
348
293
static void lg_g510_leds_sync_work (struct work_struct * work )
349
294
{
350
295
struct lg_g15_data * g15 = container_of (work , struct lg_g15_data , work );
296
+ struct lg_g15_led * g15_led = & g15 -> leds [LG_G15_KBD_BRIGHTNESS ];
351
297
352
298
mutex_lock (& g15 -> mutex );
353
- lg_g510_kbd_led_write (g15 , & g15 -> leds [LG_G15_KBD_BRIGHTNESS ],
354
- g15 -> leds [LG_G15_KBD_BRIGHTNESS ].brightness );
299
+ lg_g510_kbd_led_write (g15 , g15_led , g15_led -> brightness );
355
300
mutex_unlock (& g15 -> mutex );
356
301
}
357
302
@@ -667,8 +612,46 @@ static void lg_g15_input_close(struct input_dev *dev)
667
612
hid_hw_close (hdev );
668
613
}
669
614
615
+ static void lg_g15_setup_led_rgb (struct lg_g15_data * g15 , int index )
616
+ {
617
+ int i ;
618
+ struct mc_subled * subled_info ;
619
+
620
+ g15 -> leds [index ].mcdev .led_cdev .brightness_set_blocking =
621
+ lg_g510_kbd_led_set ;
622
+ g15 -> leds [index ].mcdev .led_cdev .brightness_get =
623
+ lg_g510_kbd_led_get ;
624
+ g15 -> leds [index ].mcdev .led_cdev .max_brightness = 255 ;
625
+ g15 -> leds [index ].mcdev .num_colors = 3 ;
626
+
627
+ subled_info = devm_kcalloc (& g15 -> hdev -> dev , 3 , sizeof (* subled_info ), GFP_KERNEL );
628
+ if (!subled_info )
629
+ return ;
630
+
631
+ for (i = 0 ; i < 3 ; i ++ ) {
632
+ switch (i + 1 ) {
633
+ case LED_COLOR_ID_RED :
634
+ subled_info [i ].color_index = LED_COLOR_ID_RED ;
635
+ subled_info [i ].intensity = g15 -> leds [index ].red ;
636
+ break ;
637
+ case LED_COLOR_ID_GREEN :
638
+ subled_info [i ].color_index = LED_COLOR_ID_GREEN ;
639
+ subled_info [i ].intensity = g15 -> leds [index ].green ;
640
+ break ;
641
+ case LED_COLOR_ID_BLUE :
642
+ subled_info [i ].color_index = LED_COLOR_ID_BLUE ;
643
+ subled_info [i ].intensity = g15 -> leds [index ].blue ;
644
+ break ;
645
+ }
646
+ subled_info [i ].channel = i ;
647
+ }
648
+ g15 -> leds [index ].mcdev .subled_info = subled_info ;
649
+ }
650
+
670
651
static int lg_g15_register_led (struct lg_g15_data * g15 , int i , const char * name )
671
652
{
653
+ int ret ;
654
+
672
655
g15 -> leds [i ].led = i ;
673
656
g15 -> leds [i ].cdev .name = name ;
674
657
@@ -685,6 +668,7 @@ static int lg_g15_register_led(struct lg_g15_data *g15, int i, const char *name)
685
668
} else {
686
669
g15 -> leds [i ].cdev .max_brightness = 1 ;
687
670
}
671
+ ret = devm_led_classdev_register (& g15 -> hdev -> dev , & g15 -> leds [i ].cdev );
688
672
break ;
689
673
case LG_G510 :
690
674
case LG_G510_USB_AUDIO :
@@ -697,24 +681,24 @@ static int lg_g15_register_led(struct lg_g15_data *g15, int i, const char *name)
697
681
g15 -> leds [i ].cdev .name = "g15::power_on_backlight_val" ;
698
682
fallthrough ;
699
683
case LG_G15_KBD_BRIGHTNESS :
700
- g15 -> leds [i ].cdev .brightness_set_blocking =
701
- lg_g510_kbd_led_set ;
702
- g15 -> leds [i ].cdev .brightness_get =
703
- lg_g510_kbd_led_get ;
704
- g15 -> leds [i ].cdev .max_brightness = 255 ;
705
- g15 -> leds [i ].cdev .groups = lg_g510_kbd_led_groups ;
684
+ /* register multicolor LED */
685
+ lg_g15_setup_led_rgb (g15 , i );
686
+ ret = devm_led_classdev_multicolor_register_ext (& g15 -> hdev -> dev ,
687
+ & g15 -> leds [i ].mcdev ,
688
+ NULL );
706
689
break ;
707
690
default :
708
691
g15 -> leds [i ].cdev .brightness_set_blocking =
709
692
lg_g510_mkey_led_set ;
710
693
g15 -> leds [i ].cdev .brightness_get =
711
694
lg_g510_mkey_led_get ;
712
695
g15 -> leds [i ].cdev .max_brightness = 1 ;
696
+ ret = devm_led_classdev_register (& g15 -> hdev -> dev , & g15 -> leds [i ].cdev );
713
697
}
714
698
break ;
715
699
}
716
700
717
- return devm_led_classdev_register ( & g15 -> hdev -> dev , & g15 -> leds [ i ]. cdev ) ;
701
+ return ret ;
718
702
}
719
703
720
704
/* Common input device init code shared between keyboards and Z-10 speaker handling */
0 commit comments