88#include <linux/device.h>
99#include <linux/hid.h>
1010#include <linux/leds.h>
11+ #include <linux/led-class-multicolor.h>
1112#include <linux/module.h>
1213#include <linux/random.h>
1314#include <linux/sched.h>
1415#include <linux/usb.h>
1516#include <linux/wait.h>
17+ #include <dt-bindings/leds/common.h>
1618
1719#include "hid-ids.h"
1820
@@ -44,9 +46,13 @@ enum lg_g15_led_type {
4446};
4547
4648struct lg_g15_led {
47- struct led_classdev cdev ;
49+ union {
50+ struct led_classdev cdev ;
51+ struct led_classdev_mc mcdev ;
52+ };
4853 enum led_brightness brightness ;
4954 enum lg_g15_led_type led ;
55+ /* Used to store initial color intensities before subled_info is allocated */
5056 u8 red , green , blue ;
5157};
5258
@@ -229,15 +235,15 @@ static int lg_g510_kbd_led_write(struct lg_g15_data *g15,
229235 struct lg_g15_led * g15_led ,
230236 enum led_brightness brightness )
231237{
238+ struct mc_subled * subleds = g15_led -> mcdev .subled_info ;
232239 int ret ;
233240
241+ led_mc_calc_color_components (& g15_led -> mcdev , brightness );
242+
234243 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 ;
241247
242248 ret = hid_hw_raw_request (g15 -> hdev ,
243249 LG_G510_FEATURE_BACKLIGHT_RGB + g15_led -> led ,
@@ -258,8 +264,9 @@ static int lg_g510_kbd_led_write(struct lg_g15_data *g15,
258264static int lg_g510_kbd_led_set (struct led_classdev * led_cdev ,
259265 enum led_brightness brightness )
260266{
267+ struct led_classdev_mc * mc = lcdev_to_mccdev (led_cdev );
261268 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 );
263270 struct lg_g15_data * g15 = dev_get_drvdata (led_cdev -> dev -> parent );
264271 int ret ;
265272
@@ -276,82 +283,20 @@ static int lg_g510_kbd_led_set(struct led_classdev *led_cdev,
276283
277284static enum led_brightness lg_g510_kbd_led_get (struct led_classdev * led_cdev )
278285{
286+ struct led_classdev_mc * mc = lcdev_to_mccdev (led_cdev );
279287 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 );
281289
282290 return g15_led -> brightness ;
283291}
284292
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-
348293static void lg_g510_leds_sync_work (struct work_struct * work )
349294{
350295 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 ];
351297
352298 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 );
355300 mutex_unlock (& g15 -> mutex );
356301}
357302
@@ -667,8 +612,46 @@ static void lg_g15_input_close(struct input_dev *dev)
667612 hid_hw_close (hdev );
668613}
669614
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+
670651static int lg_g15_register_led (struct lg_g15_data * g15 , int i , const char * name )
671652{
653+ int ret ;
654+
672655 g15 -> leds [i ].led = i ;
673656 g15 -> leds [i ].cdev .name = name ;
674657
@@ -685,6 +668,7 @@ static int lg_g15_register_led(struct lg_g15_data *g15, int i, const char *name)
685668 } else {
686669 g15 -> leds [i ].cdev .max_brightness = 1 ;
687670 }
671+ ret = devm_led_classdev_register (& g15 -> hdev -> dev , & g15 -> leds [i ].cdev );
688672 break ;
689673 case LG_G510 :
690674 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)
697681 g15 -> leds [i ].cdev .name = "g15::power_on_backlight_val" ;
698682 fallthrough ;
699683 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 );
706689 break ;
707690 default :
708691 g15 -> leds [i ].cdev .brightness_set_blocking =
709692 lg_g510_mkey_led_set ;
710693 g15 -> leds [i ].cdev .brightness_get =
711694 lg_g510_mkey_led_get ;
712695 g15 -> leds [i ].cdev .max_brightness = 1 ;
696+ ret = devm_led_classdev_register (& g15 -> hdev -> dev , & g15 -> leds [i ].cdev );
713697 }
714698 break ;
715699 }
716700
717- return devm_led_classdev_register ( & g15 -> hdev -> dev , & g15 -> leds [ i ]. cdev ) ;
701+ return ret ;
718702}
719703
720704/* Common input device init code shared between keyboards and Z-10 speaker handling */
0 commit comments