• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   *  acpi_fan.c - ACPI Fan Driver ($Revision: 29 $)
3   *
4   *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5   *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6   *
7   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8   *
9   *  This program is free software; you can redistribute it and/or modify
10   *  it under the terms of the GNU General Public License as published by
11   *  the Free Software Foundation; either version 2 of the License, or (at
12   *  your option) any later version.
13   *
14   *  This program is distributed in the hope that it will be useful, but
15   *  WITHOUT ANY WARRANTY; without even the implied warranty of
16   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   *  General Public License for more details.
18   *
19   *  You should have received a copy of the GNU General Public License along
20   *  with this program; if not, write to the Free Software Foundation, Inc.,
21   *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22   *
23   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24   */
25  
26  #include <linux/kernel.h>
27  #include <linux/module.h>
28  #include <linux/init.h>
29  #include <linux/types.h>
30  #include <linux/uaccess.h>
31  #include <linux/thermal.h>
32  #include <linux/acpi.h>
33  #include <linux/platform_device.h>
34  #include <linux/sort.h>
35  
36  MODULE_AUTHOR("Paul Diefenbaugh");
37  MODULE_DESCRIPTION("ACPI Fan Driver");
38  MODULE_LICENSE("GPL");
39  
40  static int acpi_fan_probe(struct platform_device *pdev);
41  static int acpi_fan_remove(struct platform_device *pdev);
42  
43  static const struct acpi_device_id fan_device_ids[] = {
44  	{"PNP0C0B", 0},
45  	{"INT3404", 0},
46  	{"", 0},
47  };
48  MODULE_DEVICE_TABLE(acpi, fan_device_ids);
49  
50  #ifdef CONFIG_PM_SLEEP
51  static int acpi_fan_suspend(struct device *dev);
52  static int acpi_fan_resume(struct device *dev);
53  static struct dev_pm_ops acpi_fan_pm = {
54  	.resume = acpi_fan_resume,
55  	.freeze = acpi_fan_suspend,
56  	.thaw = acpi_fan_resume,
57  	.restore = acpi_fan_resume,
58  };
59  #define FAN_PM_OPS_PTR (&acpi_fan_pm)
60  #else
61  #define FAN_PM_OPS_PTR NULL
62  #endif
63  
64  struct acpi_fan_fps {
65  	u64 control;
66  	u64 trip_point;
67  	u64 speed;
68  	u64 noise_level;
69  	u64 power;
70  };
71  
72  struct acpi_fan_fif {
73  	u64 revision;
74  	u64 fine_grain_ctrl;
75  	u64 step_size;
76  	u64 low_speed_notification;
77  };
78  
79  struct acpi_fan {
80  	bool acpi4;
81  	struct acpi_fan_fif fif;
82  	struct acpi_fan_fps *fps;
83  	int fps_count;
84  	struct thermal_cooling_device *cdev;
85  };
86  
87  static struct platform_driver acpi_fan_driver = {
88  	.probe = acpi_fan_probe,
89  	.remove = acpi_fan_remove,
90  	.driver = {
91  		.name = "acpi-fan",
92  		.acpi_match_table = fan_device_ids,
93  		.pm = FAN_PM_OPS_PTR,
94  	},
95  };
96  
97  /* thermal cooling device callbacks */
fan_get_max_state(struct thermal_cooling_device * cdev,unsigned long * state)98  static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
99  			     *state)
100  {
101  	struct acpi_device *device = cdev->devdata;
102  	struct acpi_fan *fan = acpi_driver_data(device);
103  
104  	if (fan->acpi4)
105  		*state = fan->fps_count - 1;
106  	else
107  		*state = 1;
108  	return 0;
109  }
110  
fan_get_state_acpi4(struct acpi_device * device,unsigned long * state)111  static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
112  {
113  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
114  	struct acpi_fan *fan = acpi_driver_data(device);
115  	union acpi_object *obj;
116  	acpi_status status;
117  	int control, i;
118  
119  	status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer);
120  	if (ACPI_FAILURE(status)) {
121  		dev_err(&device->dev, "Get fan state failed\n");
122  		return status;
123  	}
124  
125  	obj = buffer.pointer;
126  	if (!obj || obj->type != ACPI_TYPE_PACKAGE ||
127  	    obj->package.count != 3 ||
128  	    obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
129  		dev_err(&device->dev, "Invalid _FST data\n");
130  		status = -EINVAL;
131  		goto err;
132  	}
133  
134  	control = obj->package.elements[1].integer.value;
135  	for (i = 0; i < fan->fps_count; i++) {
136  		if (control == fan->fps[i].control)
137  			break;
138  	}
139  	if (i == fan->fps_count) {
140  		dev_dbg(&device->dev, "Invalid control value returned\n");
141  		status = -EINVAL;
142  		goto err;
143  	}
144  
145  	*state = i;
146  
147  err:
148  	kfree(obj);
149  	return status;
150  }
151  
fan_get_state(struct acpi_device * device,unsigned long * state)152  static int fan_get_state(struct acpi_device *device, unsigned long *state)
153  {
154  	int result;
155  	int acpi_state = ACPI_STATE_D0;
156  
157  	result = acpi_device_update_power(device, &acpi_state);
158  	if (result)
159  		return result;
160  
161  	*state = (acpi_state == ACPI_STATE_D3_COLD ? 0 :
162  		 (acpi_state == ACPI_STATE_D0 ? 1 : -1));
163  	return 0;
164  }
165  
fan_get_cur_state(struct thermal_cooling_device * cdev,unsigned long * state)166  static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
167  			     *state)
168  {
169  	struct acpi_device *device = cdev->devdata;
170  	struct acpi_fan *fan = acpi_driver_data(device);
171  
172  	if (fan->acpi4)
173  		return fan_get_state_acpi4(device, state);
174  	else
175  		return fan_get_state(device, state);
176  }
177  
fan_set_state(struct acpi_device * device,unsigned long state)178  static int fan_set_state(struct acpi_device *device, unsigned long state)
179  {
180  	if (state != 0 && state != 1)
181  		return -EINVAL;
182  
183  	return acpi_device_set_power(device,
184  				     state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
185  }
186  
fan_set_state_acpi4(struct acpi_device * device,unsigned long state)187  static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
188  {
189  	struct acpi_fan *fan = acpi_driver_data(device);
190  	acpi_status status;
191  
192  	if (state >= fan->fps_count)
193  		return -EINVAL;
194  
195  	status = acpi_execute_simple_method(device->handle, "_FSL",
196  					    fan->fps[state].control);
197  	if (ACPI_FAILURE(status)) {
198  		dev_dbg(&device->dev, "Failed to set state by _FSL\n");
199  		return status;
200  	}
201  
202  	return 0;
203  }
204  
205  static int
fan_set_cur_state(struct thermal_cooling_device * cdev,unsigned long state)206  fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
207  {
208  	struct acpi_device *device = cdev->devdata;
209  	struct acpi_fan *fan = acpi_driver_data(device);
210  
211  	if (fan->acpi4)
212  		return fan_set_state_acpi4(device, state);
213  	else
214  		return fan_set_state(device, state);
215   }
216  
217  static const struct thermal_cooling_device_ops fan_cooling_ops = {
218  	.get_max_state = fan_get_max_state,
219  	.get_cur_state = fan_get_cur_state,
220  	.set_cur_state = fan_set_cur_state,
221  };
222  
223  /* --------------------------------------------------------------------------
224   *                               Driver Interface
225   * --------------------------------------------------------------------------
226  */
227  
acpi_fan_is_acpi4(struct acpi_device * device)228  static bool acpi_fan_is_acpi4(struct acpi_device *device)
229  {
230  	return acpi_has_method(device->handle, "_FIF") &&
231  	       acpi_has_method(device->handle, "_FPS") &&
232  	       acpi_has_method(device->handle, "_FSL") &&
233  	       acpi_has_method(device->handle, "_FST");
234  }
235  
acpi_fan_get_fif(struct acpi_device * device)236  static int acpi_fan_get_fif(struct acpi_device *device)
237  {
238  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
239  	struct acpi_fan *fan = acpi_driver_data(device);
240  	struct acpi_buffer format = { sizeof("NNNN"), "NNNN" };
241  	struct acpi_buffer fif = { sizeof(fan->fif), &fan->fif };
242  	union acpi_object *obj;
243  	acpi_status status;
244  
245  	status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer);
246  	if (ACPI_FAILURE(status))
247  		return status;
248  
249  	obj = buffer.pointer;
250  	if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
251  		dev_err(&device->dev, "Invalid _FIF data\n");
252  		status = -EINVAL;
253  		goto err;
254  	}
255  
256  	status = acpi_extract_package(obj, &format, &fif);
257  	if (ACPI_FAILURE(status)) {
258  		dev_err(&device->dev, "Invalid _FIF element\n");
259  		status = -EINVAL;
260  	}
261  
262  err:
263  	kfree(obj);
264  	return status;
265  }
266  
acpi_fan_speed_cmp(const void * a,const void * b)267  static int acpi_fan_speed_cmp(const void *a, const void *b)
268  {
269  	const struct acpi_fan_fps *fps1 = a;
270  	const struct acpi_fan_fps *fps2 = b;
271  	return fps1->speed - fps2->speed;
272  }
273  
acpi_fan_get_fps(struct acpi_device * device)274  static int acpi_fan_get_fps(struct acpi_device *device)
275  {
276  	struct acpi_fan *fan = acpi_driver_data(device);
277  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
278  	union acpi_object *obj;
279  	acpi_status status;
280  	int i;
281  
282  	status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer);
283  	if (ACPI_FAILURE(status))
284  		return status;
285  
286  	obj = buffer.pointer;
287  	if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
288  		dev_err(&device->dev, "Invalid _FPS data\n");
289  		status = -EINVAL;
290  		goto err;
291  	}
292  
293  	fan->fps_count = obj->package.count - 1; /* minus revision field */
294  	fan->fps = devm_kzalloc(&device->dev,
295  				fan->fps_count * sizeof(struct acpi_fan_fps),
296  				GFP_KERNEL);
297  	if (!fan->fps) {
298  		dev_err(&device->dev, "Not enough memory\n");
299  		status = -ENOMEM;
300  		goto err;
301  	}
302  	for (i = 0; i < fan->fps_count; i++) {
303  		struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
304  		struct acpi_buffer fps = { sizeof(fan->fps[i]), &fan->fps[i] };
305  		status = acpi_extract_package(&obj->package.elements[i + 1],
306  					      &format, &fps);
307  		if (ACPI_FAILURE(status)) {
308  			dev_err(&device->dev, "Invalid _FPS element\n");
309  			break;
310  		}
311  	}
312  
313  	/* sort the state array according to fan speed in increase order */
314  	sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
315  	     acpi_fan_speed_cmp, NULL);
316  
317  err:
318  	kfree(obj);
319  	return status;
320  }
321  
acpi_fan_probe(struct platform_device * pdev)322  static int acpi_fan_probe(struct platform_device *pdev)
323  {
324  	int result = 0;
325  	struct thermal_cooling_device *cdev;
326  	struct acpi_fan *fan;
327  	struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
328  
329  	fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
330  	if (!fan) {
331  		dev_err(&device->dev, "No memory for fan\n");
332  		return -ENOMEM;
333  	}
334  	device->driver_data = fan;
335  	platform_set_drvdata(pdev, fan);
336  
337  	if (acpi_fan_is_acpi4(device)) {
338  		if (acpi_fan_get_fif(device) || acpi_fan_get_fps(device))
339  			goto end;
340  		fan->acpi4 = true;
341  	} else {
342  		result = acpi_device_update_power(device, NULL);
343  		if (result) {
344  			dev_err(&device->dev, "Setting initial power state\n");
345  			goto end;
346  		}
347  	}
348  
349  	cdev = thermal_cooling_device_register("Fan", device,
350  						&fan_cooling_ops);
351  	if (IS_ERR(cdev)) {
352  		result = PTR_ERR(cdev);
353  		goto end;
354  	}
355  
356  	dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id);
357  
358  	fan->cdev = cdev;
359  	result = sysfs_create_link(&pdev->dev.kobj,
360  				   &cdev->device.kobj,
361  				   "thermal_cooling");
362  	if (result)
363  		dev_err(&pdev->dev, "Failed to create sysfs link 'thermal_cooling'\n");
364  
365  	result = sysfs_create_link(&cdev->device.kobj,
366  				   &pdev->dev.kobj,
367  				   "device");
368  	if (result)
369  		dev_err(&pdev->dev, "Failed to create sysfs link 'device'\n");
370  
371  end:
372  	return result;
373  }
374  
acpi_fan_remove(struct platform_device * pdev)375  static int acpi_fan_remove(struct platform_device *pdev)
376  {
377  	struct acpi_fan *fan = platform_get_drvdata(pdev);
378  
379  	sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
380  	sysfs_remove_link(&fan->cdev->device.kobj, "device");
381  	thermal_cooling_device_unregister(fan->cdev);
382  
383  	return 0;
384  }
385  
386  #ifdef CONFIG_PM_SLEEP
acpi_fan_suspend(struct device * dev)387  static int acpi_fan_suspend(struct device *dev)
388  {
389  	struct acpi_fan *fan = dev_get_drvdata(dev);
390  	if (fan->acpi4)
391  		return 0;
392  
393  	acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D0);
394  
395  	return AE_OK;
396  }
397  
acpi_fan_resume(struct device * dev)398  static int acpi_fan_resume(struct device *dev)
399  {
400  	int result;
401  	struct acpi_fan *fan = dev_get_drvdata(dev);
402  
403  	if (fan->acpi4)
404  		return 0;
405  
406  	result = acpi_device_update_power(ACPI_COMPANION(dev), NULL);
407  	if (result)
408  		dev_err(dev, "Error updating fan power state\n");
409  
410  	return result;
411  }
412  #endif
413  
414  module_platform_driver(acpi_fan_driver);
415