First working but buggy implementation of leds interface for TongFang/Uniwill

This commit is contained in:
Werner Sembach 2022-09-21 18:18:35 +02:00
parent f2c442bc2a
commit a0c9995518
4 changed files with 225 additions and 270 deletions

View file

@ -102,22 +102,4 @@ static struct color_list_t color_list = {
} }
}; };
/**
* Looks up a color in the color_list
*
* Returns found color value, or 0xffffffff if string did not match
*/
static u32 color_lookup(const struct color_list_t *color_list, const char *color_name)
{
u32 found_color = 0xffffffff;
int i;
for (i = 0; i < color_list->size; ++i) {
if (strcmp(color_list->colors[i].name, color_name) == 0) {
found_color = color_list->colors[i].code;
}
}
return found_color;
}
#endif #endif

View file

@ -35,10 +35,16 @@
#define UNIWILL_INTERFACE_WMI_STRID "uniwill_wmi" #define UNIWILL_INTERFACE_WMI_STRID "uniwill_wmi"
typedef u32 (uniwill_read_ec_ram_t)(u16, u8*); typedef int (uniwill_read_ec_ram_t)(u16, u8*);
typedef u32 (uniwill_write_ec_ram_t)(u16, u8); typedef int (uniwill_write_ec_ram_t)(u16, u8);
typedef void (uniwill_event_callb_t)(u32); typedef void (uniwill_event_callb_t)(u32);
#define UW_EC_REG_KBD_BL_MAX_BRIGHTNESS 0x1801
#define UW_EC_REG_KBD_BL_WHITE_BRIGHTNESS 0x1802
#define UW_EC_REG_KBD_BL_RGB_RED_BRIGHTNESS 0x1803
#define UW_EC_REG_KBD_BL_RGB_GREEN_BRIGHTNESS 0x1805
#define UW_EC_REG_KBD_BL_RGB_BLUE_BRIGHTNESS 0x1808
struct uniwill_interface_t { struct uniwill_interface_t {
char *string_id; char *string_id;
uniwill_event_callb_t *event_callb; uniwill_event_callb_t *event_callb;
@ -46,11 +52,11 @@ struct uniwill_interface_t {
uniwill_write_ec_ram_t *write_ec_ram; uniwill_write_ec_ram_t *write_ec_ram;
}; };
u32 uniwill_add_interface(struct uniwill_interface_t *new_interface); int uniwill_add_interface(struct uniwill_interface_t *new_interface);
u32 uniwill_remove_interface(struct uniwill_interface_t *interface); int uniwill_remove_interface(struct uniwill_interface_t *interface);
uniwill_read_ec_ram_t uniwill_read_ec_ram; uniwill_read_ec_ram_t uniwill_read_ec_ram;
uniwill_write_ec_ram_t uniwill_write_ec_ram; uniwill_write_ec_ram_t uniwill_write_ec_ram;
u32 uniwill_get_active_interface_id(char **id_str); int uniwill_get_active_interface_id(char **id_str);
union uw_ec_read_return { union uw_ec_read_return {
u32 dword; u32 dword;

View file

@ -31,6 +31,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/version.h> #include <linux/version.h>
#include "uniwill_interfaces.h" #include "uniwill_interfaces.h"
#include "uniwill_leds.h"
#define UNIWILL_OSD_RADIOON 0x01A #define UNIWILL_OSD_RADIOON 0x01A
#define UNIWILL_OSD_RADIOOFF 0x01B #define UNIWILL_OSD_RADIOOFF 0x01B
@ -77,9 +78,9 @@ static struct uniwill_interfaces_t {
uniwill_event_callb_t uniwill_event_callb; uniwill_event_callb_t uniwill_event_callb;
u32 uniwill_read_ec_ram(u16 address, u8 *data) int uniwill_read_ec_ram(u16 address, u8 *data)
{ {
u32 status; int status;
if (!IS_ERR_OR_NULL(uniwill_interfaces.wmi)) if (!IS_ERR_OR_NULL(uniwill_interfaces.wmi))
status = uniwill_interfaces.wmi->read_ec_ram(address, data); status = uniwill_interfaces.wmi->read_ec_ram(address, data);
@ -92,9 +93,9 @@ u32 uniwill_read_ec_ram(u16 address, u8 *data)
} }
EXPORT_SYMBOL(uniwill_read_ec_ram); EXPORT_SYMBOL(uniwill_read_ec_ram);
u32 uniwill_write_ec_ram(u16 address, u8 data) int uniwill_write_ec_ram(u16 address, u8 data)
{ {
u32 status; int status;
if (!IS_ERR_OR_NULL(uniwill_interfaces.wmi)) if (!IS_ERR_OR_NULL(uniwill_interfaces.wmi))
status = uniwill_interfaces.wmi->write_ec_ram(address, data); status = uniwill_interfaces.wmi->write_ec_ram(address, data);
@ -109,7 +110,7 @@ EXPORT_SYMBOL(uniwill_write_ec_ram);
static DEFINE_MUTEX(uniwill_interface_modification_lock); static DEFINE_MUTEX(uniwill_interface_modification_lock);
u32 uniwill_add_interface(struct uniwill_interface_t *interface) int uniwill_add_interface(struct uniwill_interface_t *interface)
{ {
mutex_lock(&uniwill_interface_modification_lock); mutex_lock(&uniwill_interface_modification_lock);
@ -131,7 +132,7 @@ u32 uniwill_add_interface(struct uniwill_interface_t *interface)
} }
EXPORT_SYMBOL(uniwill_add_interface); EXPORT_SYMBOL(uniwill_add_interface);
u32 uniwill_remove_interface(struct uniwill_interface_t *interface) int uniwill_remove_interface(struct uniwill_interface_t *interface)
{ {
mutex_lock(&uniwill_interface_modification_lock); mutex_lock(&uniwill_interface_modification_lock);
@ -151,7 +152,7 @@ u32 uniwill_remove_interface(struct uniwill_interface_t *interface)
} }
EXPORT_SYMBOL(uniwill_remove_interface); EXPORT_SYMBOL(uniwill_remove_interface);
u32 uniwill_get_active_interface_id(char **id_str) int uniwill_get_active_interface_id(char **id_str)
{ {
if (IS_ERR_OR_NULL(uniwill_interfaces.wmi)) if (IS_ERR_OR_NULL(uniwill_interfaces.wmi))
return -ENODEV; return -ENODEV;
@ -208,18 +209,6 @@ static struct notifier_block keyboard_notifier_block = {
.notifier_call = keyboard_notifier_callb .notifier_call = keyboard_notifier_callb
}; };
static u8 uniwill_read_kbd_bl_enabled(void)
{
u8 backlight_data;
u8 enabled = 0xff;
uniwill_read_ec_ram(0x078c, &backlight_data);
enabled = (backlight_data >> 1) & 0x01;
enabled = !enabled;
return enabled;
}
static void uniwill_write_kbd_bl_enable(u8 enable) static void uniwill_write_kbd_bl_enable(u8 enable)
{ {
u8 backlight_data; u8 backlight_data;
@ -231,11 +220,6 @@ static void uniwill_write_kbd_bl_enable(u8 enable)
uniwill_write_ec_ram(0x078c, backlight_data); uniwill_write_ec_ram(0x078c, backlight_data);
} }
static void uniwill_write_kbd_bl_reset(void)
{
uniwill_write_ec_ram(0x078c, 0x10);
}
void uniwill_event_callb(u32 code) void uniwill_event_callb(u32 code)
{ {
if (uniwill_keyboard_driver.input_device != NULL) if (uniwill_keyboard_driver.input_device != NULL)
@ -254,145 +238,11 @@ void uniwill_event_callb(u32 code)
input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTMETA, 0); input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTMETA, 0);
input_sync(uniwill_keyboard_driver.input_device); input_sync(uniwill_keyboard_driver.input_device);
} }
// Keyboard backlight brightness toggle
if (uniwill_kbd_bl_type_rgb_single_color) {
switch (code) {
case UNIWILL_OSD_KB_LED_LEVEL0:
kbd_led_state_uw.brightness = 0x00;
uniwill_write_kbd_bl_state();
break;
case UNIWILL_OSD_KB_LED_LEVEL1:
kbd_led_state_uw.brightness = 0x20;
uniwill_write_kbd_bl_state();
break;
case UNIWILL_OSD_KB_LED_LEVEL2:
kbd_led_state_uw.brightness = 0x50;
uniwill_write_kbd_bl_state();
break;
case UNIWILL_OSD_KB_LED_LEVEL3:
kbd_led_state_uw.brightness = 0x80;
uniwill_write_kbd_bl_state();
break;
case UNIWILL_OSD_KB_LED_LEVEL4:
kbd_led_state_uw.brightness = 0xc8;
uniwill_write_kbd_bl_state();
break;
// Also refresh keyboard state on cable switch event
case UNIWILL_OSD_DC_ADAPTER_CHANGE:
uniwill_write_kbd_bl_state();
break;
}
}
} }
static ssize_t uw_brightness_show(struct device *child,
struct device_attribute *attr, char *buffer)
{
return sprintf(buffer, "%d\n", kbd_led_state_uw.brightness);
}
static enum led_brightness ledcdev_get_uw(struct led_classdev *led_cdev) {
return kbd_led_state_uw.brightness;
}
static ssize_t uw_brightness_store(struct device *child,
struct device_attribute *attr,
const char *buffer, size_t size)
{
u32 brightness_input;
int err = kstrtouint(buffer, 0, &brightness_input);
if (err) return err;
if (brightness_input > UNIWILL_BRIGHTNESS_MAX) return -EINVAL;
kbd_led_state_uw.brightness = (u8)brightness_input;
uniwill_write_kbd_bl_state();
return size;
}
static int ledcdev_set_blocking_uw_mc(struct led_classdev *led_cdev, enum led_brightness brightness) {
struct led_classdev_mc *led_cdev_mc = lcdev_to_mccdev(led_cdev);
led_mc_calc_color_components(led_cdev_mc, brightness);
uniwill_write_kbd_bl_rgb(led_cdev_mc->subled_info[0].brightness,
led_cdev_mc->subled_info[1].brightness,
led_cdev_mc->subled_info[2].brightness);
kbd_led_state_uw.color = ((led_cdev_mc->subled_info[0].intensity * 255 / 200) << 16) +
((led_cdev_mc->subled_info[1].intensity * 255 / 200) << 8) +
(led_cdev_mc->subled_info[2].intensity * 255 / 200);
kbd_led_state_uw.brightness = brightness;
return 0;
}
static ssize_t uw_color_string_show(struct device *child,
struct device_attribute *attr, char *buffer)
{
int i;
sprintf(buffer, "Color values:");
for (i = 0; i < color_list.size; ++i) {
sprintf(buffer + strlen(buffer), " %s",
color_list.colors[i].name);
}
sprintf(buffer + strlen(buffer), "\n");
return strlen(buffer);
}
static ssize_t uw_color_string_store(struct device *child,
struct device_attribute *attr,
const char *buffer, size_t size)
{
u32 color_value;
char *buffer_copy;
buffer_copy = kmalloc(size + 1, GFP_KERNEL);
strcpy(buffer_copy, buffer);
color_value = color_lookup(&color_list, strstrip(buffer_copy));
kfree(buffer_copy);
if (color_value > 0xffffff) return -EINVAL;
kbd_led_state_uw.color = color_value;
uniwill_write_kbd_bl_state();
return size;
}
// Device attributes used by uw kbd
struct uw_kbd_dev_attrs_t {
struct device_attribute brightness;
struct device_attribute color_string;
} uw_kbd_dev_attrs = {
.brightness = __ATTR(brightness, 0644, uw_brightness_show, uw_brightness_store),
.color_string = __ATTR(color_string, 0644, uw_color_string_show, uw_color_string_store)
};
// Device attributes used for uw_kbd_bl_color
static struct attribute *uw_kbd_bl_color_attrs[] = {
&uw_kbd_dev_attrs.brightness.attr,
&uw_kbd_dev_attrs.color_string.attr,
NULL
};
static struct attribute_group uw_kbd_bl_color_attr_group = {
.name = "uw_kbd_bl_color",
.attrs = uw_kbd_bl_color_attrs
};
static void uw_kbd_bl_init_set(void) static void uw_kbd_bl_init_set(void)
{ {
if (uniwill_kbd_bl_type_rgb_single_color) { uniwill_leds_init_late();
// Reset keyboard backlight
uniwill_write_kbd_bl_reset();
// Make sure reset finish before continue
msleep(100);
// Disable backlight while initializing
// uniwill_write_kbd_bl_enable(0);
// Update keyboard backlight according to the current state
uniwill_write_kbd_bl_state();
}
// Enable keyboard backlight
uniwill_write_kbd_bl_enable(1); uniwill_write_kbd_bl_enable(1);
} }
@ -406,6 +256,26 @@ static struct timer_list uw_kbd_bl_init_timer;
static volatile int uw_kbd_bl_check_count = 40; static volatile int uw_kbd_bl_check_count = 40;
static int uw_kbd_bl_init_check_interval_ms = 500; static int uw_kbd_bl_init_check_interval_ms = 500;
static int uniwill_read_kbd_bl_rgb(u8 *red, u8 *green, u8 *blue)
{
int result = 0;
result = uniwill_read_ec_ram(UW_EC_REG_KBD_BL_RGB_RED_BRIGHTNESS, red);
if (result) {
return result;
}
result = uniwill_read_ec_ram(UW_EC_REG_KBD_BL_RGB_GREEN_BRIGHTNESS, green);
if (result) {
return result;
}
result = uniwill_read_ec_ram(UW_EC_REG_KBD_BL_RGB_BLUE_BRIGHTNESS, blue);
if (result) {
return result;
}
return result;
}
static void uw_kbd_bl_init_ready_check_work_func(struct work_struct *work) static void uw_kbd_bl_init_ready_check_work_func(struct work_struct *work)
{ {
u8 uw_cur_red, uw_cur_green, uw_cur_blue; u8 uw_cur_red, uw_cur_green, uw_cur_blue;
@ -446,56 +316,16 @@ static int uw_kbd_bl_init(struct platform_device *dev)
{ {
int status = 0; int status = 0;
uniwill_kbd_bl_type_rgb_single_color = false
// New names
| dmi_match(DMI_BOARD_NAME, "POLARIS1501A1650TI")
| dmi_match(DMI_BOARD_NAME, "POLARIS1501A2060")
| dmi_match(DMI_BOARD_NAME, "POLARIS1501I1650TI")
| dmi_match(DMI_BOARD_NAME, "POLARIS1501I2060")
| dmi_match(DMI_BOARD_NAME, "POLARIS1701A1650TI")
| dmi_match(DMI_BOARD_NAME, "POLARIS1701A2060")
| dmi_match(DMI_BOARD_NAME, "POLARIS1701I1650TI")
| dmi_match(DMI_BOARD_NAME, "POLARIS1701I2060")
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XA02")
| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XI02")
| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XA03")
| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XI03")
#endif
// Old names
// | dmi_match(DMI_BOARD_NAME, "Polaris15I01")
// | dmi_match(DMI_BOARD_NAME, "Polaris17I01")
// | dmi_match(DMI_BOARD_NAME, "Polaris15A01")
// | dmi_match(DMI_BOARD_NAME, "Polaris1501I2060")
// | dmi_match(DMI_BOARD_NAME, "Polaris1701I2060")
;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0)
TUXEDO_ERROR( TUXEDO_ERROR("Warning: Kernel version less that 4.18, keyboard backlight might not be properly recognized.");
"Warning: Kernel version less that 4.18, keyboard backlight might not be properly recognized.");
#endif #endif
// Save previous enable state uniwill_leds_init_early(dev);
uniwill_kbd_bl_enable_state_on_start = uniwill_read_kbd_bl_enabled();
if (uniwill_kbd_bl_type_rgb_single_color) { if (uniwill_kbd_bl_type_rgb_single_color) {
// Initialize keyboard backlight driver state according to parameters
if (param_brightness > UNIWILL_BRIGHTNESS_MAX) param_brightness = UNIWILL_BRIGHTNESS_DEFAULT;
kbd_led_state_uw.brightness = param_brightness;
if (color_lookup(&color_list, param_color) <= (u32) 0xffffff) kbd_led_state_uw.color = color_lookup(&color_list, param_color);
else kbd_led_state_uw.color = UNIWILL_COLOR_DEFAULT;
// Init sysfs bl attributes group
status = sysfs_create_group(&dev->dev.kobj, &uw_kbd_bl_color_attr_group);
if (status) TUXEDO_ERROR("Failed to create sysfs group\n");
// Start periodic checking of animation, set and enable bl when done // Start periodic checking of animation, set and enable bl when done
timer_setup(&uw_kbd_bl_init_timer, uw_kbd_bl_init_ready_check, 0); timer_setup(&uw_kbd_bl_init_timer, uw_kbd_bl_init_ready_check, 0);
mod_timer(&uw_kbd_bl_init_timer, jiffies + msecs_to_jiffies(uw_kbd_bl_init_check_interval_ms)); mod_timer(&uw_kbd_bl_init_timer, jiffies + msecs_to_jiffies(uw_kbd_bl_init_check_interval_ms));
// Register leds sysfs interface
devm_led_classdev_multicolor_register(&dev->dev, &cdev_kb_uw_mc);
} else { } else {
// For non-RGB versions // For non-RGB versions
// Enable keyboard backlight immediately (should it be disabled) // Enable keyboard backlight immediately (should it be disabled)
@ -721,10 +551,7 @@ static int uniwill_keyboard_probe(struct platform_device *dev)
static int uniwill_keyboard_remove(struct platform_device *dev) static int uniwill_keyboard_remove(struct platform_device *dev)
{ {
uniwill_leds_remove(dev);
if (uniwill_kbd_bl_type_rgb_single_color) {
sysfs_remove_group(&dev->dev.kobj, &uw_kbd_bl_color_attr_group);
}
// Restore previous backlight enable state // Restore previous backlight enable state
if (uniwill_kbd_bl_enable_state_on_start != 0xff) { if (uniwill_kbd_bl_enable_state_on_start != 0xff) {
@ -752,11 +579,6 @@ static int uniwill_keyboard_suspend(struct platform_device *dev, pm_message_t st
static int uniwill_keyboard_resume(struct platform_device *dev) static int uniwill_keyboard_resume(struct platform_device *dev)
{ {
if (uniwill_kbd_bl_type_rgb_single_color) {
uniwill_write_kbd_bl_reset();
msleep(100);
uniwill_write_kbd_bl_state();
}
uniwill_write_kbd_bl_enable(1); uniwill_write_kbd_bl_enable(1);
return 0; return 0;
} }

View file

@ -22,18 +22,8 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/leds.h>
#define UNIWILL_KBD_BRIGHTNESS_MIN 0x00 #include <linux/completion.h>
#define UNIWILL_KBD_BRIGHTNESS_MAX 0xff // Uniwill devices actually operate on a range
// from 0x00 - 0xc8 (200), but because
// userspace will get it wrong we do the
// conversion in driver.
#define UNIWILL_KBD_BRIGHTNESS_DEFAULT (UNIWILL_KBD_BRIGHTNESS_MAX * 0.5)
#define UNIWILL_KB_COLOR_DEFAULT_RED 0xff // Same applies as for brightness: Actuall
#define UNIWILL_KB_COLOR_DEFAULT_GREEN 0xff // range is 0x00 - 0xc8. Conversion is done in
#define UNIWILL_KB_COLOR_DEFAULT_BLUE 0xff // this driver.
#define UNIWILL_KB_COLOR_DEFAULT ((UNIWILL_KB_COLOR_DEFAULT_RED << 16) + (UNIWILL_KB_COLOR_DEFAULT_GREEN << 8) + UNIWILL_KB_COLOR_DEFAULT_BLUE)
enum uniwill_kb_backlight_types { enum uniwill_kb_backlight_types {
UNIWILL_KB_BACKLIGHT_TYPE_NONE, UNIWILL_KB_BACKLIGHT_TYPE_NONE,
@ -42,49 +32,97 @@ enum uniwill_kb_backlight_types {
UNIWILL_KB_BACKLIGHT_TYPE_PER_KEY_RGB UNIWILL_KB_BACKLIGHT_TYPE_PER_KEY_RGB
}; };
int uniwill_leds_init(struct platform_device *dev); #define UNIWILL_KBD_BRIGHTNESS_MAX 0xff
#define UNIWILL_KBD_BRIGHTNESS_DEFAULT (UNIWILL_KBD_BRIGHTNESS_MAX * 0.5)
#define UNIWILL_KB_COLOR_DEFAULT_RED 0xff
#define UNIWILL_KB_COLOR_DEFAULT_GREEN 0xff
#define UNIWILL_KB_COLOR_DEFAULT_BLUE 0xff
#define UNIWILL_KB_COLOR_DEFAULT ((UNIWILL_KB_COLOR_DEFAULT_RED << 16) + (UNIWILL_KB_COLOR_DEFAULT_GREEN << 8) + UNIWILL_KB_COLOR_DEFAULT_BLUE)
int uniwill_leds_init_early(struct platform_device *dev);
int uniwill_leds_init_late(void);
int uniwill_leds_remove(struct platform_device *dev); int uniwill_leds_remove(struct platform_device *dev);
enum uniwill_kb_backlight_types uniwill_leds_get_backlight_type(void); enum uniwill_kb_backlight_types uniwill_leds_get_backlight_type(void);
void uniwill_leds_set_brightness_extern(u32 brightness); void uniwill_leds_set_brightness_extern(enum led_brightness brightness);
void uniwill_leds_set_color_extern(u32 color); void uniwill_leds_set_color_extern(u32 color);
// TODO The following should go into a seperate .c file, but for this to work more reworking is required in the tuxedo_keyboard structure. // TODO The following should go into a seperate .c file, but for this to work more reworking is required in the tuxedo_keyboard structure.
#include "clevo_leds.h" #include "uniwill_leds.h"
#include "clevo_interfaces.h" #include "uniwill_interfaces.h"
#include <linux/leds.h>
#include <linux/led-class-multicolor.h> #include <linux/led-class-multicolor.h>
#define FF_TO_UW_RANGE(x) (x * 0xc8 / 0xff) static enum uniwill_kb_backlight_types uniwill_kb_backlight_type = UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR;
#define UW_TO_FF_RANGE(x) (x * 0xff / 0xc8) static bool uw_leds_initialized = false;
//static DECLARE_COMPLETION(init_done);
static u32 uniwill_read_kbd_bl_rgb(u8 *red, u8 *green, u8 *blue) static int uniwill_write_kbd_bl_white(u8 brightness)
{ {
u32 result; //wait_for_completion(&init_done);
uniwill_read_ec_ram(0x1803, red); return uniwill_write_ec_ram(UW_EC_REG_KBD_BL_WHITE_BRIGHTNESS, brightness);
uniwill_read_ec_ram(0x1805, green); }
uniwill_read_ec_ram(0x1808, blue);
result = 0; static int uniwill_write_kbd_bl_rgb(u8 red, u8 green, u8 blue)
{
int result = 0;
//wait_for_completion(&init_done);
result = uniwill_write_ec_ram(UW_EC_REG_KBD_BL_RGB_RED_BRIGHTNESS, red);
if (result) {
return result;
}
result = uniwill_write_ec_ram(UW_EC_REG_KBD_BL_RGB_GREEN_BRIGHTNESS, green);
if (result) {
return result;
}
result = uniwill_write_ec_ram(UW_EC_REG_KBD_BL_RGB_BLUE_BRIGHTNESS, blue);
if (result) {
return result;
}
pr_debug("Wrote kbd color [%0#4x, %0#4x, %0#4x]\n", red, green, blue);
return result; return result;
} }
static void uniwill_write_kbd_bl_rgb(u8 red, u8 green, u8 blue) static void uniwill_leds_set_brightness(struct led_classdev *led_cdev __always_unused, enum led_brightness brightness) {
{ int ret = uniwill_write_kbd_bl_white(brightness);
if (red > 0xc8) red = 0xc8; if (ret) {
if (green > 0xc8) green = 0xc8; pr_debug("uniwill_leds_set_brightness(): uniwill_write_kbd_bl_white() failed\n");
if (blue > 0xc8) blue = 0xc8; return;
uniwill_write_ec_ram(0x1803, red); }
uniwill_write_ec_ram(0x1805, green); led_cdev->brightness = brightness;
uniwill_write_ec_ram(0x1808, blue);
TUXEDO_DEBUG("Wrote kbd color [%0#4x, %0#4x, %0#4x]\n", red, green, blue);
} }
static struct mc_subled clevo_mcled_cdev_subleds[3] = { static void uniwill_leds_set_brightness_mc(struct led_classdev *led_cdev, enum led_brightness brightness) {
int ret;
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
led_mc_calc_color_components(mcled_cdev, brightness);
ret = uniwill_write_kbd_bl_rgb(mcled_cdev->subled_info[0].brightness,
mcled_cdev->subled_info[1].brightness,
mcled_cdev->subled_info[2].brightness);
if (ret) {
pr_debug("uniwill_leds_set_brightness_mc(): uniwill_write_kbd_bl_rgb() failed\n");
return;
}
led_cdev->brightness = brightness;
}
static struct led_classdev uniwill_led_cdev = {
.name = "white:" LED_FUNCTION_KBD_BACKLIGHT,
.max_brightness = UNIWILL_KBD_BRIGHTNESS_MAX,
.brightness_set = &uniwill_leds_set_brightness,
.brightness = UNIWILL_KBD_BRIGHTNESS_DEFAULT
};
static struct mc_subled uw_mcled_cdev_subleds[3] = {
{ {
.color_index = LED_COLOR_ID_RED, .color_index = LED_COLOR_ID_RED,
.brightness = UNIWILL_KBD_BRIGHTNESS_MAX, .brightness = UNIWILL_KBD_BRIGHTNESS_MAX,
@ -108,10 +146,117 @@ static struct mc_subled clevo_mcled_cdev_subleds[3] = {
static struct led_classdev_mc uniwill_mcled_cdev = { static struct led_classdev_mc uniwill_mcled_cdev = {
.led_cdev.name = "rgb:" LED_FUNCTION_KBD_BACKLIGHT, .led_cdev.name = "rgb:" LED_FUNCTION_KBD_BACKLIGHT,
.led_cdev.max_brightness = UNIWILL_KBD_BRIGHTNESS_MAX, .led_cdev.max_brightness = UNIWILL_KBD_BRIGHTNESS_MAX,
.led_cdev.brightness = &uniwill_leds_set_brightness_mc, .led_cdev.brightness_set = &uniwill_leds_set_brightness_mc,
.led_cdev.brightness = UNIWILL_KBD_BRIGHTNESS_DEFAULT, .led_cdev.brightness = UNIWILL_KBD_BRIGHTNESS_DEFAULT,
.num_colors = 3, .num_colors = 3,
.subled_info = cdev_kb_uw_mc_subled .subled_info = uw_mcled_cdev_subleds
}; };
int uniwill_leds_init_early(struct platform_device *dev)
{
int ret;
if ( dmi_match(DMI_BOARD_NAME, "POLARIS1501A1650TI")
|| dmi_match(DMI_BOARD_NAME, "POLARIS1501A2060")
|| dmi_match(DMI_BOARD_NAME, "POLARIS1501I1650TI")
|| dmi_match(DMI_BOARD_NAME, "POLARIS1501I2060")
|| dmi_match(DMI_BOARD_NAME, "POLARIS1701A1650TI")
|| dmi_match(DMI_BOARD_NAME, "POLARIS1701A2060")
|| dmi_match(DMI_BOARD_NAME, "POLARIS1701I1650TI")
|| dmi_match(DMI_BOARD_NAME, "POLARIS1701I2060")
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
|| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XA02")
|| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XI02")
|| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XA03")
|| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XI03")
#endif
) {
uniwill_kb_backlight_type = UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB;
}
pr_debug("Keyboard backlight type: 0x%02x\n", uniwill_kb_backlight_type);
if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
pr_debug("Registering fixed color leds interface\n");
ret = led_classdev_register(&dev->dev, &uniwill_led_cdev);
if (ret) {
pr_err("Registering fixed color leds interface failed\n");
return ret;
}
}
else if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
pr_debug("Registering single zone rgb leds interface\n");
ret = devm_led_classdev_multicolor_register(&dev->dev, &uniwill_mcled_cdev);
if (ret) {
pr_err("Registering single zone rgb leds interface failed\n");
return ret;
}
}
uw_leds_initialized = true;
return 0;
}
EXPORT_SYMBOL(uniwill_leds_init_early);
int uniwill_leds_init_late()
{
int ret;
ret = uniwill_write_ec_ram(UW_EC_REG_KBD_BL_MAX_BRIGHTNESS, 0xff);
if (ret) {
pr_err("Setting max keyboard brightness value failed\n");
return ret;
}
uniwill_leds_set_brightness_extern(UNIWILL_KBD_BRIGHTNESS_DEFAULT);
uniwill_leds_set_color_extern(UNIWILL_KB_COLOR_DEFAULT);
//complete_all(&init_done);
return 0;
}
EXPORT_SYMBOL(uniwill_leds_init_late);
int uniwill_leds_remove(struct platform_device *dev) {
if (uw_leds_initialized) {
if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
led_classdev_unregister(&uniwill_led_cdev);
}
else if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
devm_led_classdev_multicolor_unregister(&dev->dev, &uniwill_mcled_cdev);
}
}
uw_leds_initialized = false;
return 0;
}
EXPORT_SYMBOL(uniwill_leds_remove);
enum uniwill_kb_backlight_types uniwill_leds_get_backlight_type() {
return uniwill_kb_backlight_type;
}
EXPORT_SYMBOL(uniwill_leds_get_backlight_type);
void uniwill_leds_set_brightness_extern(enum led_brightness brightness) {
if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
uniwill_led_cdev.brightness_set(&uniwill_led_cdev, brightness);
}
else if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
uniwill_mcled_cdev.led_cdev.brightness_set(&uniwill_mcled_cdev.led_cdev, brightness);
}
}
EXPORT_SYMBOL(uniwill_leds_set_brightness_extern);
void uniwill_leds_set_color_extern(u32 color) {
if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
uniwill_mcled_cdev.subled_info[0].intensity = (color >> 16) & 0xff;
uniwill_mcled_cdev.subled_info[1].intensity = (color >> 8) & 0xff;
uniwill_mcled_cdev.subled_info[2].intensity = color & 0xff;
uniwill_mcled_cdev.led_cdev.brightness_set(&uniwill_mcled_cdev.led_cdev, uniwill_mcled_cdev.led_cdev.brightness);
}
}
EXPORT_SYMBOL(uniwill_leds_set_color_extern);
MODULE_LICENSE("GPL");
#endif // UNIWILL_LEDS_H #endif // UNIWILL_LEDS_H