diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 52fcac5b393a..3f945b4cf115 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -1,32 +1,65 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- *  Huawei WMI hotkeys
+ *  Huawei WMI laptop extras driver
  *
  *  Copyright (C) 2018	      Ayman Bagabas <ayman.bagabas@gmail.com>
  */
 
 #include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
 #include <linux/leds.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
 #include <linux/wmi.h>
 
 /*
  * Huawei WMI GUIDs
  */
-#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
+#define AMW0_METHOD_GUID "ABBC0F5B-8EA1-11D1-A000-C90629100000"
 #define AMW0_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
 
+/* Legacy GUIDs */
 #define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
+#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
+
+/* AMW0_commands */
+
+enum wmaa_cmd {
+	BATTERY_GET, /* \GBTT 0x00001103 */
+	BATTERY_SET, /* \SBTT 0xXXYY1003 */
+	FN_LOCK_GET, /* \GFRS 0x00000604 */
+	FN_LOCK_SET, /* \SFRS 0x000X0704 */
+	MICMUTE_LED, /* \SMLS 0x000X0b04 */
+};
+
+enum fn_state {
+	FN_LOCK_OFF = 0x01,
+	FN_LOCK_ON = 0x02,
+};
+
+struct quirk_entry {
+	bool battery_sleep;
+	bool ec_micmute;
+	bool report_brightness;
+};
 
-struct huawei_wmi_priv {
-	struct input_dev *idev;
+static struct quirk_entry *quirks;
+
+struct huawei_wmi {
 	struct led_classdev cdev;
-	acpi_handle handle;
-	char *acpi_method;
+	struct mutex wmi_lock;
+	struct mutex battery_lock;
+	struct input_dev *idev[2];
+	struct platform_device *pdev;
 };
 
+struct platform_device *huawei_wmi_pdev;
+
 static const struct key_entry huawei_wmi_keymap[] = {
 	{ KE_KEY,    0x281, { KEY_BRIGHTNESSDOWN } },
 	{ KE_KEY,    0x282, { KEY_BRIGHTNESSUP } },
@@ -37,73 +70,183 @@ static const struct key_entry huawei_wmi_keymap[] = {
 	{ KE_KEY,    0x289, { KEY_WLAN } },
 	// Huawei |M| key
 	{ KE_KEY,    0x28a, { KEY_CONFIG } },
-	// Keyboard backlight
+	// Keyboard backlit
 	{ KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } },
 	{ KE_IGNORE, 0x294, { KEY_KBDILLUMUP } },
 	{ KE_IGNORE, 0x295, { KEY_KBDILLUMUP } },
 	{ KE_END,	 0 }
 };
 
-static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
-		enum led_brightness brightness)
+static bool battery_sleep;
+static bool report_brightness;
+
+module_param(battery_sleep, bool, 0444);
+MODULE_PARM_DESC(battery_sleep,
+		"Delay after setting battery charging thresholds.");
+module_param(report_brightness, bool, 0444);
+MODULE_PARM_DESC(report_brightness,
+		"Report brightness key events.");
+
+/* Quirks */
+
+static int __init dmi_matched(const struct dmi_system_id *dmi)
 {
-	struct huawei_wmi_priv *priv = dev_get_drvdata(led_cdev->dev->parent);
+	quirks = dmi->driver_data;
+	return 1;
+}
+
+static struct quirk_entry quirk_unknown = {
+};
+
+static struct quirk_entry quirk_battery_sleep = {
+	.battery_sleep = true,
+};
+
+static struct quirk_entry quirk_matebook_x = {
+	.ec_micmute = true,
+	.report_brightness = true,
+};
+
+static const struct dmi_system_id huawei_quirks[] = {
+	{
+		.callback = dmi_matched,
+		.ident = "Huawei MACH-WX9",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MACH-WX9"),
+		},
+		.driver_data = &quirk_battery_sleep
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Huawei MateBook X",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HUAWEI MateBook X")
+		},
+		.driver_data = &quirk_matebook_x
+	},
+	{  }
+};
+
+/* Utils */
+
+static int huawei_wmi_eval(struct device *dev, u8 *arg,
+		u8 *buf, size_t buflen)
+{
+	struct huawei_wmi *huawei = dev_get_drvdata(dev);
+	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer in;
+	union acpi_object *obj;
 	acpi_status status;
-	union acpi_object args[3];
-	struct acpi_object_list arg_list = {
-		.pointer = args,
-		.count = ARRAY_SIZE(args),
-	};
-
-	args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
-	args[1].integer.value = 0x04;
-
-	if (strcmp(priv->acpi_method, "SPIN") == 0) {
-		args[0].integer.value = 0;
-		args[2].integer.value = brightness ? 1 : 0;
-	} else if (strcmp(priv->acpi_method, "WPIN") == 0) {
-		args[0].integer.value = 1;
-		args[2].integer.value = brightness ? 0 : 1;
-	} else {
-		return -EINVAL;
+	size_t len;
+	int err = -EIO;
+
+	in.length = sizeof(u8) * 4;
+	in.pointer = (u32 *)arg;
+	mutex_lock(&huawei->wmi_lock);
+	status = wmi_evaluate_method(AMW0_METHOD_GUID, 0, 1, &in, &out);
+	if (ACPI_FAILURE(status)) {
+		dev_err(dev, "Failed to evaluate wmi method\n");
+		err = -ENODEV;
+		goto wmi_eval_fail;
+	}
+
+	/* WMAA takes a 4 bytes buffer as an input. It returns a package
+	 * with two buffer elements. The first buffer is 4 bytes long and
+	 * the second is 0x100 (256) bytes long. The first buffer is always
+	 * zeros. The second stores the output from every call. The first
+	 * byte of the second buffer always have the return status of the
+	 * called command.
+	 */
+	obj = out.pointer;
+	if (!obj)
+		goto wmi_eval_fail;
+	if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 2) {
+		dev_err(dev, "Unknown response type %d\n", obj->type);
+		goto wmi_eval_fail;
 	}
 
-	status = acpi_evaluate_object(priv->handle, priv->acpi_method, &arg_list, NULL);
-	if (ACPI_FAILURE(status))
-		return -ENXIO;
+	obj = &(obj->package.elements[1]);
+	if (!obj || obj->type != ACPI_TYPE_BUFFER)
+		goto wmi_eval_fail;
 
-	return 0;
+	if (buf) {
+		len = min(buflen, obj->buffer.length);
+		memcpy(buf, obj->buffer.pointer, len);
+	}
+	err = 0;
+
+wmi_eval_fail:
+	mutex_unlock(&huawei->wmi_lock);
+	kfree(out.pointer);
+	return err;
 }
 
