File Index
Files and directories
Sign in
FILE

uniwill-acpi.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/x86/uniwill/uniwill-acpi.c C
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Linux driver for Uniwill notebooks.
   4 *
   5 * Special thanks go to Pőcze Barnabás, Christoffer Sandberg and Werner Sembach
   6 * for supporting the development of this driver either through prior work or
   7 * by answering questions regarding the underlying ACPI and WMI interfaces.
   8 *
   9 * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
  10 */
  11
  12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13
  14#include <linux/acpi.h>
  15#include <linux/array_size.h>
  16#include <linux/bits.h>
  17#include <linux/bitfield.h>
  18#include <linux/cleanup.h>
  19#include <linux/debugfs.h>
  20#include <linux/delay.h>
  21#include <linux/device.h>
  22#include <linux/device/driver.h>
  23#include <linux/dmi.h>
  24#include <linux/errno.h>
  25#include <linux/fixp-arith.h>
  26#include <linux/hwmon.h>
  27#include <linux/hwmon-sysfs.h>
  28#include <linux/init.h>
  29#include <linux/input.h>
  30#include <linux/input/sparse-keymap.h>
  31#include <linux/kernel.h>
  32#include <linux/kstrtox.h>
  33#include <linux/leds.h>
  34#include <linux/led-class-multicolor.h>
  35#include <linux/limits.h>
  36#include <linux/list.h>
  37#include <linux/minmax.h>
  38#include <linux/module.h>
  39#include <linux/mutex.h>
  40#include <linux/notifier.h>
  41#include <linux/platform_device.h>
  42#include <linux/pm.h>
  43#include <linux/printk.h>
  44#include <linux/regmap.h>
  45#include <linux/string.h>
  46#include <linux/sysfs.h>
  47#include <linux/types.h>
  48#include <linux/units.h>
  49
  50#include <acpi/battery.h>
  51
  52#include "uniwill-wmi.h"
  53
  54#define EC_ADDR_BAT_POWER_UNIT_1	0x0400
  55
  56#define EC_ADDR_BAT_POWER_UNIT_2	0x0401
  57
  58#define EC_ADDR_BAT_DESIGN_CAPACITY_1	0x0402
  59
  60#define EC_ADDR_BAT_DESIGN_CAPACITY_2	0x0403
  61
  62#define EC_ADDR_BAT_FULL_CAPACITY_1	0x0404
  63
  64#define EC_ADDR_BAT_FULL_CAPACITY_2	0x0405
  65
  66#define EC_ADDR_BAT_DESIGN_VOLTAGE_1	0x0408
  67
  68#define EC_ADDR_BAT_DESIGN_VOLTAGE_2	0x0409
  69
  70#define EC_ADDR_BAT_STATUS_1		0x0432
  71#define BAT_DISCHARGING			BIT(0)
  72
  73#define EC_ADDR_BAT_STATUS_2		0x0433
  74
  75#define EC_ADDR_BAT_CURRENT_1		0x0434
  76
  77#define EC_ADDR_BAT_CURRENT_2		0x0435
  78
  79#define EC_ADDR_BAT_REMAIN_CAPACITY_1	0x0436
  80
  81#define EC_ADDR_BAT_REMAIN_CAPACITY_2	0x0437
  82
  83#define EC_ADDR_BAT_VOLTAGE_1		0x0438
  84
  85#define EC_ADDR_BAT_VOLTAGE_2		0x0439
  86
  87#define EC_ADDR_CPU_TEMP		0x043E
  88
  89#define EC_ADDR_GPU_TEMP		0x044F
  90
  91#define EC_ADDR_MAIN_FAN_RPM_1		0x0464
  92
  93#define EC_ADDR_MAIN_FAN_RPM_2		0x0465
  94
  95#define EC_ADDR_SECOND_FAN_RPM_1	0x046C
  96
  97#define EC_ADDR_SECOND_FAN_RPM_2	0x046D
  98
  99#define EC_ADDR_DEVICE_STATUS		0x047B
 100#define WIFI_STATUS_ON			BIT(7)
 101/* BIT(5) is also unset depending on the rfkill state (bluetooth?) */
 102
 103#define EC_ADDR_BAT_ALERT		0x0494
 104
 105#define EC_ADDR_BAT_CYCLE_COUNT_1	0x04A6
 106
 107#define EC_ADDR_BAT_CYCLE_COUNT_2	0x04A7
 108
 109#define EC_ADDR_PROJECT_ID		0x0740
 110
 111#define EC_ADDR_AP_OEM			0x0741
 112#define	ENABLE_MANUAL_CTRL		BIT(0)
 113#define ITE_KBD_EFFECT_REACTIVE		BIT(3)
 114#define FAN_ABNORMAL			BIT(5)
 115
 116#define EC_ADDR_SUPPORT_5		0x0742
 117#define FAN_TURBO_SUPPORTED		BIT(4)
 118#define FAN_SUPPORT			BIT(5)
 119
 120#define EC_ADDR_CTGP_DB_CTRL		0x0743
 121#define CTGP_DB_GENERAL_ENABLE		BIT(0)
 122#define CTGP_DB_DB_ENABLE		BIT(1)
 123#define CTGP_DB_CTGP_ENABLE		BIT(2)
 124
 125#define EC_ADDR_CTGP_OFFSET		0x0744
 126
 127#define EC_ADDR_TPP_OFFSET		0x0745
 128
 129#define EC_ADDR_MAX_TGP			0x0746
 130
 131#define EC_ADDR_LIGHTBAR_AC_CTRL	0x0748
 132#define LIGHTBAR_APP_EXISTS		BIT(0)
 133#define LIGHTBAR_POWER_SAVE		BIT(1)
 134#define LIGHTBAR_S0_OFF			BIT(2)
 135#define LIGHTBAR_S3_OFF			BIT(3)	// Breathing animation when suspended
 136#define LIGHTBAR_WELCOME		BIT(7)	// Rainbow animation
 137
 138#define EC_ADDR_LIGHTBAR_AC_RED		0x0749
 139
 140#define EC_ADDR_LIGHTBAR_AC_GREEN	0x074A
 141
 142#define EC_ADDR_LIGHTBAR_AC_BLUE	0x074B
 143
 144#define EC_ADDR_BIOS_OEM		0x074E
 145#define FN_LOCK_STATUS			BIT(4)
 146
 147#define EC_ADDR_MANUAL_FAN_CTRL		0x0751
 148#define FAN_LEVEL_MASK			GENMASK(2, 0)
 149#define FAN_MODE_TURBO			BIT(4)
 150#define FAN_MODE_HIGH			BIT(5)
 151#define FAN_MODE_BOOST			BIT(6)
 152#define FAN_MODE_USER			BIT(7)
 153
 154#define EC_ADDR_PWM_1			0x075B
 155
 156#define EC_ADDR_PWM_2			0x075C
 157
 158/* Unreliable */
 159#define EC_ADDR_SUPPORT_1		0x0765
 160#define AIRPLANE_MODE			BIT(0)
 161#define GPS_SWITCH			BIT(1)
 162#define OVERCLOCK			BIT(2)
 163#define MACRO_KEY			BIT(3)
 164#define SHORTCUT_KEY			BIT(4)
 165#define SUPER_KEY_LOCK			BIT(5)
 166#define LIGHTBAR			BIT(6)
 167#define FAN_BOOST			BIT(7)
 168
 169#define EC_ADDR_SUPPORT_2		0x0766
 170#define SILENT_MODE			BIT(0)
 171#define USB_CHARGING			BIT(1)
 172#define RGB_KEYBOARD			BIT(2)
 173#define CHINA_MODE			BIT(5)
 174#define MY_BATTERY			BIT(6)
 175
 176#define EC_ADDR_TRIGGER			0x0767
 177#define TRIGGER_SUPER_KEY_LOCK		BIT(0)
 178#define TRIGGER_LIGHTBAR		BIT(1)
 179#define TRIGGER_FAN_BOOST		BIT(2)
 180#define TRIGGER_SILENT_MODE		BIT(3)
 181#define TRIGGER_USB_CHARGING		BIT(4)
 182#define RGB_APPLY_COLOR			BIT(5)
 183#define RGB_LOGO_EFFECT			BIT(6)
 184#define RGB_RAINBOW_EFFECT		BIT(7)
 185
 186#define EC_ADDR_SWITCH_STATUS		0x0768
 187#define SUPER_KEY_LOCK_STATUS		BIT(0)
 188#define LIGHTBAR_STATUS			BIT(1)
 189#define FAN_BOOST_STATUS		BIT(2)
 190#define MACRO_KEY_STATUS		BIT(3)
 191#define MY_BAT_POWER_BAT_STATUS		BIT(4)
 192
 193#define EC_ADDR_RGB_RED			0x0769
 194
 195#define EC_ADDR_RGB_GREEN		0x076A
 196
 197#define EC_ADDR_RGB_BLUE		0x076B
 198
 199#define EC_ADDR_ROMID_START		0x0770
 200#define ROMID_LENGTH			14
 201
 202#define EC_ADDR_ROMID_EXTRA_1		0x077E
 203
 204#define EC_ADDR_ROMID_EXTRA_2		0x077F
 205
 206#define EC_ADDR_BIOS_OEM_2		0x0782
 207#define FAN_V2_NEW			BIT(0)
 208#define FAN_QKEY			BIT(1)
 209#define FAN_TABLE_OFFICE_MODE		BIT(2)
 210#define FAN_V3				BIT(3)
 211#define DEFAULT_MODE			BIT(4)
 212
 213#define EC_ADDR_PL1_SETTING		0x0783
 214
 215#define EC_ADDR_PL2_SETTING		0x0784
 216
 217#define EC_ADDR_PL4_SETTING		0x0785
 218
 219#define EC_ADDR_FAN_DEFAULT		0x0786
 220#define FAN_CURVE_LENGTH		5
 221
 222#define EC_ADDR_KBD_STATUS		0x078C
 223#define KBD_WHITE_ONLY			BIT(0)	// ~single color
 224#define KBD_SINGLE_COLOR_OFF		BIT(1)
 225#define KBD_TURBO_LEVEL_MASK		GENMASK(3, 2)
 226#define KBD_APPLY			BIT(4)
 227#define KBD_BRIGHTNESS			GENMASK(7, 5)
 228
 229#define EC_ADDR_FAN_CTRL		0x078E
 230#define FAN3P5				BIT(1)
 231#define CHARGING_PROFILE		BIT(3)
 232#define UNIVERSAL_FAN_CTRL		BIT(6)
 233
 234#define EC_ADDR_BIOS_OEM_3		0x07A3
 235#define FAN_REDUCED_DURY_CYCLE		BIT(5)
 236#define FAN_ALWAYS_ON			BIT(6)
 237
 238#define EC_ADDR_BIOS_BYTE		0x07A4
 239#define FN_LOCK_SWITCH			BIT(3)
 240
 241#define EC_ADDR_OEM_3			0x07A5
 242#define POWER_LED_MASK			GENMASK(1, 0)
 243#define POWER_LED_LEFT			0x00
 244#define POWER_LED_BOTH			0x01
 245#define POWER_LED_NONE			0x02
 246#define FAN_QUIET			BIT(2)
 247#define OVERBOOST			BIT(4)
 248#define HIGH_POWER			BIT(7)
 249
 250#define EC_ADDR_OEM_4			0x07A6
 251#define OVERBOOST_DYN_TEMP_OFF		BIT(1)
 252#define TOUCHPAD_TOGGLE_OFF		BIT(6)
 253
 254#define EC_ADDR_CHARGE_CTRL		0x07B9
 255#define CHARGE_CTRL_MASK		GENMASK(6, 0)
 256#define CHARGE_CTRL_REACHED		BIT(7)
 257
 258#define EC_ADDR_UNIVERSAL_FAN_CTRL	0x07C5
 259#define SPLIT_TABLES			BIT(7)
 260
 261#define EC_ADDR_AP_OEM_6		0x07C6
 262#define ENABLE_UNIVERSAL_FAN_CTRL	BIT(2)
 263#define BATTERY_CHARGE_FULL_OVER_24H	BIT(3)
 264#define BATTERY_ERM_STATUS_REACHED	BIT(4)
 265
 266#define EC_ADDR_CHARGE_PRIO		0x07CC
 267#define CHARGING_PERFORMANCE		BIT(7)
 268
 269/* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
 270#define EC_ADDR_LIGHTBAR_BAT_CTRL	0x07E2
 271
 272#define EC_ADDR_LIGHTBAR_BAT_RED	0x07E3
 273
 274#define EC_ADDR_LIGHTBAR_BAT_GREEN	0x07E4
 275
 276#define EC_ADDR_LIGHTBAR_BAT_BLUE	0x07E5
 277
 278#define EC_ADDR_CPU_TEMP_END_TABLE	0x0F00
 279
 280#define EC_ADDR_CPU_TEMP_START_TABLE	0x0F10
 281
 282#define EC_ADDR_CPU_FAN_SPEED_TABLE	0x0F20
 283
 284#define EC_ADDR_GPU_TEMP_END_TABLE	0x0F30
 285
 286#define EC_ADDR_GPU_TEMP_START_TABLE	0x0F40
 287
 288#define EC_ADDR_GPU_FAN_SPEED_TABLE	0x0F50
 289
 290/*
 291 * Those two registers technically allow for manual fan control,
 292 * but are unstable on some models and are likely not meant to
 293 * be used by applications as they are only accessible when using
 294 * the WMI interface.
 295 */
 296#define EC_ADDR_PWM_1_WRITEABLE		0x1804
 297
 298#define EC_ADDR_PWM_2_WRITEABLE		0x1809
 299
 300#define DRIVER_NAME	"uniwill"
 301
 302/*
 303 * The OEM software always sleeps up to 6 ms after reading/writing EC
 304 * registers, so we emulate this behaviour for maximum compatibility.
 305 */
 306#define UNIWILL_EC_DELAY_US	6000
 307
 308#define PWM_MAX			200
 309#define FAN_TABLE_LENGTH	16
 310
 311#define LED_CHANNELS		3
 312#define LED_MAX_BRIGHTNESS	200
 313
 314#define UNIWILL_FEATURE_FN_LOCK_TOGGLE		BIT(0)
 315#define UNIWILL_FEATURE_SUPER_KEY_TOGGLE	BIT(1)
 316#define UNIWILL_FEATURE_TOUCHPAD_TOGGLE		BIT(2)
 317#define UNIWILL_FEATURE_LIGHTBAR		BIT(3)
 318#define UNIWILL_FEATURE_BATTERY			BIT(4)
 319#define UNIWILL_FEATURE_HWMON			BIT(5)
 320
 321struct uniwill_data {
 322	struct device *dev;
 323	acpi_handle handle;
 324	struct regmap *regmap;
 325	struct acpi_battery_hook hook;
 326	unsigned int last_charge_ctrl;
 327	struct mutex battery_lock;	/* Protects the list of currently registered batteries */
 328	unsigned int last_switch_status;
 329	struct mutex super_key_lock;	/* Protects the toggling of the super key lock state */
 330	struct list_head batteries;
 331	struct mutex led_lock;		/* Protects writes to the lightbar registers */
 332	struct led_classdev_mc led_mc_cdev;
 333	struct mc_subled led_mc_subled_info[LED_CHANNELS];
 334	struct mutex input_lock;	/* Protects input sequence during notify */
 335	struct input_dev *input_device;
 336	struct notifier_block nb;
 337};
 338
 339struct uniwill_battery_entry {
 340	struct list_head head;
 341	struct power_supply *battery;
 342};
 343
 344static bool force;
 345module_param_unsafe(force, bool, 0);
 346MODULE_PARM_DESC(force, "Force loading without checking for supported devices\n");
 347
 348/* Feature bitmask since the associated registers are not reliable */
 349static unsigned int supported_features;
 350
 351static const char * const uniwill_temp_labels[] = {
 352	"CPU",
 353	"GPU",
 354};
 355
 356static const char * const uniwill_fan_labels[] = {
 357	"Main",
 358	"Secondary",
 359};
 360
 361static const struct key_entry uniwill_keymap[] = {
 362	/* Reported via keyboard controller */
 363	{ KE_IGNORE,    UNIWILL_OSD_CAPSLOCK,                   { KEY_CAPSLOCK }},
 364	{ KE_IGNORE,    UNIWILL_OSD_NUMLOCK,                    { KEY_NUMLOCK }},
 365
 366	/* Reported when the user locks/unlocks the super key */
 367	{ KE_IGNORE,    UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE,      { KEY_UNKNOWN }},
 368	{ KE_IGNORE,    UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE,     { KEY_UNKNOWN }},
 369	/* Optional, might not be reported by all devices */
 370	{ KE_IGNORE,	UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED,	{ KEY_UNKNOWN }},
 371
 372	/* Reported in manual mode when toggling the airplane mode status */
 373	{ KE_KEY,       UNIWILL_OSD_RFKILL,                     { KEY_RFKILL }},
 374	{ KE_IGNORE,    UNIWILL_OSD_RADIOON,                    { KEY_UNKNOWN }},
 375	{ KE_IGNORE,    UNIWILL_OSD_RADIOOFF,                   { KEY_UNKNOWN }},
 376
 377	/* Reported when user wants to cycle the platform profile */
 378	{ KE_KEY,       UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE,    { KEY_F14 }},
 379
 380	/* Reported when the user wants to adjust the brightness of the keyboard */
 381	{ KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN,               { KEY_KBDILLUMDOWN }},
 382	{ KE_KEY,       UNIWILL_OSD_KBDILLUMUP,                 { KEY_KBDILLUMUP }},
 383
 384	/* Reported when the user wants to toggle the microphone mute status */
 385	{ KE_KEY,       UNIWILL_OSD_MIC_MUTE,                   { KEY_MICMUTE }},
 386
 387	/* Reported when the user wants to toggle the mute status */
 388	{ KE_IGNORE,    UNIWILL_OSD_MUTE,                       { KEY_MUTE }},
 389
 390	/* Reported when the user locks/unlocks the Fn key */
 391	{ KE_IGNORE,    UNIWILL_OSD_FN_LOCK,                    { KEY_FN_ESC }},
 392
 393	/* Reported when the user wants to toggle the brightness of the keyboard */
 394	{ KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE,             { KEY_KBDILLUMTOGGLE }},
 395	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0,              { KEY_KBDILLUMTOGGLE }},
 396	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1,              { KEY_KBDILLUMTOGGLE }},
 397	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2,              { KEY_KBDILLUMTOGGLE }},
 398	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3,              { KEY_KBDILLUMTOGGLE }},
 399	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4,              { KEY_KBDILLUMTOGGLE }},
 400
 401	/* FIXME: find out the exact meaning of those events */
 402	{ KE_IGNORE,    UNIWILL_OSD_BAT_CHARGE_FULL_24_H,       { KEY_UNKNOWN }},
 403	{ KE_IGNORE,    UNIWILL_OSD_BAT_ERM_UPDATE,             { KEY_UNKNOWN }},
 404
 405	/* Reported when the user wants to toggle the benchmark mode status */
 406	{ KE_IGNORE,    UNIWILL_OSD_BENCHMARK_MODE_TOGGLE,      { KEY_UNKNOWN }},
 407
 408	/* Reported when the user wants to toggle the webcam */
 409	{ KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE,              { KEY_UNKNOWN }},
 410
 411	{ KE_END }
 412};
 413
 414static int uniwill_ec_reg_write(void *context, unsigned int reg, unsigned int val)
 415{
 416	union acpi_object params[2] = {
 417		{
 418			.integer = {
 419				.type = ACPI_TYPE_INTEGER,
 420				.value = reg,
 421			},
 422		},
 423		{
 424			.integer = {
 425				.type = ACPI_TYPE_INTEGER,
 426				.value = val,
 427			},
 428		},
 429	};
 430	struct uniwill_data *data = context;
 431	struct acpi_object_list input = {
 432		.count = ARRAY_SIZE(params),
 433		.pointer = params,
 434	};
 435	acpi_status status;
 436
 437	status = acpi_evaluate_object(data->handle, "ECRW", &input, NULL);
 438	if (ACPI_FAILURE(status))
 439		return -EIO;
 440
 441	usleep_range(UNIWILL_EC_DELAY_US, UNIWILL_EC_DELAY_US * 2);
 442
 443	return 0;
 444}
 445
 446static int uniwill_ec_reg_read(void *context, unsigned int reg, unsigned int *val)
 447{
 448	union acpi_object params[1] = {
 449		{
 450			.integer = {
 451				.type = ACPI_TYPE_INTEGER,
 452				.value = reg,
 453			},
 454		},
 455	};
 456	struct uniwill_data *data = context;
 457	struct acpi_object_list input = {
 458		.count = ARRAY_SIZE(params),
 459		.pointer = params,
 460	};
 461	unsigned long long output;
 462	acpi_status status;
 463
 464	status = acpi_evaluate_integer(data->handle, "ECRR", &input, &output);
 465	if (ACPI_FAILURE(status))
 466		return -EIO;
 467
 468	if (output > U8_MAX)
 469		return -ENXIO;
 470
 471	usleep_range(UNIWILL_EC_DELAY_US, UNIWILL_EC_DELAY_US * 2);
 472
 473	*val = output;
 474
 475	return 0;
 476}
 477
 478static const struct regmap_bus uniwill_ec_bus = {
 479	.reg_write = uniwill_ec_reg_write,
 480	.reg_read = uniwill_ec_reg_read,
 481	.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
 482	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
 483};
 484
 485static bool uniwill_writeable_reg(struct device *dev, unsigned int reg)
 486{
 487	switch (reg) {
 488	case EC_ADDR_AP_OEM:
 489	case EC_ADDR_LIGHTBAR_AC_CTRL:
 490	case EC_ADDR_LIGHTBAR_AC_RED:
 491	case EC_ADDR_LIGHTBAR_AC_GREEN:
 492	case EC_ADDR_LIGHTBAR_AC_BLUE:
 493	case EC_ADDR_BIOS_OEM:
 494	case EC_ADDR_TRIGGER:
 495	case EC_ADDR_OEM_4:
 496	case EC_ADDR_CHARGE_CTRL:
 497	case EC_ADDR_LIGHTBAR_BAT_CTRL:
 498	case EC_ADDR_LIGHTBAR_BAT_RED:
 499	case EC_ADDR_LIGHTBAR_BAT_GREEN:
 500	case EC_ADDR_LIGHTBAR_BAT_BLUE:
 501		return true;
 502	default:
 503		return false;
 504	}
 505}
 506
 507static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
 508{
 509	switch (reg) {
 510	case EC_ADDR_CPU_TEMP:
 511	case EC_ADDR_GPU_TEMP:
 512	case EC_ADDR_MAIN_FAN_RPM_1:
 513	case EC_ADDR_MAIN_FAN_RPM_2:
 514	case EC_ADDR_SECOND_FAN_RPM_1:
 515	case EC_ADDR_SECOND_FAN_RPM_2:
 516	case EC_ADDR_BAT_ALERT:
 517	case EC_ADDR_PROJECT_ID:
 518	case EC_ADDR_AP_OEM:
 519	case EC_ADDR_LIGHTBAR_AC_CTRL:
 520	case EC_ADDR_LIGHTBAR_AC_RED:
 521	case EC_ADDR_LIGHTBAR_AC_GREEN:
 522	case EC_ADDR_LIGHTBAR_AC_BLUE:
 523	case EC_ADDR_BIOS_OEM:
 524	case EC_ADDR_PWM_1:
 525	case EC_ADDR_PWM_2:
 526	case EC_ADDR_TRIGGER:
 527	case EC_ADDR_SWITCH_STATUS:
 528	case EC_ADDR_OEM_4:
 529	case EC_ADDR_CHARGE_CTRL:
 530	case EC_ADDR_LIGHTBAR_BAT_CTRL:
 531	case EC_ADDR_LIGHTBAR_BAT_RED:
 532	case EC_ADDR_LIGHTBAR_BAT_GREEN:
 533	case EC_ADDR_LIGHTBAR_BAT_BLUE:
 534		return true;
 535	default:
 536		return false;
 537	}
 538}
 539
 540static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
 541{
 542	switch (reg) {
 543	case EC_ADDR_CPU_TEMP:
 544	case EC_ADDR_GPU_TEMP:
 545	case EC_ADDR_MAIN_FAN_RPM_1:
 546	case EC_ADDR_MAIN_FAN_RPM_2:
 547	case EC_ADDR_SECOND_FAN_RPM_1:
 548	case EC_ADDR_SECOND_FAN_RPM_2:
 549	case EC_ADDR_BAT_ALERT:
 550	case EC_ADDR_PWM_1:
 551	case EC_ADDR_PWM_2:
 552	case EC_ADDR_TRIGGER:
 553	case EC_ADDR_SWITCH_STATUS:
 554	case EC_ADDR_CHARGE_CTRL:
 555		return true;
 556	default:
 557		return false;
 558	}
 559}
 560
 561static const struct regmap_config uniwill_ec_config = {
 562	.reg_bits = 16,
 563	.val_bits = 8,
 564	.writeable_reg = uniwill_writeable_reg,
 565	.readable_reg = uniwill_readable_reg,
 566	.volatile_reg = uniwill_volatile_reg,
 567	.can_sleep = true,
 568	.max_register = 0xFFF,
 569	.cache_type = REGCACHE_MAPLE,
 570	.use_single_read = true,
 571	.use_single_write = true,
 572};
 573
 574static ssize_t fn_lock_toggle_enable_store(struct device *dev, struct device_attribute *attr,
 575					   const char *buf, size_t count)
 576{
 577	struct uniwill_data *data = dev_get_drvdata(dev);
 578	unsigned int value;
 579	bool enable;
 580	int ret;
 581
 582	ret = kstrtobool(buf, &enable);
 583	if (ret < 0)
 584		return ret;
 585
 586	if (enable)
 587		value = FN_LOCK_STATUS;
 588	else
 589		value = 0;
 590
 591	ret = regmap_update_bits(data->regmap, EC_ADDR_BIOS_OEM, FN_LOCK_STATUS, value);
 592	if (ret < 0)
 593		return ret;
 594
 595	return count;
 596}
 597
 598static ssize_t fn_lock_toggle_enable_show(struct device *dev, struct device_attribute *attr,
 599					  char *buf)
 600{
 601	struct uniwill_data *data = dev_get_drvdata(dev);
 602	unsigned int value;
 603	int ret;
 604
 605	ret = regmap_read(data->regmap, EC_ADDR_BIOS_OEM, &value);
 606	if (ret < 0)
 607		return ret;
 608
 609	return sysfs_emit(buf, "%d\n", !!(value & FN_LOCK_STATUS));
 610}
 611
 612static DEVICE_ATTR_RW(fn_lock_toggle_enable);
 613
 614static ssize_t super_key_toggle_enable_store(struct device *dev, struct device_attribute *attr,
 615					     const char *buf, size_t count)
 616{
 617	struct uniwill_data *data = dev_get_drvdata(dev);
 618	unsigned int value;
 619	bool enable;
 620	int ret;
 621
 622	ret = kstrtobool(buf, &enable);
 623	if (ret < 0)
 624		return ret;
 625
 626	guard(mutex)(&data->super_key_lock);
 627
 628	ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
 629	if (ret < 0)
 630		return ret;
 631
 632	/*
 633	 * We can only toggle the super key lock, so we return early if the setting
 634	 * is already in the correct state.
 635	 */
 636	if (enable == !(value & SUPER_KEY_LOCK_STATUS))
 637		return count;
 638
 639	ret = regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK,
 640				TRIGGER_SUPER_KEY_LOCK);
 641	if (ret < 0)
 642		return ret;
 643
 644	return count;
 645}
 646
 647static ssize_t super_key_toggle_enable_show(struct device *dev, struct device_attribute *attr,
 648					    char *buf)
 649{
 650	struct uniwill_data *data = dev_get_drvdata(dev);
 651	unsigned int value;
 652	int ret;
 653
 654	ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
 655	if (ret < 0)
 656		return ret;
 657
 658	return sysfs_emit(buf, "%d\n", !(value & SUPER_KEY_LOCK_STATUS));
 659}
 660
 661static DEVICE_ATTR_RW(super_key_toggle_enable);
 662
 663static ssize_t touchpad_toggle_enable_store(struct device *dev, struct device_attribute *attr,
 664					    const char *buf, size_t count)
 665{
 666	struct uniwill_data *data = dev_get_drvdata(dev);
 667	unsigned int value;
 668	bool enable;
 669	int ret;
 670
 671	ret = kstrtobool(buf, &enable);
 672	if (ret < 0)
 673		return ret;
 674
 675	if (enable)
 676		value = 0;
 677	else
 678		value = TOUCHPAD_TOGGLE_OFF;
 679
 680	ret = regmap_update_bits(data->regmap, EC_ADDR_OEM_4, TOUCHPAD_TOGGLE_OFF, value);
 681	if (ret < 0)
 682		return ret;
 683
 684	return count;
 685}
 686
 687static ssize_t touchpad_toggle_enable_show(struct device *dev, struct device_attribute *attr,
 688					   char *buf)
 689{
 690	struct uniwill_data *data = dev_get_drvdata(dev);
 691	unsigned int value;
 692	int ret;
 693
 694	ret = regmap_read(data->regmap, EC_ADDR_OEM_4, &value);
 695	if (ret < 0)
 696		return ret;
 697
 698	return sysfs_emit(buf, "%d\n", !(value & TOUCHPAD_TOGGLE_OFF));
 699}
 700
 701static DEVICE_ATTR_RW(touchpad_toggle_enable);
 702
 703static ssize_t rainbow_animation_store(struct device *dev, struct device_attribute *attr,
 704				       const char *buf, size_t count)
 705{
 706	struct uniwill_data *data = dev_get_drvdata(dev);
 707	unsigned int value;
 708	bool enable;
 709	int ret;
 710
 711	ret = kstrtobool(buf, &enable);
 712	if (ret < 0)
 713		return ret;
 714
 715	if (enable)
 716		value = LIGHTBAR_WELCOME;
 717	else
 718		value = 0;
 719
 720	guard(mutex)(&data->led_lock);
 721
 722	ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_WELCOME, value);
 723	if (ret < 0)
 724		return ret;
 725
 726	ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_WELCOME, value);
 727	if (ret < 0)
 728		return ret;
 729
 730	return count;
 731}
 732
 733static ssize_t rainbow_animation_show(struct device *dev, struct device_attribute *attr, char *buf)
 734{
 735	struct uniwill_data *data = dev_get_drvdata(dev);
 736	unsigned int value;
 737	int ret;
 738
 739	ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value);
 740	if (ret < 0)
 741		return ret;
 742
 743	return sysfs_emit(buf, "%d\n", !!(value & LIGHTBAR_WELCOME));
 744}
 745
 746static DEVICE_ATTR_RW(rainbow_animation);
 747
 748static ssize_t breathing_in_suspend_store(struct device *dev, struct device_attribute *attr,
 749					  const char *buf, size_t count)
 750{
 751	struct uniwill_data *data = dev_get_drvdata(dev);
 752	unsigned int value;
 753	bool enable;
 754	int ret;
 755
 756	ret = kstrtobool(buf, &enable);
 757	if (ret < 0)
 758		return ret;
 759
 760	if (enable)
 761		value = 0;
 762	else
 763		value = LIGHTBAR_S3_OFF;
 764
 765	/* We only access a single register here, so we do not need to use data->led_lock */
 766	ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_S3_OFF, value);
 767	if (ret < 0)
 768		return ret;
 769
 770	return count;
 771}
 772
 773static ssize_t breathing_in_suspend_show(struct device *dev, struct device_attribute *attr,
 774					 char *buf)
 775{
 776	struct uniwill_data *data = dev_get_drvdata(dev);
 777	unsigned int value;
 778	int ret;
 779
 780	ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value);
 781	if (ret < 0)
 782		return ret;
 783
 784	return sysfs_emit(buf, "%d\n", !(value & LIGHTBAR_S3_OFF));
 785}
 786
 787static DEVICE_ATTR_RW(breathing_in_suspend);
 788
 789static struct attribute *uniwill_attrs[] = {
 790	/* Keyboard-related */
 791	&dev_attr_fn_lock_toggle_enable.attr,
 792	&dev_attr_super_key_toggle_enable.attr,
 793	&dev_attr_touchpad_toggle_enable.attr,
 794	/* Lightbar-related */
 795	&dev_attr_rainbow_animation.attr,
 796	&dev_attr_breathing_in_suspend.attr,
 797	NULL
 798};
 799
 800static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
 801{
 802	if (attr == &dev_attr_fn_lock_toggle_enable.attr) {
 803		if (supported_features & UNIWILL_FEATURE_FN_LOCK_TOGGLE)
 804			return attr->mode;
 805	}
 806
 807	if (attr == &dev_attr_super_key_toggle_enable.attr) {
 808		if (supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE)
 809			return attr->mode;
 810	}
 811
 812	if (attr == &dev_attr_touchpad_toggle_enable.attr) {
 813		if (supported_features & UNIWILL_FEATURE_TOUCHPAD_TOGGLE)
 814			return attr->mode;
 815	}
 816
 817	if (attr == &dev_attr_rainbow_animation.attr ||
 818	    attr == &dev_attr_breathing_in_suspend.attr) {
 819		if (supported_features & UNIWILL_FEATURE_LIGHTBAR)
 820			return attr->mode;
 821	}
 822
 823	return 0;
 824}
 825
 826static const struct attribute_group uniwill_group = {
 827	.is_visible = uniwill_attr_is_visible,
 828	.attrs = uniwill_attrs,
 829};
 830
 831static const struct attribute_group *uniwill_groups[] = {
 832	&uniwill_group,
 833	NULL
 834};
 835
 836static int uniwill_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
 837			long *val)
 838{
 839	struct uniwill_data *data = dev_get_drvdata(dev);
 840	unsigned int value;
 841	__be16 rpm;
 842	int ret;
 843
 844	switch (type) {
 845	case hwmon_temp:
 846		switch (channel) {
 847		case 0:
 848			ret = regmap_read(data->regmap, EC_ADDR_CPU_TEMP, &value);
 849			break;
 850		case 1:
 851			ret = regmap_read(data->regmap, EC_ADDR_GPU_TEMP, &value);
 852			break;
 853		default:
 854			return -EOPNOTSUPP;
 855		}
 856
 857		if (ret < 0)
 858			return ret;
 859
 860		*val = value * MILLIDEGREE_PER_DEGREE;
 861		return 0;
 862	case hwmon_fan:
 863		switch (channel) {
 864		case 0:
 865			ret = regmap_bulk_read(data->regmap, EC_ADDR_MAIN_FAN_RPM_1, &rpm,
 866					       sizeof(rpm));
 867			break;
 868		case 1:
 869			ret = regmap_bulk_read(data->regmap, EC_ADDR_SECOND_FAN_RPM_1, &rpm,
 870					       sizeof(rpm));
 871			break;
 872		default:
 873			return -EOPNOTSUPP;
 874		}
 875
 876		if (ret < 0)
 877			return ret;
 878
 879		*val = be16_to_cpu(rpm);
 880		return 0;
 881	case hwmon_pwm:
 882		switch (channel) {
 883		case 0:
 884			ret = regmap_read(data->regmap, EC_ADDR_PWM_1, &value);
 885			break;
 886		case 1:
 887			ret = regmap_read(data->regmap, EC_ADDR_PWM_2, &value);
 888			break;
 889		default:
 890			return -EOPNOTSUPP;
 891		}
 892
 893		if (ret < 0)
 894			return ret;
 895
 896		*val = fixp_linear_interpolate(0, 0, PWM_MAX, U8_MAX, value);
 897		return 0;
 898	default:
 899		return -EOPNOTSUPP;
 900	}
 901}
 902
 903static int uniwill_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
 904			       int channel, const char **str)
 905{
 906	switch (type) {
 907	case hwmon_temp:
 908		*str = uniwill_temp_labels[channel];
 909		return 0;
 910	case hwmon_fan:
 911		*str = uniwill_fan_labels[channel];
 912		return 0;
 913	default:
 914		return -EOPNOTSUPP;
 915	}
 916}
 917
 918static const struct hwmon_ops uniwill_ops = {
 919	.visible = 0444,
 920	.read = uniwill_read,
 921	.read_string = uniwill_read_string,
 922};
 923
 924static const struct hwmon_channel_info * const uniwill_info[] = {
 925	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
 926	HWMON_CHANNEL_INFO(temp,
 927			   HWMON_T_INPUT | HWMON_T_LABEL,
 928			   HWMON_T_INPUT | HWMON_T_LABEL),
 929	HWMON_CHANNEL_INFO(fan,
 930			   HWMON_F_INPUT | HWMON_F_LABEL,
 931			   HWMON_F_INPUT | HWMON_F_LABEL),
 932	HWMON_CHANNEL_INFO(pwm,
 933			   HWMON_PWM_INPUT,
 934			   HWMON_PWM_INPUT),
 935	NULL
 936};
 937
 938static const struct hwmon_chip_info uniwill_chip_info = {
 939	.ops = &uniwill_ops,
 940	.info = uniwill_info,
 941};
 942
 943static int uniwill_hwmon_init(struct uniwill_data *data)
 944{
 945	struct device *hdev;
 946
 947	if (!(supported_features & UNIWILL_FEATURE_HWMON))
 948		return 0;
 949
 950	hdev = devm_hwmon_device_register_with_info(data->dev, "uniwill", data,
 951						    &uniwill_chip_info, NULL);
 952
 953	return PTR_ERR_OR_ZERO(hdev);
 954}
 955
 956static const unsigned int uniwill_led_channel_to_bat_reg[LED_CHANNELS] = {
 957	EC_ADDR_LIGHTBAR_BAT_RED,
 958	EC_ADDR_LIGHTBAR_BAT_GREEN,
 959	EC_ADDR_LIGHTBAR_BAT_BLUE,
 960};
 961
 962static const unsigned int uniwill_led_channel_to_ac_reg[LED_CHANNELS] = {
 963	EC_ADDR_LIGHTBAR_AC_RED,
 964	EC_ADDR_LIGHTBAR_AC_GREEN,
 965	EC_ADDR_LIGHTBAR_AC_BLUE,
 966};
 967
 968static int uniwill_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness)
 969{
 970	struct led_classdev_mc *led_mc_cdev = lcdev_to_mccdev(led_cdev);
 971	struct uniwill_data *data = container_of(led_mc_cdev, struct uniwill_data, led_mc_cdev);
 972	unsigned int value;
 973	int ret;
 974
 975	ret = led_mc_calc_color_components(led_mc_cdev, brightness);
 976	if (ret < 0)
 977		return ret;
 978
 979	guard(mutex)(&data->led_lock);
 980
 981	for (int i = 0; i < LED_CHANNELS; i++) {
 982		/* Prevent the brightness values from overflowing */
 983		value = min(LED_MAX_BRIGHTNESS, data->led_mc_subled_info[i].brightness);
 984		ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value);
 985		if (ret < 0)
 986			return ret;
 987
 988		ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i], value);
 989		if (ret < 0)
 990			return ret;
 991	}
 992
 993	if (brightness)
 994		value = 0;
 995	else
 996		value = LIGHTBAR_S0_OFF;
 997
 998	ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_S0_OFF, value);
 999	if (ret < 0)
