Blame view

drivers/acpi/fan.c 12.2 KB
c942fddf8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   *  acpi_fan.c - ACPI Fan Driver ($Revision: 29 $)
   *
   *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
   *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/types.h>
88989fd26   Sudip Mukherjee   ACPI / fan: print...
13
  #include <linux/uaccess.h>
05a83d972   Zhang Rui   ACPI: register AC...
14
  #include <linux/thermal.h>
8b48463f8   Lv Zheng   ACPI: Clean up in...
15
  #include <linux/acpi.h>
19593a1fb   Aaron Lu   ACPI / fan: conve...
16
  #include <linux/platform_device.h>
9519a6356   Aaron Lu   ACPI / Fan: add A...
17
  #include <linux/sort.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18

f52fd66d2   Len Brown   ACPI: clean up AC...
19
  MODULE_AUTHOR("Paul Diefenbaugh");
7cda93e00   Len Brown   ACPI: delete extr...
20
  MODULE_DESCRIPTION("ACPI Fan Driver");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  MODULE_LICENSE("GPL");
19593a1fb   Aaron Lu   ACPI / fan: conve...
22
23
  static int acpi_fan_probe(struct platform_device *pdev);
  static int acpi_fan_remove(struct platform_device *pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
25
26
  static const struct acpi_device_id fan_device_ids[] = {
  	{"PNP0C0B", 0},
c248dfe7e   Gayatri Kammela   ACPI: fan: Add Ti...
27
  	{"INT1044", 0},
d806c6e9c   Aaron Lu   ACPI / Fan: suppo...
28
  	{"INT3404", 0},
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
29
30
31
  	{"", 0},
  };
  MODULE_DEVICE_TABLE(acpi, fan_device_ids);
906924048   Rafael J. Wysocki   ACPI / PM: Fix un...
32
  #ifdef CONFIG_PM_SLEEP
62fcbdd95   Rafael J. Wysocki   ACPI: Use struct ...
33
34
  static int acpi_fan_suspend(struct device *dev);
  static int acpi_fan_resume(struct device *dev);
1d751584e   Kaiyen Chang   ACPI / fan: Make ...
35
  static const struct dev_pm_ops acpi_fan_pm = {
b9b8515f3   Aaron Lu   ACPI / fan: do no...
36
37
38
39
40
41
  	.resume = acpi_fan_resume,
  	.freeze = acpi_fan_suspend,
  	.thaw = acpi_fan_resume,
  	.restore = acpi_fan_resume,
  };
  #define FAN_PM_OPS_PTR (&acpi_fan_pm)
b108e0ea9   Shuah Khan   ACPI / fan: fix f...
42
  #else
b9b8515f3   Aaron Lu   ACPI / fan: do no...
43
  #define FAN_PM_OPS_PTR NULL
906924048   Rafael J. Wysocki   ACPI / PM: Fix un...
44
  #endif
62fcbdd95   Rafael J. Wysocki   ACPI: Use struct ...
45

d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
46
  #define ACPI_FPS_NAME_LEN	20
9519a6356   Aaron Lu   ACPI / Fan: add A...
47
48
49
50
51
52
  struct acpi_fan_fps {
  	u64 control;
  	u64 trip_point;
  	u64 speed;
  	u64 noise_level;
  	u64 power;
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
53
54
  	char name[ACPI_FPS_NAME_LEN];
  	struct device_attribute dev_attr;
9519a6356   Aaron Lu   ACPI / Fan: add A...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  };
  
  struct acpi_fan_fif {
  	u64 revision;
  	u64 fine_grain_ctrl;
  	u64 step_size;
  	u64 low_speed_notification;
  };
  
  struct acpi_fan {
  	bool acpi4;
  	struct acpi_fan_fif fif;
  	struct acpi_fan_fps *fps;
  	int fps_count;
  	struct thermal_cooling_device *cdev;
  };
19593a1fb   Aaron Lu   ACPI / fan: conve...
71
72
73
74
75
76
77
78
  static struct platform_driver acpi_fan_driver = {
  	.probe = acpi_fan_probe,
  	.remove = acpi_fan_remove,
  	.driver = {
  		.name = "acpi-fan",
  		.acpi_match_table = fan_device_ids,
  		.pm = FAN_PM_OPS_PTR,
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  };
05a83d972   Zhang Rui   ACPI: register AC...
80
  /* thermal cooling device callbacks */
6503e5df0   Matthew Garrett   thermal: use inte...
81
82
  static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
  			     *state)
05a83d972   Zhang Rui   ACPI: register AC...
83
  {
9519a6356   Aaron Lu   ACPI / Fan: add A...
84
85
86
87
88
89
90
  	struct acpi_device *device = cdev->devdata;
  	struct acpi_fan *fan = acpi_driver_data(device);
  
  	if (fan->acpi4)
  		*state = fan->fps_count - 1;
  	else
  		*state = 1;
6503e5df0   Matthew Garrett   thermal: use inte...
91
  	return 0;
05a83d972   Zhang Rui   ACPI: register AC...
92
  }
9519a6356   Aaron Lu   ACPI / Fan: add A...
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
  {
  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  	struct acpi_fan *fan = acpi_driver_data(device);
  	union acpi_object *obj;
  	acpi_status status;
  	int control, i;
  
  	status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer);
  	if (ACPI_FAILURE(status)) {
  		dev_err(&device->dev, "Get fan state failed
  ");
  		return status;
  	}
  
  	obj = buffer.pointer;
  	if (!obj || obj->type != ACPI_TYPE_PACKAGE ||
  	    obj->package.count != 3 ||
  	    obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
  		dev_err(&device->dev, "Invalid _FST data
  ");
  		status = -EINVAL;
  		goto err;
  	}
  
  	control = obj->package.elements[1].integer.value;
  	for (i = 0; i < fan->fps_count; i++) {
84baf1725   Srinivas Pandruvada   ACPI / fan: Fix e...
120
121
122
123
124
125
126
127
  		/*
  		 * When Fine Grain Control is set, return the state
  		 * corresponding to maximum fan->fps[i].control
  		 * value compared to the current speed. Here the
  		 * fan->fps[] is sorted array with increasing speed.
  		 */
  		if (fan->fif.fine_grain_ctrl && control < fan->fps[i].control) {
  			i = (i > 0) ? i - 1 : 0;
9519a6356   Aaron Lu   ACPI / Fan: add A...
128
  			break;
84baf1725   Srinivas Pandruvada   ACPI / fan: Fix e...
129
130
131
  		} else if (control == fan->fps[i].control) {
  			break;
  		}
9519a6356   Aaron Lu   ACPI / Fan: add A...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  	}
  	if (i == fan->fps_count) {
  		dev_dbg(&device->dev, "Invalid control value returned
  ");
  		status = -EINVAL;
  		goto err;
  	}
  
  	*state = i;
  
  err:
  	kfree(obj);
  	return status;
  }
  
  static int fan_get_state(struct acpi_device *device, unsigned long *state)
05a83d972   Zhang Rui   ACPI: register AC...
148
  {
05a83d972   Zhang Rui   ACPI: register AC...
149
  	int result;
85eb98274   Naresh Bhat   ACPI / fan: Initi...
150
  	int acpi_state = ACPI_STATE_D0;
05a83d972   Zhang Rui   ACPI: register AC...
151

2bb3a2bf9   Aaron Lu   ACPI / fan: use a...
152
  	result = acpi_device_update_power(device, &acpi_state);
05a83d972   Zhang Rui   ACPI: register AC...
153
154
  	if (result)
  		return result;
20dacb71a   Rafael J. Wysocki   ACPI / PM: Rework...
155
156
157
  	*state = acpi_state == ACPI_STATE_D3_COLD
  			|| acpi_state == ACPI_STATE_D3_HOT ?
  		0 : (acpi_state == ACPI_STATE_D0 ? 1 : -1);
6503e5df0   Matthew Garrett   thermal: use inte...
158
  	return 0;
05a83d972   Zhang Rui   ACPI: register AC...
159
  }
9519a6356   Aaron Lu   ACPI / Fan: add A...
160
161
  static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
  			     *state)
05a83d972   Zhang Rui   ACPI: register AC...
162
163
  {
  	struct acpi_device *device = cdev->devdata;
9519a6356   Aaron Lu   ACPI / Fan: add A...
164
  	struct acpi_fan *fan = acpi_driver_data(device);
05a83d972   Zhang Rui   ACPI: register AC...
165

9519a6356   Aaron Lu   ACPI / Fan: add A...
166
167
168
169
170
  	if (fan->acpi4)
  		return fan_get_state_acpi4(device, state);
  	else
  		return fan_get_state(device, state);
  }
05a83d972   Zhang Rui   ACPI: register AC...
171

9519a6356   Aaron Lu   ACPI / Fan: add A...
172
173
174
  static int fan_set_state(struct acpi_device *device, unsigned long state)
  {
  	if (state != 0 && state != 1)
05a83d972   Zhang Rui   ACPI: register AC...
175
  		return -EINVAL;
9519a6356   Aaron Lu   ACPI / Fan: add A...
176
177
178
  	return acpi_device_set_power(device,
  				     state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
  }
05a83d972   Zhang Rui   ACPI: register AC...
179

9519a6356   Aaron Lu   ACPI / Fan: add A...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
  {
  	struct acpi_fan *fan = acpi_driver_data(device);
  	acpi_status status;
  
  	if (state >= fan->fps_count)
  		return -EINVAL;
  
  	status = acpi_execute_simple_method(device->handle, "_FSL",
  					    fan->fps[state].control);
  	if (ACPI_FAILURE(status)) {
  		dev_dbg(&device->dev, "Failed to set state by _FSL
  ");
  		return status;
  	}
  
  	return 0;
05a83d972   Zhang Rui   ACPI: register AC...
197
  }
9519a6356   Aaron Lu   ACPI / Fan: add A...
198
199
200
201
202
203
204
205
206
207
  static int
  fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
  {
  	struct acpi_device *device = cdev->devdata;
  	struct acpi_fan *fan = acpi_driver_data(device);
  
  	if (fan->acpi4)
  		return fan_set_state_acpi4(device, state);
  	else
  		return fan_set_state(device, state);
447a5647c   Joe Perches   treewide: Align f...
208
  }
9519a6356   Aaron Lu   ACPI / Fan: add A...
209

9c8b04be4   Vasiliy Kulikov   ACPI: constify op...
210
  static const struct thermal_cooling_device_ops fan_cooling_ops = {
05a83d972   Zhang Rui   ACPI: register AC...
211
212
213
214
  	.get_max_state = fan_get_max_state,
  	.get_cur_state = fan_get_cur_state,
  	.set_cur_state = fan_set_cur_state,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  /* --------------------------------------------------------------------------
88989fd26   Sudip Mukherjee   ACPI / fan: print...
216
217
218
   *                               Driver Interface
   * --------------------------------------------------------------------------
  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219

9519a6356   Aaron Lu   ACPI / Fan: add A...
220
  static bool acpi_fan_is_acpi4(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  {
9519a6356   Aaron Lu   ACPI / Fan: add A...
222
223
224
225
226
  	return acpi_has_method(device->handle, "_FIF") &&
  	       acpi_has_method(device->handle, "_FPS") &&
  	       acpi_has_method(device->handle, "_FSL") &&
  	       acpi_has_method(device->handle, "_FST");
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227

9519a6356   Aaron Lu   ACPI / Fan: add A...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  static int acpi_fan_get_fif(struct acpi_device *device)
  {
  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  	struct acpi_fan *fan = acpi_driver_data(device);
  	struct acpi_buffer format = { sizeof("NNNN"), "NNNN" };
  	struct acpi_buffer fif = { sizeof(fan->fif), &fan->fif };
  	union acpi_object *obj;
  	acpi_status status;
  
  	status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer);
  	if (ACPI_FAILURE(status))
  		return status;
  
  	obj = buffer.pointer;
  	if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
  		dev_err(&device->dev, "Invalid _FIF data
  ");
  		status = -EINVAL;
  		goto err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

9519a6356   Aaron Lu   ACPI / Fan: add A...
249
250
251
252
253
254
  	status = acpi_extract_package(obj, &format, &fif);
  	if (ACPI_FAILURE(status)) {
  		dev_err(&device->dev, "Invalid _FIF element
  ");
  		status = -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255

9519a6356   Aaron Lu   ACPI / Fan: add A...
256
257
258
259
260
261
262
263
264
265
266
  err:
  	kfree(obj);
  	return status;
  }
  
  static int acpi_fan_speed_cmp(const void *a, const void *b)
  {
  	const struct acpi_fan_fps *fps1 = a;
  	const struct acpi_fan_fps *fps2 = b;
  	return fps1->speed - fps2->speed;
  }
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
267
268
269
270
271
272
  static ssize_t show_state(struct device *dev, struct device_attribute *attr, char *buf)
  {
  	struct acpi_fan_fps *fps = container_of(attr, struct acpi_fan_fps, dev_attr);
  	int count;
  
  	if (fps->control == 0xFFFFFFFF || fps->control > 100)
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
273
  		count = scnprintf(buf, PAGE_SIZE, "not-defined:");
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
274
  	else
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
275
  		count = scnprintf(buf, PAGE_SIZE, "%lld:", fps->control);
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
276
277
  
  	if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
278
  		count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
279
  	else
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
280
  		count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->trip_point);
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
281
282
  
  	if (fps->speed == 0xFFFFFFFF)
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
283
  		count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
284
  	else
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
285
  		count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->speed);
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
286
287
  
  	if (fps->noise_level == 0xFFFFFFFF)
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
288
  		count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
289
  	else
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
290
  		count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->noise_level * 100);
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
291
292
  
  	if (fps->power == 0xFFFFFFFF)
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
293
294
  		count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined
  ");
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
295
  	else
949fe25f2   Takashi Iwai   ACPI: fan: Use sc...
296
297
  		count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld
  ", fps->power);
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
298
299
300
  
  	return count;
  }
9519a6356   Aaron Lu   ACPI / Fan: add A...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  static int acpi_fan_get_fps(struct acpi_device *device)
  {
  	struct acpi_fan *fan = acpi_driver_data(device);
  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  	union acpi_object *obj;
  	acpi_status status;
  	int i;
  
  	status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer);
  	if (ACPI_FAILURE(status))
  		return status;
  
  	obj = buffer.pointer;
  	if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
  		dev_err(&device->dev, "Invalid _FPS data
  ");
  		status = -EINVAL;
  		goto err;
  	}
  
  	fan->fps_count = obj->package.count - 1; /* minus revision field */
a86854d0c   Kees Cook   treewide: devm_kz...
322
323
  	fan->fps = devm_kcalloc(&device->dev,
  				fan->fps_count, sizeof(struct acpi_fan_fps),
9519a6356   Aaron Lu   ACPI / Fan: add A...
324
325
326
327
328
329
330
331
332
  				GFP_KERNEL);
  	if (!fan->fps) {
  		dev_err(&device->dev, "Not enough memory
  ");
  		status = -ENOMEM;
  		goto err;
  	}
  	for (i = 0; i < fan->fps_count; i++) {
  		struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
333
334
  		struct acpi_buffer fps = { offsetof(struct acpi_fan_fps, name),
  						&fan->fps[i] };
9519a6356   Aaron Lu   ACPI / Fan: add A...
335
336
337
338
339
  		status = acpi_extract_package(&obj->package.elements[i + 1],
  					      &format, &fps);
  		if (ACPI_FAILURE(status)) {
  			dev_err(&device->dev, "Invalid _FPS element
  ");
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
340
  			goto err;
9519a6356   Aaron Lu   ACPI / Fan: add A...
341
342
343
344
345
346
  		}
  	}
  
  	/* sort the state array according to fan speed in increase order */
  	sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
  	     acpi_fan_speed_cmp, NULL);
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  	for (i = 0; i < fan->fps_count; ++i) {
  		struct acpi_fan_fps *fps = &fan->fps[i];
  
  		snprintf(fps->name, ACPI_FPS_NAME_LEN, "state%d", i);
  		fps->dev_attr.show = show_state;
  		fps->dev_attr.store = NULL;
  		fps->dev_attr.attr.name = fps->name;
  		fps->dev_attr.attr.mode = 0444;
  		status = sysfs_create_file(&device->dev.kobj, &fps->dev_attr.attr);
  		if (status) {
  			int j;
  
  			for (j = 0; j < i; ++j)
  				sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr);
  			break;
  		}
  	}
9519a6356   Aaron Lu   ACPI / Fan: add A...
364
365
366
367
  err:
  	kfree(obj);
  	return status;
  }
19593a1fb   Aaron Lu   ACPI / fan: conve...
368
  static int acpi_fan_probe(struct platform_device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
370
  	int result = 0;
05a83d972   Zhang Rui   ACPI: register AC...
371
  	struct thermal_cooling_device *cdev;
9519a6356   Aaron Lu   ACPI / Fan: add A...
372
  	struct acpi_fan *fan;
19593a1fb   Aaron Lu   ACPI / fan: conve...
373
  	struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
bbb16fef1   Srinivas Pandruvada   ACPI / Fan: Use b...
374
  	char *name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375

9519a6356   Aaron Lu   ACPI / Fan: add A...
376
377
378
379
380
381
382
383
384
385
  	fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
  	if (!fan) {
  		dev_err(&device->dev, "No memory for fan
  ");
  		return -ENOMEM;
  	}
  	device->driver_data = fan;
  	platform_set_drvdata(pdev, fan);
  
  	if (acpi_fan_is_acpi4(device)) {
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
386
387
388
389
390
391
392
  		result = acpi_fan_get_fif(device);
  		if (result)
  			return result;
  
  		result = acpi_fan_get_fps(device);
  		if (result)
  			return result;
9519a6356   Aaron Lu   ACPI / Fan: add A...
393
394
395
396
  		fan->acpi4 = true;
  	} else {
  		result = acpi_device_update_power(device, NULL);
  		if (result) {
f97279996   Andy Lutomirski   ACPI / fan: Impro...
397
398
  			dev_err(&device->dev, "Failed to set initial power state
  ");
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
399
  			goto err_end;
9519a6356   Aaron Lu   ACPI / Fan: add A...
400
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  	}
bbb16fef1   Srinivas Pandruvada   ACPI / Fan: Use b...
402
403
404
405
406
407
  	if (!strncmp(pdev->name, "PNP0C0B", strlen("PNP0C0B")))
  		name = "Fan";
  	else
  		name = acpi_device_bid(device);
  
  	cdev = thermal_cooling_device_register(name, device,
05a83d972   Zhang Rui   ACPI: register AC...
408
  						&fan_cooling_ops);
19b36780e   Thomas Sujith   ACPI fan: extract...
409
410
  	if (IS_ERR(cdev)) {
  		result = PTR_ERR(cdev);
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
411
  		goto err_end;
19b36780e   Thomas Sujith   ACPI fan: extract...
412
  	}
9030062f3   Julia Lawall   ACPI: elide a non...
413

19593a1fb   Aaron Lu   ACPI / fan: conve...
414
415
  	dev_dbg(&pdev->dev, "registered as cooling_device%d
  ", cdev->id);
9030062f3   Julia Lawall   ACPI: elide a non...
416

9519a6356   Aaron Lu   ACPI / Fan: add A...
417
  	fan->cdev = cdev;
19593a1fb   Aaron Lu   ACPI / fan: conve...
418
  	result = sysfs_create_link(&pdev->dev.kobj,
9030062f3   Julia Lawall   ACPI: elide a non...
419
420
421
  				   &cdev->device.kobj,
  				   "thermal_cooling");
  	if (result)
8264fce6d   Linus Torvalds   Merge branch 'nex...
422
423
  		dev_err(&pdev->dev, "Failed to create sysfs link 'thermal_cooling'
  ");
9030062f3   Julia Lawall   ACPI: elide a non...
424
425
  
  	result = sysfs_create_link(&cdev->device.kobj,
19593a1fb   Aaron Lu   ACPI / fan: conve...
426
  				   &pdev->dev.kobj,
9030062f3   Julia Lawall   ACPI: elide a non...
427
  				   "device");
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
428
  	if (result) {
8264fce6d   Linus Torvalds   Merge branch 'nex...
429
430
  		dev_err(&pdev->dev, "Failed to create sysfs link 'device'
  ");
d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
431
432
433
434
435
436
437
438
439
440
441
442
  		goto err_end;
  	}
  
  	return 0;
  
  err_end:
  	if (fan->acpi4) {
  		int i;
  
  		for (i = 0; i < fan->fps_count; ++i)
  			sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443

d550d98d3   Patrick Mochel   ACPI: delete trac...
444
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  }
19593a1fb   Aaron Lu   ACPI / fan: conve...
446
  static int acpi_fan_remove(struct platform_device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  {
9519a6356   Aaron Lu   ACPI / Fan: add A...
448
  	struct acpi_fan *fan = platform_get_drvdata(pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449

d19e470b6   Srinivas Pandruvada   ACPI: fan: Expose...
450
451
452
453
454
455
456
  	if (fan->acpi4) {
  		struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
  		int i;
  
  		for (i = 0; i < fan->fps_count; ++i)
  			sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
  	}
19593a1fb   Aaron Lu   ACPI / fan: conve...
457
  	sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
9519a6356   Aaron Lu   ACPI / Fan: add A...
458
459
  	sysfs_remove_link(&fan->cdev->device.kobj, "device");
  	thermal_cooling_device_unregister(fan->cdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460

d550d98d3   Patrick Mochel   ACPI: delete trac...
461
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  }
906924048   Rafael J. Wysocki   ACPI / PM: Fix un...
463
  #ifdef CONFIG_PM_SLEEP
62fcbdd95   Rafael J. Wysocki   ACPI: Use struct ...
464
  static int acpi_fan_suspend(struct device *dev)
ec68373c0   Len Brown   Revert "ACPI: Fan...
465
  {
9519a6356   Aaron Lu   ACPI / Fan: add A...
466
467
468
  	struct acpi_fan *fan = dev_get_drvdata(dev);
  	if (fan->acpi4)
  		return 0;
ec68373c0   Len Brown   Revert "ACPI: Fan...
469

19593a1fb   Aaron Lu   ACPI / fan: conve...
470
  	acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D0);
ec68373c0   Len Brown   Revert "ACPI: Fan...
471
472
473
  
  	return AE_OK;
  }
62fcbdd95   Rafael J. Wysocki   ACPI: Use struct ...
474
  static int acpi_fan_resume(struct device *dev)
ec68373c0   Len Brown   Revert "ACPI: Fan...
475
  {
488a76c52   Rafael J. Wysocki   ACPI / Fan: Rewor...
476
  	int result;
9519a6356   Aaron Lu   ACPI / Fan: add A...
477
  	struct acpi_fan *fan = dev_get_drvdata(dev);
ec68373c0   Len Brown   Revert "ACPI: Fan...
478

9519a6356   Aaron Lu   ACPI / Fan: add A...
479
480
  	if (fan->acpi4)
  		return 0;
ec68373c0   Len Brown   Revert "ACPI: Fan...
481

19593a1fb   Aaron Lu   ACPI / fan: conve...
482
  	result = acpi_device_update_power(ACPI_COMPANION(dev), NULL);
488a76c52   Rafael J. Wysocki   ACPI / Fan: Rewor...
483
  	if (result)
88989fd26   Sudip Mukherjee   ACPI / fan: print...
484
485
  		dev_err(dev, "Error updating fan power state
  ");
ec68373c0   Len Brown   Revert "ACPI: Fan...
486
487
488
  
  	return result;
  }
906924048   Rafael J. Wysocki   ACPI / PM: Fix un...
489
  #endif
ec68373c0   Len Brown   Revert "ACPI: Fan...
490

19593a1fb   Aaron Lu   ACPI / fan: conve...
491
  module_platform_driver(acpi_fan_driver);