diff options
author | Jean Delvare <khali@linux-fr.org> | 2012-12-19 16:16:59 -0500 |
---|---|---|
committer | Jean Delvare <khali@endymion.delvare> | 2012-12-19 16:16:59 -0500 |
commit | 7e630bb55a52cfaa35011c0ebc2efc96f13e5135 (patch) | |
tree | f3f405eb3d9fd80d8729b62799624072837c15d3 /drivers/hwmon | |
parent | 275b7d6ebe9e3599b2d178089171afd63d3fda02 (diff) |
hwmon: (w83627ehf) Add support for suspend
On suspend some register values are lost, most notably the Value RAM
areas but also other limits and settings. Restore them on resume.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/w83627ehf.c | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 55ac41c05561..7fbd0ba0f26f 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * w83627ehf - Driver for the hardware monitoring functionality of | 2 | * w83627ehf - Driver for the hardware monitoring functionality of |
3 | * the Winbond W83627EHF Super-I/O chip | 3 | * the Winbond W83627EHF Super-I/O chip |
4 | * Copyright (C) 2005-2011 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2005-2012 Jean Delvare <khali@linux-fr.org> |
5 | * Copyright (C) 2006 Yuan Mu (Winbond), | 5 | * Copyright (C) 2006 Yuan Mu (Winbond), |
6 | * Rudolf Marek <r.marek@assembler.cz> | 6 | * Rudolf Marek <r.marek@assembler.cz> |
7 | * David Hubbard <david.c.hubbard@gmail.com> | 7 | * David Hubbard <david.c.hubbard@gmail.com> |
@@ -502,6 +502,13 @@ struct w83627ehf_data { | |||
502 | u16 have_temp_offset; | 502 | u16 have_temp_offset; |
503 | u8 in6_skip:1; | 503 | u8 in6_skip:1; |
504 | u8 temp3_val_only:1; | 504 | u8 temp3_val_only:1; |
505 | |||
506 | #ifdef CONFIG_PM | ||
507 | /* Remember extra register values over suspend/resume */ | ||
508 | u8 vbat; | ||
509 | u8 fandiv1; | ||
510 | u8 fandiv2; | ||
511 | #endif | ||
505 | }; | 512 | }; |
506 | 513 | ||
507 | struct w83627ehf_sio_data { | 514 | struct w83627ehf_sio_data { |
@@ -2608,10 +2615,96 @@ static int w83627ehf_remove(struct platform_device *pdev) | |||
2608 | return 0; | 2615 | return 0; |
2609 | } | 2616 | } |
2610 | 2617 | ||
2618 | #ifdef CONFIG_PM | ||
2619 | static int w83627ehf_suspend(struct device *dev) | ||
2620 | { | ||
2621 | struct w83627ehf_data *data = w83627ehf_update_device(dev); | ||
2622 | struct w83627ehf_sio_data *sio_data = dev->platform_data; | ||
2623 | |||
2624 | mutex_lock(&data->update_lock); | ||
2625 | data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT); | ||
2626 | if (sio_data->kind == nct6775) { | ||
2627 | data->fandiv1 = w83627ehf_read_value(data, NCT6775_REG_FANDIV1); | ||
2628 | data->fandiv2 = w83627ehf_read_value(data, NCT6775_REG_FANDIV2); | ||
2629 | } | ||
2630 | mutex_unlock(&data->update_lock); | ||
2631 | |||
2632 | return 0; | ||
2633 | } | ||
2634 | |||
2635 | static int w83627ehf_resume(struct device *dev) | ||
2636 | { | ||
2637 | struct w83627ehf_data *data = dev_get_drvdata(dev); | ||
2638 | struct w83627ehf_sio_data *sio_data = dev->platform_data; | ||
2639 | int i; | ||
2640 | |||
2641 | mutex_lock(&data->update_lock); | ||
2642 | data->bank = 0xff; /* Force initial bank selection */ | ||
2643 | |||
2644 | /* Restore limits */ | ||
2645 | for (i = 0; i < data->in_num; i++) { | ||
2646 | if ((i == 6) && data->in6_skip) | ||
2647 | continue; | ||
2648 | |||
2649 | w83627ehf_write_value(data, W83627EHF_REG_IN_MIN(i), | ||
2650 | data->in_min[i]); | ||
2651 | w83627ehf_write_value(data, W83627EHF_REG_IN_MAX(i), | ||
2652 | data->in_max[i]); | ||
2653 | } | ||
2654 | |||
2655 | for (i = 0; i < 5; i++) { | ||
2656 | if (!(data->has_fan_min & (1 << i))) | ||
2657 | continue; | ||
2658 | |||
2659 | w83627ehf_write_value(data, data->REG_FAN_MIN[i], | ||
2660 | data->fan_min[i]); | ||
2661 | } | ||
2662 | |||
2663 | for (i = 0; i < NUM_REG_TEMP; i++) { | ||
2664 | if (!(data->have_temp & (1 << i))) | ||
2665 | continue; | ||
2666 | |||
2667 | if (data->reg_temp_over[i]) | ||
2668 | w83627ehf_write_temp(data, data->reg_temp_over[i], | ||
2669 | data->temp_max[i]); | ||
2670 | if (data->reg_temp_hyst[i]) | ||
2671 | w83627ehf_write_temp(data, data->reg_temp_hyst[i], | ||
2672 | data->temp_max_hyst[i]); | ||
2673 | if (data->have_temp_offset & (1 << i)) | ||
2674 | w83627ehf_write_value(data, | ||
2675 | W83627EHF_REG_TEMP_OFFSET[i], | ||
2676 | data->temp_offset[i]); | ||
2677 | } | ||
2678 | |||
2679 | /* Restore other settings */ | ||
2680 | w83627ehf_write_value(data, W83627EHF_REG_VBAT, data->vbat); | ||
2681 | if (sio_data->kind == nct6775) { | ||
2682 | w83627ehf_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1); | ||
2683 | w83627ehf_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2); | ||
2684 | } | ||
2685 | |||
2686 | /* Force re-reading all values */ | ||
2687 | data->valid = 0; | ||
2688 | mutex_unlock(&data->update_lock); | ||
2689 | |||
2690 | return 0; | ||
2691 | } | ||
2692 | |||
2693 | static const struct dev_pm_ops w83627ehf_dev_pm_ops = { | ||
2694 | .suspend = w83627ehf_suspend, | ||
2695 | .resume = w83627ehf_resume, | ||
2696 | }; | ||
2697 | |||
2698 | #define W83627EHF_DEV_PM_OPS (&w83627ehf_dev_pm_ops) | ||
2699 | #else | ||
2700 | #define W83627EHF_DEV_PM_OPS NULL | ||
2701 | #endif /* CONFIG_PM */ | ||
2702 | |||
2611 | static struct platform_driver w83627ehf_driver = { | 2703 | static struct platform_driver w83627ehf_driver = { |
2612 | .driver = { | 2704 | .driver = { |
2613 | .owner = THIS_MODULE, | 2705 | .owner = THIS_MODULE, |
2614 | .name = DRVNAME, | 2706 | .name = DRVNAME, |
2707 | .pm = W83627EHF_DEV_PM_OPS, | ||
2615 | }, | 2708 | }, |
2616 | .probe = w83627ehf_probe, | 2709 | .probe = w83627ehf_probe, |
2617 | .remove = w83627ehf_remove, | 2710 | .remove = w83627ehf_remove, |