1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
6 #include <linux/acpi.h>
7 #include <linux/backlight.h>
8 #include <linux/mod_devicetable.h>
9 #include <linux/module.h>
10 #include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h>
11 #include <linux/types.h>
12 #include <linux/wmi.h>
13 #include <acpi/video.h>
16 module_param(force
, bool, 0444);
17 MODULE_PARM_DESC(force
, "Force loading (disable acpi_backlight=xxx checks");
20 * wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method
21 * @w: Pointer to the struct wmi_device identified by %WMI_BRIGHTNESS_GUID
22 * @id: The WMI method ID to call (e.g. %WMI_BRIGHTNESS_METHOD_LEVEL or
23 * %WMI_BRIGHTNESS_METHOD_SOURCE)
24 * @mode: The operation to perform on the method (e.g. %WMI_BRIGHTNESS_MODE_SET
25 * or %WMI_BRIGHTNESS_MODE_GET)
26 * @val: Pointer to a value passed in by the caller when @mode is
27 * %WMI_BRIGHTNESS_MODE_SET, or a value passed out to caller when @mode
28 * is %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL.
30 * Returns 0 on success, or a negative error number on failure.
32 static int wmi_brightness_notify(struct wmi_device
*w
, enum wmi_brightness_method id
, enum wmi_brightness_mode mode
, u32
*val
)
34 struct wmi_brightness_args args
= {
39 struct acpi_buffer buf
= { (acpi_size
)sizeof(args
), &args
};
42 if (id
< WMI_BRIGHTNESS_METHOD_LEVEL
||
43 id
>= WMI_BRIGHTNESS_METHOD_MAX
||
44 mode
< WMI_BRIGHTNESS_MODE_GET
|| mode
>= WMI_BRIGHTNESS_MODE_MAX
)
47 if (mode
== WMI_BRIGHTNESS_MODE_SET
)
50 status
= wmidev_evaluate_method(w
, 0, id
, &buf
, &buf
);
51 if (ACPI_FAILURE(status
)) {
52 dev_err(&w
->dev
, "EC backlight control failed: %s\n",
53 acpi_format_exception(status
));
57 if (mode
!= WMI_BRIGHTNESS_MODE_SET
)
63 static int nvidia_wmi_ec_backlight_update_status(struct backlight_device
*bd
)
65 struct wmi_device
*wdev
= bl_get_data(bd
);
67 return wmi_brightness_notify(wdev
, WMI_BRIGHTNESS_METHOD_LEVEL
,
68 WMI_BRIGHTNESS_MODE_SET
,
69 &bd
->props
.brightness
);
72 static int nvidia_wmi_ec_backlight_get_brightness(struct backlight_device
*bd
)
74 struct wmi_device
*wdev
= bl_get_data(bd
);
78 ret
= wmi_brightness_notify(wdev
, WMI_BRIGHTNESS_METHOD_LEVEL
,
79 WMI_BRIGHTNESS_MODE_GET
, &level
);
86 static const struct backlight_ops nvidia_wmi_ec_backlight_ops
= {
87 .update_status
= nvidia_wmi_ec_backlight_update_status
,
88 .get_brightness
= nvidia_wmi_ec_backlight_get_brightness
,
91 static int nvidia_wmi_ec_backlight_probe(struct wmi_device
*wdev
, const void *ctx
)
93 struct backlight_properties props
= {};
94 struct backlight_device
*bdev
;
97 /* drivers/acpi/video_detect.c also checks that SOURCE == EC */
98 if (!force
&& acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec
)
102 * Identify this backlight device as a firmware device so that it can
103 * be prioritized over any exposed GPU-driven raw device(s).
105 props
.type
= BACKLIGHT_FIRMWARE
;
107 ret
= wmi_brightness_notify(wdev
, WMI_BRIGHTNESS_METHOD_LEVEL
,
108 WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL
,
109 &props
.max_brightness
);
113 ret
= wmi_brightness_notify(wdev
, WMI_BRIGHTNESS_METHOD_LEVEL
,
114 WMI_BRIGHTNESS_MODE_GET
, &props
.brightness
);
118 bdev
= devm_backlight_device_register(&wdev
->dev
,
119 "nvidia_wmi_ec_backlight",
121 &nvidia_wmi_ec_backlight_ops
,
123 return PTR_ERR_OR_ZERO(bdev
);
126 static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table
[] = {
127 { .guid_string
= WMI_BRIGHTNESS_GUID
},
130 MODULE_DEVICE_TABLE(wmi
, nvidia_wmi_ec_backlight_id_table
);
132 static struct wmi_driver nvidia_wmi_ec_backlight_driver
= {
134 .name
= "nvidia-wmi-ec-backlight",
136 .probe
= nvidia_wmi_ec_backlight_probe
,
137 .id_table
= nvidia_wmi_ec_backlight_id_table
,
139 module_wmi_driver(nvidia_wmi_ec_backlight_driver
);
141 MODULE_AUTHOR("Daniel Dadap <ddadap@nvidia.com>");
142 MODULE_DESCRIPTION("NVIDIA WMI EC Backlight driver");
143 MODULE_LICENSE("GPL");