#include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/wmi.h>
+#include <linux/cleanup.h>
 
 #define WMI_LENOVO_CAMERABUTTON_EVENT_GUID "50C76F1F-D8E4-D895-0A3D-62F4EA400013"
 
        SW_CAMERA_ON    = 1,
 };
 
+static int camera_shutter_input_setup(struct wmi_device *wdev, u8 camera_mode)
+{
+       struct lenovo_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
+       int err;
+
+       priv->idev = input_allocate_device();
+       if (!priv->idev)
+               return -ENOMEM;
+
+       priv->idev->name = "Lenovo WMI Camera Button";
+       priv->idev->phys = "wmi/input0";
+       priv->idev->id.bustype = BUS_HOST;
+       priv->idev->dev.parent = &wdev->dev;
+
+       input_set_capability(priv->idev, EV_SW, SW_CAMERA_LENS_COVER);
+
+       input_report_switch(priv->idev, SW_CAMERA_LENS_COVER,
+                           camera_mode == SW_CAMERA_ON ? 0 : 1);
+       input_sync(priv->idev);
+
+       err = input_register_device(priv->idev);
+       if (err) {
+               input_free_device(priv->idev);
+               priv->idev = NULL;
+       }
+
+       return err;
+}
+
 static void lenovo_wmi_notify(struct wmi_device *wdev, union acpi_object *obj)
 {
        struct lenovo_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
-       unsigned int keycode;
        u8 camera_mode;
 
        if (obj->type != ACPI_TYPE_BUFFER) {
                return;
        }
 
-       mutex_lock(&priv->notify_lock);
+       guard(mutex)(&priv->notify_lock);
 
-       keycode = camera_mode == SW_CAMERA_ON ?
-                  KEY_CAMERA_ACCESS_ENABLE : KEY_CAMERA_ACCESS_DISABLE;
-       input_report_key(priv->idev, keycode, 1);
-       input_sync(priv->idev);
-       input_report_key(priv->idev, keycode, 0);
-       input_sync(priv->idev);
+       if (!priv->idev) {
+               if (camera_shutter_input_setup(wdev, camera_mode))
+                       dev_warn(&wdev->dev, "Failed to register input device\n");
+               return;
+       }
 
-       mutex_unlock(&priv->notify_lock);
+       if (camera_mode == SW_CAMERA_ON)
+               input_report_switch(priv->idev, SW_CAMERA_LENS_COVER, 0);
+       else
+               input_report_switch(priv->idev, SW_CAMERA_LENS_COVER, 1);
+       input_sync(priv->idev);
 }
 
 static int lenovo_wmi_probe(struct wmi_device *wdev, const void *context)
 {
        struct lenovo_wmi_priv *priv;
-       int ret;
 
        priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
 
        dev_set_drvdata(&wdev->dev, priv);
 
-       priv->idev = devm_input_allocate_device(&wdev->dev);
-       if (!priv->idev)
-               return -ENOMEM;
-
-       priv->idev->name = "Lenovo WMI Camera Button";
-       priv->idev->phys = "wmi/input0";
-       priv->idev->id.bustype = BUS_HOST;
-       priv->idev->dev.parent = &wdev->dev;
-       input_set_capability(priv->idev, EV_KEY, KEY_CAMERA_ACCESS_ENABLE);
-       input_set_capability(priv->idev, EV_KEY, KEY_CAMERA_ACCESS_DISABLE);
-
-       ret = input_register_device(priv->idev);
-       if (ret)
-               return ret;
-
        mutex_init(&priv->notify_lock);
 
        return 0;
 {
        struct lenovo_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
 
+       if (priv->idev)
+               input_unregister_device(priv->idev);
+
        mutex_destroy(&priv->notify_lock);
 }