aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/thinkpad_acpi.c326
-rw-r--r--drivers/misc/thinkpad_acpi.h6
2 files changed, 309 insertions, 23 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index d5526e882ddd..a4d7ee472396 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -2695,6 +2695,7 @@ static enum fan_control_access_mode fan_control_access_mode;
2695static enum fan_control_commands fan_control_commands; 2695static enum fan_control_commands fan_control_commands;
2696 2696
2697static u8 fan_control_initial_status; 2697static u8 fan_control_initial_status;
2698static u8 fan_control_desired_level;
2698 2699
2699static void fan_watchdog_fire(struct work_struct *ignored); 2700static void fan_watchdog_fire(struct work_struct *ignored);
2700static int fan_watchdog_maxinterval; 2701static int fan_watchdog_maxinterval;
@@ -2708,8 +2709,222 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
2708 "JFNS", /* 770x-JL */ 2709 "JFNS", /* 770x-JL */
2709 ); /* all others */ 2710 ); /* all others */
2710 2711
2712/*
2713 * SYSFS fan layout: hwmon compatible (device)
2714 *
2715 * pwm*_enable:
2716 * 0: "disengaged" mode
2717 * 1: manual mode
2718 * 2: native EC "auto" mode (recommended, hardware default)
2719 *
2720 * pwm*: set speed in manual mode, ignored otherwise.
2721 * 0 is level 0; 255 is level 7. Intermediate points done with linear
2722 * interpolation.
2723 *
2724 * fan*_input: tachometer reading, RPM
2725 *
2726 *
2727 * SYSFS fan layout: extensions
2728 *
2729 * fan_watchdog (driver):
2730 * fan watchdog interval in seconds, 0 disables (default), max 120
2731 */
2732
2733/* sysfs fan pwm1_enable ----------------------------------------------- */
2734static ssize_t fan_pwm1_enable_show(struct device *dev,
2735 struct device_attribute *attr,
2736 char *buf)
2737{
2738 int res, mode;
2739 u8 status;
2740
2741 res = fan_get_status_safe(&status);
2742 if (res)
2743 return res;
2744
2745 if (unlikely(tp_features.fan_ctrl_status_undef)) {
2746 if (status != fan_control_initial_status) {
2747 tp_features.fan_ctrl_status_undef = 0;
2748 } else {
2749 /* Return most likely status. In fact, it
2750 * might be the only possible status */
2751 status = TP_EC_FAN_AUTO;
2752 }
2753 }
2754
2755 if (status & TP_EC_FAN_FULLSPEED) {
2756 mode = 0;
2757 } else if (status & TP_EC_FAN_AUTO) {
2758 mode = 2;
2759 } else
2760 mode = 1;
2761
2762 return snprintf(buf, PAGE_SIZE, "%d\n", mode);
2763}
2764
2765static ssize_t fan_pwm1_enable_store(struct device *dev,
2766 struct device_attribute *attr,
2767 const char *buf, size_t count)
2768{
2769 unsigned long t;
2770 int res, level;
2771
2772 if (parse_strtoul(buf, 2, &t))
2773 return -EINVAL;
2774
2775 switch (t) {
2776 case 0:
2777 level = TP_EC_FAN_FULLSPEED;
2778 break;
2779 case 1:
2780 level = TPACPI_FAN_LAST_LEVEL;
2781 break;
2782 case 2:
2783 level = TP_EC_FAN_AUTO;
2784 break;
2785 case 3:
2786 /* reserved for software-controlled auto mode */
2787 return -ENOSYS;
2788 default:
2789 return -EINVAL;
2790 }
2791
2792 res = fan_set_level_safe(level);
2793 if (res < 0)
2794 return res;
2795
2796 fan_watchdog_reset();
2797
2798 return count;
2799}
2800
2801static struct device_attribute dev_attr_fan_pwm1_enable =
2802 __ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
2803 fan_pwm1_enable_show, fan_pwm1_enable_store);
2804
2805/* sysfs fan pwm1 ------------------------------------------------------ */
2806static ssize_t fan_pwm1_show(struct device *dev,
2807 struct device_attribute *attr,
2808 char *buf)
2809{
2810 int res;
2811 u8 status;
2812
2813 res = fan_get_status_safe(&status);
2814 if (res)
2815 return res;
2816
2817 if (unlikely(tp_features.fan_ctrl_status_undef)) {
2818 if (status != fan_control_initial_status) {
2819 tp_features.fan_ctrl_status_undef = 0;
2820 } else {
2821 status = TP_EC_FAN_AUTO;
2822 }
2823 }
2824
2825 if ((status &
2826 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
2827 status = fan_control_desired_level;
2828
2829 if (status > 7)
2830 status = 7;
2831
2832 return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7);
2833}
2834
2835static ssize_t fan_pwm1_store(struct device *dev,
2836 struct device_attribute *attr,
2837 const char *buf, size_t count)
2838{
2839 unsigned long s;
2840 int rc;
2841 u8 status, newlevel;
2842
2843 if (parse_strtoul(buf, 255, &s))
2844 return -EINVAL;
2845
2846 /* scale down from 0-255 to 0-7 */
2847 newlevel = (s >> 5) & 0x07;
2848
2849 rc = mutex_lock_interruptible(&fan_mutex);
2850 if (rc < 0)
2851 return rc;
2852
2853 rc = fan_get_status(&status);
2854 if (!rc && (status &
2855 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
2856 rc = fan_set_level(newlevel);
2857 if (!rc)
2858 fan_update_desired_level(newlevel);
2859 fan_watchdog_reset();
2860 }
2861
2862 mutex_unlock(&fan_mutex);
2863 return (rc)? rc : count;
2864}
2865
2866static struct device_attribute dev_attr_fan_pwm1 =
2867 __ATTR(pwm1, S_IWUSR | S_IRUGO,
2868 fan_pwm1_show, fan_pwm1_store);
2869
2870/* sysfs fan fan1_input ------------------------------------------------ */
2871static ssize_t fan_fan1_input_show(struct device *dev,
2872 struct device_attribute *attr,
2873 char *buf)
2874{
2875 int res;
2876 unsigned int speed;
2877
2878 res = fan_get_speed(&speed);
2879 if (res < 0)
2880 return res;
2881
2882 return snprintf(buf, PAGE_SIZE, "%u\n", speed);
2883}
2884
2885static struct device_attribute dev_attr_fan_fan1_input =
2886 __ATTR(fan1_input, S_IRUGO,
2887 fan_fan1_input_show, NULL);
2888
2889/* sysfs fan fan_watchdog (driver) ------------------------------------- */
2890static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
2891 char *buf)
2892{
2893 return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
2894}
2895
2896static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
2897 const char *buf, size_t count)
2898{
2899 unsigned long t;
2900
2901 if (parse_strtoul(buf, 120, &t))
2902 return -EINVAL;
2903
2904 fan_watchdog_maxinterval = t;
2905 fan_watchdog_reset();
2906
2907 return count;
2908}
2909
2910static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
2911 fan_fan_watchdog_show, fan_fan_watchdog_store);
2912
2913/* --------------------------------------------------------------------- */
2914static struct attribute *fan_attributes[] = {
2915 &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
2916 &dev_attr_fan_fan1_input.attr,
2917 NULL
2918};
2919
2920static const struct attribute_group fan_attr_group = {
2921 .attrs = fan_attributes,
2922};
2923
2711static int __init fan_init(struct ibm_init_struct *iibm) 2924static int __init fan_init(struct ibm_init_struct *iibm)
2712{ 2925{
2926 int rc;
2927
2713 vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); 2928 vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
2714 2929
2715 mutex_init(&fan_mutex); 2930 mutex_init(&fan_mutex);
@@ -2718,6 +2933,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
2718 fan_control_commands = 0; 2933 fan_control_commands = 0;
2719 fan_watchdog_maxinterval = 0; 2934 fan_watchdog_maxinterval = 0;
2720 tp_features.fan_ctrl_status_undef = 0; 2935 tp_features.fan_ctrl_status_undef = 0;
2936 fan_control_desired_level = 7;
2721 2937
2722 IBM_ACPIHANDLE_INIT(fans); 2938 IBM_ACPIHANDLE_INIT(fans);
2723 IBM_ACPIHANDLE_INIT(gfan); 2939 IBM_ACPIHANDLE_INIT(gfan);
@@ -2796,9 +3012,36 @@ static int __init fan_init(struct ibm_init_struct *iibm)
2796 fan_control_access_mode != TPACPI_FAN_WR_NONE), 3012 fan_control_access_mode != TPACPI_FAN_WR_NONE),
2797 fan_status_access_mode, fan_control_access_mode); 3013 fan_status_access_mode, fan_control_access_mode);
2798 3014
2799 return (fan_status_access_mode != TPACPI_FAN_NONE || 3015 /* update fan_control_desired_level */
2800 fan_control_access_mode != TPACPI_FAN_WR_NONE)? 3016 if (fan_status_access_mode != TPACPI_FAN_NONE)
2801 0 : 1; 3017 fan_get_status_safe(NULL);
3018
3019 if (fan_status_access_mode != TPACPI_FAN_NONE ||
3020 fan_control_access_mode != TPACPI_FAN_WR_NONE) {
3021 rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
3022 &fan_attr_group);
3023 if (!(rc < 0))
3024 rc = driver_create_file(&tpacpi_pdriver.driver,
3025 &driver_attr_fan_watchdog);
3026 if (rc < 0)
3027 return rc;
3028 return 0;
3029 } else
3030 return 1;
3031}
3032
3033/*
3034 * Call with fan_mutex held
3035 */
3036static void fan_update_desired_level(u8 status)
3037{
3038 if ((status &
3039 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
3040 if (status > 7)
3041 fan_control_desired_level = 7;
3042 else
3043 fan_control_desired_level = status;
3044 }
2802} 3045}
2803 3046
2804static int fan_get_status(u8 *status) 3047static int fan_get_status(u8 *status)
@@ -2837,9 +3080,33 @@ static int fan_get_status(u8 *status)
2837 return 0; 3080 return 0;
2838} 3081}
2839 3082
3083static int fan_get_status_safe(u8 *status)
3084{
3085 int rc;
3086 u8 s;
3087
3088 rc = mutex_lock_interruptible(&fan_mutex);
3089 if (rc < 0)
3090 return rc;
3091 rc = fan_get_status(&s);
3092 if (!rc)
3093 fan_update_desired_level(s);
3094 mutex_unlock(&fan_mutex);
3095
3096 if (status)
3097 *status = s;
3098
3099 return rc;
3100}
3101
2840static void fan_exit(void) 3102static void fan_exit(void)
2841{ 3103{
2842 vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); 3104 vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
3105
3106 /* FIXME: can we really do this unconditionally? */
3107 sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
3108 driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
3109
2843 cancel_delayed_work(&fan_watchdog_task); 3110 cancel_delayed_work(&fan_watchdog_task);
2844 flush_scheduled_work(); 3111 flush_scheduled_work();
2845} 3112}
@@ -2902,17 +3169,10 @@ static void fan_watchdog_reset(void)
2902 3169
2903static int fan_set_level(int level) 3170static int fan_set_level(int level)
2904{ 3171{
2905 int res;
2906
2907 switch (fan_control_access_mode) { 3172 switch (fan_control_access_mode) {
2908 case TPACPI_FAN_WR_ACPI_SFAN: 3173 case TPACPI_FAN_WR_ACPI_SFAN:
2909 if (level >= 0 && level <= 7) { 3174 if (level >= 0 && level <= 7) {
2910 res = mutex_lock_interruptible(&fan_mutex); 3175 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
2911 if (res < 0)
2912 return res;
2913 res = acpi_evalf(sfan_handle, NULL, NULL, "vd", level);
2914 mutex_unlock(&fan_mutex);
2915 if (!res)
2916 return -EIO; 3176 return -EIO;
2917 } else 3177 } else
2918 return -EINVAL; 3178 return -EINVAL;
@@ -2925,12 +3185,7 @@ static int fan_set_level(int level)
2925 ((level < 0) || (level > 7))) 3185 ((level < 0) || (level > 7)))
2926 return -EINVAL; 3186 return -EINVAL;
2927 3187
2928 res = mutex_lock_interruptible(&fan_mutex); 3188 if (!acpi_ec_write(fan_status_offset, level))
2929 if (res < 0)
2930 return res;
2931 res = acpi_ec_write(fan_status_offset, level);
2932 mutex_unlock(&fan_mutex);
2933 if (!res)
2934 return -EIO; 3189 return -EIO;
2935 else 3190 else
2936 tp_features.fan_ctrl_status_undef = 0; 3191 tp_features.fan_ctrl_status_undef = 0;
@@ -2942,6 +3197,25 @@ static int fan_set_level(int level)
2942 return 0; 3197 return 0;
2943} 3198}
2944 3199
3200static int fan_set_level_safe(int level)
3201{
3202 int rc;
3203
3204 rc = mutex_lock_interruptible(&fan_mutex);
3205 if (rc < 0)
3206 return rc;
3207
3208 if (level == TPACPI_FAN_LAST_LEVEL)
3209 level = fan_control_desired_level;
3210
3211 rc = fan_set_level(level);
3212 if (!rc)
3213 fan_update_desired_level(level);
3214
3215 mutex_unlock(&fan_mutex);
3216 return rc;
3217}
3218
2945static int fan_set_enable(void) 3219static int fan_set_enable(void)
2946{ 3220{
2947 u8 s; 3221 u8 s;
@@ -3009,19 +3283,24 @@ static int fan_set_disable(void)
3009 case TPACPI_FAN_WR_TPEC: 3283 case TPACPI_FAN_WR_TPEC:
3010 if (!acpi_ec_write(fan_status_offset, 0x00)) 3284 if (!acpi_ec_write(fan_status_offset, 0x00))
3011 rc = -EIO; 3285 rc = -EIO;
3012 else 3286 else {
3287 fan_control_desired_level = 0;
3013 tp_features.fan_ctrl_status_undef = 0; 3288 tp_features.fan_ctrl_status_undef = 0;
3289 }
3014 break; 3290 break;
3015 3291
3016 case TPACPI_FAN_WR_ACPI_SFAN: 3292 case TPACPI_FAN_WR_ACPI_SFAN:
3017 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) 3293 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
3018 rc = -EIO; 3294 rc = -EIO;
3295 else
3296 fan_control_desired_level = 0;
3019 break; 3297 break;
3020 3298
3021 default: 3299 default:
3022 rc = -ENXIO; 3300 rc = -ENXIO;
3023 } 3301 }
3024 3302
3303
3025 mutex_unlock(&fan_mutex); 3304 mutex_unlock(&fan_mutex);
3026 return rc; 3305 return rc;
3027} 3306}
@@ -3063,7 +3342,7 @@ static int fan_read(char *p)
3063 switch (fan_status_access_mode) { 3342 switch (fan_status_access_mode) {
3064 case TPACPI_FAN_RD_ACPI_GFAN: 3343 case TPACPI_FAN_RD_ACPI_GFAN:
3065 /* 570, 600e/x, 770e, 770x */ 3344 /* 570, 600e/x, 770e, 770x */
3066 if ((rc = fan_get_status(&status)) < 0) 3345 if ((rc = fan_get_status_safe(&status)) < 0)
3067 return rc; 3346 return rc;
3068 3347
3069 len += sprintf(p + len, "status:\t\t%s\n" 3348 len += sprintf(p + len, "status:\t\t%s\n"
@@ -3073,7 +3352,7 @@ static int fan_read(char *p)
3073 3352
3074 case TPACPI_FAN_RD_TPEC: 3353 case TPACPI_FAN_RD_TPEC:
3075 /* all except 570, 600e/x, 770e, 770x */ 3354 /* all except 570, 600e/x, 770e, 770x */
3076 if ((rc = fan_get_status(&status)) < 0) 3355 if ((rc = fan_get_status_safe(&status)) < 0)
3077 return rc; 3356 return rc;
3078 3357
3079 if (unlikely(tp_features.fan_ctrl_status_undef)) { 3358 if (unlikely(tp_features.fan_ctrl_status_undef)) {
@@ -3117,7 +3396,7 @@ static int fan_read(char *p)
3117 3396
3118 default: 3397 default:
3119 len += sprintf(p + len, " (<level> is 0-7, " 3398 len += sprintf(p + len, " (<level> is 0-7, "
3120 "auto, disengaged)\n"); 3399 "auto, disengaged, full-speed)\n");
3121 break; 3400 break;
3122 } 3401 }
3123 } 3402 }
@@ -3140,12 +3419,13 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
3140 3419
3141 if (strlencmp(cmd, "level auto") == 0) 3420 if (strlencmp(cmd, "level auto") == 0)
3142 level = TP_EC_FAN_AUTO; 3421 level = TP_EC_FAN_AUTO;
3143 else if (strlencmp(cmd, "level disengaged") == 0) 3422 else if ((strlencmp(cmd, "level disengaged") == 0) |
3423 (strlencmp(cmd, "level full-speed") == 0))
3144 level = TP_EC_FAN_FULLSPEED; 3424 level = TP_EC_FAN_FULLSPEED;
3145 else if (sscanf(cmd, "level %d", &level) != 1) 3425 else if (sscanf(cmd, "level %d", &level) != 1)
3146 return 0; 3426 return 0;
3147 3427
3148 if ((*rc = fan_set_level(level)) == -ENXIO) 3428 if ((*rc = fan_set_level_safe(level)) == -ENXIO)
3149 printk(IBM_ERR "level command accepted for unsupported " 3429 printk(IBM_ERR "level command accepted for unsupported "
3150 "access mode %d", fan_control_access_mode); 3430 "access mode %d", fan_control_access_mode);
3151 3431
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index e833ff3caf39..2fe4d61cc27f 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -349,6 +349,8 @@ enum { /* Fan control constants */
349 349
350 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ 350 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
351 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ 351 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
352
353 TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
352}; 354};
353 355
354enum fan_status_access_mode { 356enum fan_status_access_mode {
@@ -375,6 +377,7 @@ static enum fan_status_access_mode fan_status_access_mode;
375static enum fan_control_access_mode fan_control_access_mode; 377static enum fan_control_access_mode fan_control_access_mode;
376static enum fan_control_commands fan_control_commands; 378static enum fan_control_commands fan_control_commands;
377static u8 fan_control_initial_status; 379static u8 fan_control_initial_status;
380static u8 fan_control_desired_level;
378static int fan_watchdog_maxinterval; 381static int fan_watchdog_maxinterval;
379 382
380struct mutex fan_mutex; 383struct mutex fan_mutex;
@@ -384,10 +387,13 @@ static acpi_handle fans_handle, gfan_handle, sfan_handle;
384static int fan_init(struct ibm_init_struct *iibm); 387static int fan_init(struct ibm_init_struct *iibm);
385static void fan_exit(void); 388static void fan_exit(void);
386static int fan_get_status(u8 *status); 389static int fan_get_status(u8 *status);
390static int fan_get_status_safe(u8 *status);
387static int fan_get_speed(unsigned int *speed); 391static int fan_get_speed(unsigned int *speed);
392static void fan_update_desired_level(u8 status);
388static void fan_watchdog_fire(struct work_struct *ignored); 393static void fan_watchdog_fire(struct work_struct *ignored);
389static void fan_watchdog_reset(void); 394static void fan_watchdog_reset(void);
390static int fan_set_level(int level); 395static int fan_set_level(int level);
396static int fan_set_level_safe(int level);
391static int fan_set_enable(void); 397static int fan_set_enable(void);
392static int fan_set_disable(void); 398static int fan_set_disable(void);
393static int fan_set_speed(int speed); 399static int fan_set_speed(int speed);