-static int huawei_wmi_leds_setup(struct wmi_device *wdev)
+static int huawei_wmi_cmd(struct device *dev, enum wmaa_cmd cmd, u8 *arg,
+		u8 *out, size_t outlen)
 {
-	struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
-
-	priv->handle = ec_get_handle();
-	if (!priv->handle)
-		return 0;
+	u8 parm[4] = { 0 };
+	u8 buf[0x100] = { 0xff };
+	int err;
 
-	if (acpi_has_method(priv->handle, "SPIN"))
-		priv->acpi_method = "SPIN";
-	else if (acpi_has_method(priv->handle, "WPIN"))
-		priv->acpi_method = "WPIN";
-	else
-		return 0;
+	if (!arg)
+		arg = parm;
+
+	switch (cmd) {
+	case BATTERY_SET:
+		arg[0] = 0x03;
+		arg[1] = 0x10;
+		break;
+	case BATTERY_GET:
+		arg[0] = 0x03;
+		arg[1] = 0x11;
+		break;
+	case FN_LOCK_GET:
+		arg[0] = 0x04;
+		arg[1] = 0x06;
+		break;
+	case FN_LOCK_SET:
+		arg[0] = 0x04;
+		arg[1] = 0x07;
+		break;
+	case MICMUTE_LED:
+		arg[0] = 0x04;
+		arg[1] = 0x0b;
+		break;
+	default:
+		dev_err(dev, "Unsupported command, got: 0x%08x\n", *(u32 *)arg);
+		return -EINVAL;
+	}
 
-	priv->cdev.name = "platform::micmute";
-	priv->cdev.max_brightness = 1;
-	priv->cdev.brightness_set_blocking = huawei_wmi_micmute_led_set;
-	priv->cdev.default_trigger = "audio-micmute";
-	priv->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
-	priv->cdev.dev = &wdev->dev;
-	priv->cdev.flags = LED_CORE_SUSPENDRESUME;
+	/* Some models require calling WMAA twice to execute
+	 * a command. We call WMAA and if we get a non-zero return
+	 * status we evaluate WMAA again. If we get another non-zero
+	 * return, we return -EIO. This way we don't need to
+	 * check for return status anywhere we call huawei_wmi_cmd.
+	 */
+	err = huawei_wmi_eval(dev, arg, buf, 0x100);
+	if (err)
+		return err;
+	if (buf[0]) {
+		err = huawei_wmi_eval(dev, arg, buf, 0x100);
+		if (err)
+			return err;
+		if (buf[0]) {
+			dev_err(dev, "Invalid response, got: %d\n", buf[0]);
+			return -EIO;
+		}
+	}
+	if (out)
+		memcpy(out, buf, outlen);
 
-	return devm_led_classdev_register(&wdev->dev, &priv->cdev);
+	return 0;
 }
 
