3131#include <linux/sysfs.h>
3232#include <linux/types.h>
3333#include <linux/wmi.h>
34+ #include <acpi/battery.h>
3435
3536#include <linux/unaligned.h>
3637
7980/* Get_Data() and Set_Data() Params */
8081#define MSI_PLATFORM_PL1_ADDR 0x50
8182#define MSI_PLATFORM_PL2_ADDR 0x51
83+ #define MSI_PLATFORM_BAT_ADDR 0xd7
8284
8385static bool force ;
8486module_param_unsafe (force , bool , 0 );
@@ -118,6 +120,7 @@ enum msi_wmi_platform_method {
118120
119121struct msi_wmi_platform_quirk {
120122 bool shift_mode ; /* Shift mode is supported */
123+ bool charge_threshold ; /* Charge threshold is supported */
121124 int pl_min ; /* Minimum PLx value */
122125 int pl1_max ; /* Maximum PL1 value */
123126 int pl2_max ; /* Maximum PL2 value */
@@ -128,6 +131,7 @@ struct msi_wmi_platform_data {
128131 struct msi_wmi_platform_quirk * quirks ;
129132 struct mutex wmi_lock ; /* Necessary when calling WMI methods */
130133 struct device * ppdev ;
134+ struct acpi_battery_hook battery_hook ;
131135 struct device * fw_attrs_dev ;
132136 struct kset * fw_attrs_kset ;
133137};
@@ -211,12 +215,14 @@ static const char * const msi_wmi_platform_debugfs_names[] = {
211215static struct msi_wmi_platform_quirk quirk_default = {};
212216static struct msi_wmi_platform_quirk quirk_gen1 = {
213217 .shift_mode = true,
218+ .charge_threshold = true,
214219 .pl_min = 8 ,
215220 .pl1_max = 43 ,
216221 .pl2_max = 45
217222};
218223static struct msi_wmi_platform_quirk quirk_gen2 = {
219224 .shift_mode = true,
225+ .charge_threshold = true,
220226 .pl_min = 8 ,
221227 .pl1_max = 30 ,
222228 .pl2_max = 37
@@ -1013,6 +1019,94 @@ static int msi_wmi_fw_attrs_init(struct msi_wmi_platform_data *data)
10131019 return 0 ;
10141020}
10151021
1022+ static int msi_platform_psy_ext_get_prop (struct power_supply * psy ,
1023+ const struct power_supply_ext * ext ,
1024+ void * data ,
1025+ enum power_supply_property psp ,
1026+ union power_supply_propval * val )
1027+ {
1028+ struct msi_wmi_platform_data * msi = data ;
1029+ u8 buffer [32 ] = { 0 };
1030+ int ret ;
1031+
1032+ switch (psp ) {
1033+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD :
1034+ buffer [0 ] = MSI_PLATFORM_BAT_ADDR ;
1035+ ret = msi_wmi_platform_query (msi , MSI_PLATFORM_GET_DATA ,
1036+ buffer , sizeof (buffer ));
1037+ if (ret )
1038+ return ret ;
1039+
1040+ val -> intval = buffer [1 ] & ~BIT (7 );
1041+ if (val -> intval > 100 )
1042+ return - EINVAL ;
1043+
1044+ return 0 ;
1045+ default :
1046+ return - EINVAL ;
1047+ }
1048+ }
1049+
1050+ static int msi_platform_psy_ext_set_prop (struct power_supply * psy ,
1051+ const struct power_supply_ext * ext ,
1052+ void * data ,
1053+ enum power_supply_property psp ,
1054+ const union power_supply_propval * val )
1055+ {
1056+ struct msi_wmi_platform_data * msi = data ;
1057+ u8 buffer [32 ] = { 0 };
1058+
1059+ switch (psp ) {
1060+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD :
1061+ if (val -> intval > 100 )
1062+ return - EINVAL ;
1063+ buffer [0 ] = MSI_PLATFORM_BAT_ADDR ;
1064+ buffer [1 ] = val -> intval | BIT (7 );
1065+ return msi_wmi_platform_query (msi , MSI_PLATFORM_SET_DATA ,
1066+ buffer , sizeof (buffer ));
1067+ default :
1068+ return - EINVAL ;
1069+ }
1070+ }
1071+
1072+ static int
1073+ msi_platform_psy_prop_is_writeable (struct power_supply * psy ,
1074+ const struct power_supply_ext * ext ,
1075+ void * data , enum power_supply_property psp )
1076+ {
1077+ return true;
1078+ }
1079+
1080+ static const enum power_supply_property oxp_psy_ext_props [] = {
1081+ POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD ,
1082+ };
1083+
1084+ static const struct power_supply_ext msi_platform_psy_ext = {
1085+ .name = "msi-platform-charge-control" ,
1086+ .properties = oxp_psy_ext_props ,
1087+ .num_properties = ARRAY_SIZE (oxp_psy_ext_props ),
1088+ .get_property = msi_platform_psy_ext_get_prop ,
1089+ .set_property = msi_platform_psy_ext_set_prop ,
1090+ .property_is_writeable = msi_platform_psy_prop_is_writeable ,
1091+ };
1092+
1093+ static int msi_wmi_platform_battery_add (struct power_supply * battery ,
1094+ struct acpi_battery_hook * hook )
1095+ {
1096+ struct msi_wmi_platform_data * data =
1097+ container_of (hook , struct msi_wmi_platform_data , battery_hook );
1098+
1099+ return power_supply_register_extension (battery , & msi_platform_psy_ext ,
1100+ & data -> wdev -> dev , data );
1101+ }
1102+
1103+ static int msi_wmi_platform_battery_remove (struct power_supply * battery ,
1104+ struct acpi_battery_hook * hook )
1105+ {
1106+ power_supply_unregister_extension (battery , & msi_platform_psy_ext );
1107+ return 0 ;
1108+ }
1109+
10161110static ssize_t msi_wmi_platform_debugfs_write (struct file * fp , const char __user * input ,
10171111 size_t length , loff_t * offset )
10181112{
@@ -1245,13 +1339,28 @@ static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context)
12451339 if (ret < 0 )
12461340 return ret ;
12471341
1342+ if (data -> quirks -> charge_threshold ) {
1343+ data -> battery_hook .name = "MSI Battery" ;
1344+ data -> battery_hook .add_battery = msi_wmi_platform_battery_add ;
1345+ data -> battery_hook .remove_battery = msi_wmi_platform_battery_remove ;
1346+ battery_hook_register (& data -> battery_hook );
1347+ }
1348+
12481349 msi_wmi_platform_debugfs_init (data );
12491350
12501351 msi_wmi_platform_profile_setup (data );
12511352
12521353 return msi_wmi_platform_hwmon_init (data );
12531354}
12541355
1356+ static void msi_wmi_platform_remove (struct wmi_device * wdev )
1357+ {
1358+ struct msi_wmi_platform_data * data = dev_get_drvdata (& wdev -> dev );
1359+
1360+ if (data -> quirks -> charge_threshold )
1361+ battery_hook_unregister (& data -> battery_hook );
1362+ }
1363+
12551364static const struct wmi_device_id msi_wmi_platform_id_table [] = {
12561365 { MSI_PLATFORM_GUID , NULL },
12571366 { }
@@ -1265,6 +1374,7 @@ static struct wmi_driver msi_wmi_platform_driver = {
12651374 },
12661375 .id_table = msi_wmi_platform_id_table ,
12671376 .probe = msi_wmi_platform_probe ,
1377+ .remove = msi_wmi_platform_remove ,
12681378 .no_singleton = true,
12691379};
12701380
0 commit comments