From nobody Sun Feb 8 12:36:43 2026 Received: from mail-dy1-f176.google.com (mail-dy1-f176.google.com [74.125.82.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 628DF24468C for ; Sat, 24 Jan 2026 01:49:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769219368; cv=none; b=gW2Kbi3KDTz7XSUfLJZbWMew59e207WBspnuns7V3irFdbMfMZdPrDihprMgBOGNETSl+80whwmql5ianIrShZdCnb76fPCqvYeu5dTV9TNMq/CyixtZHLiCD5NBWRqDd66lD/PZ1D3UeHUD47RRNIXJAizPi8z/RRtBkGSXvTg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769219368; c=relaxed/simple; bh=akfu/gqz275Z2VtjZlBAejfEYa0YzbKf7Gn0R+UJx+s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dGobhPK+VVmQGNnXQOYnJlLywsR9q5QKogeRuhoXchXXpoMFruYqpmxb07YnZPn9JdDzwNcRSQ4N/q6e9XtpKSGzrnfEq0xbHiExcIMTNOB95LVdgDkVjCNv4DfAyaUFMTL8mxAHlY7jhsmLvMkF0baItF6iWnTCZf1r64/VA90= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=K2VDDvU9; arc=none smtp.client-ip=74.125.82.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="K2VDDvU9" Received: by mail-dy1-f176.google.com with SMTP id 5a478bee46e88-2b71557299dso4025251eec.1 for ; Fri, 23 Jan 2026 17:49:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1769219364; x=1769824164; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=PluhxiDPPhMGcw1dhjJulXPC1agxFWmfzUD6W8pTh4g=; b=K2VDDvU9W79JidVEvAQasMeGuuL9626Svj1Bi6gz//LZ35+YinDKf2M1hI8Ei77d/T X3VLgs5CWL5oB7aQyqdIEQdIao+bSs9uK7o8c2trtLZjvUIkRZhUmgTjInYidXWHF1R7 c+L405LQGgNzFg5ApNZ6V92WhXtkor6jH+H6k8muxRXkou2bR1d7lIrnd7VEXMB/GL2I 5kRxPFAjL+bunolKFOE8JKd1Nr7l3fqHm322GSpRH9nn37Q5Fa5L6K4RmnYMcGDoad0e woLDB1yv3QHGTXPXKbE47F8oK1XKsMX+2Z4y8G6IwB57VJAyu7jiQoUncOhlsLCzHwPC iM+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769219364; x=1769824164; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=PluhxiDPPhMGcw1dhjJulXPC1agxFWmfzUD6W8pTh4g=; b=LWvPwYoLbZrwjhQskkzcxW/vdOkmf6h06c2nrDLXjY1lE3YJ1gy+TyDKYjWPYwCQya 6zsYF2WyL2ujnUu2h/IS8+JuVhUMkbgUr29hK/f/27Tv84p9OnFxxtExwlbhOkInyJao g3YTswE/ngUUr2PGfNR/G89V+cWWQdYO3V9xVqJMWoqKbrXqeZYc2uRB51mnH/PAtdnW cXhNOaB/T5IbGwgbRfk8vAOukzpcr34TNJyv8hA/GxCzoauZNhw7ulfT5ZHiOeGg6nLy EnvmbVI4DZsOpTxz0nszgJkWPOHKEEHtPkrcAWmiIfNy2cBMTy2YeYcGr/B+NqBiK6PJ Ot6g== X-Forwarded-Encrypted: i=1; AJvYcCWLdfkP+wgKOSUQXtQHeOzT6hQgfMxY0Al9eM3VK+Hr0iLVRHy7EEU7Z7B9FMniBv5bgf8NeBsVvbcmlNI=@vger.kernel.org X-Gm-Message-State: AOJu0YwZUTQNJ0lTrWZ0pHH9cIpzcmnhLz9tFVE7c+JccU4P+uO6MqBb AQ+P43qIqe3ChMqmy8q2wHGIWJ7+vvX2yT+wzfrPiQEksX9yiGBQb/e8 X-Gm-Gg: AZuq6aI1N/9tlQ2vMzZuFSXYxif2ZIMKyaq3QiRf9Ux0YmLvFH1+ya35vR52JGv7d3W p8vJXzdWnlZZqw1OChIBHK1BzfZDO4C8WZ2SOeCt3XXg8dzZNdCKsud86xMSOsGDI0roqE6vJI+ rSsDCiR6iPguu2JWt7Ojb6tq51Y8RrIL5qihn1bnO6nvtsJEbKPinBtsz8jx3ivg5bzj4v3+E8u 4UVBQIP99KzTAyI0aydZZ+T20T+WM/WULVni1hZM7AgWxpZMKvxG+G0Cl6D7Kb0crRxNLWUMfWu oYOSTAoY+7qLOydbQRSqWwWBuB0bLDaPkZki7PcwXp/hgXN6TbQc6kFcO7hRIkMas75cuS2eGjk ajGo9cZnY9ME+2ht6NcFysqtSdubl6dt85bk3yST2g8UK62/FRZhT3prTJCmfBqxyFEOuDds/PW uYAYjaThU0S/9ViDhoQ9BUUlOPXpX7ylW4u691fkv6If4HSJ0kkIsdU5PBhd6FcBw= X-Received: by 2002:a05:7300:cb0a:b0:2ab:ca55:89ab with SMTP id 5a478bee46e88-2b739c2d8aemr2325977eec.42.1769219363435; Fri, 23 Jan 2026 17:49:23 -0800 (PST) Received: from lappy (108-228-232-20.lightspeed.sndgca.sbcglobal.net. [108.228.232.20]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2b73aa22707sm5160014eec.29.2026.01.23.17.49.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 23 Jan 2026 17:49:23 -0800 (PST) From: "Derek J. Clark" To: Jiri Kosina , Benjamin Tissoires Cc: Mario Limonciello , Zhixin Zhang , Mia Shao , Mark Pearson , "Pierre-Loup A . Griffais" , "Derek J . Clark" , linux-input@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 14/16] HID: hid-lenovo-go-s: Add RGB LED control interface Date: Sat, 24 Jan 2026 01:49:05 +0000 Message-ID: <20260124014907.991265-15-derekjohn.clark@gmail.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260124014907.991265-1-derekjohn.clark@gmail.com> References: <20260124014907.991265-1-derekjohn.clark@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Adds an LED multicolor class device and attribute group for controlling the RGB of the Left and right joystick rings. In addition to the standard led_cdev attributes, additional attributes that allow for the control of the effect (monocolor, breathe, rainbow, and chroma), speed of the effect change, an enable toggle, and profile. Signed-off-by: Derek J. Clark --- drivers/hid/hid-lenovo-go-s.c | 456 ++++++++++++++++++++++++++++++++++ 1 file changed, 456 insertions(+) diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c index 38425e3d6cb2..e422f3977517 100644 --- a/drivers/hid/hid-lenovo-go-s.c +++ b/drivers/hid/hid-lenovo-go-s.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ struct hid_gos_cfg { unsigned char *buf; struct delayed_work gos_cfg_setup; struct completion send_cmd_complete; + struct led_classdev *led_cdev; struct hid_device *hdev; struct mutex cfg_mutex; /*ensure single synchronous output report*/ u8 gp_auto_sleep_time; @@ -45,7 +47,11 @@ struct hid_gos_cfg { u8 mcu_id[12]; u8 mouse_step; u8 os_mode; + u8 rgb_effect; u8 rgb_en; + u8 rgb_mode; + u8 rgb_profile; + u8 rgb_speed; u8 tp_en; u8 tp_linux_mode; u8 tp_windows_mode; @@ -163,6 +169,38 @@ enum touchpad_config_index { =20 }; =20 +enum rgb_mode_index { + RGB_MODE_DYNAMIC, + RGB_MODE_CUSTOM, +}; + +static const char *const rgb_mode_text[] =3D { + [RGB_MODE_DYNAMIC] =3D "dynamic", + [RGB_MODE_CUSTOM] =3D "custom", +}; + +enum rgb_effect_index { + RGB_EFFECT_MONO, + RGB_EFFECT_BREATHE, + RGB_EFFECT_CHROMA, + RGB_EFFECT_RAINBOW, +}; + +static const char *const rgb_effect_text[] =3D { + [RGB_EFFECT_MONO] =3D "monocolor", + [RGB_EFFECT_BREATHE] =3D "breathe", + [RGB_EFFECT_CHROMA] =3D "chroma", + [RGB_EFFECT_RAINBOW] =3D "rainbow", +}; + +enum rgb_config_index { + LIGHT_MODE_SEL =3D 0x01, + LIGHT_PROFILE_SEL, + USR_LIGHT_PROFILE_1, + USR_LIGHT_PROFILE_2, + USR_LIGHT_PROFILE_3, +}; + static int hid_gos_version_event(u8 *data) { struct version_report *ver_rep =3D (struct version_report *)data; @@ -241,6 +279,39 @@ static int hid_gos_touchpad_event(struct command_repor= t *cmd_rep) return ret; } =20 +static int hid_gos_light_event(struct command_report *cmd_rep) +{ + struct led_classdev_mc *mc_cdev; + int ret =3D 0; + + switch (cmd_rep->sub_cmd) { + case LIGHT_MODE_SEL: + drvdata.rgb_mode =3D cmd_rep->data[0]; + ret =3D 0; + break; + case LIGHT_PROFILE_SEL: + drvdata.rgb_profile =3D cmd_rep->data[0]; + ret =3D 0; + break; + case USR_LIGHT_PROFILE_1: + case USR_LIGHT_PROFILE_2: + case USR_LIGHT_PROFILE_3: + mc_cdev =3D lcdev_to_mccdev(drvdata.led_cdev); + drvdata.rgb_effect =3D cmd_rep->data[0]; + mc_cdev->subled_info[0].intensity =3D cmd_rep->data[1]; + mc_cdev->subled_info[1].intensity =3D cmd_rep->data[2]; + mc_cdev->subled_info[2].intensity =3D cmd_rep->data[3]; + drvdata.led_cdev->brightness =3D cmd_rep->data[4]; + drvdata.rgb_speed =3D cmd_rep->data[5]; + ret =3D 0; + break; + default: + ret =3D -EINVAL; + break; + } + return ret; +} + static int hid_gos_set_event_return(struct command_report *cmd_rep) { if (cmd_rep->data[0] !=3D 0) @@ -291,7 +362,11 @@ static int hid_gos_raw_event(struct hid_device *hdev, = struct hid_report *report, case GET_TP_PARAM: ret =3D hid_gos_touchpad_event(cmd_rep); break; + case GET_RGB_CFG: + ret =3D hid_gos_light_event(cmd_rep); + break; case SET_GAMEPAD_CFG: + case SET_RGB_CFG: case SET_TP_PARAM: ret =3D hid_gos_set_event_return(cmd_rep); break; @@ -673,6 +748,276 @@ static ssize_t mcu_id_show(struct device *dev, struct= device_attribute *attr, return sysfs_emit(buf, "%*phN\n", 12, &drvdata.mcu_id); } =20 +static int rgb_cfg_call(struct hid_device *hdev, enum mcu_command_index cm= d, + enum rgb_config_index index, u8 *val, size_t size) +{ + if (cmd !=3D SET_RGB_CFG && cmd !=3D GET_RGB_CFG) + return -EINVAL; + + if (index < LIGHT_MODE_SEL || index > USR_LIGHT_PROFILE_3) + return -EINVAL; + + return mcu_property_out(hdev, cmd, index, val, size); +} + +static int rgb_attr_show(void) +{ + enum rgb_config_index index; + + index =3D drvdata.rgb_profile + 2; + + return rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, index, 0, 0); +}; + +static ssize_t rgb_effect_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct led_classdev_mc *mc_cdev =3D lcdev_to_mccdev(drvdata.led_cdev); + enum rgb_config_index index; + u8 effect; + int ret; + + ret =3D sysfs_match_string(rgb_effect_text, buf); + if (ret < 0) + return ret; + + effect =3D ret; + index =3D drvdata.rgb_profile + 2; + u8 rgb_profile[6] =3D { effect, + mc_cdev->subled_info[0].intensity, + mc_cdev->subled_info[1].intensity, + mc_cdev->subled_info[2].intensity, + drvdata.led_cdev->brightness, + drvdata.rgb_speed }; + + ret =3D rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6); + if (ret) + return ret; + + drvdata.rgb_effect =3D effect; + return count; +}; + +static ssize_t rgb_effect_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret =3D rgb_attr_show(); + if (ret) + return ret; + + if (drvdata.rgb_effect >=3D ARRAY_SIZE(rgb_effect_text)) + return -EINVAL; + + return sysfs_emit(buf, "%s\n", rgb_effect_text[drvdata.rgb_effect]); +} + +static ssize_t rgb_effect_index_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count =3D 0; + unsigned int i; + + for (i =3D 0; i < ARRAY_SIZE(rgb_effect_text); i++) + count +=3D sysfs_emit_at(buf, count, "%s ", rgb_effect_text[i]); + + if (count) + buf[count - 1] =3D '\n'; + + return count; +} + +static ssize_t rgb_speed_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct led_classdev_mc *mc_cdev =3D lcdev_to_mccdev(drvdata.led_cdev); + enum rgb_config_index index; + int val =3D 0; + int ret; + + ret =3D kstrtoint(buf, 10, &val); + if (ret) + return ret; + + if (val < 0 || val > 100) + return -EINVAL; + + index =3D drvdata.rgb_profile + 2; + u8 rgb_profile[6] =3D { drvdata.rgb_effect, + mc_cdev->subled_info[0].intensity, + mc_cdev->subled_info[1].intensity, + mc_cdev->subled_info[2].intensity, + drvdata.led_cdev->brightness, + val }; + + ret =3D rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6); + if (ret) + return ret; + + drvdata.rgb_speed =3D val; + + return count; +}; + +static ssize_t rgb_speed_show(struct device *dev, struct device_attribute = *attr, + char *buf) +{ + int ret; + + ret =3D rgb_attr_show(); + if (ret) + return ret; + + if (drvdata.rgb_speed > 100) + return -EINVAL; + + return sysfs_emit(buf, "%hhu\n", drvdata.rgb_speed); +} + +static ssize_t rgb_speed_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "0-100\n"); +} + +static ssize_t rgb_mode_store(struct device *dev, struct device_attribute = *attr, + const char *buf, size_t count) +{ + int ret; + u8 val; + + ret =3D sysfs_match_string(rgb_mode_text, buf); + if (ret <=3D 0) + return ret; + + val =3D ret; + + ret =3D rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, LIGHT_MODE_SEL, &val, + 1); + if (ret) + return ret; + + drvdata.rgb_mode =3D val; + + return count; +}; + +static ssize_t rgb_mode_show(struct device *dev, struct device_attribute *= attr, + char *buf) +{ + int ret; + + ret =3D rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, LIGHT_MODE_SEL, 0, 0); + if (ret) + return ret; + + if (drvdata.rgb_mode >=3D ARRAY_SIZE(rgb_mode_text)) + return -EINVAL; + + return sysfs_emit(buf, "%s\n", rgb_mode_text[drvdata.rgb_mode]); +}; + +static ssize_t rgb_mode_index_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count =3D 0; + unsigned int i; + + for (i =3D 1; i < ARRAY_SIZE(rgb_mode_text); i++) + count +=3D sysfs_emit_at(buf, count, "%s ", rgb_mode_text[i]); + + if (count) + buf[count - 1] =3D '\n'; + + return count; +} + +static ssize_t rgb_profile_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + size_t size =3D 1; + int ret; + u8 val; + + ret =3D kstrtou8(buf, 10, &val); + if (ret < 0) + return ret; + + if (val < 1 || val > 3) + return -EINVAL; + + ret =3D rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, LIGHT_PROFILE_SEL, &val, + size); + if (ret) + return ret; + + drvdata.rgb_profile =3D val; + + return count; +}; + +static ssize_t rgb_profile_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret =3D rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, LIGHT_PROFILE_SEL, 0, + 0); + if (ret) + return ret; + + if (drvdata.rgb_profile < 1 || drvdata.rgb_profile > 3) + return -EINVAL; + + return sysfs_emit(buf, "%hhu\n", drvdata.rgb_profile); +}; + +static ssize_t rgb_profile_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "1-3\n"); +} + +static void hid_gos_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct led_classdev_mc *mc_cdev =3D lcdev_to_mccdev(drvdata.led_cdev); + enum rgb_config_index index; + int ret; + + if (brightness > led_cdev->max_brightness) { + dev_err(led_cdev->dev, "Invalid argument\n"); + return; + } + + index =3D drvdata.rgb_profile + 2; + u8 rgb_profile[6] =3D { drvdata.rgb_effect, + mc_cdev->subled_info[0].intensity, + mc_cdev->subled_info[1].intensity, + mc_cdev->subled_info[2].intensity, + brightness, + drvdata.rgb_speed }; + + ret =3D rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6); + switch (ret) { + case 0: + led_cdev->brightness =3D brightness; + break; + case -ENODEV: /* during switch to IAP -ENODEV is expected */ + case -ENOSYS: /* during rmmod -ENOSYS is expected */ + dev_dbg(led_cdev->dev, "Failed to write RGB profile: %i\n", + ret); + break; + default: + dev_err(led_cdev->dev, "Failed to write RGB profile: %i\n", + ret); + }; +} + #define LEGOS_DEVICE_ATTR_RW(_name, _attrname, _rtype, _group) = \ static ssize_t _name##_store(struct device *dev, \ struct device_attribute *attr, \ @@ -828,6 +1173,70 @@ static const struct attribute_group *top_level_attr_g= roups[] =3D { NULL, }; =20 +/* RGB */ +struct gos_cfg_attr rgb_enabled =3D { FEATURE_RGB_ENABLE }; +LEGOS_DEVICE_ATTR_RW(rgb_enabled, "enabled", index, gamepad); +static DEVICE_ATTR_RO_NAMED(rgb_enabled_index, "enabled_index"); + +static DEVICE_ATTR_RW_NAMED(rgb_effect, "effect"); +static DEVICE_ATTR_RO_NAMED(rgb_effect_index, "effect_index"); +static DEVICE_ATTR_RW_NAMED(rgb_mode, "mode"); +static DEVICE_ATTR_RO_NAMED(rgb_mode_index, "mode_index"); +static DEVICE_ATTR_RW_NAMED(rgb_profile, "profile"); +static DEVICE_ATTR_RO_NAMED(rgb_profile_range, "profile_range"); +static DEVICE_ATTR_RW_NAMED(rgb_speed, "speed"); +static DEVICE_ATTR_RO_NAMED(rgb_speed_range, "speed_range"); + +static struct attribute *gos_rgb_attrs[] =3D { + &dev_attr_rgb_enabled.attr, + &dev_attr_rgb_enabled_index.attr, + &dev_attr_rgb_effect.attr, + &dev_attr_rgb_effect_index.attr, + &dev_attr_rgb_mode.attr, + &dev_attr_rgb_mode_index.attr, + &dev_attr_rgb_profile.attr, + &dev_attr_rgb_profile_range.attr, + &dev_attr_rgb_speed.attr, + &dev_attr_rgb_speed_range.attr, + NULL, +}; + +static struct attribute_group rgb_attr_group =3D { + .attrs =3D gos_rgb_attrs, +}; + +struct mc_subled gos_rgb_subled_info[] =3D { + { + .color_index =3D LED_COLOR_ID_RED, + .brightness =3D 0x50, + .intensity =3D 0x24, + .channel =3D 0x1, + }, + { + .color_index =3D LED_COLOR_ID_GREEN, + .brightness =3D 0x50, + .intensity =3D 0x22, + .channel =3D 0x2, + }, + { + .color_index =3D LED_COLOR_ID_BLUE, + .brightness =3D 0x50, + .intensity =3D 0x99, + .channel =3D 0x3, + }, +}; + +struct led_classdev_mc gos_cdev_rgb =3D { + .led_cdev =3D { + .name =3D "go_s:rgb:joystick_rings", + .brightness =3D 0x50, + .max_brightness =3D 0x64, + .brightness_set =3D hid_gos_brightness_set, + }, + .num_colors =3D ARRAY_SIZE(gos_rgb_subled_info), + .subled_info =3D gos_rgb_subled_info, +}; + static void cfg_setup(struct work_struct *work) { int ret; @@ -846,6 +1255,38 @@ static void cfg_setup(struct work_struct *work) "Failed to retrieve MCU Version: %i\n", ret); return; } + + /* RGB */ + ret =3D mcu_property_out(drvdata.hdev, GET_GAMEPAD_CFG, FEATURE_RGB_ENABL= E, + 0, 0); + if (ret < 0) { + dev_err(drvdata.led_cdev->dev, + "Failed to retrieve RGB enabled: %i\n", ret); + return; + } + + ret =3D mcu_property_out(drvdata.hdev, GET_RGB_CFG, LIGHT_MODE_SEL, 0, + 0); + if (ret < 0) { + dev_err(drvdata.led_cdev->dev, + "Failed to retrieve RGB Mode: %i\n", ret); + return; + } + + ret =3D mcu_property_out(drvdata.hdev, GET_RGB_CFG, LIGHT_PROFILE_SEL, + 0, 0); + if (ret < 0) { + dev_err(drvdata.led_cdev->dev, + "Failed to retrieve RGB Profile: %i\n", ret); + return; + } + + ret =3D rgb_attr_show(); + if (ret < 0) { + dev_err(drvdata.led_cdev->dev, + "Failed to retrieve RGB Profile Data: %i\n", ret); + return; + } } =20 static int hid_gos_cfg_probe(struct hid_device *hdev, @@ -870,6 +1311,21 @@ static int hid_gos_cfg_probe(struct hid_device *hdev, return ret; } =20 + ret =3D devm_led_classdev_multicolor_register(&hdev->dev, &gos_cdev_rgb); + if (ret) { + dev_err_probe(&hdev->dev, ret, "Failed to create RGB device\n"); + return ret; + } + + ret =3D devm_device_add_group(gos_cdev_rgb.led_cdev.dev, &rgb_attr_group); + if (ret) { + dev_err_probe(&hdev->dev, ret, + "Failed to create RGB configuratiion attributes\n"); + return ret; + } + + drvdata.led_cdev =3D &gos_cdev_rgb.led_cdev; + init_completion(&drvdata.send_cmd_complete); =20 /* Executing calls prior to returning from probe will lock the MCU. Sched= ule --=20 2.52.0