-static void huawei_wmi_process_key(struct wmi_device *wdev, int code)
+/* Input */
+
+static void huawei_wmi_process_key(struct input_dev *idev, int code)
 {
-	struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
 	const struct key_entry *key;
 
 	/*
@@ -127,81 +270,390 @@ static void huawei_wmi_process_key(struct wmi_device *wdev, int code)
 		kfree(response.pointer);
 	}
 
-	key = sparse_keymap_entry_from_scancode(priv->idev, code);
+	key = sparse_keymap_entry_from_scancode(idev, code);
 	if (!key) {
-		dev_info(&wdev->dev, "Unknown key pressed, code: 0x%04x\n", code);
+		dev_info(&idev->dev, "Unknown key pressed, code: 0x%04x\n", code);
 		return;
 	}
 
-	sparse_keymap_report_entry(priv->idev, key, 1, true);
+	if (quirks && !quirks->report_brightness &&
+			(key->sw.code == KEY_BRIGHTNESSDOWN ||
+			key->sw.code == KEY_BRIGHTNESSUP))
+		return;
+
+	sparse_keymap_report_entry(idev, key, 1, true);
 }
 
-static void huawei_wmi_notify(struct wmi_device *wdev,
-		union acpi_object *obj)
+static void huawei_wmi_input_notify(u32 value, void *context)
 {
-	if (obj->type == ACPI_TYPE_INTEGER)
-		huawei_wmi_process_key(wdev, obj->integer.value);
+	struct input_dev *idev = (struct input_dev *)context;
+	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	acpi_status status;
+
+	if (!idev) {
+		dev_err(&huawei_wmi_pdev->dev, "No input_dev\n");
+		return;
+	}
+
+	status = wmi_get_event_data(value, &response);
+	if (ACPI_FAILURE(status)) {
+		dev_err(&idev->dev, "Unable to get event data\n");
+		return;
+	}
+
+	obj = (union acpi_object *)response.pointer;
+	if (obj && obj->type == ACPI_TYPE_INTEGER)
+		huawei_wmi_process_key(idev, obj->integer.value);
 	else
-		dev_info(&wdev->dev, "Bad response type %d\n", obj->type);
+		dev_err(&idev->dev, "Bad response type\n");
+
+	kfree(response.pointer);
 }
 
-static int huawei_wmi_input_setup(struct wmi_device *wdev)
+static int huawei_wmi_input_setup(struct platform_device *pdev,
+		struct input_dev **idev)
 {
-	struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
 	int err;
 
-	priv->idev = devm_input_allocate_device(&wdev->dev);
-	if (!priv->idev)
+	*idev = devm_input_allocate_device(&pdev->dev);
+	if (!*idev)
 		return -ENOMEM;
 
-	priv->idev->name = "Huawei WMI hotkeys";
-	priv->idev->phys = "wmi/input0";
-	priv->idev->id.bustype = BUS_HOST;
-	priv->idev->dev.parent = &wdev->dev;
+	(*idev)->name = "Huawei WMI hotkeys";
+	(*idev)->phys = "wmi/input0";
+	(*idev)->id.bustype = BUS_HOST;
+	(*idev)->dev.parent = &pdev->dev;
+
+	err = sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL);
+	if (err)
+		return err;
+
+	return input_register_device(*idev);
+}
+
+/* LEDs */
+
+static void huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
+		enum led_brightness brightness)
+{
+	/* This is a workaround until the "legacy" interface is implemented. */
+	if (quirks && quirks->ec_micmute) {
+		char *acpi_method;
+		acpi_handle handle;
+		union acpi_object args[3];
+		struct acpi_object_list arg_list = {
+			.pointer = args,
+			.count = ARRAY_SIZE(args),
+		};
+
+		handle = ec_get_handle();
+		if (!handle) {
+			dev_err(led_cdev->dev->parent, "Failed to get EC handle\n");
+			return;
+		}
+
+		args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
+		args[1].integer.value = 0x04;
+
+		if (acpi_has_method(handle, "SPIN")) {
+			acpi_method = "SPIN";
+			args[0].integer.value = 0;
+			args[2].integer.value = brightness ? 1 : 0;
+		} else if (acpi_has_method(handle, "WPIN")) {
+			acpi_method = "WPIN";
+			args[0].integer.value = 1;
+			args[2].integer.value = brightness ? 0 : 1;
+		} else {
+			return;
+		}
+
+		acpi_evaluate_object(handle, acpi_method, &arg_list, NULL);
+	} else {
+		u8 arg[] = { 0, 0, brightness, 0 };
+
+		huawei_wmi_cmd(led_cdev->dev->parent, MICMUTE_LED, arg, NULL, NULL);
+	}
+}
+
+static int huawei_wmi_leds_setup(struct device *dev)
+{
+	struct huawei_wmi *huawei = dev_get_drvdata(dev);
 
-	err = sparse_keymap_setup(priv->idev, huawei_wmi_keymap, NULL);
+	huawei->cdev.name = "platform::micmute";
+	huawei->cdev.max_brightness = 1;
+	huawei->cdev.brightness_set = huawei_wmi_micmute_led_set;
+	huawei->cdev.default_trigger = "audio-micmute";
+	huawei->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
+	huawei->cdev.dev = dev->parent;
+	huawei->cdev.flags = LED_CORE_SUSPENDRESUME;
+
+	return devm_led_classdev_register(dev, &huawei->cdev);
+}
+
+/* Battery protection */
+
+static int huawei_wmi_battery_get(struct device *dev, int *low, int *high)
+{
+	struct huawei_wmi *huawei = dev_get_drvdata(dev);
+	u8 ret[0x100] = { 0 };
+	int err, i = 0x100;
+
+	mutex_lock(&huawei->battery_lock);
+	err = huawei_wmi_cmd(dev, BATTERY_GET, NULL, ret, 0x100);
+	mutex_unlock(&huawei->battery_lock);
 	if (err)
 		return err;
 
-	return input_register_device(priv->idev);
+	/* Returned buffer positions battery thresholds either in index
+	 * 3 and 2 or in 2 and 1. 0 reserved for return status. We
+	 * find the first non-zero value.
+	 */
+	while (i > 0 && !ret[i--])
+		;
+	*low = ret[i];
+	*high = ret[i+1];
+
+	return 0;
 }
 
