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