0001
0002
0003
0004
0005
0006 #include <linux/acpi.h>
0007 #include <linux/backlight.h>
0008 #include <linux/mod_devicetable.h>
0009 #include <linux/module.h>
0010 #include <linux/types.h>
0011 #include <linux/wmi.h>
0012
0013
0014
0015
0016
0017
0018 enum wmi_brightness_method {
0019 WMI_BRIGHTNESS_METHOD_LEVEL = 1,
0020 WMI_BRIGHTNESS_METHOD_SOURCE = 2,
0021 WMI_BRIGHTNESS_METHOD_MAX
0022 };
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 enum wmi_brightness_mode {
0033 WMI_BRIGHTNESS_MODE_GET = 0,
0034 WMI_BRIGHTNESS_MODE_SET = 1,
0035 WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2,
0036 WMI_BRIGHTNESS_MODE_MAX
0037 };
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 enum wmi_brightness_source {
0048 WMI_BRIGHTNESS_SOURCE_GPU = 1,
0049 WMI_BRIGHTNESS_SOURCE_EC = 2,
0050 WMI_BRIGHTNESS_SOURCE_AUX = 3,
0051 WMI_BRIGHTNESS_SOURCE_MAX
0052 };
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 struct wmi_brightness_args {
0072 u32 mode;
0073 u32 val;
0074 u32 ret;
0075 u32 ignored[3];
0076 };
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091 static int wmi_brightness_notify(struct wmi_device *w, enum wmi_brightness_method id, enum wmi_brightness_mode mode, u32 *val)
0092 {
0093 struct wmi_brightness_args args = {
0094 .mode = mode,
0095 .val = 0,
0096 .ret = 0,
0097 };
0098 struct acpi_buffer buf = { (acpi_size)sizeof(args), &args };
0099 acpi_status status;
0100
0101 if (id < WMI_BRIGHTNESS_METHOD_LEVEL ||
0102 id >= WMI_BRIGHTNESS_METHOD_MAX ||
0103 mode < WMI_BRIGHTNESS_MODE_GET || mode >= WMI_BRIGHTNESS_MODE_MAX)
0104 return -EINVAL;
0105
0106 if (mode == WMI_BRIGHTNESS_MODE_SET)
0107 args.val = *val;
0108
0109 status = wmidev_evaluate_method(w, 0, id, &buf, &buf);
0110 if (ACPI_FAILURE(status)) {
0111 dev_err(&w->dev, "EC backlight control failed: %s\n",
0112 acpi_format_exception(status));
0113 return -EIO;
0114 }
0115
0116 if (mode != WMI_BRIGHTNESS_MODE_SET)
0117 *val = args.ret;
0118
0119 return 0;
0120 }
0121
0122 static int nvidia_wmi_ec_backlight_update_status(struct backlight_device *bd)
0123 {
0124 struct wmi_device *wdev = bl_get_data(bd);
0125
0126 return wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL,
0127 WMI_BRIGHTNESS_MODE_SET,
0128 &bd->props.brightness);
0129 }
0130
0131 static int nvidia_wmi_ec_backlight_get_brightness(struct backlight_device *bd)
0132 {
0133 struct wmi_device *wdev = bl_get_data(bd);
0134 u32 level;
0135 int ret;
0136
0137 ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL,
0138 WMI_BRIGHTNESS_MODE_GET, &level);
0139 if (ret < 0)
0140 return ret;
0141
0142 return level;
0143 }
0144
0145 static const struct backlight_ops nvidia_wmi_ec_backlight_ops = {
0146 .update_status = nvidia_wmi_ec_backlight_update_status,
0147 .get_brightness = nvidia_wmi_ec_backlight_get_brightness,
0148 };
0149
0150 static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ctx)
0151 {
0152 struct backlight_properties props = {};
0153 struct backlight_device *bdev;
0154 u32 source;
0155 int ret;
0156
0157 ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_SOURCE,
0158 WMI_BRIGHTNESS_MODE_GET, &source);
0159 if (ret)
0160 return ret;
0161
0162
0163
0164
0165
0166 if (source != WMI_BRIGHTNESS_SOURCE_EC)
0167 return -ENODEV;
0168
0169
0170
0171
0172
0173 props.type = BACKLIGHT_FIRMWARE;
0174
0175 ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL,
0176 WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL,
0177 &props.max_brightness);
0178 if (ret)
0179 return ret;
0180
0181 ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL,
0182 WMI_BRIGHTNESS_MODE_GET, &props.brightness);
0183 if (ret)
0184 return ret;
0185
0186 bdev = devm_backlight_device_register(&wdev->dev,
0187 "nvidia_wmi_ec_backlight",
0188 &wdev->dev, wdev,
0189 &nvidia_wmi_ec_backlight_ops,
0190 &props);
0191 return PTR_ERR_OR_ZERO(bdev);
0192 }
0193
0194 #define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7"
0195
0196 static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table[] = {
0197 { .guid_string = WMI_BRIGHTNESS_GUID },
0198 { }
0199 };
0200 MODULE_DEVICE_TABLE(wmi, nvidia_wmi_ec_backlight_id_table);
0201
0202 static struct wmi_driver nvidia_wmi_ec_backlight_driver = {
0203 .driver = {
0204 .name = "nvidia-wmi-ec-backlight",
0205 },
0206 .probe = nvidia_wmi_ec_backlight_probe,
0207 .id_table = nvidia_wmi_ec_backlight_id_table,
0208 };
0209 module_wmi_driver(nvidia_wmi_ec_backlight_driver);
0210
0211 MODULE_AUTHOR("Daniel Dadap <ddadap@nvidia.com>");
0212 MODULE_DESCRIPTION("NVIDIA WMI EC Backlight driver");
0213 MODULE_LICENSE("GPL");