1*4ed460ceSYo-Jung Leo Lin (AMD) // SPDX-License-Identifier: GPL-2.0
2*4ed460ceSYo-Jung Leo Lin (AMD) /*
3*4ed460ceSYo-Jung Leo Lin (AMD) * AMD Halo Box RGB LED Driver
4*4ed460ceSYo-Jung Leo Lin (AMD) *
5*4ed460ceSYo-Jung Leo Lin (AMD) * Copyright (C) 2026 Advanced Micro Devices, Inc.
6*4ed460ceSYo-Jung Leo Lin (AMD) *
7*4ed460ceSYo-Jung Leo Lin (AMD) * This driver provides RGB LED control for AMD Halo Box devices through
8*4ed460ceSYo-Jung Leo Lin (AMD) * the LED multicolor subsystem. The Halo Box light bar can be controlled
9*4ed460ceSYo-Jung Leo Lin (AMD) * via sysfs to display any RGB color combination.
10*4ed460ceSYo-Jung Leo Lin (AMD) */
11*4ed460ceSYo-Jung Leo Lin (AMD)
12*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/array_size.h>
13*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/cleanup.h>
14*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/compiler_attributes.h>
15*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/container_of.h>
16*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/dev_printk.h>
17*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/device.h>
18*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/device/devres.h>
19*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/led-class-multicolor.h>
20*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/leds.h>
21*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/module.h>
22*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/mutex.h>
23*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/slab.h>
24*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/types.h>
25*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/wmi.h>
26*4ed460ceSYo-Jung Leo Lin (AMD)
27*4ed460ceSYo-Jung Leo Lin (AMD) #include <linux/byteorder/generic.h>
28*4ed460ceSYo-Jung Leo Lin (AMD)
29*4ed460ceSYo-Jung Leo Lin (AMD) #define AMD_HALO_GUID "081E747B-E028-4232-AF24-EAAEAB2B1E86"
30*4ed460ceSYo-Jung Leo Lin (AMD)
31*4ed460ceSYo-Jung Leo Lin (AMD) /* WMI method IDs from MOF */
32*4ed460ceSYo-Jung Leo Lin (AMD) enum {
33*4ed460ceSYo-Jung Leo Lin (AMD) AMD_HALO_WMI_TURN_OFF = 0x04,
34*4ed460ceSYo-Jung Leo Lin (AMD) AMD_HALO_WMI_RGB = 0x07,
35*4ed460ceSYo-Jung Leo Lin (AMD) };
36*4ed460ceSYo-Jung Leo Lin (AMD)
37*4ed460ceSYo-Jung Leo Lin (AMD) /* Arg0 of the AMD_HALO_WMI_RGB Method */
38*4ed460ceSYo-Jung Leo Lin (AMD) enum {
39*4ed460ceSYo-Jung Leo Lin (AMD) AMD_HALO_RGB_CMD_GET = 0x0,
40*4ed460ceSYo-Jung Leo Lin (AMD) AMD_HALO_RGB_CMD_SET = 0x1,
41*4ed460ceSYo-Jung Leo Lin (AMD) };
42*4ed460ceSYo-Jung Leo Lin (AMD)
43*4ed460ceSYo-Jung Leo Lin (AMD) /* Status codes from spec */
44*4ed460ceSYo-Jung Leo Lin (AMD) #define AMD_HALO_STATUS_SUCCESS 0x0000
45*4ed460ceSYo-Jung Leo Lin (AMD) #define AMD_HALO_STATUS_INVALID_PARAM 0xFFFD
46*4ed460ceSYo-Jung Leo Lin (AMD)
47*4ed460ceSYo-Jung Leo Lin (AMD) /* Brightness uses 0-100 range */
48*4ed460ceSYo-Jung Leo Lin (AMD) #define AMD_HALO_MAX_HW_BRIGHTNESS 100
49*4ed460ceSYo-Jung Leo Lin (AMD)
50*4ed460ceSYo-Jung Leo Lin (AMD) /**
51*4ed460ceSYo-Jung Leo Lin (AMD) * struct amd_halo_led_data - Driver private data
52*4ed460ceSYo-Jung Leo Lin (AMD) * @wdev: WMI device pointer
53*4ed460ceSYo-Jung Leo Lin (AMD) * @led_mc: LED multicolor class device
54*4ed460ceSYo-Jung Leo Lin (AMD) * @subled_info: RGB channel information
55*4ed460ceSYo-Jung Leo Lin (AMD) * @lock: Mutex to protect WMI calls
56*4ed460ceSYo-Jung Leo Lin (AMD) */
57*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_led_data {
58*4ed460ceSYo-Jung Leo Lin (AMD) struct wmi_device *wdev;
59*4ed460ceSYo-Jung Leo Lin (AMD) struct led_classdev_mc led_mc;
60*4ed460ceSYo-Jung Leo Lin (AMD) struct mc_subled subled_info[3];
61*4ed460ceSYo-Jung Leo Lin (AMD) struct mutex lock;
62*4ed460ceSYo-Jung Leo Lin (AMD) };
63*4ed460ceSYo-Jung Leo Lin (AMD)
64*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_wmi_args {
65*4ed460ceSYo-Jung Leo Lin (AMD) __le32 arg0;
66*4ed460ceSYo-Jung Leo Lin (AMD) __le32 arg1;
67*4ed460ceSYo-Jung Leo Lin (AMD) };
68*4ed460ceSYo-Jung Leo Lin (AMD)
69*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_wmi_args_rgb {
70*4ed460ceSYo-Jung Leo Lin (AMD) __le32 cmd;
71*4ed460ceSYo-Jung Leo Lin (AMD) __le32 red;
72*4ed460ceSYo-Jung Leo Lin (AMD) __le32 green;
73*4ed460ceSYo-Jung Leo Lin (AMD) __le32 blue;
74*4ed460ceSYo-Jung Leo Lin (AMD) };
75*4ed460ceSYo-Jung Leo Lin (AMD)
76*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_wmi_output_rgb {
77*4ed460ceSYo-Jung Leo Lin (AMD) __le16 status;
78*4ed460ceSYo-Jung Leo Lin (AMD) u8 red;
79*4ed460ceSYo-Jung Leo Lin (AMD) u8 green;
80*4ed460ceSYo-Jung Leo Lin (AMD) u8 blue;
81*4ed460ceSYo-Jung Leo Lin (AMD) } __packed;
82*4ed460ceSYo-Jung Leo Lin (AMD)
wmi_status_to_err(u16 status)83*4ed460ceSYo-Jung Leo Lin (AMD) static inline int wmi_status_to_err(u16 status)
84*4ed460ceSYo-Jung Leo Lin (AMD) {
85*4ed460ceSYo-Jung Leo Lin (AMD) switch (status) {
86*4ed460ceSYo-Jung Leo Lin (AMD) case AMD_HALO_STATUS_SUCCESS:
87*4ed460ceSYo-Jung Leo Lin (AMD) return 0;
88*4ed460ceSYo-Jung Leo Lin (AMD) case AMD_HALO_STATUS_INVALID_PARAM:
89*4ed460ceSYo-Jung Leo Lin (AMD) return -EINVAL;
90*4ed460ceSYo-Jung Leo Lin (AMD) default:
91*4ed460ceSYo-Jung Leo Lin (AMD) return -EIO;
92*4ed460ceSYo-Jung Leo Lin (AMD) }
93*4ed460ceSYo-Jung Leo Lin (AMD) }
94*4ed460ceSYo-Jung Leo Lin (AMD)
__amd_halo_wmi_call(struct wmi_device * wdev,u32 method_id,void * data,size_t length)95*4ed460ceSYo-Jung Leo Lin (AMD) static int __amd_halo_wmi_call(struct wmi_device *wdev,
96*4ed460ceSYo-Jung Leo Lin (AMD) u32 method_id, void *data, size_t length)
97*4ed460ceSYo-Jung Leo Lin (AMD) {
98*4ed460ceSYo-Jung Leo Lin (AMD) struct wmi_buffer input = {
99*4ed460ceSYo-Jung Leo Lin (AMD) .length = length,
100*4ed460ceSYo-Jung Leo Lin (AMD) .data = data,
101*4ed460ceSYo-Jung Leo Lin (AMD) };
102*4ed460ceSYo-Jung Leo Lin (AMD) struct wmi_buffer output = { };
103*4ed460ceSYo-Jung Leo Lin (AMD) int ret;
104*4ed460ceSYo-Jung Leo Lin (AMD)
105*4ed460ceSYo-Jung Leo Lin (AMD) /* Return buffer per spec: Bytes[0:1] = Status (little-endian) */
106*4ed460ceSYo-Jung Leo Lin (AMD) ret = wmidev_invoke_method(wdev, 0, method_id,
107*4ed460ceSYo-Jung Leo Lin (AMD) &input, &output, sizeof(__le16));
108*4ed460ceSYo-Jung Leo Lin (AMD) if (ret)
109*4ed460ceSYo-Jung Leo Lin (AMD) return ret;
110*4ed460ceSYo-Jung Leo Lin (AMD)
111*4ed460ceSYo-Jung Leo Lin (AMD) __le16 *result_status __free(kfree) = output.data;
112*4ed460ceSYo-Jung Leo Lin (AMD)
113*4ed460ceSYo-Jung Leo Lin (AMD) return wmi_status_to_err(le16_to_cpu(*result_status));
114*4ed460ceSYo-Jung Leo Lin (AMD) }
115*4ed460ceSYo-Jung Leo Lin (AMD)
116*4ed460ceSYo-Jung Leo Lin (AMD) /**
117*4ed460ceSYo-Jung Leo Lin (AMD) * amd_halo_wmi_turn_off - Turn off all LED channels
118*4ed460ceSYo-Jung Leo Lin (AMD) * @wdev: WMI device pointer
119*4ed460ceSYo-Jung Leo Lin (AMD) *
120*4ed460ceSYo-Jung Leo Lin (AMD) * Return: 0 on success, negative error code on failure
121*4ed460ceSYo-Jung Leo Lin (AMD) */
amd_halo_wmi_turn_off(struct wmi_device * wdev)122*4ed460ceSYo-Jung Leo Lin (AMD) static int amd_halo_wmi_turn_off(struct wmi_device *wdev)
123*4ed460ceSYo-Jung Leo Lin (AMD) {
124*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_wmi_args args = { };
125*4ed460ceSYo-Jung Leo Lin (AMD)
126*4ed460ceSYo-Jung Leo Lin (AMD) return __amd_halo_wmi_call(wdev, AMD_HALO_WMI_TURN_OFF, &args, sizeof(args));
127*4ed460ceSYo-Jung Leo Lin (AMD) }
128*4ed460ceSYo-Jung Leo Lin (AMD)
129*4ed460ceSYo-Jung Leo Lin (AMD) /**
130*4ed460ceSYo-Jung Leo Lin (AMD) * amd_halo_wmi_set_rgb - Set all RGB channels atomically
131*4ed460ceSYo-Jung Leo Lin (AMD) * @wdev: WMI device pointer
132*4ed460ceSYo-Jung Leo Lin (AMD) * @r: brightness for red channel (0 - 100)
133*4ed460ceSYo-Jung Leo Lin (AMD) * @g: brightness for green channel (0 - 100)
134*4ed460ceSYo-Jung Leo Lin (AMD) * @b: brightness for blue channel (0 - 100)
135*4ed460ceSYo-Jung Leo Lin (AMD) *
136*4ed460ceSYo-Jung Leo Lin (AMD) * Return: 0 on success, negative error code on failure
137*4ed460ceSYo-Jung Leo Lin (AMD) */
amd_halo_wmi_set_rgb(struct wmi_device * wdev,u32 r,u32 g,u32 b)138*4ed460ceSYo-Jung Leo Lin (AMD) static int amd_halo_wmi_set_rgb(struct wmi_device *wdev, u32 r, u32 g, u32 b)
139*4ed460ceSYo-Jung Leo Lin (AMD) {
140*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_wmi_args_rgb args = {
141*4ed460ceSYo-Jung Leo Lin (AMD) .cmd = cpu_to_le32(AMD_HALO_RGB_CMD_SET),
142*4ed460ceSYo-Jung Leo Lin (AMD) .red = cpu_to_le32(r),
143*4ed460ceSYo-Jung Leo Lin (AMD) .green = cpu_to_le32(g),
144*4ed460ceSYo-Jung Leo Lin (AMD) .blue = cpu_to_le32(b),
145*4ed460ceSYo-Jung Leo Lin (AMD) };
146*4ed460ceSYo-Jung Leo Lin (AMD)
147*4ed460ceSYo-Jung Leo Lin (AMD) if (r > AMD_HALO_MAX_HW_BRIGHTNESS ||
148*4ed460ceSYo-Jung Leo Lin (AMD) g > AMD_HALO_MAX_HW_BRIGHTNESS ||
149*4ed460ceSYo-Jung Leo Lin (AMD) b > AMD_HALO_MAX_HW_BRIGHTNESS) {
150*4ed460ceSYo-Jung Leo Lin (AMD) return -EINVAL;
151*4ed460ceSYo-Jung Leo Lin (AMD) }
152*4ed460ceSYo-Jung Leo Lin (AMD)
153*4ed460ceSYo-Jung Leo Lin (AMD) return __amd_halo_wmi_call(wdev, AMD_HALO_WMI_RGB, &args, sizeof(args));
154*4ed460ceSYo-Jung Leo Lin (AMD) }
155*4ed460ceSYo-Jung Leo Lin (AMD)
156*4ed460ceSYo-Jung Leo Lin (AMD) /**
157*4ed460ceSYo-Jung Leo Lin (AMD) * amd_halo_wmi_get_rgb - Get RGB values
158*4ed460ceSYo-Jung Leo Lin (AMD) * @wdev: WMI device pointer
159*4ed460ceSYo-Jung Leo Lin (AMD) * @r: output buffer for red value
160*4ed460ceSYo-Jung Leo Lin (AMD) * @g: output buffer for green value
161*4ed460ceSYo-Jung Leo Lin (AMD) * @b: output buffer for blue value
162*4ed460ceSYo-Jung Leo Lin (AMD) *
163*4ed460ceSYo-Jung Leo Lin (AMD) * Return: 0 on success, negative error code on failure
164*4ed460ceSYo-Jung Leo Lin (AMD) */
amd_halo_wmi_get_rgb(struct wmi_device * wdev,u8 * r,u8 * g,u8 * b)165*4ed460ceSYo-Jung Leo Lin (AMD) static int amd_halo_wmi_get_rgb(struct wmi_device *wdev, u8 *r, u8 *g, u8 *b)
166*4ed460ceSYo-Jung Leo Lin (AMD) {
167*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_wmi_args_rgb args = {
168*4ed460ceSYo-Jung Leo Lin (AMD) .cmd = cpu_to_le32(AMD_HALO_RGB_CMD_GET),
169*4ed460ceSYo-Jung Leo Lin (AMD) };
170*4ed460ceSYo-Jung Leo Lin (AMD) struct wmi_buffer input = {
171*4ed460ceSYo-Jung Leo Lin (AMD) .length = sizeof(args),
172*4ed460ceSYo-Jung Leo Lin (AMD) .data = &args,
173*4ed460ceSYo-Jung Leo Lin (AMD) };
174*4ed460ceSYo-Jung Leo Lin (AMD) struct wmi_buffer output = { };
175*4ed460ceSYo-Jung Leo Lin (AMD) int ret;
176*4ed460ceSYo-Jung Leo Lin (AMD)
177*4ed460ceSYo-Jung Leo Lin (AMD) ret = wmidev_invoke_method(wdev, 0, AMD_HALO_WMI_RGB,
178*4ed460ceSYo-Jung Leo Lin (AMD) &input, &output, sizeof(struct amd_halo_wmi_output_rgb));
179*4ed460ceSYo-Jung Leo Lin (AMD) if (ret)
180*4ed460ceSYo-Jung Leo Lin (AMD) return ret;
181*4ed460ceSYo-Jung Leo Lin (AMD)
182*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_wmi_output_rgb *data __free(kfree) = output.data;
183*4ed460ceSYo-Jung Leo Lin (AMD)
184*4ed460ceSYo-Jung Leo Lin (AMD) ret = wmi_status_to_err(le16_to_cpu(data->status));
185*4ed460ceSYo-Jung Leo Lin (AMD) if (ret)
186*4ed460ceSYo-Jung Leo Lin (AMD) return ret;
187*4ed460ceSYo-Jung Leo Lin (AMD)
188*4ed460ceSYo-Jung Leo Lin (AMD) if (data->red > AMD_HALO_MAX_HW_BRIGHTNESS ||
189*4ed460ceSYo-Jung Leo Lin (AMD) data->green > AMD_HALO_MAX_HW_BRIGHTNESS ||
190*4ed460ceSYo-Jung Leo Lin (AMD) data->blue > AMD_HALO_MAX_HW_BRIGHTNESS) {
191*4ed460ceSYo-Jung Leo Lin (AMD) return -EPROTO;
192*4ed460ceSYo-Jung Leo Lin (AMD) }
193*4ed460ceSYo-Jung Leo Lin (AMD)
194*4ed460ceSYo-Jung Leo Lin (AMD) *r = data->red;
195*4ed460ceSYo-Jung Leo Lin (AMD) *g = data->green;
196*4ed460ceSYo-Jung Leo Lin (AMD) *b = data->blue;
197*4ed460ceSYo-Jung Leo Lin (AMD)
198*4ed460ceSYo-Jung Leo Lin (AMD) return 0;
199*4ed460ceSYo-Jung Leo Lin (AMD) }
200*4ed460ceSYo-Jung Leo Lin (AMD)
201*4ed460ceSYo-Jung Leo Lin (AMD) /**
202*4ed460ceSYo-Jung Leo Lin (AMD) * amd_halo_brightness_set - Set LED brightness
203*4ed460ceSYo-Jung Leo Lin (AMD) * @cdev: LED class device
204*4ed460ceSYo-Jung Leo Lin (AMD) * @brightness: Brightness value
205*4ed460ceSYo-Jung Leo Lin (AMD) *
206*4ed460ceSYo-Jung Leo Lin (AMD) * Return: 0 on success, negative error code on failure
207*4ed460ceSYo-Jung Leo Lin (AMD) */
amd_halo_brightness_set(struct led_classdev * cdev,enum led_brightness brightness)208*4ed460ceSYo-Jung Leo Lin (AMD) static int amd_halo_brightness_set(struct led_classdev *cdev,
209*4ed460ceSYo-Jung Leo Lin (AMD) enum led_brightness brightness)
210*4ed460ceSYo-Jung Leo Lin (AMD) {
211*4ed460ceSYo-Jung Leo Lin (AMD) struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
212*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_led_data *data = container_of(mc_cdev,
213*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_led_data,
214*4ed460ceSYo-Jung Leo Lin (AMD) led_mc);
215*4ed460ceSYo-Jung Leo Lin (AMD) u32 red_hw, green_hw, blue_hw;
216*4ed460ceSYo-Jung Leo Lin (AMD) int ret;
217*4ed460ceSYo-Jung Leo Lin (AMD)
218*4ed460ceSYo-Jung Leo Lin (AMD) guard(mutex)(&data->lock);
219*4ed460ceSYo-Jung Leo Lin (AMD)
220*4ed460ceSYo-Jung Leo Lin (AMD) led_mc_calc_color_components(mc_cdev, brightness);
221*4ed460ceSYo-Jung Leo Lin (AMD)
222*4ed460ceSYo-Jung Leo Lin (AMD) if (brightness == 0)
223*4ed460ceSYo-Jung Leo Lin (AMD) return amd_halo_wmi_turn_off(data->wdev);
224*4ed460ceSYo-Jung Leo Lin (AMD)
225*4ed460ceSYo-Jung Leo Lin (AMD) red_hw = mc_cdev->subled_info[0].brightness;
226*4ed460ceSYo-Jung Leo Lin (AMD) green_hw = mc_cdev->subled_info[1].brightness;
227*4ed460ceSYo-Jung Leo Lin (AMD) blue_hw = mc_cdev->subled_info[2].brightness;
228*4ed460ceSYo-Jung Leo Lin (AMD)
229*4ed460ceSYo-Jung Leo Lin (AMD) ret = amd_halo_wmi_set_rgb(data->wdev, red_hw, green_hw, blue_hw);
230*4ed460ceSYo-Jung Leo Lin (AMD) if (ret)
231*4ed460ceSYo-Jung Leo Lin (AMD) goto out;
232*4ed460ceSYo-Jung Leo Lin (AMD)
233*4ed460ceSYo-Jung Leo Lin (AMD) return 0;
234*4ed460ceSYo-Jung Leo Lin (AMD)
235*4ed460ceSYo-Jung Leo Lin (AMD) out:
236*4ed460ceSYo-Jung Leo Lin (AMD) /*
237*4ed460ceSYo-Jung Leo Lin (AMD) * Consider the light bar non-functional if AMD_HALO_WMI_RGB failed.
238*4ed460ceSYo-Jung Leo Lin (AMD) * Attempt to turn the LED off completely as clean-up.
239*4ed460ceSYo-Jung Leo Lin (AMD) */
240*4ed460ceSYo-Jung Leo Lin (AMD) if (amd_halo_wmi_turn_off(data->wdev))
241*4ed460ceSYo-Jung Leo Lin (AMD) dev_warn_ratelimited(&data->wdev->dev, "Failed to turn LED off on cleanup\n");
242*4ed460ceSYo-Jung Leo Lin (AMD)
243*4ed460ceSYo-Jung Leo Lin (AMD) return ret;
244*4ed460ceSYo-Jung Leo Lin (AMD) }
245*4ed460ceSYo-Jung Leo Lin (AMD)
amd_halo_probe(struct wmi_device * wdev,const void * context)246*4ed460ceSYo-Jung Leo Lin (AMD) static int amd_halo_probe(struct wmi_device *wdev, const void *context)
247*4ed460ceSYo-Jung Leo Lin (AMD) {
248*4ed460ceSYo-Jung Leo Lin (AMD) struct led_init_data led_init_data = {
249*4ed460ceSYo-Jung Leo Lin (AMD) .devicename = "amd_halo",
250*4ed460ceSYo-Jung Leo Lin (AMD) .default_label = "multicolor:" LED_FUNCTION_STATUS,
251*4ed460ceSYo-Jung Leo Lin (AMD) .devname_mandatory = true,
252*4ed460ceSYo-Jung Leo Lin (AMD) };
253*4ed460ceSYo-Jung Leo Lin (AMD) struct amd_halo_led_data *data;
254*4ed460ceSYo-Jung Leo Lin (AMD) u8 r, g, b;
255*4ed460ceSYo-Jung Leo Lin (AMD) int ret;
256*4ed460ceSYo-Jung Leo Lin (AMD)
257*4ed460ceSYo-Jung Leo Lin (AMD) data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
258*4ed460ceSYo-Jung Leo Lin (AMD) if (!data)
259*4ed460ceSYo-Jung Leo Lin (AMD) return -ENOMEM;
260*4ed460ceSYo-Jung Leo Lin (AMD)
261*4ed460ceSYo-Jung Leo Lin (AMD) ret = devm_mutex_init(&wdev->dev, &data->lock);
262*4ed460ceSYo-Jung Leo Lin (AMD) if (ret)
263*4ed460ceSYo-Jung Leo Lin (AMD) return ret;
264*4ed460ceSYo-Jung Leo Lin (AMD)
265*4ed460ceSYo-Jung Leo Lin (AMD) data->wdev = wdev;
266*4ed460ceSYo-Jung Leo Lin (AMD) dev_set_drvdata(&wdev->dev, data);
267*4ed460ceSYo-Jung Leo Lin (AMD)
268*4ed460ceSYo-Jung Leo Lin (AMD) data->subled_info[0].color_index = LED_COLOR_ID_RED;
269*4ed460ceSYo-Jung Leo Lin (AMD) data->subled_info[1].color_index = LED_COLOR_ID_GREEN;
270*4ed460ceSYo-Jung Leo Lin (AMD) data->subled_info[2].color_index = LED_COLOR_ID_BLUE;
271*4ed460ceSYo-Jung Leo Lin (AMD)
272*4ed460ceSYo-Jung Leo Lin (AMD) data->led_mc.led_cdev.brightness = AMD_HALO_MAX_HW_BRIGHTNESS;
273*4ed460ceSYo-Jung Leo Lin (AMD) data->led_mc.led_cdev.max_brightness = AMD_HALO_MAX_HW_BRIGHTNESS;
274*4ed460ceSYo-Jung Leo Lin (AMD) data->led_mc.led_cdev.brightness_set_blocking = amd_halo_brightness_set;
275*4ed460ceSYo-Jung Leo Lin (AMD) data->led_mc.led_cdev.flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
276*4ed460ceSYo-Jung Leo Lin (AMD) data->led_mc.num_colors = ARRAY_SIZE(data->subled_info);
277*4ed460ceSYo-Jung Leo Lin (AMD) data->led_mc.subled_info = data->subled_info;
278*4ed460ceSYo-Jung Leo Lin (AMD)
279*4ed460ceSYo-Jung Leo Lin (AMD) ret = amd_halo_wmi_get_rgb(wdev, &r, &g, &b);
280*4ed460ceSYo-Jung Leo Lin (AMD) if (ret)
281*4ed460ceSYo-Jung Leo Lin (AMD) return ret;
282*4ed460ceSYo-Jung Leo Lin (AMD)
283*4ed460ceSYo-Jung Leo Lin (AMD) data->subled_info[0].intensity = r;
284*4ed460ceSYo-Jung Leo Lin (AMD) data->subled_info[1].intensity = g;
285*4ed460ceSYo-Jung Leo Lin (AMD) data->subled_info[2].intensity = b;
286*4ed460ceSYo-Jung Leo Lin (AMD)
287*4ed460ceSYo-Jung Leo Lin (AMD) ret = devm_led_classdev_multicolor_register_ext(&wdev->dev, &data->led_mc,
288*4ed460ceSYo-Jung Leo Lin (AMD) &led_init_data);
289*4ed460ceSYo-Jung Leo Lin (AMD) if (ret)
290*4ed460ceSYo-Jung Leo Lin (AMD) return dev_err_probe(&wdev->dev, ret,
291*4ed460ceSYo-Jung Leo Lin (AMD) "Failed to register multicolor LED\n");
292*4ed460ceSYo-Jung Leo Lin (AMD) return 0;
293*4ed460ceSYo-Jung Leo Lin (AMD) }
294*4ed460ceSYo-Jung Leo Lin (AMD)
295*4ed460ceSYo-Jung Leo Lin (AMD) static const struct wmi_device_id amd_halo_id_table[] = {
296*4ed460ceSYo-Jung Leo Lin (AMD) { .guid_string = AMD_HALO_GUID },
297*4ed460ceSYo-Jung Leo Lin (AMD) { }
298*4ed460ceSYo-Jung Leo Lin (AMD) };
299*4ed460ceSYo-Jung Leo Lin (AMD) MODULE_DEVICE_TABLE(wmi, amd_halo_id_table);
300*4ed460ceSYo-Jung Leo Lin (AMD)
301*4ed460ceSYo-Jung Leo Lin (AMD) static struct wmi_driver amd_halo_driver = {
302*4ed460ceSYo-Jung Leo Lin (AMD) .driver = {
303*4ed460ceSYo-Jung Leo Lin (AMD) .name = "amd_halo_led",
304*4ed460ceSYo-Jung Leo Lin (AMD) },
305*4ed460ceSYo-Jung Leo Lin (AMD) .id_table = amd_halo_id_table,
306*4ed460ceSYo-Jung Leo Lin (AMD) .probe = amd_halo_probe,
307*4ed460ceSYo-Jung Leo Lin (AMD) .no_singleton = true,
308*4ed460ceSYo-Jung Leo Lin (AMD) };
309*4ed460ceSYo-Jung Leo Lin (AMD)
310*4ed460ceSYo-Jung Leo Lin (AMD) module_wmi_driver(amd_halo_driver);
311*4ed460ceSYo-Jung Leo Lin (AMD)
312*4ed460ceSYo-Jung Leo Lin (AMD) MODULE_AUTHOR("Mario Limonciello (AMD) <superm1@kernel.org>");
313*4ed460ceSYo-Jung Leo Lin (AMD) MODULE_AUTHOR("Yo-Jung Leo Lin (AMD) <Leo.Lin@amd.com>");
314*4ed460ceSYo-Jung Leo Lin (AMD) MODULE_DESCRIPTION("AMD Halo Box RGB LED Control Driver");
315*4ed460ceSYo-Jung Leo Lin (AMD) MODULE_LICENSE("GPL");
316