-static int huawei_wmi_probe(struct wmi_device *wdev)
+static int huawei_wmi_battery_set(struct device *dev, int low, int high)
 {
-	struct huawei_wmi_priv *priv;
+	struct huawei_wmi *huawei = dev_get_drvdata(dev);
+	u8 arg[] = { 0, 0, low, high };
 	int err;
 
-	priv = devm_kzalloc(&wdev->dev, sizeof(struct huawei_wmi_priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	/* This is an edge case were some models turn battery protection
+	 * off without changing their thresholds values. We clear the
+	 * values before turning off protection. We need a blocking delay to
+	 * make sure these values make their way to EC.
+	 */
+	if (low == 0 && high == 100)
+		huawei_wmi_battery_set(dev, 0, 0);
 
-	dev_set_drvdata(&wdev->dev, priv);
+	mutex_lock(&huawei->battery_lock);
+	err = huawei_wmi_cmd(dev, BATTERY_SET, arg, NULL, NULL);
+	if (quirks && quirks->battery_sleep)
+		msleep(1000);
+	mutex_unlock(&huawei->battery_lock);
 
-	err = huawei_wmi_input_setup(wdev);
+	return err;
+}
+
+/* Fn lock */
+
+static int huawei_wmi_fn_lock_get(struct device *dev, int *on)
+{
+	u8 ret[0x100] = { 0 };
+	int err, i = 0;
+
+	err = huawei_wmi_cmd(dev, FN_LOCK_GET, NULL, ret, 0x100);
 	if (err)
 		return err;
 
-	return huawei_wmi_leds_setup(wdev);
+	/* Find the first non-zero value */
+	while (i <= 0x100 && !ret[i++])
+		;
+	*on = (ret[i-1] == FN_LOCK_OFF) ? 0 : 1;
+
+	return 0;
 }
 
-static const struct wmi_device_id huawei_wmi_id_table[] = {
-	{ .guid_string = WMI0_EVENT_GUID },
-	{ .guid_string = AMW0_EVENT_GUID },
-	{  }
+static int huawei_wmi_fn_lock_set(struct device *dev, int on)
+{
+	u8 arg[] = { 0, 0, (on) ? FN_LOCK_ON : FN_LOCK_OFF, 0 };
+
+	return huawei_wmi_cmd(dev, FN_LOCK_SET, arg, NULL, NULL);
+}
+
+/* sysfs */
+
+static ssize_t charge_thresholds_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t size)
+{
+	int low, high, err;
+
+	if (sscanf(buf, "%d %d", &low, &high) != 2 ||
+			low < 0 || high > 100 ||
+			low > high)
+		return -EINVAL;
+
+	err = huawei_wmi_battery_set(dev, low, high);
+	if (err)
+		return err;
+
+	return size;
+}
+
+static ssize_t fn_lock_state_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t size)
+{
+	int on, err;
+
+	if (kstrtoint(buf, 10, &on) ||
+			on < 0 || on > 1)
+		return -EINVAL;
+
+	err = huawei_wmi_fn_lock_set(dev, on);
+	if (err)
+		return err;
+
+	return size;
+}
+
+static ssize_t charge_thresholds_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	int err, low = -1, high = -1;
+
+	err = huawei_wmi_battery_get(dev, &low, &high);
+	if (err)
+		return err;
+
+	return sprintf(buf, "%d %d\n", low, high);
+}
+
+static ssize_t fn_lock_state_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	int err, on = -1;
+
+	err = huawei_wmi_fn_lock_get(dev, &on);
+	if (err)
+		return err;
+
+	return sprintf(buf, "%d\n", on);
+}
+
+static DEVICE_ATTR_RW(charge_thresholds);
+static DEVICE_ATTR_RW(fn_lock_state);
+
+static struct attribute *huawei_wmi_attrs[] = {
+	&dev_attr_charge_thresholds.attr,
+	&dev_attr_fn_lock_state.attr,
+	NULL
+};
+
+static const struct attribute_group huawei_wmi_group = {
+	.attrs = huawei_wmi_attrs
 };
 
