aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Lu <aaron.lu@intel.com>2014-04-01 03:50:27 -0400
committerZhang Rui <rui.zhang@intel.com>2014-10-10 01:57:13 -0400
commit9519a6356cbf63b1f22a7a208385dc56092c8b7d (patch)
tree6c933347a873e8c3617c26af7710bca27763b5c2
parent19593a1fb1f6718406afca5b867dab184289d406 (diff)
ACPI / Fan: add ACPI 4.0 style fan support
This patch adds support for ACPI 4.0 style fan, lacking part is: no support for 'Low Speed Notification Support', 'Fine Grain Control' is not used yet. It's not clear what to do on suspend/resume callback for 4.0 style ACPI fan, so it does nothing for now. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
-rw-r--r--drivers/acpi/fan.c268
1 files changed, 241 insertions, 27 deletions
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 8a5b450576df..f7d1c8027736 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -31,6 +31,7 @@
31#include <linux/thermal.h> 31#include <linux/thermal.h>
32#include <linux/acpi.h> 32#include <linux/acpi.h>
33#include <linux/platform_device.h> 33#include <linux/platform_device.h>
34#include <linux/sort.h>
34 35
35MODULE_AUTHOR("Paul Diefenbaugh"); 36MODULE_AUTHOR("Paul Diefenbaugh");
36MODULE_DESCRIPTION("ACPI Fan Driver"); 37MODULE_DESCRIPTION("ACPI Fan Driver");
@@ -59,6 +60,29 @@ static struct dev_pm_ops acpi_fan_pm = {
59#define FAN_PM_OPS_PTR NULL 60#define FAN_PM_OPS_PTR NULL
60#endif 61#endif
61 62
63struct acpi_fan_fps {
64 u64 control;
65 u64 trip_point;
66 u64 speed;
67 u64 noise_level;
68 u64 power;
69};
70
71struct acpi_fan_fif {
72 u64 revision;
73 u64 fine_grain_ctrl;
74 u64 step_size;
75 u64 low_speed_notification;
76};
77
78struct acpi_fan {
79 bool acpi4;
80 struct acpi_fan_fif fif;
81 struct acpi_fan_fps *fps;
82 int fps_count;
83 struct thermal_cooling_device *cdev;
84};
85
62static struct platform_driver acpi_fan_driver = { 86static struct platform_driver acpi_fan_driver = {
63 .probe = acpi_fan_probe, 87 .probe = acpi_fan_probe,
64 .remove = acpi_fan_remove, 88 .remove = acpi_fan_remove,
@@ -73,21 +97,62 @@ static struct platform_driver acpi_fan_driver = {
73static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long 97static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
74 *state) 98 *state)
75{ 99{
76 /* ACPI fan device only support two states: ON/OFF */ 100 struct acpi_device *device = cdev->devdata;
77 *state = 1; 101 struct acpi_fan *fan = acpi_driver_data(device);
102
103 if (fan->acpi4)
104 *state = fan->fps_count - 1;
105 else
106 *state = 1;
78 return 0; 107 return 0;
79} 108}
80 109
81static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long 110static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
82 *state) 111{
112 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
113 struct acpi_fan *fan = acpi_driver_data(device);
114 union acpi_object *obj;
115 acpi_status status;
116 int control, i;
117
118 status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer);
119 if (ACPI_FAILURE(status)) {
120 dev_err(&device->dev, "Get fan state failed\n");
121 return status;
122 }
123
124 obj = buffer.pointer;
125 if (!obj || obj->type != ACPI_TYPE_PACKAGE ||
126 obj->package.count != 3 ||
127 obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
128 dev_err(&device->dev, "Invalid _FST data\n");
129 status = -EINVAL;
130 goto err;
131 }
132
133 control = obj->package.elements[1].integer.value;
134 for (i = 0; i < fan->fps_count; i++) {
135 if (control == fan->fps[i].control)
136 break;
137 }
138 if (i == fan->fps_count) {
139 dev_dbg(&device->dev, "Invalid control value returned\n");
140 status = -EINVAL;
141 goto err;
142 }
143
144 *state = i;
145
146err:
147 kfree(obj);
148 return status;
149}
150
151static int fan_get_state(struct acpi_device *device, unsigned long *state)
83{ 152{
84 struct acpi_device *device = cdev->devdata;
85 int result; 153 int result;
86 int acpi_state = ACPI_STATE_D0; 154 int acpi_state = ACPI_STATE_D0;
87 155
88 if (!device)
89 return -EINVAL;
90
91 result = acpi_device_update_power(device, &acpi_state); 156 result = acpi_device_update_power(device, &acpi_state);
92 if (result) 157 if (result)
93 return result; 158 return result;
@@ -97,21 +162,57 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
97 return 0; 162 return 0;
98} 163}
99 164
100static int 165static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
101fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) 166 *state)
102{ 167{
103 struct acpi_device *device = cdev->devdata; 168 struct acpi_device *device = cdev->devdata;
104 int result; 169 struct acpi_fan *fan = acpi_driver_data(device);
170
171 if (fan->acpi4)
172 return fan_get_state_acpi4(device, state);
173 else
174 return fan_get_state(device, state);
175}
105 176
106 if (!device || (state != 0 && state != 1)) 177static int fan_set_state(struct acpi_device *device, unsigned long state)
178{
179 if (state != 0 && state != 1)
107 return -EINVAL; 180 return -EINVAL;
108 181
109 result = acpi_device_set_power(device, 182 return acpi_device_set_power(device,
110 state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD); 183 state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
184}
111 185
112 return result; 186static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
187{
188 struct acpi_fan *fan = acpi_driver_data(device);
189 acpi_status status;
190
191 if (state >= fan->fps_count)
192 return -EINVAL;
193
194 status = acpi_execute_simple_method(device->handle, "_FSL",
195 fan->fps[state].control);
196 if (ACPI_FAILURE(status)) {
197 dev_dbg(&device->dev, "Failed to set state by _FSL\n");
198 return status;
199 }
200
201 return 0;
113} 202}
114 203
204static int
205fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
206{
207 struct acpi_device *device = cdev->devdata;
208 struct acpi_fan *fan = acpi_driver_data(device);
209
210 if (fan->acpi4)
211 return fan_set_state_acpi4(device, state);
212 else
213 return fan_set_state(device, state);
214 }
215
115static const struct thermal_cooling_device_ops fan_cooling_ops = { 216static const struct thermal_cooling_device_ops fan_cooling_ops = {
116 .get_max_state = fan_get_max_state, 217 .get_max_state = fan_get_max_state,
117 .get_cur_state = fan_get_cur_state, 218 .get_cur_state = fan_get_cur_state,
@@ -122,16 +223,125 @@ static const struct thermal_cooling_device_ops fan_cooling_ops = {
122 Driver Interface 223 Driver Interface
123 -------------------------------------------------------------------------- */ 224 -------------------------------------------------------------------------- */
124 225
226static bool acpi_fan_is_acpi4(struct acpi_device *device)
227{
228 return acpi_has_method(device->handle, "_FIF") &&
229 acpi_has_method(device->handle, "_FPS") &&
230 acpi_has_method(device->handle, "_FSL") &&
231 acpi_has_method(device->handle, "_FST");
232}
233
234static int acpi_fan_get_fif(struct acpi_device *device)
235{