1000		return ret;
1001
1002	return regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_S0_OFF, value);
1003}
1004
1005#define LIGHTBAR_MASK	(LIGHTBAR_APP_EXISTS | LIGHTBAR_S0_OFF | LIGHTBAR_S3_OFF | LIGHTBAR_WELCOME)
1006
1007static int uniwill_led_init(struct uniwill_data *data)
1008{
1009	struct led_init_data init_data = {
1010		.devicename = DRIVER_NAME,
1011		.default_label = "multicolor:" LED_FUNCTION_STATUS,
1012		.devname_mandatory = true,
1013	};
1014	unsigned int color_indices[3] = {
1015		LED_COLOR_ID_RED,
1016		LED_COLOR_ID_GREEN,
1017		LED_COLOR_ID_BLUE,
1018	};
1019	unsigned int value;
1020	int ret;
1021
1022	if (!(supported_features & UNIWILL_FEATURE_LIGHTBAR))
1023		return 0;
1024
1025	ret = devm_mutex_init(data->dev, &data->led_lock);
1026	if (ret < 0)
1027		return ret;
1028
1029	/*
1030	 * The EC has separate lightbar settings for AC and battery mode,
1031	 * so we have to ensure that both settings are the same.
1032	 */
1033	ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value);
1034	if (ret < 0)
1035		return ret;
1036
1037	value |= LIGHTBAR_APP_EXISTS;
1038	ret = regmap_write(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, value);
1039	if (ret < 0)
1040		return ret;
1041
1042	/*
1043	 * The breathing animation during suspend is not supported when
1044	 * running on battery power.
1045	 */
1046	value |= LIGHTBAR_S3_OFF;
1047	ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_MASK, value);
1048	if (ret < 0)
1049		return ret;
1050
1051	data->led_mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI;
1052	data->led_mc_cdev.led_cdev.max_brightness = LED_MAX_BRIGHTNESS;
1053	data->led_mc_cdev.led_cdev.flags = LED_REJECT_NAME_CONFLICT;
1054	data->led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_led_brightness_set;
1055
1056	if (value & LIGHTBAR_S0_OFF)
1057		data->led_mc_cdev.led_cdev.brightness = 0;
1058	else
1059		data->led_mc_cdev.led_cdev.brightness = LED_MAX_BRIGHTNESS;
1060
1061	for (int i = 0; i < LED_CHANNELS; i++) {
1062		data->led_mc_subled_info[i].color_index = color_indices[i];
1063
1064		ret = regmap_read(data->regmap, uniwill_led_channel_to_ac_reg[i], &value);
1065		if (ret < 0)
1066			return ret;
1067
1068		/*
1069		 * Make sure that the initial intensity value is not greater than
1070		 * the maximum brightness.
1071		 */
1072		value = min(LED_MAX_BRIGHTNESS, value);
1073		ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value);
1074		if (ret < 0)
1075			return ret;
1076
1077		ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i], value);
1078		if (ret < 0)
1079			return ret;
1080
1081		data->led_mc_subled_info[i].intensity = value;
1082		data->led_mc_subled_info[i].channel = i;
1083	}
1084
1085	data->led_mc_cdev.subled_info = data->led_mc_subled_info;
1086	data->led_mc_cdev.num_colors = LED_CHANNELS;
1087
1088	return devm_led_classdev_multicolor_register_ext(data->dev, &data->led_mc_cdev,
1089							 &init_data);
1090}
1091
1092static int uniwill_get_property(struct power_supply *psy, const struct power_supply_ext *ext,
1093				void *drvdata, enum power_supply_property psp,
1094				union power_supply_propval *val)
1095{
1096	struct uniwill_data *data = drvdata;
1097	union power_supply_propval prop;
1098	unsigned int regval;
1099	int ret;
1100
1101	switch (psp) {
1102	case POWER_SUPPLY_PROP_HEALTH:
1103		ret = power_supply_get_property_direct(psy, POWER_SUPPLY_PROP_PRESENT, &prop);
1104		if (ret < 0)
1105			return ret;
1106
1107		if (!prop.intval) {
1108			val->intval = POWER_SUPPLY_HEALTH_NO_BATTERY;
1109			return 0;
1110		}
1111
1112		ret = power_supply_get_property_direct(psy, POWER_SUPPLY_PROP_STATUS, &prop);
1113		if (ret < 0)
1114			return ret;
1115
1116		if (prop.intval == POWER_SUPPLY_STATUS_UNKNOWN) {
1117			val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
1118			return 0;
1119		}
1120
1121		ret = regmap_read(data->regmap, EC_ADDR_BAT_ALERT, &regval);
1122		if (ret < 0)
1123			return ret;
1124
1125		if (regval) {
1126			/* Charging issue */
1127			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
1128			return 0;
1129		}
1130
1131		val->intval = POWER_SUPPLY_HEALTH_GOOD;
1132		return 0;
1133	case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
1134		ret = regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &regval);
1135		if (ret < 0)
1136			return ret;
1137
1138		val->intval = clamp_val(FIELD_GET(CHARGE_CTRL_MASK, regval), 0, 100);
1139		return 0;
1140	default:
1141		return -EINVAL;
1142	}
1143}
1144
1145static int uniwill_set_property(struct power_supply *psy, const struct power_supply_ext *ext,
1146				void *drvdata, enum power_supply_property psp,
1147				const union power_supply_propval *val)
1148{
1149	struct uniwill_data *data = drvdata;
1150
1151	switch (psp) {
1152	case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
1153		if (val->intval < 1 || val->intval > 100)
1154			return -EINVAL;
1155
1156		return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
1157					  val->intval);
1158	default:
1159		return -EINVAL;
1160	}
1161}
1162
1163static int uniwill_property_is_writeable(struct power_supply *psy,
1164					 const struct power_supply_ext *ext, void *drvdata,
1165					 enum power_supply_property psp)
1166{
1167	if (psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD)
1168		return true;
1169
1170	return false;
1171}
1172
1173static const enum power_supply_property uniwill_properties[] = {
1174	POWER_SUPPLY_PROP_HEALTH,
1175	POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
1176};
1177
1178static const struct power_supply_ext uniwill_extension = {
1179	.name = DRIVER_NAME,
1180	.properties = uniwill_properties,
1181	.num_properties = ARRAY_SIZE(uniwill_properties),
1182	.get_property = uniwill_get_property,
1183	.set_property = uniwill_set_property,
1184	.property_is_writeable = uniwill_property_is_writeable,
1185};
1186
1187static int uniwill_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
1188{
1189	struct uniwill_data *data = container_of(hook, struct uniwill_data, hook);
1190	struct uniwill_battery_entry *entry;
1191	int ret;
1192
1193	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1194	if (!entry)
1195		return -ENOMEM;
1196
1197	ret = power_supply_register_extension(battery, &uniwill_extension, data->dev, data);
1198	if (ret < 0) {
1199		kfree(entry);
1200		return ret;
1201	}
1202
1203	guard(mutex)(&data->battery_lock);
1204
1205	entry->battery = battery;
1206	list_add(&entry->head, &data->batteries);
1207
1208	return 0;
1209}
1210
1211static int uniwill_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
1212{
1213	struct uniwill_data *data = container_of(hook, struct uniwill_data, hook);
1214	struct uniwill_battery_entry *entry, *tmp;
1215
1216	scoped_guard(mutex, &data->battery_lock) {
1217		list_for_each_entry_safe(entry, tmp, &data->batteries, head) {
1218			if (entry->battery == battery) {
1219				list_del(&entry->head);
1220				kfree(entry);
1221				break;
1222			}
1223		}
1224	}
1225
1226	power_supply_unregister_extension(battery, &uniwill_extension);
1227
1228	return 0;
1229}
1230
1231static int uniwill_battery_init(struct uniwill_data *data)
1232{
1233	int ret;
1234
1235	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
1236		return 0;
1237
1238	ret = devm_mutex_init(data->dev, &data->battery_lock);
1239	if (ret < 0)
1240		return ret;
1241
1242	INIT_LIST_HEAD(&data->batteries);
1243	data->hook.name = "Uniwill Battery Extension";
1244	data->hook.add_battery = uniwill_add_battery;
1245	data->hook.remove_battery = uniwill_remove_battery;
1246
1247	return devm_battery_hook_register(data->dev, &data->hook);
1248}
1249
1250static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action, void *dummy)
1251{
1252	struct uniwill_data *data = container_of(nb, struct uniwill_data, nb);
1253	struct uniwill_battery_entry *entry;
1254
1255	switch (action) {
1256	case UNIWILL_OSD_BATTERY_ALERT:
1257		mutex_lock(&data->battery_lock);
1258		list_for_each_entry(entry, &data->batteries, head) {
1259			power_supply_changed(entry->battery);
1260		}
1261		mutex_unlock(&data->battery_lock);
1262
1263		return NOTIFY_OK;
1264	case UNIWILL_OSD_DC_ADAPTER_CHANGED:
1265		/* noop for the time being, will change once charging priority
1266		 * gets implemented.
1267		 */
1268
1269		return NOTIFY_OK;
1270	default:
1271		mutex_lock(&data->input_lock);
1272		sparse_keymap_report_event(data->input_device, action, 1, true);
1273		mutex_unlock(&data->input_lock);
1274
1275		return NOTIFY_OK;
1276	}
1277}
1278
1279static int uniwill_input_init(struct uniwill_data *data)
1280{
1281	int ret;
1282
1283	ret = devm_mutex_init(data->dev, &data->input_lock);
1284	if (ret < 0)
1285		return ret;
1286
1287	data->input_device = devm_input_allocate_device(data->dev);
1288	if (!data->input_device)
1289		return -ENOMEM;
1290
1291	ret = sparse_keymap_setup(data->input_device, uniwill_keymap, NULL);
1292	if (ret < 0)
1293		return ret;
1294
1295	data->input_device->name = "Uniwill WMI hotkeys";
1296	data->input_device->phys = "wmi/input0";
1297	data->input_device->id.bustype = BUS_HOST;
1298	ret = input_register_device(data->input_device);
1299	if (ret < 0)
1300		return ret;
1301
1302	data->nb.notifier_call = uniwill_notifier_call;
1303
1304	return devm_uniwill_wmi_register_notifier(data->dev, &data->nb);
1305}
1306
1307static void uniwill_disable_manual_control(void *context)
1308{
1309	struct uniwill_data *data = context;
1310
1311	regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
1312}
1313
1314static int uniwill_ec_init(struct uniwill_data *data)
1315{
1316	unsigned int value;
1317	int ret;
1318
1319	ret = regmap_read(data->regmap, EC_ADDR_PROJECT_ID, &value);
1320	if (ret < 0)
1321		return ret;
1322
1323	dev_dbg(data->dev, "Project ID: %u\n", value);
1324
1325	ret = regmap_set_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
1326	if (ret < 0)
1327		return ret;
1328
1329	return devm_add_action_or_reset(data->dev, uniwill_disable_manual_control, data);
1330}
1331
1332static int uniwill_probe(struct platform_device *pdev)
1333{
1334	struct uniwill_data *data;
1335	struct regmap *regmap;
1336	acpi_handle handle;
1337	int ret;
1338
1339	handle = ACPI_HANDLE(&pdev->dev);
1340	if (!handle)
1341		return -ENODEV;
1342
1343	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
1344	if (!data)
1345		return -ENOMEM;
1346
1347	data->dev = &pdev->dev;
1348	data->handle = handle;
1349	platform_set_drvdata(pdev, data);
1350
1351	regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, &uniwill_ec_config);
1352	if (IS_ERR(regmap))
1353		return PTR_ERR(regmap);
1354
1355	data->regmap = regmap;
1356	ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
1357	if (ret < 0)
1358		return ret;
1359
1360	ret = uniwill_ec_init(data);
1361	if (ret < 0)
1362		return ret;
1363
1364	ret = uniwill_battery_init(data);
1365	if (ret < 0)
1366		return ret;
1367
1368	ret = uniwill_led_init(data);
1369	if (ret < 0)
1370		return ret;
1371
1372	ret = uniwill_hwmon_init(data);
1373	if (ret < 0)
1374		return ret;
1375
1376	return uniwill_input_init(data);
1377}
1378
1379static void uniwill_shutdown(struct platform_device *pdev)
1380{
1381	struct uniwill_data *data = platform_get_drvdata(pdev);
1382
1383	regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
1384}
1385
1386static int uniwill_suspend_keyboard(struct uniwill_data *data)
1387{
1388	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
1389		return 0;
1390
1391	/*
1392	 * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to restore it
1393	 * ourselves.
1394	 */
1395	return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &data->last_switch_status);
1396}
1397
1398static int uniwill_suspend_battery(struct uniwill_data *data)
1399{
1400	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
1401		return 0;
1402
1403	/*
1404	 * Save the current charge limit in order to restore it during resume.
1405	 * We cannot use the regmap code for that since this register needs to
1406	 * be declared as volatile due to CHARGE_CTRL_REACHED.
1407	 */
1408	return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &data->last_charge_ctrl);
1409}
1410
1411static int uniwill_suspend(struct device *dev)
1412{
1413	struct uniwill_data *data = dev_get_drvdata(dev);
1414	int ret;
1415
1416	ret = uniwill_suspend_keyboard(data);
1417	if (ret < 0)
1418		return ret;
1419
1420	ret = uniwill_suspend_battery(data);
1421	if (ret < 0)
1422		return ret;
1423
1424	regcache_cache_only(data->regmap, true);
1425	regcache_mark_dirty(data->regmap);
1426
1427	return 0;
1428}
1429
1430static int uniwill_resume_keyboard(struct uniwill_data *data)
1431{
1432	unsigned int value;
1433	int ret;
1434
1435	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
1436		return 0;
1437
1438	ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
1439	if (ret < 0)
1440		return ret;
1441
1442	if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & SUPER_KEY_LOCK_STATUS))
1443		return 0;
1444
1445	return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK,
1446				 TRIGGER_SUPER_KEY_LOCK);
1447}
1448
1449static int uniwill_resume_battery(struct uniwill_data *data)
1450{
1451	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
1452		return 0;
1453
1454	return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
1455				  data->last_charge_ctrl);
1456}
1457
1458static int uniwill_resume(struct device *dev)
1459{
1460	struct uniwill_data *data = dev_get_drvdata(dev);
1461	int ret;
1462
1463	regcache_cache_only(data->regmap, false);
1464
1465	ret = regcache_sync(data->regmap);
1466	if (ret < 0)
1467		return ret;
1468
1469	ret = uniwill_resume_keyboard(data);
1470	if (ret < 0)
1471		return ret;
1472
1473	return uniwill_resume_battery(data);
1474}
1475
1476static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume);
1477
1478/*
1479 * We only use the DMI table for auoloading because the ACPI device itself
1480 * does not guarantee that the underlying EC implementation is supported.
1481 */
1482static const struct acpi_device_id uniwill_id_table[] = {
1483	{ "INOU0000" },
1484	{ },
1485};
1486
1487static struct platform_driver uniwill_driver = {
1488	.driver = {
1489		.name = DRIVER_NAME,
1490		.dev_groups = uniwill_groups,
1491		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
1492		.acpi_match_table = uniwill_id_table,
1493		.pm = pm_sleep_ptr(&uniwill_pm_ops),
1494	},
1495	.probe = uniwill_probe,
1496	.shutdown = uniwill_shutdown,
1497};
1498
1499static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
1500	{
1501		.ident = "XMG FUSION 15",
1502		.matches = {
1503			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
1504			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
1505		},
1506	},
1507	{
1508		.ident = "XMG FUSION 15",
1509		.matches = {
1510			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
1511			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
1512		},
1513	},
1514	{
1515		.ident = "Intel NUC x15",
1516		.matches = {
1517			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
1518			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LAPAC71H"),
1519		},
1520		.driver_data = (void *)(UNIWILL_FEATURE_FN_LOCK_TOGGLE |
1521					UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
1522					UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
1523					UNIWILL_FEATURE_BATTERY |
1524					UNIWILL_FEATURE_HWMON),
1525	},
1526	{
1527		.ident = "Intel NUC x15",
1528		.matches = {
1529			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
1530			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LAPKC71F"),
1531		},
1532		.driver_data = (void *)(UNIWILL_FEATURE_FN_LOCK_TOGGLE |
1533					UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
1534					UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
1535					UNIWILL_FEATURE_LIGHTBAR |
1536					UNIWILL_FEATURE_BATTERY |
1537					UNIWILL_FEATURE_HWMON),
1538	},
1539	{
1540		.ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
1541		.matches = {
1542			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1543			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"),
1544		},
1545	},
1546	{
1547		.ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
1548		.matches = {
1549			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1550			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
1551		},
1552	},
1553	{
1554		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
1555		.matches = {
1556			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1557			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
1558		},
1559	},
1560	{
1561		.ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore Omnia-Book Pro Gen 7",
1562		.matches = {
1563			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1564			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
1565		},
1566	},
1567	{
1568		.ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
1569		.matches = {
1570			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1571			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"),
1572		},
1573	},
1574	{
1575		.ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
1576		.matches = {
1577			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1578			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
1579		},
1580	},
1581	{
1582		.ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
1583		.matches = {
1584			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1585			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
1586		},
1587	},
1588	{
1589		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
1590		.matches = {
1591			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1592			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"),
1593		},
1594	},
1595	{
1596		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9",
1597		.matches = {
1598			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1599			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"),
1600		},
1601	},
1602	{
1603		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
1604		.matches = {
1605			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1606			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
1607		},
1608	},
1609	{
1610		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
1611		.matches = {
1612			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1613			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
1614		},
1615	},
1616	{
1617		.ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel",
1618		.matches = {
1619			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1620			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"),
1621		},
1622	},
1623	{
1624		.ident = "TUXEDO InfinityBook Max 15 Gen10 AMD",
1625		.matches = {
1626			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1627			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"),
1628		},
1629	},
1630	{
1631		.ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
1632		.matches = {
1633			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1634			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6HP45xU"),
1635		},
1636	},
1637	{
1638		.ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
1639		.matches = {
1640			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1641			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"),
1642		},
1643	},
1644	{
1645		.ident = "TUXEDO InfinityBook Max 15 Gen10 Intel",
1646		.matches = {
1647			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1648			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5AR45xS"),
1649		},
1650	},
1651	{
1652		.ident = "TUXEDO InfinityBook Max 16 Gen10 Intel",
1653		.matches = {
1654			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1655			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR55xU"),
1656		},
1657	},
1658	{
1659		.ident = "TUXEDO Polaris 15 Gen1 AMD",
1660		.matches = {
1661			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1662			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
1663		},
1664	},
1665	{
1666		.ident = "TUXEDO Polaris 15 Gen1 AMD",
1667		.matches = {
1668			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1669			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
1670		},
1671	},
1672	{
1673		.ident = "TUXEDO Polaris 17 Gen1 AMD",
1674		.matches = {
1675			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1676			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
1677		},
1678	},
1679	{
1680		.ident = "TUXEDO Polaris 17 Gen1 AMD",
1681		.matches = {
1682			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1683			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
1684		},
1685	},
1686	{
1687		.ident = "TUXEDO Polaris 15 Gen1 Intel",
1688		.matches = {
1689			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1690			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"),
1691		},
1692	},
1693	{
1694		.ident = "TUXEDO Polaris 15 Gen1 Intel",
1695		.matches = {
1696			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1697			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"),
1698		},
1699	},
1700	{
1701		.ident = "TUXEDO Polaris 17 Gen1 Intel",
1702		.matches = {
1703			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1704			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"),
1705		},
1706	},
1707	{
1708		.ident = "TUXEDO Polaris 17 Gen1 Intel",
1709		.matches = {
1710			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1711			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"),
1712		},
1713	},
1714	{
1715		.ident = "TUXEDO Trinity 15 Intel Gen1",
1716		.matches = {
1717			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1718			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"),
1719		},
1720	},
1721	{
1722		.ident = "TUXEDO Trinity 17 Intel Gen1",
1723		.matches = {
1724			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1725			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"),
1726		},
1727	},
1728	{
1729		.ident = "TUXEDO Polaris 15/17 Gen2 AMD",
1730		.matches = {
1731			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1732			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
1733		},
1734	},
1735	{
1736		.ident = "TUXEDO Polaris 15/17 Gen2 Intel",
1737		.matches = {
1738			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1739			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
1740		},
1741	},
1742	{
1743		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
1744		.matches = {
1745			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1746			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
1747		},
1748	},
1749	{
1750		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
1751		.matches = {
1752			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1753			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
1754		},
1755	},
1756	{
1757		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
1758		.matches = {
1759			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1760			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
1761		},
1762	},
1763	{
1764		.ident = "TUXEDO Stellaris 15 Gen4 Intel",
1765		.matches = {
1766			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1767			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
1768		},
1769	},
1770	{
1771		.ident = "TUXEDO Polaris 15/17 Gen5 AMD",
1772		.matches = {
1773			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1774			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
1775		},
1776	},
1777	{
1778		.ident = "TUXEDO Stellaris 16 Gen5 AMD",
1779		.matches = {
1780			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1781			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
1782		},
1783	},
1784	{
1785		.ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
1786		.matches = {
1787			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1788			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
1789		},
1790	},
1791	{
1792		.ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
1793		.matches = {
1794			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1795			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
1796		},
1797	},
1798	{
1799		.ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6",
1800		.matches = {
1801			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1802			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
1803		},
1804	},
1805	{
1806		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
1807		.matches = {
1808			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1809			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
1810		},
1811	},
1812	{
1813		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
1814		.matches = {
1815			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1816			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
1817		},
1818	},
1819	{
1820		.ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
1821		.matches = {
1822			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1823			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
1824		},
1825	},
1826	{
1827		.ident = "TUXEDO Stellaris 16 Gen7 AMD",
1828		.matches = {
1829			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1830			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
1831		},
1832	},
1833	{
1834		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
1835		.matches = {
1836			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1837			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
1838		},
1839	},
1840	{
1841		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
1842		.matches = {
1843			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1844			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
1845		},
1846	},
1847	{
1848		.ident = "TUXEDO Book BA15 Gen10 AMD",
1849		.matches = {
1850			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1851			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
1852		},
1853	},
1854	{
1855		.ident = "TUXEDO Pulse 14 Gen1 AMD",
1856		.matches = {
1857			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1858			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"),
1859		},
1860	},
1861	{
1862		.ident = "TUXEDO Pulse 15 Gen1 AMD",
1863		.matches = {
1864			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1865			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"),
1866		},
1867	},
1868	{
1869		.ident = "TUXEDO Pulse 15 Gen2 AMD",
1870		.matches = {
1871			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
1872			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
1873		},
1874	},
1875	{ }
1876};
1877MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
1878
1879static int __init uniwill_init(void)
1880{
1881	const struct dmi_system_id *id;
1882	int ret;
1883
1884	id = dmi_first_match(uniwill_dmi_table);
1885	if (!id) {
1886		if (!force)
1887			return -ENODEV;
1888
1889		/* Assume that the device supports all features */
1890		supported_features = UINT_MAX;
1891		pr_warn("Loading on a potentially unsupported device\n");
1892	} else {
1893		supported_features = (uintptr_t)id->driver_data;
1894	}
1895
1896	ret = platform_driver_register(&uniwill_driver);
1897	if (ret < 0)
1898		return ret;
1899
1900	ret = uniwill_wmi_register_driver();
1901	if (ret < 0) {
1902		platform_driver_unregister(&uniwill_driver);
1903		return ret;
1904	}
1905
1906	return 0;
1907}
1908module_init(uniwill_init);
1909
1910static void __exit uniwill_exit(void)
1911{
1912	uniwill_wmi_unregister_driver();
1913	platform_driver_unregister(&uniwill_driver);
1914}
1915module_exit(uniwill_exit);
1916
1917MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>");
1918MODULE_DESCRIPTION("Uniwill notebook driver");
1919MODULE_LICENSE("GPL");
~/ Read-only file preview.