-static struct wmi_driver huawei_wmi_driver = {
+/* Huawei driver */
+
+static int huawei_wmi_probe(struct platform_device *pdev)
+{
+	struct huawei_wmi *huawei;
+	int err;
+
+	huawei = devm_kzalloc(&pdev->dev, sizeof(struct huawei_wmi), GFP_KERNEL);
+	if (!huawei)
+		return -ENOMEM;
+
+	huawei->pdev = pdev;
+	dev_set_drvdata(&pdev->dev, huawei);
+
+	if (wmi_has_guid(WMI0_EVENT_GUID)) {
+		err = huawei_wmi_input_setup(pdev, &huawei->idev[0]);
+		if (err)
+			dev_err(&pdev->dev, "Failed to setup input device\n");
+		err = wmi_install_notify_handler(WMI0_EVENT_GUID,
+				huawei_wmi_input_notify, huawei->idev[0]);
+		if (err)
+			dev_err(&pdev->dev, "Failed to install notify handler\n");
+	}
+
+	if (wmi_has_guid(AMW0_EVENT_GUID)) {
+		err = huawei_wmi_input_setup(pdev, &huawei->idev[1]);
+		if (err)
+			dev_err(&pdev->dev, "Failed to setup input device\n");
+		err = wmi_install_notify_handler(AMW0_EVENT_GUID,
+				huawei_wmi_input_notify, huawei->idev[1]);
+		if (err)
+			dev_err(&pdev->dev, "Failed to install notify handler\n");
+	}
+
+	if (wmi_has_guid(AMW0_METHOD_GUID)) {
+
+		mutex_init(&huawei->wmi_lock);
+		mutex_init(&huawei->battery_lock);
+
+		err = sysfs_create_group(&pdev->dev.kobj, &huawei_wmi_group);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to create sysfs interface\n");
+			return err;
+		}
+
+		err = huawei_wmi_leds_setup(&pdev->dev);
+		if (err)
+			dev_err(&pdev->dev, "Failed to setup leds\n");
+	}
+
+	return 0;
+}
+
+static int huawei_wmi_remove(struct platform_device *pdev)
+{
+	if (wmi_has_guid(WMI0_EVENT_GUID))
+		wmi_remove_notify_handler(WMI0_EVENT_GUID);
+
+	if (wmi_has_guid(AMW0_EVENT_GUID))
+		wmi_remove_notify_handler(AMW0_EVENT_GUID);
+
+	if (wmi_has_guid(AMW0_METHOD_GUID))
+		sysfs_remove_group(&pdev->dev.kobj, &huawei_wmi_group);
+
+	return 0;
+}
+
+static struct platform_driver huawei_wmi_driver = {
 	.driver = {
 		.name = "huawei-wmi",
 	},
-	.id_table = huawei_wmi_id_table,
 	.probe = huawei_wmi_probe,
-	.notify = huawei_wmi_notify,
+	.remove = huawei_wmi_remove,
 };
 
