1616#include <linux/kernel.h>
1717#include <linux/module.h>
1818#include <linux/platform_device.h>
19+ #include <linux/pm.h>
1920#include <linux/power_supply.h>
2021#include <linux/sysfs.h>
2122#include <acpi/battery.h>
@@ -52,6 +53,11 @@ struct ayaneo_ec_platform_data {
5253 struct platform_device * pdev ;
5354 struct ayaneo_ec_quirk * quirks ;
5455 struct acpi_battery_hook battery_hook ;
56+
57+ // Protects access to restore_pwm
58+ struct mutex hwmon_lock ;
59+ bool restore_charge_limit ;
60+ bool restore_pwm ;
5561};
5662
5763static const struct ayaneo_ec_quirk quirk_fan = {
@@ -208,10 +214,16 @@ static int ayaneo_ec_read(struct device *dev, enum hwmon_sensor_types type,
208214static int ayaneo_ec_write (struct device * dev , enum hwmon_sensor_types type ,
209215 u32 attr , int channel , long val )
210216{
217+ struct ayaneo_ec_platform_data * data = dev_get_drvdata (dev );
218+ int ret ;
219+
220+ guard (mutex )(& data -> hwmon_lock );
221+
211222 switch (type ) {
212223 case hwmon_pwm :
213224 switch (attr ) {
214225 case hwmon_pwm_enable :
226+ data -> restore_pwm = false;
215227 switch (val ) {
216228 case 1 :
217229 return ec_write (AYANEO_PWM_ENABLE_REG ,
@@ -225,6 +237,17 @@ static int ayaneo_ec_write(struct device *dev, enum hwmon_sensor_types type,
225237 case hwmon_pwm_input :
226238 if (val < 0 || val > 255 )
227239 return - EINVAL ;
240+ if (data -> restore_pwm ) {
241+ /*
242+ * Defer restoring PWM control to after
243+ * userspace resumes successfully
244+ */
245+ ret = ec_write (AYANEO_PWM_ENABLE_REG ,
246+ AYANEO_PWM_MODE_MANUAL );
247+ if (ret )
248+ return ret ;
249+ data -> restore_pwm = false;
250+ }
228251 return ec_write (AYANEO_PWM_REG , (val * 100 ) / 255 );
229252 default :
230253 break ;
@@ -454,11 +477,14 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
454477
455478 data -> pdev = pdev ;
456479 data -> quirks = dmi_entry -> driver_data ;
480+ ret = devm_mutex_init (& pdev -> dev , & data -> hwmon_lock );
481+ if (ret )
482+ return ret ;
457483 platform_set_drvdata (pdev , data );
458484
459485 if (data -> quirks -> has_fan_control ) {
460486 hwdev = devm_hwmon_device_register_with_info (& pdev -> dev ,
461- "ayaneo_ec" , NULL , & ayaneo_ec_chip_info , NULL );
487+ "ayaneo_ec" , data , & ayaneo_ec_chip_info , NULL );
462488 if (IS_ERR (hwdev ))
463489 return PTR_ERR (hwdev );
464490 }
@@ -475,10 +501,67 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
475501 return 0 ;
476502}
477503
504+ static int ayaneo_freeze (struct device * dev )
505+ {
506+ struct platform_device * pdev = to_platform_device (dev );
507+ struct ayaneo_ec_platform_data * data = platform_get_drvdata (pdev );
508+ int ret ;
509+ u8 tmp ;
510+
511+ if (data -> quirks -> has_charge_control ) {
512+ ret = ec_read (AYANEO_CHARGE_REG , & tmp );
513+ if (ret )
514+ return ret ;
515+
516+ data -> restore_charge_limit = tmp == AYANEO_CHARGE_VAL_INHIBIT ;
517+ }
518+
519+ if (data -> quirks -> has_fan_control ) {
520+ ret = ec_read (AYANEO_PWM_ENABLE_REG , & tmp );
521+ if (ret )
522+ return ret ;
523+
524+ data -> restore_pwm = tmp == AYANEO_PWM_MODE_MANUAL ;
525+
526+ /*
527+ * Release the fan when entering hibernation to avoid
528+ * overheating if hibernation fails and hangs.
529+ */
530+ if (data -> restore_pwm ) {
531+ ret = ec_write (AYANEO_PWM_ENABLE_REG , AYANEO_PWM_MODE_AUTO );
532+ if (ret )
533+ return ret ;
534+ }
535+ }
536+
537+ return 0 ;
538+ }
539+
540+ static int ayaneo_restore (struct device * dev )
541+ {
542+ struct platform_device * pdev = to_platform_device (dev );
543+ struct ayaneo_ec_platform_data * data = platform_get_drvdata (pdev );
544+ int ret ;
545+
546+ if (data -> quirks -> has_charge_control && data -> restore_charge_limit ) {
547+ ret = ec_write (AYANEO_CHARGE_REG , AYANEO_CHARGE_VAL_INHIBIT );
548+ if (ret )
549+ return ret ;
550+ }
551+
552+ return 0 ;
553+ }
554+
555+ static const struct dev_pm_ops ayaneo_pm_ops = {
556+ .freeze = ayaneo_freeze ,
557+ .restore = ayaneo_restore ,
558+ };
559+
478560static struct platform_driver ayaneo_platform_driver = {
479561 .driver = {
480562 .name = "ayaneo-ec" ,
481563 .dev_groups = ayaneo_ec_groups ,
564+ .pm = pm_sleep_ptr (& ayaneo_pm_ops ),
482565 },
483566 .probe = ayaneo_ec_probe ,
484567};
0 commit comments