2021-09-02 19:38:39 -05: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>
2022-08-17 14:03:32 +02:00
# include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h>
2021-09-02 19:38:39 -05:00
# include <linux/types.h>
# include <linux/wmi.h>
2022-08-17 14:37:21 +02:00
# include <acpi/video.h>
2021-09-02 19:38:39 -05:00
/**
2021-09-27 15:23:58 -05: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-02 19:38:39 -05:00
* @ val : Pointer to a value passed in by the caller when @ mode is
2021-09-27 15:23:58 -05: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-02 19:38:39 -05:00
*
* Returns 0 on success , or a negative error number on failure .
*/
2021-09-27 15:23:58 -05:00
static int wmi_brightness_notify ( struct wmi_device * w , enum wmi_brightness_method id , enum wmi_brightness_mode mode , u32 * val )
2021-09-02 19:38:39 -05:00
{
2021-09-27 15:23:58 -05:00
struct wmi_brightness_args args = {
2021-09-02 19:38:39 -05:00
. mode = mode ,
. val = 0 ,
. ret = 0 ,
} ;
struct acpi_buffer buf = { ( acpi_size ) sizeof ( args ) , & args } ;
acpi_status status ;
2021-09-27 15:23:58 -05:00
if ( id < WMI_BRIGHTNESS_METHOD_LEVEL | |
id > = WMI_BRIGHTNESS_METHOD_MAX | |
mode < WMI_BRIGHTNESS_MODE_GET | | mode > = WMI_BRIGHTNESS_MODE_MAX )
2021-09-02 19:38:39 -05:00
return - EINVAL ;
2021-09-27 15:23:58 -05:00
if ( mode = = WMI_BRIGHTNESS_MODE_SET )
2021-09-02 19:38:39 -05:00
args . val = * val ;
status = wmidev_evaluate_method ( w , 0 , id , & buf , & buf ) ;
if ( ACPI_FAILURE ( status ) ) {
2021-09-27 15:23:58 -05:00
dev_err ( & w - > dev , " EC backlight control failed: %s \n " ,
2021-09-02 19:38:39 -05:00
acpi_format_exception ( status ) ) ;
return - EIO ;
}
2021-09-27 15:23:58 -05:00
if ( mode ! = WMI_BRIGHTNESS_MODE_SET )
2021-09-02 19:38:39 -05:00
* val = args . ret ;
return 0 ;
}
2021-09-27 15:23:58 -05:00
static int nvidia_wmi_ec_backlight_update_status ( struct backlight_device * bd )
2021-09-02 19:38:39 -05:00
{
struct wmi_device * wdev = bl_get_data ( bd ) ;
2021-09-27 15:23:58 -05:00
return wmi_brightness_notify ( wdev , WMI_BRIGHTNESS_METHOD_LEVEL ,
WMI_BRIGHTNESS_MODE_SET ,
& bd - > props . brightness ) ;
2021-09-02 19:38:39 -05:00
}
2021-09-27 15:23:58 -05:00
static int nvidia_wmi_ec_backlight_get_brightness ( struct backlight_device * bd )
2021-09-02 19:38:39 -05:00
{
struct wmi_device * wdev = bl_get_data ( bd ) ;
u32 level ;
int ret ;
2021-09-27 15:23:58 -05:00
ret = wmi_brightness_notify ( wdev , WMI_BRIGHTNESS_METHOD_LEVEL ,
WMI_BRIGHTNESS_MODE_GET , & level ) ;
2021-09-02 19:38:39 -05:00
if ( ret < 0 )
return ret ;
return level ;
}
2021-09-27 15:23:58 -05: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-02 19:38:39 -05:00
} ;
2021-09-27 15:23:58 -05:00
static int nvidia_wmi_ec_backlight_probe ( struct wmi_device * wdev , const void * ctx )
2021-09-02 19:38:39 -05:00
{
struct backlight_properties props = { } ;
struct backlight_device * bdev ;
int ret ;
2022-08-17 14:37:21 +02:00
/* drivers/acpi/video_detect.c also checks that SOURCE == EC */
if ( acpi_video_get_backlight_type ( ) ! = acpi_backlight_nvidia_wmi_ec )
2021-09-02 19:38:39 -05: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 15:23:58 -05:00
ret = wmi_brightness_notify ( wdev , WMI_BRIGHTNESS_METHOD_LEVEL ,
WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL ,
& props . max_brightness ) ;
2021-09-02 19:38:39 -05:00
if ( ret )
return ret ;
2021-09-27 15:23:58 -05:00
ret = wmi_brightness_notify ( wdev , WMI_BRIGHTNESS_METHOD_LEVEL ,
WMI_BRIGHTNESS_MODE_GET , & props . brightness ) ;
2021-09-02 19:38:39 -05:00
if ( ret )
return ret ;
2021-09-27 15:23:58 -05:00
bdev = devm_backlight_device_register ( & wdev - > dev ,
" nvidia_wmi_ec_backlight " ,
2021-09-02 19:38:39 -05:00
& wdev - > dev , wdev ,
2021-09-27 15:23:58 -05:00
& nvidia_wmi_ec_backlight_ops ,
& props ) ;
2021-09-02 19:38:39 -05:00
return PTR_ERR_OR_ZERO ( bdev ) ;
}
2021-09-27 15:23:58 -05:00
static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table [ ] = {
{ . guid_string = WMI_BRIGHTNESS_GUID } ,
2021-09-02 19:38:39 -05:00
{ }
} ;
2021-09-27 15:23:58 -05:00
MODULE_DEVICE_TABLE ( wmi , nvidia_wmi_ec_backlight_id_table ) ;
2021-09-02 19:38:39 -05:00
2021-09-27 15:23:58 -05:00
static struct wmi_driver nvidia_wmi_ec_backlight_driver = {
2021-09-02 19:38:39 -05:00
. driver = {
2021-09-27 15:23:58 -05:00
. name = " nvidia-wmi-ec-backlight " ,
2021-09-02 19:38:39 -05:00
} ,
2021-09-27 15:23:58 -05:00
. probe = nvidia_wmi_ec_backlight_probe ,
. id_table = nvidia_wmi_ec_backlight_id_table ,
2021-09-02 19:38:39 -05:00
} ;
2021-09-27 15:23:58 -05:00
module_wmi_driver ( nvidia_wmi_ec_backlight_driver ) ;
2021-09-02 19:38:39 -05:00
MODULE_AUTHOR ( " Daniel Dadap <ddadap@nvidia.com> " ) ;
2021-09-27 15:23:58 -05:00
MODULE_DESCRIPTION ( " NVIDIA WMI EC Backlight driver " ) ;
2021-09-02 19:38:39 -05:00
MODULE_LICENSE ( " GPL " ) ;