This source file includes following definitions.
- pm121_correct
- pm121_connect
- pm121_create_sys_fans
- pm121_sys_fans_tick
- pm121_create_cpu_fans
- pm121_cpu_fans_tick
- pm121_tick
- pm121_register_control
- pm121_new_control
- pm121_register_sensor
- pm121_new_sensor
- pm121_notify
- pm121_init_pm
- pm121_probe
- pm121_remove
- pm121_init
- pm121_exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191 #undef DEBUG
192
193 #include <linux/types.h>
194 #include <linux/errno.h>
195 #include <linux/kernel.h>
196 #include <linux/delay.h>
197 #include <linux/slab.h>
198 #include <linux/init.h>
199 #include <linux/spinlock.h>
200 #include <linux/wait.h>
201 #include <linux/kmod.h>
202 #include <linux/device.h>
203 #include <linux/platform_device.h>
204 #include <asm/prom.h>
205 #include <asm/machdep.h>
206 #include <asm/io.h>
207 #include <asm/sections.h>
208 #include <asm/smu.h>
209
210 #include "windfarm.h"
211 #include "windfarm_pid.h"
212
213 #define VERSION "0.3"
214
215 static int pm121_mach_model;
216
217
218 static struct wf_sensor *sensor_cpu_power;
219 static struct wf_sensor *sensor_cpu_temp;
220 static struct wf_sensor *sensor_cpu_voltage;
221 static struct wf_sensor *sensor_cpu_current;
222 static struct wf_sensor *sensor_gpu_temp;
223 static struct wf_sensor *sensor_north_bridge_temp;
224 static struct wf_sensor *sensor_hard_drive_temp;
225 static struct wf_sensor *sensor_optical_drive_temp;
226 static struct wf_sensor *sensor_incoming_air_temp;
227
228 enum {
229 FAN_CPU,
230 FAN_HD,
231 FAN_OD,
232 CPUFREQ,
233 N_CONTROLS
234 };
235 static struct wf_control *controls[N_CONTROLS] = {};
236
237
238 static int pm121_all_controls_ok, pm121_all_sensors_ok;
239 static bool pm121_started;
240
241 enum {
242 FAILURE_FAN = 1 << 0,
243 FAILURE_SENSOR = 1 << 1,
244 FAILURE_OVERTEMP = 1 << 2
245 };
246
247
248
249 enum {
250 LOOP_GPU,
251
252 LOOP_HD,
253 LOOP_KODIAK,
254 LOOP_OD,
255 N_LOOPS
256 };
257
258 static const char *loop_names[N_LOOPS] = {
259 "GPU",
260 "HD",
261 "KODIAK",
262 "OD",
263 };
264
265 #define PM121_NUM_CONFIGS 2
266
267 static unsigned int pm121_failure_state;
268 static int pm121_readjust, pm121_skipping;
269 static bool pm121_overtemp;
270 static s32 average_power;
271
272 struct pm121_correction {
273 int offset;
274 int slope;
275 };
276
277 static struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = {
278
279 {
280
281 { .offset = -19563152,
282 .slope = 1956315
283 },
284
285 { .offset = -15650652,
286 .slope = 1565065
287 },
288 },
289
290 {
291
292 { .offset = -15650652,
293 .slope = 1565065
294 },
295
296 { .offset = -19563152,
297 .slope = 1956315
298 },
299 },
300
301 {
302
303 { .offset = -25431900,
304 .slope = 2543190
305 },
306
307 { .offset = -15650652,
308 .slope = 1565065
309 },
310 },
311
312 };
313
314 struct pm121_connection {
315 unsigned int control_id;
316 unsigned int ref_id;
317 struct pm121_correction correction;
318 };
319
320 static struct pm121_connection pm121_connections[] = {
321
322 { .control_id = FAN_CPU,
323 .ref_id = FAN_OD,
324 { .offset = -32768000,
325 .slope = 65536
326 }
327 },
328
329 { .control_id = FAN_OD,
330 .ref_id = FAN_HD,
331 { .offset = -32768000,
332 .slope = 65536
333 }
334 },
335 };
336
337
338 static struct pm121_connection *pm121_connection;
339
340
341
342
343
344
345
346
347
348
349
350 struct pm121_sys_param {
351
352 int model_id;
353 struct wf_sensor **sensor;
354 s32 gp, itarget;
355 unsigned int control_id;
356 };
357
358 static struct pm121_sys_param
359 pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = {
360
361 {
362 { .model_id = 2,
363 .sensor = &sensor_gpu_temp,
364 .gp = 0x002A6666,
365 .itarget = 0x5A0000,
366 .control_id = FAN_HD,
367 },
368 { .model_id = 3,
369 .sensor = &sensor_gpu_temp,
370 .gp = 0x0010CCCC,
371 .itarget = 0x500000,
372 .control_id = FAN_CPU,
373 },
374 },
375
376 {
377 { .model_id = 2,
378 .sensor = &sensor_hard_drive_temp,
379 .gp = 0x002D70A3,
380 .itarget = 0x370000,
381 .control_id = FAN_HD,
382 },
383 { .model_id = 3,
384 .sensor = &sensor_hard_drive_temp,
385 .gp = 0x002170A3,
386 .itarget = 0x370000,
387 .control_id = FAN_HD,
388 },
389 },
390
391 {
392 { .model_id = 2,
393 .sensor = &sensor_north_bridge_temp,
394 .gp = 0x003BD70A,
395 .itarget = 0x550000,
396 .control_id = FAN_OD,
397 },
398 { .model_id = 3,
399 .sensor = &sensor_north_bridge_temp,
400 .gp = 0x0030F5C2,
401 .itarget = 0x550000,
402 .control_id = FAN_HD,
403 },
404 },
405
406 {
407 { .model_id = 2,
408 .sensor = &sensor_optical_drive_temp,
409 .gp = 0x001FAE14,
410 .itarget = 0x320000,
411 .control_id = FAN_OD,
412 },
413 { .model_id = 3,
414 .sensor = &sensor_optical_drive_temp,
415 .gp = 0x001FAE14,
416 .itarget = 0x320000,
417 .control_id = FAN_OD,
418 },
419 },
420 };
421
422
423 #define PM121_SYS_GD 0x00000000
424 #define PM121_SYS_GR 0x00019999
425 #define PM121_SYS_HISTORY_SIZE 2
426 #define PM121_SYS_INTERVAL 5
427
428
429
430 struct pm121_sys_state {
431 int ticks;
432 s32 setpoint;
433 struct wf_pid_state pid;
434 };
435
436 struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {};
437
438
439
440
441
442
443 #define PM121_CPU_INTERVAL 1
444
445
446
447 struct pm121_cpu_state {
448 int ticks;
449 s32 setpoint;
450 struct wf_cpu_pid_state pid;
451 };
452
453 static struct pm121_cpu_state *pm121_cpu_state;
454
455
456
457
458
459
460
461
462
463 static s32 pm121_correct(s32 new_setpoint,
464 unsigned int control_id,
465 s32 min)
466 {
467 s32 new_min;
468 struct pm121_correction *correction;
469 correction = &corrections[control_id][pm121_mach_model - 2];
470
471 new_min = (average_power * correction->slope) >> 16;
472 new_min += correction->offset;
473 new_min = (new_min >> 16) + min;
474
475 return max3(new_setpoint, new_min, 0);
476 }
477
478 static s32 pm121_connect(unsigned int control_id, s32 setpoint)
479 {
480 s32 new_min, value, new_setpoint;
481
482 if (pm121_connection->control_id == control_id) {
483 controls[control_id]->ops->get_value(controls[control_id],
484 &value);
485 new_min = value * pm121_connection->correction.slope;
486 new_min += pm121_connection->correction.offset;
487 if (new_min > 0) {
488 new_setpoint = max(setpoint, (new_min >> 16));
489 if (new_setpoint != setpoint) {
490 pr_debug("pm121: %s depending on %s, "
491 "corrected from %d to %d RPM\n",
492 controls[control_id]->name,
493 controls[pm121_connection->ref_id]->name,
494 (int) setpoint, (int) new_setpoint);
495 }
496 } else
497 new_setpoint = setpoint;
498 }
499
500 else
501 new_setpoint = setpoint;
502
503 return new_setpoint;
504 }
505
506
507 static void pm121_create_sys_fans(int loop_id)
508 {
509 struct pm121_sys_param *param = NULL;
510 struct wf_pid_param pid_param;
511 struct wf_control *control = NULL;
512 int i;
513
514
515 for (i = 0; i < PM121_NUM_CONFIGS; i++) {
516 if (pm121_sys_all_params[loop_id][i].model_id == pm121_mach_model) {
517 param = &(pm121_sys_all_params[loop_id][i]);
518 break;
519 }
520 }
521
522
523 if (param == NULL) {
524 printk(KERN_WARNING "pm121: %s fan config not found "
525 " for this machine model\n",
526 loop_names[loop_id]);
527 goto fail;
528 }
529
530 control = controls[param->control_id];
531
532
533 pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state),
534 GFP_KERNEL);
535 if (pm121_sys_state[loop_id] == NULL) {
536 printk(KERN_WARNING "pm121: Memory allocation error\n");
537 goto fail;
538 }
539 pm121_sys_state[loop_id]->ticks = 1;
540
541
542 pid_param.gd = PM121_SYS_GD;
543 pid_param.gp = param->gp;
544 pid_param.gr = PM121_SYS_GR;
545 pid_param.interval = PM121_SYS_INTERVAL;
546 pid_param.history_len = PM121_SYS_HISTORY_SIZE;
547 pid_param.itarget = param->itarget;
548 if(control)
549 {
550 pid_param.min = control->ops->get_min(control);
551 pid_param.max = control->ops->get_max(control);
552 } else {
553
554
555
556
557 pid_param.min = 0;
558 pid_param.max = 0;
559 }
560
561 wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param);
562
563 pr_debug("pm121: %s Fan control loop initialized.\n"
564 " itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
565 loop_names[loop_id], FIX32TOPRINT(pid_param.itarget),
566 pid_param.min, pid_param.max);
567 return;
568
569 fail:
570
571
572 printk(KERN_WARNING "pm121: failed to set up %s loop "
573 "setting \"%s\" to max speed.\n",
574 loop_names[loop_id], control ? control->name : "uninitialized value");
575
576 if (control)
577 wf_control_set_max(control);
578 }
579
580 static void pm121_sys_fans_tick(int loop_id)
581 {
582 struct pm121_sys_param *param;
583 struct pm121_sys_state *st;
584 struct wf_sensor *sensor;
585 struct wf_control *control;
586 s32 temp, new_setpoint;
587 int rc;
588
589 param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]);
590 st = pm121_sys_state[loop_id];
591 sensor = *(param->sensor);
592 control = controls[param->control_id];
593
594 if (--st->ticks != 0) {
595 if (pm121_readjust)
596 goto readjust;
597 return;
598 }
599 st->ticks = PM121_SYS_INTERVAL;
600
601 rc = sensor->ops->get_value(sensor, &temp);
602 if (rc) {
603 printk(KERN_WARNING "windfarm: %s sensor error %d\n",
604 sensor->name, rc);
605 pm121_failure_state |= FAILURE_SENSOR;
606 return;
607 }
608
609 pr_debug("pm121: %s Fan tick ! %s: %d.%03d\n",
610 loop_names[loop_id], sensor->name,
611 FIX32TOPRINT(temp));
612
613 new_setpoint = wf_pid_run(&st->pid, temp);
614
615
616 new_setpoint = pm121_correct(new_setpoint,
617 param->control_id,
618 st->pid.param.min);
619
620 new_setpoint = pm121_connect(param->control_id, new_setpoint);
621
622 if (new_setpoint == st->setpoint)
623 return;
624 st->setpoint = new_setpoint;
625 pr_debug("pm121: %s corrected setpoint: %d RPM\n",
626 control->name, (int)new_setpoint);
627 readjust:
628 if (control && pm121_failure_state == 0) {
629 rc = control->ops->set_value(control, st->setpoint);
630 if (rc) {
631 printk(KERN_WARNING "windfarm: %s fan error %d\n",
632 control->name, rc);
633 pm121_failure_state |= FAILURE_FAN;
634 }
635 }
636 }
637
638
639
640 static void pm121_create_cpu_fans(void)
641 {
642 struct wf_cpu_pid_param pid_param;
643 const struct smu_sdbp_header *hdr;
644 struct smu_sdbp_cpupiddata *piddata;
645 struct smu_sdbp_fvt *fvt;
646 struct wf_control *fan_cpu;
647 s32 tmax, tdelta, maxpow, powadj;
648
649 fan_cpu = controls[FAN_CPU];
650
651
652 hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
653 if (hdr == 0) {
654 printk(KERN_WARNING "pm121: CPU PID fan config not found.\n");
655 goto fail;
656 }
657 piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
658
659
660
661
662 hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
663 if (hdr) {
664 fvt = (struct smu_sdbp_fvt *)&hdr[1];
665 tmax = ((s32)fvt->maxtemp) << 16;
666 } else
667 tmax = 0x5e0000;
668
669
670 pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state),
671 GFP_KERNEL);
672 if (pm121_cpu_state == NULL)
673 goto fail;
674 pm121_cpu_state->ticks = 1;
675
676
677 pid_param.interval = PM121_CPU_INTERVAL;
678 pid_param.history_len = piddata->history_len;
679 if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
680 printk(KERN_WARNING "pm121: History size overflow on "
681 "CPU control loop (%d)\n", piddata->history_len);
682 pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
683 }
684 pid_param.gd = piddata->gd;
685 pid_param.gp = piddata->gp;
686 pid_param.gr = piddata->gr / pid_param.history_len;
687
688 tdelta = ((s32)piddata->target_temp_delta) << 16;
689 maxpow = ((s32)piddata->max_power) << 16;
690 powadj = ((s32)piddata->power_adj) << 16;
691
692 pid_param.tmax = tmax;
693 pid_param.ttarget = tmax - tdelta;
694 pid_param.pmaxadj = maxpow - powadj;
695
696 pid_param.min = fan_cpu->ops->get_min(fan_cpu);
697 pid_param.max = fan_cpu->ops->get_max(fan_cpu);
698
699 wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param);
700
701 pr_debug("pm121: CPU Fan control initialized.\n");
702 pr_debug(" ttarget=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n",
703 FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
704 pid_param.min, pid_param.max);
705
706 return;
707
708 fail:
709 printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n");
710
711 if (controls[CPUFREQ])
712 wf_control_set_max(controls[CPUFREQ]);
713 if (fan_cpu)
714 wf_control_set_max(fan_cpu);
715 }
716
717
718 static void pm121_cpu_fans_tick(struct pm121_cpu_state *st)
719 {
720 s32 new_setpoint, temp, power;
721 struct wf_control *fan_cpu = NULL;
722 int rc;
723
724 if (--st->ticks != 0) {
725 if (pm121_readjust)
726 goto readjust;
727 return;
728 }
729 st->ticks = PM121_CPU_INTERVAL;
730
731 fan_cpu = controls[FAN_CPU];
732
733 rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
734 if (rc) {
735 printk(KERN_WARNING "pm121: CPU temp sensor error %d\n",
736 rc);
737 pm121_failure_state |= FAILURE_SENSOR;
738 return;
739 }
740
741 rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
742 if (rc) {
743 printk(KERN_WARNING "pm121: CPU power sensor error %d\n",
744 rc);
745 pm121_failure_state |= FAILURE_SENSOR;
746 return;
747 }
748
749 pr_debug("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n",
750 FIX32TOPRINT(temp), FIX32TOPRINT(power));
751
752 if (temp > st->pid.param.tmax)
753 pm121_failure_state |= FAILURE_OVERTEMP;
754
755 new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
756
757
758 new_setpoint = pm121_correct(new_setpoint,
759 FAN_CPU,
760 st->pid.param.min);
761
762
763 new_setpoint = pm121_connect(FAN_CPU, new_setpoint);
764
765 if (st->setpoint == new_setpoint)
766 return;
767 st->setpoint = new_setpoint;
768 pr_debug("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint);
769
770 readjust:
771 if (fan_cpu && pm121_failure_state == 0) {
772 rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint);
773 if (rc) {
774 printk(KERN_WARNING "pm121: %s fan error %d\n",
775 fan_cpu->name, rc);
776 pm121_failure_state |= FAILURE_FAN;
777 }
778 }
779 }
780
781
782
783
784
785
786 static void pm121_tick(void)
787 {
788 unsigned int last_failure = pm121_failure_state;
789 unsigned int new_failure;
790 s32 total_power;
791 int i;
792
793 if (!pm121_started) {
794 pr_debug("pm121: creating control loops !\n");
795 for (i = 0; i < N_LOOPS; i++)
796 pm121_create_sys_fans(i);
797
798 pm121_create_cpu_fans();
799 pm121_started = true;
800 }
801
802
803 if (pm121_skipping && --pm121_skipping)
804 return;
805
806
807 total_power = 0;
808 for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++)
809 total_power += pm121_cpu_state->pid.powers[i];
810
811 average_power = total_power / pm121_cpu_state->pid.param.history_len;
812
813
814 pm121_failure_state = 0;
815 for (i = 0 ; i < N_LOOPS; i++) {
816 if (pm121_sys_state[i])
817 pm121_sys_fans_tick(i);
818 }
819
820 if (pm121_cpu_state)
821 pm121_cpu_fans_tick(pm121_cpu_state);
822
823 pm121_readjust = 0;
824 new_failure = pm121_failure_state & ~last_failure;
825
826
827
828
829 if (pm121_failure_state && !last_failure) {
830 for (i = 0; i < N_CONTROLS; i++) {
831 if (controls[i])
832 wf_control_set_max(controls[i]);
833 }
834 }
835
836
837
838
839 if (!pm121_failure_state && last_failure) {
840 if (controls[CPUFREQ])
841 wf_control_set_min(controls[CPUFREQ]);
842 pm121_readjust = 1;
843 }
844
845
846
847
848 if (new_failure & FAILURE_OVERTEMP) {
849 wf_set_overtemp();
850 pm121_skipping = 2;
851 pm121_overtemp = true;
852 }
853
854
855
856
857
858
859
860 if (!pm121_failure_state && pm121_overtemp) {
861 wf_clear_overtemp();
862 pm121_overtemp = false;
863 }
864 }
865
866
867 static struct wf_control* pm121_register_control(struct wf_control *ct,
868 const char *match,
869 unsigned int id)
870 {
871 if (controls[id] == NULL && !strcmp(ct->name, match)) {
872 if (wf_get_control(ct) == 0)
873 controls[id] = ct;
874 }
875 return controls[id];
876 }
877
878 static void pm121_new_control(struct wf_control *ct)
879 {
880 int all = 1;
881
882 if (pm121_all_controls_ok)
883 return;
884
885 all = pm121_register_control(ct, "optical-drive-fan", FAN_OD) && all;
886 all = pm121_register_control(ct, "hard-drive-fan", FAN_HD) && all;
887 all = pm121_register_control(ct, "cpu-fan", FAN_CPU) && all;
888 all = pm121_register_control(ct, "cpufreq-clamp", CPUFREQ) && all;
889
890 if (all)
891 pm121_all_controls_ok = 1;
892 }
893
894
895
896
897 static struct wf_sensor* pm121_register_sensor(struct wf_sensor *sensor,
898 const char *match,
899 struct wf_sensor **var)
900 {
901 if (*var == NULL && !strcmp(sensor->name, match)) {
902 if (wf_get_sensor(sensor) == 0)
903 *var = sensor;
904 }
905 return *var;
906 }
907
908 static void pm121_new_sensor(struct wf_sensor *sr)
909 {
910 int all = 1;
911
912 if (pm121_all_sensors_ok)
913 return;
914
915 all = pm121_register_sensor(sr, "cpu-temp",
916 &sensor_cpu_temp) && all;
917 all = pm121_register_sensor(sr, "cpu-current",
918 &sensor_cpu_current) && all;
919 all = pm121_register_sensor(sr, "cpu-voltage",
920 &sensor_cpu_voltage) && all;
921 all = pm121_register_sensor(sr, "cpu-power",
922 &sensor_cpu_power) && all;
923 all = pm121_register_sensor(sr, "hard-drive-temp",
924 &sensor_hard_drive_temp) && all;
925 all = pm121_register_sensor(sr, "optical-drive-temp",
926 &sensor_optical_drive_temp) && all;
927 all = pm121_register_sensor(sr, "incoming-air-temp",
928 &sensor_incoming_air_temp) && all;
929 all = pm121_register_sensor(sr, "north-bridge-temp",
930 &sensor_north_bridge_temp) && all;
931 all = pm121_register_sensor(sr, "gpu-temp",
932 &sensor_gpu_temp) && all;
933
934 if (all)
935 pm121_all_sensors_ok = 1;
936 }
937
938
939
940 static int pm121_notify(struct notifier_block *self,
941 unsigned long event, void *data)
942 {
943 switch (event) {
944 case WF_EVENT_NEW_CONTROL:
945 pr_debug("pm121: new control %s detected\n",
946 ((struct wf_control *)data)->name);
947 pm121_new_control(data);
948 break;
949 case WF_EVENT_NEW_SENSOR:
950 pr_debug("pm121: new sensor %s detected\n",
951 ((struct wf_sensor *)data)->name);
952 pm121_new_sensor(data);
953 break;
954 case WF_EVENT_TICK:
955 if (pm121_all_controls_ok && pm121_all_sensors_ok)
956 pm121_tick();
957 break;
958 }
959
960 return 0;
961 }
962
963 static struct notifier_block pm121_events = {
964 .notifier_call = pm121_notify,
965 };
966
967 static int pm121_init_pm(void)
968 {
969 const struct smu_sdbp_header *hdr;
970
971 hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
972 if (hdr != 0) {
973 struct smu_sdbp_sensortree *st =
974 (struct smu_sdbp_sensortree *)&hdr[1];
975 pm121_mach_model = st->model_id;
976 }
977
978 pm121_connection = &pm121_connections[pm121_mach_model - 2];
979
980 printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n",
981 pm121_mach_model);
982
983 return 0;
984 }
985
986
987 static int pm121_probe(struct platform_device *ddev)
988 {
989 wf_register_client(&pm121_events);
990
991 return 0;
992 }
993
994 static int pm121_remove(struct platform_device *ddev)
995 {
996 wf_unregister_client(&pm121_events);
997 return 0;
998 }
999
1000 static struct platform_driver pm121_driver = {
1001 .probe = pm121_probe,
1002 .remove = pm121_remove,
1003 .driver = {
1004 .name = "windfarm",
1005 .bus = &platform_bus_type,
1006 },
1007 };
1008
1009
1010 static int __init pm121_init(void)
1011 {
1012 int rc = -ENODEV;
1013
1014 if (of_machine_is_compatible("PowerMac12,1"))
1015 rc = pm121_init_pm();
1016
1017 if (rc == 0) {
1018 request_module("windfarm_smu_controls");
1019 request_module("windfarm_smu_sensors");
1020 request_module("windfarm_smu_sat");
1021 request_module("windfarm_lm75_sensor");
1022 request_module("windfarm_max6690_sensor");
1023 request_module("windfarm_cpufreq_clamp");
1024 platform_driver_register(&pm121_driver);
1025 }
1026
1027 return rc;
1028 }
1029
1030 static void __exit pm121_exit(void)
1031 {
1032
1033 platform_driver_unregister(&pm121_driver);
1034 }
1035
1036
1037 module_init(pm121_init);
1038 module_exit(pm121_exit);
1039
1040 MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>");
1041 MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)");
1042 MODULE_LICENSE("GPL");
1043