2021-09-03 03:38:39 +03:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright ( c ) 2020 , NVIDIA CORPORATION . All rights reserved .
*/
# include <linux/acpi.h>
# include <linux/backlight.h>
# include <linux/mod_devicetable.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/wmi.h>
/**
2021-09-27 23:23:58 +03:00
* enum wmi_brightness_method - WMI method IDs
* @ WMI_BRIGHTNESS_METHOD_LEVEL : Get / Set EC brightness level status
* @ WMI_BRIGHTNESS_METHOD_SOURCE : Get / Set EC Brightness Source
2021-09-03 03:38:39 +03:00
*/
2021-09-27 23:23:58 +03:00
enum wmi_brightness_method {
WMI_BRIGHTNESS_METHOD_LEVEL = 1 ,
WMI_BRIGHTNESS_METHOD_SOURCE = 2 ,
WMI_BRIGHTNESS_METHOD_MAX
2021-09-03 03:38:39 +03:00
} ;
/**
2021-09-27 23:23:58 +03:00
* enum wmi_brightness_mode - Operation mode for WMI - wrapped method
* @ WMI_BRIGHTNESS_MODE_GET : Get the current brightness level / source .
* @ WMI_BRIGHTNESS_MODE_SET : Set the brightness level .
* @ WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL : Get the maximum brightness level . This
* is only valid when the WMI method is
* % WMI_BRIGHTNESS_METHOD_LEVEL .
2021-09-03 03:38:39 +03:00
*/
2021-09-27 23:23:58 +03:00
enum wmi_brightness_mode {
WMI_BRIGHTNESS_MODE_GET = 0 ,
WMI_BRIGHTNESS_MODE_SET = 1 ,
WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2 ,
WMI_BRIGHTNESS_MODE_MAX
2021-09-03 03:38:39 +03:00
} ;
/**
2021-09-27 23:23:58 +03:00
* enum wmi_brightness_source - Backlight brightness control source selection
* @ WMI_BRIGHTNESS_SOURCE_GPU : Backlight brightness is controlled by the GPU .
* @ WMI_BRIGHTNESS_SOURCE_EC : Backlight brightness is controlled by the
* system ' s Embedded Controller ( EC ) .
* @ WMI_BRIGHTNESS_SOURCE_AUX : Backlight brightness is controlled over the
* DisplayPort AUX channel .
2021-09-03 03:38:39 +03:00
*/
2021-09-27 23:23:58 +03:00
enum wmi_brightness_source {
WMI_BRIGHTNESS_SOURCE_GPU = 1 ,
WMI_BRIGHTNESS_SOURCE_EC = 2 ,
WMI_BRIGHTNESS_SOURCE_AUX = 3 ,
WMI_BRIGHTNESS_SOURCE_MAX
2021-09-03 03:38:39 +03:00
} ;
/**
2021-09-27 23:23:58 +03:00
* struct wmi_brightness_args - arguments for the WMI - wrapped ACPI method
* @ mode : Pass in an & enum wmi_brightness_mode value to select between
* getting or setting a value .
* @ val : In parameter for value to set when using % WMI_BRIGHTNESS_MODE_SET
* mode . Not used in conjunction with % WMI_BRIGHTNESS_MODE_GET or
* % WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode .
2021-09-03 03:38:39 +03:00
* @ ret : Out parameter returning retrieved value when operating in
2021-09-27 23:23:58 +03:00
* % WMI_BRIGHTNESS_MODE_GET or % WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL
* mode . Not used in % WMI_BRIGHTNESS_MODE_SET mode .
2021-09-03 03:38:39 +03:00
* @ ignored : Padding ; not used . The ACPI method expects a 24 byte params struct .
*
2021-09-27 23:23:58 +03:00
* This is the parameters structure for the WmiBrightnessNotify ACPI method as
* wrapped by WMI . The value passed in to @ val or returned by @ ret will be a
* brightness value when the WMI method ID is % WMI_BRIGHTNESS_METHOD_LEVEL , or
* an & enum wmi_brightness_source value with % WMI_BRIGHTNESS_METHOD_SOURCE .
2021-09-03 03:38:39 +03:00
*/
2021-09-27 23:23:58 +03:00
struct wmi_brightness_args {
2021-09-03 03:38:39 +03:00
u32 mode ;
u32 val ;
u32 ret ;
u32 ignored [ 3 ] ;
} ;
/**
2021-09-27 23:23:58 +03:00
* wmi_brightness_notify ( ) - helper function for calling WMI - wrapped ACPI method
* @ w : Pointer to the struct wmi_device identified by % WMI_BRIGHTNESS_GUID
* @ id : The WMI method ID to call ( e . g . % WMI_BRIGHTNESS_METHOD_LEVEL or
* % WMI_BRIGHTNESS_METHOD_SOURCE )
* @ mode : The operation to perform on the method ( e . g . % WMI_BRIGHTNESS_MODE_SET
* or % WMI_BRIGHTNESS_MODE_GET )
2021-09-03 03:38:39 +03:00
* @ val : Pointer to a value passed in by the caller when @ mode is
2021-09-27 23:23:58 +03:00
* % WMI_BRIGHTNESS_MODE_SET , or a value passed out to caller when @ mode
* is % WMI_BRIGHTNESS_MODE_GET or % WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL .
2021-09-03 03:38:39 +03:00
*
* Returns 0 on success , or a negative error number on failure .
*/
2021-09-27 23:23:58 +03:00
static int wmi_brightness_notify ( struct wmi_device * w , enum wmi_brightness_method id , enum wmi_brightness_mode mode , u32 * val )
2021-09-03 03:38:39 +03:00
{
2021-09-27 23:23:58 +03:00
struct wmi_brightness_args args = {
2021-09-03 03:38:39 +03:00
. mode = mode ,
. val = 0 ,
. ret = 0 ,
} ;
struct acpi_buffer buf = { ( acpi_size ) sizeof ( args ) , & args } ;
acpi_status status ;
2021-09-27 23:23:58 +03:00
if ( id < WMI_BRIGHTNESS_METHOD_LEVEL | |
id > = WMI_BRIGHTNESS_METHOD_MAX | |
mode < WMI_BRIGHTNESS_MODE_GET | | mode > = WMI_BRIGHTNESS_MODE_MAX )
2021-09-03 03:38:39 +03:00
return - EINVAL ;
2021-09-27 23:23:58 +03:00
if ( mode = = WMI_BRIGHTNESS_MODE_SET )
2021-09-03 03:38:39 +03:00
args . val = * val ;
status = wmidev_evaluate_method ( w , 0 , id , & buf , & buf ) ;
if ( ACPI_FAILURE ( status ) ) {
2021-09-27 23:23:58 +03:00
dev_err ( & w - > dev , " EC backlight control failed: %s \n " ,
2021-09-03 03:38:39 +03:00
acpi_format_exception ( status ) ) ;
return - EIO ;
}
2021-09-27 23:23:58 +03:00
if ( mode ! = WMI_BRIGHTNESS_MODE_SET )
2021-09-03 03:38:39 +03:00
* val = args . ret ;
return 0 ;
}
2021-09-27 23:23:58 +03:00
static int nvidia_wmi_ec_backlight_update_status ( struct backlight_device * bd )
2021-09-03 03:38:39 +03:00
{
struct wmi_device * wdev = bl_get_data ( bd ) ;
2021-09-27 23:23:58 +03:00
return wmi_brightness_notify ( wdev , WMI_BRIGHTNESS_METHOD_LEVEL ,
WMI_BRIGHTNESS_MODE_SET ,
& bd - > props . brightness ) ;
2021-09-03 03:38:39 +03:00
}
2021-09-27 23:23:58 +03:00
static int nvidia_wmi_ec_backlight_get_brightness ( struct backlight_device * bd )
2021-09-03 03:38:39 +03:00
{
struct wmi_device * wdev = bl_get_data ( bd ) ;
u32 level ;
int ret ;
2021-09-27 23:23:58 +03:00
ret = wmi_brightness_notify ( wdev , WMI_BRIGHTNESS_METHOD_LEVEL ,
WMI_BRIGHTNESS_MODE_GET , & level ) ;
2021-09-03 03:38:39 +03:00
if ( ret < 0 )
return ret ;
return level ;
}
2021-09-27 23:23:58 +03:00
static const struct backlight_ops nvidia_wmi_ec_backlight_ops = {
. update_status = nvidia_wmi_ec_backlight_update_status ,
. get_brightness = nvidia_wmi_ec_backlight_get_brightness ,
2021-09-03 03:38:39 +03:00
} ;
2021-09-27 23:23:58 +03:00
static int nvidia_wmi_ec_backlight_probe ( struct wmi_device * wdev , const void * ctx )
2021-09-03 03:38:39 +03:00
{
struct backlight_properties props = { } ;
struct backlight_device * bdev ;
u32 source ;
int ret ;
2021-09-27 23:23:58 +03:00
ret = wmi_brightness_notify ( wdev , WMI_BRIGHTNESS_METHOD_SOURCE ,
WMI_BRIGHTNESS_MODE_GET , & source ) ;
2021-09-03 03:38:39 +03:00
if ( ret )
return ret ;
/*
* This driver is only to be used when brightness control is handled
* by the EC ; otherwise , the GPU driver ( s ) should control brightness .
*/
2021-09-27 23:23:58 +03:00
if ( source ! = WMI_BRIGHTNESS_SOURCE_EC )
2021-09-03 03:38:39 +03:00
return - ENODEV ;
/*
* Identify this backlight device as a firmware device so that it can
* be prioritized over any exposed GPU - driven raw device ( s ) .
*/
props . type = BACKLIGHT_FIRMWARE ;
2021-09-27 23:23:58 +03:00
ret = wmi_brightness_notify ( wdev , WMI_BRIGHTNESS_METHOD_LEVEL ,
WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL ,
& props . max_brightness ) ;
2021-09-03 03:38:39 +03:00
if ( ret )
return ret ;
2021-09-27 23:23:58 +03:00
ret = wmi_brightness_notify ( wdev , WMI_BRIGHTNESS_METHOD_LEVEL ,
WMI_BRIGHTNESS_MODE_GET , & props . brightness ) ;
2021-09-03 03:38:39 +03:00
if ( ret )
return ret ;
2021-09-27 23:23:58 +03:00
bdev = devm_backlight_device_register ( & wdev - > dev ,
" nvidia_wmi_ec_backlight " ,
2021-09-03 03:38:39 +03:00
& wdev - > dev , wdev ,
2021-09-27 23:23:58 +03:00
& nvidia_wmi_ec_backlight_ops ,
& props ) ;
2021-09-03 03:38:39 +03:00
return PTR_ERR_OR_ZERO ( bdev ) ;
}
2021-09-27 23:23:58 +03:00
# define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7"
2021-09-03 03:38:39 +03:00
2021-09-27 23:23:58 +03:00
static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table [ ] = {
{ . guid_string = WMI_BRIGHTNESS_GUID } ,
2021-09-03 03:38:39 +03:00
{ }
} ;
2021-09-27 23:23:58 +03:00
MODULE_DEVICE_TABLE ( wmi , nvidia_wmi_ec_backlight_id_table ) ;
2021-09-03 03:38:39 +03:00
2021-09-27 23:23:58 +03:00
static struct wmi_driver nvidia_wmi_ec_backlight_driver = {
2021-09-03 03:38:39 +03:00
. driver = {
2021-09-27 23:23:58 +03:00
. name = " nvidia-wmi-ec-backlight " ,
2021-09-03 03:38:39 +03:00
} ,
2021-09-27 23:23:58 +03:00
. probe = nvidia_wmi_ec_backlight_probe ,
. id_table = nvidia_wmi_ec_backlight_id_table ,
2021-09-03 03:38:39 +03:00
} ;
2021-09-27 23:23:58 +03:00
module_wmi_driver ( nvidia_wmi_ec_backlight_driver ) ;
2021-09-03 03:38:39 +03:00
MODULE_AUTHOR ( " Daniel Dadap <ddadap@nvidia.com> " ) ;
2021-09-27 23:23:58 +03:00
MODULE_DESCRIPTION ( " NVIDIA WMI EC Backlight driver " ) ;
2021-09-03 03:38:39 +03:00
MODULE_LICENSE ( " GPL " ) ;