1 /* 2 * Windfarm PowerMac thermal control. SMU based 1 CPU desktop control loops 3 * 4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. 5 * <benh@kernel.crashing.org> 6 * 7 * Released under the term of the GNU GPL v2. 8 * 9 * The algorithm used is the PID control algorithm, used the same 10 * way the published Darwin code does, using the same values that 11 * are present in the Darwin 8.2 snapshot property lists (note however 12 * that none of the code has been re-used, it's a complete re-implementation 13 * 14 * The various control loops found in Darwin config file are: 15 * 16 * PowerMac9,1 17 * =========== 18 * 19 * Has 3 control loops: CPU fans is similar to PowerMac8,1 (though it doesn't 20 * try to play with other control loops fans). Drive bay is rather basic PID 21 * with one sensor and one fan. Slots area is a bit different as the Darwin 22 * driver is supposed to be capable of working in a special "AGP" mode which 23 * involves the presence of an AGP sensor and an AGP fan (possibly on the 24 * AGP card itself). I can't deal with that special mode as I don't have 25 * access to those additional sensor/fans for now (though ultimately, it would 26 * be possible to add sensor objects for them) so I'm only implementing the 27 * basic PCI slot control loop 28 */ 29 30 #include <linux/types.h> 31 #include <linux/errno.h> 32 #include <linux/kernel.h> 33 #include <linux/delay.h> 34 #include <linux/slab.h> 35 #include <linux/init.h> 36 #include <linux/spinlock.h> 37 #include <linux/wait.h> 38 #include <linux/kmod.h> 39 #include <linux/device.h> 40 #include <linux/platform_device.h> 41 #include <asm/prom.h> 42 #include <asm/machdep.h> 43 #include <asm/io.h> 44 #include <asm/sections.h> 45 #include <asm/smu.h> 46 47 #include "windfarm.h" 48 #include "windfarm_pid.h" 49 50 #define VERSION "0.4" 51 52 #undef DEBUG 53 54 #ifdef DEBUG 55 #define DBG(args...) printk(args) 56 #else 57 #define DBG(args...) do { } while(0) 58 #endif 59 60 /* define this to force CPU overtemp to 74 degree, useful for testing 61 * the overtemp code 62 */ 63 #undef HACKED_OVERTEMP 64 65 /* Controls & sensors */ 66 static struct wf_sensor *sensor_cpu_power; 67 static struct wf_sensor *sensor_cpu_temp; 68 static struct wf_sensor *sensor_hd_temp; 69 static struct wf_sensor *sensor_slots_power; 70 static struct wf_control *fan_cpu_main; 71 static struct wf_control *fan_cpu_second; 72 static struct wf_control *fan_cpu_third; 73 static struct wf_control *fan_hd; 74 static struct wf_control *fan_slots; 75 static struct wf_control *cpufreq_clamp; 76 77 /* Set to kick the control loop into life */ 78 static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started; 79 80 /* Failure handling.. could be nicer */ 81 #define FAILURE_FAN 0x01 82 #define FAILURE_SENSOR 0x02 83 #define FAILURE_OVERTEMP 0x04 84 85 static unsigned int wf_smu_failure_state; 86 static int wf_smu_readjust, wf_smu_skipping; 87 88 /* 89 * ****** CPU Fans Control Loop ****** 90 * 91 */ 92 93 94 #define WF_SMU_CPU_FANS_INTERVAL 1 95 #define WF_SMU_CPU_FANS_MAX_HISTORY 16 96 97 /* State data used by the cpu fans control loop 98 */ 99 struct wf_smu_cpu_fans_state { 100 int ticks; 101 s32 cpu_setpoint; 102 struct wf_cpu_pid_state pid; 103 }; 104 105 static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans; 106 107 108 109 /* 110 * ****** Drive Fan Control Loop ****** 111 * 112 */ 113 114 struct wf_smu_drive_fans_state { 115 int ticks; 116 s32 setpoint; 117 struct wf_pid_state pid; 118 }; 119 120 static struct wf_smu_drive_fans_state *wf_smu_drive_fans; 121 122 /* 123 * ****** Slots Fan Control Loop ****** 124 * 125 */ 126 127 struct wf_smu_slots_fans_state { 128 int ticks; 129 s32 setpoint; 130 struct wf_pid_state pid; 131 }; 132 133 static struct wf_smu_slots_fans_state *wf_smu_slots_fans; 134 135 /* 136 * ***** Implementation ***** 137 * 138 */ 139 140 141 static void wf_smu_create_cpu_fans(void) 142 { 143 struct wf_cpu_pid_param pid_param; 144 const struct smu_sdbp_header *hdr; 145 struct smu_sdbp_cpupiddata *piddata; 146 struct smu_sdbp_fvt *fvt; 147 s32 tmax, tdelta, maxpow, powadj; 148 149 /* First, locate the PID params in SMU SBD */ 150 hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL); 151 if (hdr == 0) { 152 printk(KERN_WARNING "windfarm: CPU PID fan config not found " 153 "max fan speed\n"); 154 goto fail; 155 } 156 piddata = (struct smu_sdbp_cpupiddata *)&hdr[1]; 157 158 /* Get the FVT params for operating point 0 (the only supported one 159 * for now) in order to get tmax 160 */ 161 hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); 162 if (hdr) { 163 fvt = (struct smu_sdbp_fvt *)&hdr[1]; 164 tmax = ((s32)fvt->maxtemp) << 16; 165 } else 166 tmax = 0x5e0000; /* 94 degree default */ 167 168 /* Alloc & initialize state */ 169 wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state), 170 GFP_KERNEL); 171 if (wf_smu_cpu_fans == NULL) 172 goto fail; 173 wf_smu_cpu_fans->ticks = 1; 174 175 /* Fill PID params */ 176 pid_param.interval = WF_SMU_CPU_FANS_INTERVAL; 177 pid_param.history_len = piddata->history_len; 178 if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) { 179 printk(KERN_WARNING "windfarm: History size overflow on " 180 "CPU control loop (%d)\n", piddata->history_len); 181 pid_param.history_len = WF_CPU_PID_MAX_HISTORY; 182 } 183 pid_param.gd = piddata->gd; 184 pid_param.gp = piddata->gp; 185 pid_param.gr = piddata->gr / pid_param.history_len; 186 187 tdelta = ((s32)piddata->target_temp_delta) << 16; 188 maxpow = ((s32)piddata->max_power) << 16; 189 powadj = ((s32)piddata->power_adj) << 16; 190 191 pid_param.tmax = tmax; 192 pid_param.ttarget = tmax - tdelta; 193 pid_param.pmaxadj = maxpow - powadj; 194 195 pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main); 196 pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main); 197 198 wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param); 199 200 DBG("wf: CPU Fan control initialized.\n"); 201 DBG(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n", 202 FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax), 203 pid_param.min, pid_param.max); 204 205 return; 206 207 fail: 208 printk(KERN_WARNING "windfarm: CPU fan config not found\n" 209 "for this machine model, max fan speed\n"); 210 211 if (cpufreq_clamp) 212 wf_control_set_max(cpufreq_clamp); 213 if (fan_cpu_main) 214 wf_control_set_max(fan_cpu_main); 215 } 216 217 static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) 218 { 219 s32 new_setpoint, temp, power; 220 int rc; 221 222 if (--st->ticks != 0) { 223 if (wf_smu_readjust) 224 goto readjust; 225 return; 226 } 227 st->ticks = WF_SMU_CPU_FANS_INTERVAL; 228 229 rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp); 230 if (rc) { 231 printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n", 232 rc); 233 wf_smu_failure_state |= FAILURE_SENSOR; 234 return; 235 } 236 237 rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power); 238 if (rc) { 239 printk(KERN_WARNING "windfarm: CPU power sensor error %d\n", 240 rc); 241 wf_smu_failure_state |= FAILURE_SENSOR; 242 return; 243 } 244 245 DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n", 246 FIX32TOPRINT(temp), FIX32TOPRINT(power)); 247 248 #ifdef HACKED_OVERTEMP 249 if (temp > 0x4a0000) 250 wf_smu_failure_state |= FAILURE_OVERTEMP; 251 #else 252 if (temp > st->pid.param.tmax) 253 wf_smu_failure_state |= FAILURE_OVERTEMP; 254 #endif 255 new_setpoint = wf_cpu_pid_run(&st->pid, power, temp); 256 257 DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint); 258 259 if (st->cpu_setpoint == new_setpoint) 260 return; 261 st->cpu_setpoint = new_setpoint; 262 readjust: 263 if (fan_cpu_main && wf_smu_failure_state == 0) { 264 rc = fan_cpu_main->ops->set_value(fan_cpu_main, 265 st->cpu_setpoint); 266 if (rc) { 267 printk(KERN_WARNING "windfarm: CPU main fan" 268 " error %d\n", rc); 269 wf_smu_failure_state |= FAILURE_FAN; 270 } 271 } 272 if (fan_cpu_second && wf_smu_failure_state == 0) { 273 rc = fan_cpu_second->ops->set_value(fan_cpu_second, 274 st->cpu_setpoint); 275 if (rc) { 276 printk(KERN_WARNING "windfarm: CPU second fan" 277 " error %d\n", rc); 278 wf_smu_failure_state |= FAILURE_FAN; 279 } 280 } 281 if (fan_cpu_third && wf_smu_failure_state == 0) { 282 rc = fan_cpu_main->ops->set_value(fan_cpu_third, 283 st->cpu_setpoint); 284 if (rc) { 285 printk(KERN_WARNING "windfarm: CPU third fan" 286 " error %d\n", rc); 287 wf_smu_failure_state |= FAILURE_FAN; 288 } 289 } 290 } 291 292 static void wf_smu_create_drive_fans(void) 293 { 294 struct wf_pid_param param = { 295 .interval = 5, 296 .history_len = 2, 297 .gd = 0x01e00000, 298 .gp = 0x00500000, 299 .gr = 0x00000000, 300 .itarget = 0x00200000, 301 }; 302 303 /* Alloc & initialize state */ 304 wf_smu_drive_fans = kmalloc(sizeof(struct wf_smu_drive_fans_state), 305 GFP_KERNEL); 306 if (wf_smu_drive_fans == NULL) { 307 printk(KERN_WARNING "windfarm: Memory allocation error" 308 " max fan speed\n"); 309 goto fail; 310 } 311 wf_smu_drive_fans->ticks = 1; 312 313 /* Fill PID params */ 314 param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN); 315 param.min = fan_hd->ops->get_min(fan_hd); 316 param.max = fan_hd->ops->get_max(fan_hd); 317 wf_pid_init(&wf_smu_drive_fans->pid, ¶m); 318 319 DBG("wf: Drive Fan control initialized.\n"); 320 DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n", 321 FIX32TOPRINT(param.itarget), param.min, param.max); 322 return; 323 324 fail: 325 if (fan_hd) 326 wf_control_set_max(fan_hd); 327 } 328 329 static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st) 330 { 331 s32 new_setpoint, temp; 332 int rc; 333 334 if (--st->ticks != 0) { 335 if (wf_smu_readjust) 336 goto readjust; 337 return; 338 } 339 st->ticks = st->pid.param.interval; 340 341 rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp); 342 if (rc) { 343 printk(KERN_WARNING "windfarm: HD temp sensor error %d\n", 344 rc); 345 wf_smu_failure_state |= FAILURE_SENSOR; 346 return; 347 } 348 349 DBG("wf_smu: Drive Fans tick ! HD temp: %d.%03d\n", 350 FIX32TOPRINT(temp)); 351 352 if (temp > (st->pid.param.itarget + 0x50000)) 353 wf_smu_failure_state |= FAILURE_OVERTEMP; 354 355 new_setpoint = wf_pid_run(&st->pid, temp); 356 357 DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint); 358 359 if (st->setpoint == new_setpoint) 360 return; 361 st->setpoint = new_setpoint; 362 readjust: 363 if (fan_hd && wf_smu_failure_state == 0) { 364 rc = fan_hd->ops->set_value(fan_hd, st->setpoint); 365 if (rc) { 366 printk(KERN_WARNING "windfarm: HD fan error %d\n", 367 rc); 368 wf_smu_failure_state |= FAILURE_FAN; 369 } 370 } 371 } 372 373 static void wf_smu_create_slots_fans(void) 374 { 375 struct wf_pid_param param = { 376 .interval = 1, 377 .history_len = 8, 378 .gd = 0x00000000, 379 .gp = 0x00000000, 380 .gr = 0x00020000, 381 .itarget = 0x00000000 382 }; 383 384 /* Alloc & initialize state */ 385 wf_smu_slots_fans = kmalloc(sizeof(struct wf_smu_slots_fans_state), 386 GFP_KERNEL); 387 if (wf_smu_slots_fans == NULL) { 388 printk(KERN_WARNING "windfarm: Memory allocation error" 389 " max fan speed\n"); 390 goto fail; 391 } 392 wf_smu_slots_fans->ticks = 1; 393 394 /* Fill PID params */ 395 param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN); 396 param.min = fan_slots->ops->get_min(fan_slots); 397 param.max = fan_slots->ops->get_max(fan_slots); 398 wf_pid_init(&wf_smu_slots_fans->pid, ¶m); 399 400 DBG("wf: Slots Fan control initialized.\n"); 401 DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n", 402 FIX32TOPRINT(param.itarget), param.min, param.max); 403 return; 404 405 fail: 406 if (fan_slots) 407 wf_control_set_max(fan_slots); 408 } 409 410 static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st) 411 { 412 s32 new_setpoint, power; 413 int rc; 414 415 if (--st->ticks != 0) { 416 if (wf_smu_readjust) 417 goto readjust; 418 return; 419 } 420 st->ticks = st->pid.param.interval; 421 422 rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power); 423 if (rc) { 424 printk(KERN_WARNING "windfarm: Slots power sensor error %d\n", 425 rc); 426 wf_smu_failure_state |= FAILURE_SENSOR; 427 return; 428 } 429 430 DBG("wf_smu: Slots Fans tick ! Slots power: %d.%03d\n", 431 FIX32TOPRINT(power)); 432 433 #if 0 /* Check what makes a good overtemp condition */ 434 if (power > (st->pid.param.itarget + 0x50000)) 435 wf_smu_failure_state |= FAILURE_OVERTEMP; 436 #endif 437 438 new_setpoint = wf_pid_run(&st->pid, power); 439 440 DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint); 441 442 if (st->setpoint == new_setpoint) 443 return; 444 st->setpoint = new_setpoint; 445 readjust: 446 if (fan_slots && wf_smu_failure_state == 0) { 447 rc = fan_slots->ops->set_value(fan_slots, st->setpoint); 448 if (rc) { 449 printk(KERN_WARNING "windfarm: Slots fan error %d\n", 450 rc); 451 wf_smu_failure_state |= FAILURE_FAN; 452 } 453 } 454 } 455 456 457 /* 458 * ****** Setup / Init / Misc ... ****** 459 * 460 */ 461 462 static void wf_smu_tick(void) 463 { 464 unsigned int last_failure = wf_smu_failure_state; 465 unsigned int new_failure; 466 467 if (!wf_smu_started) { 468 DBG("wf: creating control loops !\n"); 469 wf_smu_create_drive_fans(); 470 wf_smu_create_slots_fans(); 471 wf_smu_create_cpu_fans(); 472 wf_smu_started = 1; 473 } 474 475 /* Skipping ticks */ 476 if (wf_smu_skipping && --wf_smu_skipping) 477 return; 478 479 wf_smu_failure_state = 0; 480 if (wf_smu_drive_fans) 481 wf_smu_drive_fans_tick(wf_smu_drive_fans); 482 if (wf_smu_slots_fans) 483 wf_smu_slots_fans_tick(wf_smu_slots_fans); 484 if (wf_smu_cpu_fans) 485 wf_smu_cpu_fans_tick(wf_smu_cpu_fans); 486 487 wf_smu_readjust = 0; 488 new_failure = wf_smu_failure_state & ~last_failure; 489 490 /* If entering failure mode, clamp cpufreq and ramp all 491 * fans to full speed. 492 */ 493 if (wf_smu_failure_state && !last_failure) { 494 if (cpufreq_clamp) 495 wf_control_set_max(cpufreq_clamp); 496 if (fan_cpu_main) 497 wf_control_set_max(fan_cpu_main); 498 if (fan_cpu_second) 499 wf_control_set_max(fan_cpu_second); 500 if (fan_cpu_third) 501 wf_control_set_max(fan_cpu_third); 502 if (fan_hd) 503 wf_control_set_max(fan_hd); 504 if (fan_slots) 505 wf_control_set_max(fan_slots); 506 } 507 508 /* If leaving failure mode, unclamp cpufreq and readjust 509 * all fans on next iteration 510 */ 511 if (!wf_smu_failure_state && last_failure) { 512 if (cpufreq_clamp) 513 wf_control_set_min(cpufreq_clamp); 514 wf_smu_readjust = 1; 515 } 516 517 /* Overtemp condition detected, notify and start skipping a couple 518 * ticks to let the temperature go down 519 */ 520 if (new_failure & FAILURE_OVERTEMP) { 521 wf_set_overtemp(); 522 wf_smu_skipping = 2; 523 } 524 525 /* We only clear the overtemp condition if overtemp is cleared 526 * _and_ no other failure is present. Since a sensor error will 527 * clear the overtemp condition (can't measure temperature) at 528 * the control loop levels, but we don't want to keep it clear 529 * here in this case 530 */ 531 if (new_failure == 0 && last_failure & FAILURE_OVERTEMP) 532 wf_clear_overtemp(); 533 } 534 535 536 static void wf_smu_new_control(struct wf_control *ct) 537 { 538 if (wf_smu_all_controls_ok) 539 return; 540 541 if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-rear-fan-0")) { 542 if (wf_get_control(ct) == 0) 543 fan_cpu_main = ct; 544 } 545 546 if (fan_cpu_second == NULL && !strcmp(ct->name, "cpu-rear-fan-1")) { 547 if (wf_get_control(ct) == 0) 548 fan_cpu_second = ct; 549 } 550 551 if (fan_cpu_third == NULL && !strcmp(ct->name, "cpu-front-fan-0")) { 552 if (wf_get_control(ct) == 0) 553 fan_cpu_third = ct; 554 } 555 556 if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) { 557 if (wf_get_control(ct) == 0) 558 cpufreq_clamp = ct; 559 } 560 561 if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) { 562 if (wf_get_control(ct) == 0) 563 fan_hd = ct; 564 } 565 566 if (fan_slots == NULL && !strcmp(ct->name, "slots-fan")) { 567 if (wf_get_control(ct) == 0) 568 fan_slots = ct; 569 } 570 571 if (fan_cpu_main && (fan_cpu_second || fan_cpu_third) && fan_hd && 572 fan_slots && cpufreq_clamp) 573 wf_smu_all_controls_ok = 1; 574 } 575 576 static void wf_smu_new_sensor(struct wf_sensor *sr) 577 { 578 if (wf_smu_all_sensors_ok) 579 return; 580 581 if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) { 582 if (wf_get_sensor(sr) == 0) 583 sensor_cpu_power = sr; 584 } 585 586 if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) { 587 if (wf_get_sensor(sr) == 0) 588 sensor_cpu_temp = sr; 589 } 590 591 if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) { 592 if (wf_get_sensor(sr) == 0) 593 sensor_hd_temp = sr; 594 } 595 596 if (sensor_slots_power == NULL && !strcmp(sr->name, "slots-power")) { 597 if (wf_get_sensor(sr) == 0) 598 sensor_slots_power = sr; 599 } 600 601 if (sensor_cpu_power && sensor_cpu_temp && 602 sensor_hd_temp && sensor_slots_power) 603 wf_smu_all_sensors_ok = 1; 604 } 605 606 607 static int wf_smu_notify(struct notifier_block *self, 608 unsigned long event, void *data) 609 { 610 switch(event) { 611 case WF_EVENT_NEW_CONTROL: 612 DBG("wf: new control %s detected\n", 613 ((struct wf_control *)data)->name); 614 wf_smu_new_control(data); 615 wf_smu_readjust = 1; 616 break; 617 case WF_EVENT_NEW_SENSOR: 618 DBG("wf: new sensor %s detected\n", 619 ((struct wf_sensor *)data)->name); 620 wf_smu_new_sensor(data); 621 break; 622 case WF_EVENT_TICK: 623 if (wf_smu_all_controls_ok && wf_smu_all_sensors_ok) 624 wf_smu_tick(); 625 } 626 627 return 0; 628 } 629 630 static struct notifier_block wf_smu_events = { 631 .notifier_call = wf_smu_notify, 632 }; 633 634 static int wf_init_pm(void) 635 { 636 printk(KERN_INFO "windfarm: Initializing for Desktop G5 model\n"); 637 638 return 0; 639 } 640 641 static int wf_smu_probe(struct platform_device *ddev) 642 { 643 wf_register_client(&wf_smu_events); 644 645 return 0; 646 } 647 648 static int __devexit wf_smu_remove(struct platform_device *ddev) 649 { 650 wf_unregister_client(&wf_smu_events); 651 652 /* XXX We don't have yet a guarantee that our callback isn't 653 * in progress when returning from wf_unregister_client, so 654 * we add an arbitrary delay. I'll have to fix that in the core 655 */ 656 msleep(1000); 657 658 /* Release all sensors */ 659 /* One more crappy race: I don't think we have any guarantee here 660 * that the attribute callback won't race with the sensor beeing 661 * disposed of, and I'm not 100% certain what best way to deal 662 * with that except by adding locks all over... I'll do that 663 * eventually but heh, who ever rmmod this module anyway ? 664 */ 665 if (sensor_cpu_power) 666 wf_put_sensor(sensor_cpu_power); 667 if (sensor_cpu_temp) 668 wf_put_sensor(sensor_cpu_temp); 669 if (sensor_hd_temp) 670 wf_put_sensor(sensor_hd_temp); 671 if (sensor_slots_power) 672 wf_put_sensor(sensor_slots_power); 673 674 /* Release all controls */ 675 if (fan_cpu_main) 676 wf_put_control(fan_cpu_main); 677 if (fan_cpu_second) 678 wf_put_control(fan_cpu_second); 679 if (fan_cpu_third) 680 wf_put_control(fan_cpu_third); 681 if (fan_hd) 682 wf_put_control(fan_hd); 683 if (fan_slots) 684 wf_put_control(fan_slots); 685 if (cpufreq_clamp) 686 wf_put_control(cpufreq_clamp); 687 688 /* Destroy control loops state structures */ 689 kfree(wf_smu_slots_fans); 690 kfree(wf_smu_drive_fans); 691 kfree(wf_smu_cpu_fans); 692 693 return 0; 694 } 695 696 static struct platform_driver wf_smu_driver = { 697 .probe = wf_smu_probe, 698 .remove = __devexit_p(wf_smu_remove), 699 .driver = { 700 .name = "windfarm", 701 .owner = THIS_MODULE, 702 }, 703 }; 704 705 706 static int __init wf_smu_init(void) 707 { 708 int rc = -ENODEV; 709 710 if (of_machine_is_compatible("PowerMac9,1")) 711 rc = wf_init_pm(); 712 713 if (rc == 0) { 714 #ifdef MODULE 715 request_module("windfarm_smu_controls"); 716 request_module("windfarm_smu_sensors"); 717 request_module("windfarm_lm75_sensor"); 718 request_module("windfarm_cpufreq_clamp"); 719 720 #endif /* MODULE */ 721 platform_driver_register(&wf_smu_driver); 722 } 723 724 return rc; 725 } 726 727 static void __exit wf_smu_exit(void) 728 { 729 730 platform_driver_unregister(&wf_smu_driver); 731 } 732 733 734 module_init(wf_smu_init); 735 module_exit(wf_smu_exit); 736 737 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 738 MODULE_DESCRIPTION("Thermal control logic for PowerMac9,1"); 739 MODULE_LICENSE("GPL"); 740 741 MODULE_ALIAS("platform:windfarm"); 742