-module_wmi_driver(huawei_wmi_driver);
+static __init int huawei_wmi_init(void)
+{
+	int err;
+
+	quirks = &quirk_unknown;
+	dmi_check_system(huawei_quirks);
+	quirks->battery_sleep |= battery_sleep;
+	quirks->report_brightness |= report_brightness;
+
+	err = platform_driver_register(&huawei_wmi_driver);
+	if (err) {
+		pr_err("Failed to register platform driver\n");
+		return err;
+	}
+
+	huawei_wmi_pdev = platform_device_register_simple("huawei-wmi", -1, NULL, 0);
+	if (IS_ERR(huawei_wmi_pdev)) {
+		pr_err("Failed to register platform device\n");
+		platform_driver_unregister(&huawei_wmi_driver);
+		return PTR_ERR(huawei_wmi_pdev);
+	}
+
+	return 0;
+}
+
+static __exit void huawei_wmi_exit(void)
+{
+	platform_device_unregister(huawei_wmi_pdev);
+	platform_driver_unregister(&huawei_wmi_driver);
+}
+
+module_init(huawei_wmi_init);
+module_exit(huawei_wmi_exit);
 
-MODULE_DEVICE_TABLE(wmi, huawei_wmi_id_table);
+MODULE_ALIAS("wmi:"WMI0_EVENT_GUID);
+MODULE_ALIAS("wmi:"AMW0_EVENT_GUID);
+MODULE_ALIAS("wmi:"AMW0_METHOD_GUID);
 MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
-MODULE_DESCRIPTION("Huawei WMI hotkeys");
+MODULE_DESCRIPTION("Huawei WMI laptop extras driver");
 MODULE_LICENSE("GPL v2");
