vserver 1.9.3
[linux-2.6.git] / drivers / macintosh / therm_adt746x.c
1 /*
2  * Device driver for the i2c thermostat found on the iBook G4, Albook G4
3  *
4  * Copyright (C) 2003, 2004 Colin Leroy, Rasmus Rohde, Benjamin Herrenschmidt
5  *
6  * Documentation from
7  * http://www.analog.com/UploadedFiles/Data_Sheets/115254175ADT7467_pra.pdf
8  * http://www.analog.com/UploadedFiles/Data_Sheets/3686221171167ADT7460_b.pdf
9  *
10  */
11
12 #include <linux/config.h>
13 #include <linux/types.h>
14 #include <linux/module.h>
15 #include <linux/errno.h>
16 #include <linux/kernel.h>
17 #include <linux/delay.h>
18 #include <linux/sched.h>
19 #include <linux/i2c.h>
20 #include <linux/slab.h>
21 #include <linux/init.h>
22 #include <linux/spinlock.h>
23 #include <linux/smp_lock.h>
24 #include <linux/wait.h>
25 #include <asm/prom.h>
26 #include <asm/machdep.h>
27 #include <asm/io.h>
28 #include <asm/system.h>
29 #include <asm/sections.h>
30 #include <asm/of_device.h>
31 #include <linux/kthread.h>
32
33 #undef DEBUG
34
35 #define CONFIG_REG   0x40
36 #define MANUAL_MASK  0xe0
37 #define AUTO_MASK    0x20
38
39 static u8 TEMP_REG[3]    = {0x26, 0x25, 0x27}; /* local, cpu, gpu */
40 static u8 LIMIT_REG[3]   = {0x6b, 0x6a, 0x6c}; /* local, cpu, gpu */
41 static u8 MANUAL_MODE[2] = {0x5c, 0x5d};       
42 static u8 REM_CONTROL[2] = {0x00, 0x40};
43 static u8 FAN_SPEED[2]   = {0x28, 0x2a};
44 static u8 FAN_SPD_SET[2] = {0x30, 0x31};
45
46 static u8 default_limits_local[3] = {70, 50, 70};    /* local, cpu, gpu */
47 static u8 default_limits_chip[3] = {80, 65, 80};    /* local, cpu, gpu */
48
49 static int limit_adjust = 0;
50 static int fan_speed = -1;
51
52 MODULE_AUTHOR("Colin Leroy <colin@colino.net>");
53 MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and Powerbook G4 Alu");
54 MODULE_LICENSE("GPL");
55
56 MODULE_PARM(limit_adjust,"i");
57 MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50 cpu, 70 gpu) by N degrees.");
58 MODULE_PARM(fan_speed,"i");
59 MODULE_PARM_DESC(fan_speed,"Specify fan speed (0-255) when lim < temp < lim+8 (default 128)");
60
61 struct thermostat {
62         struct i2c_client       clt;
63         u8                      cached_temp[3];
64         u8                      initial_limits[3];
65         u8                      limits[3];
66         int                     last_speed[2];
67         int                     overriding[2];
68 };
69
70 static enum {ADT7460, ADT7467} therm_type;
71 static int therm_bus, therm_address;
72 static struct of_device * of_dev;
73 static struct thermostat* thermostat;
74 static struct task_struct *thread_therm = NULL;
75
76 static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno);
77 static void write_both_fan_speed(struct thermostat *th, int speed);
78 static void write_fan_speed(struct thermostat *th, int speed, int fan);
79
80 static int
81 write_reg(struct thermostat* th, int reg, u8 data)
82 {
83         u8 tmp[2];
84         int rc;
85         
86         tmp[0] = reg;
87         tmp[1] = data;
88         rc = i2c_master_send(&th->clt, (const char *)tmp, 2);
89         if (rc < 0)
90                 return rc;
91         if (rc != 2)
92                 return -ENODEV;
93         return 0;
94 }
95
96 static int
97 read_reg(struct thermostat* th, int reg)
98 {
99         u8 reg_addr, data;
100         int rc;
101
102         reg_addr = (u8)reg;
103         rc = i2c_master_send(&th->clt, &reg_addr, 1);
104         if (rc < 0)
105                 return rc;
106         if (rc != 1)
107                 return -ENODEV;
108         rc = i2c_master_recv(&th->clt, (char *)&data, 1);
109         if (rc < 0)
110                 return rc;
111         return data;
112 }
113
114 static int
115 attach_thermostat(struct i2c_adapter *adapter)
116 {
117         unsigned long bus_no;
118
119         if (strncmp(adapter->name, "uni-n", 5))
120                 return -ENODEV;
121         bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
122         if (bus_no != therm_bus)
123                 return -ENODEV;
124         return attach_one_thermostat(adapter, therm_address, bus_no);
125 }
126
127 static int
128 detach_thermostat(struct i2c_adapter *adapter)
129 {
130         struct thermostat* th;
131         int i;
132         
133         if (thermostat == NULL)
134                 return 0;
135
136         th = thermostat;
137
138         if (thread_therm != NULL) {
139                 kthread_stop(thread_therm);
140         }
141                 
142         printk(KERN_INFO "adt746x: Putting max temperatures back from %d, %d, %d,"
143                 " to %d, %d, %d\n",
144                 th->limits[0], th->limits[1], th->limits[2],
145                 th->initial_limits[0], th->initial_limits[1], th->initial_limits[2]);
146         
147         for (i = 0; i < 3; i++)
148                 write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
149
150         write_both_fan_speed(th, -1);
151
152         i2c_detach_client(&th->clt);
153
154         thermostat = NULL;
155
156         kfree(th);
157
158         return 0;
159 }
160
161 static struct i2c_driver thermostat_driver = {  
162         .name           ="Apple Thermostat ADT746x",
163         .id             =0xDEAD7467,
164         .flags          =I2C_DF_NOTIFY,
165         .attach_adapter =&attach_thermostat,
166         .detach_adapter =&detach_thermostat,
167 };
168
169 static int read_fan_speed(struct thermostat *th, u8 addr)
170 {
171         u8 tmp[2];
172         u16 res;
173         
174         /* should start with low byte */
175         tmp[1] = read_reg(th, addr);
176         tmp[0] = read_reg(th, addr + 1);
177         
178         res = tmp[1] + (tmp[0] << 8);
179         /* "a value of 0xffff means that the fan has stopped" */
180         return (res == 0xffff ? 0 : (90000*60)/res);
181 }
182
183 static void write_both_fan_speed(struct thermostat *th, int speed)
184 {
185         write_fan_speed(th, speed, 0);
186         if (therm_type == ADT7460)
187                 write_fan_speed(th, speed, 1);
188 }
189
190 static void write_fan_speed(struct thermostat *th, int speed, int fan)
191 {
192         u8 manual;
193         
194         if (speed > 0xff) 
195                 speed = 0xff;
196         else if (speed < -1) 
197                 speed = 0;
198         
199         if (therm_type == ADT7467 && fan == 1)
200                 return;
201         
202         if (th->last_speed[fan] != speed) {
203                 if (speed == -1)
204                         printk(KERN_INFO "adt746x: Setting speed to: automatic for %s fan.\n",
205                                 fan?"GPU":"CPU");
206                 else
207                         printk(KERN_INFO "adt746x: Setting speed to: %d for %s fan.\n",
208                                 speed, fan?"GPU":"CPU");
209         } else
210                 return;
211         
212         if (speed >= 0) {
213                 manual = read_reg(th, MANUAL_MODE[fan]);
214                 write_reg(th, MANUAL_MODE[fan], manual|MANUAL_MASK);
215                 write_reg(th, FAN_SPD_SET[fan], speed);
216         } else {
217                 /* back to automatic */
218                 if(therm_type == ADT7460) {
219                         manual = read_reg(th, MANUAL_MODE[fan]) & (~MANUAL_MASK);
220                         write_reg(th, MANUAL_MODE[fan], manual|REM_CONTROL[fan]);
221                 } else {
222                         manual = read_reg(th, MANUAL_MODE[fan]);
223                         write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK));
224                 }
225         }
226         
227         th->last_speed[fan] = speed;                    
228 }
229
230 static int monitor_task(void *arg)
231 {
232         struct thermostat* th = arg;
233         u8 temps[3];
234         u8 lims[3];
235         int i;
236 #ifdef DEBUG
237         int mfan_speed;
238 #endif
239         while(!kthread_should_stop())
240         {
241                 msleep_interruptible(2000);
242
243                 /* Check status */
244                 /* local   : chip */
245                 /* remote 1: CPU ?*/
246                 /* remote 2: GPU ?*/
247 #ifndef DEBUG
248                 if (fan_speed != -1) {
249 #endif
250                         for (i = 0; i < 3; i++) {
251                                 temps[i]  = read_reg(th, TEMP_REG[i]);
252                                 lims[i]   = th->limits[i];
253                         }
254 #ifndef DEBUG
255                 }
256 #endif          
257                 if (fan_speed != -1) {
258                         int lastvar = 0;                /* for iBook */
259                         for (i = 1; i < 3; i++) {       /* we don't care about local sensor */
260                                 int started = 0;
261                                 int fan_number = (therm_type == ADT7460 && i == 2);
262                                 int var = temps[i] - lims[i];
263                                 if (var > 8) {
264                                         if (th->overriding[fan_number] == 0)
265                                                 printk(KERN_INFO "adt746x: Limit exceeded by %d, overriding specified fan speed for %s.\n",
266                                                         var, fan_number?"GPU":"CPU");
267                                         th->overriding[fan_number] = 1;
268                                         write_fan_speed(th, 255, fan_number);
269                                         started = 1;
270                                 } else if ((!th->overriding[fan_number] || var < 6) && var > 0) {
271                                         if (th->overriding[fan_number] == 1)
272                                                 printk(KERN_INFO "adt746x: Limit exceeded by %d, setting speed to specified for %s.\n",
273                                                         var, fan_number?"GPU":"CPU");                                   
274                                         th->overriding[fan_number] = 0;
275                                         write_fan_speed(th, fan_speed, fan_number);
276                                         started = 1;
277                                 } else if (var < -1) {
278                                         /* don't stop iBook fan if GPU is cold and CPU is not
279                                          * so cold (lastvar >= -1) */
280                                         if (therm_type == ADT7460 || lastvar < -1 || i == 1) {
281                                                 if (th->last_speed[fan_number] != 0)
282                                                         printk(KERN_INFO "adt746x: Stopping %s fan.\n",
283                                                                 fan_number?"GPU":"CPU");
284                                                 write_fan_speed(th, 0, fan_number);
285                                         }
286                                 }
287                                 
288                                 lastvar = var;
289                                 
290                                 if (started && therm_type == ADT7467)
291                                         break; /* we don't want to re-stop the fan
292                                                 * if CPU is heating and GPU is not */
293                         }
294                 }
295 #ifdef DEBUG
296                 mfan_speed = read_fan_speed(th, FAN_SPEED[0]);
297                 /* only one fan in the iBook G4 */
298                                 
299                 if (temps[0] != th->cached_temp[0]
300                 ||  temps[1] != th->cached_temp[1]
301                 ||  temps[2] != th->cached_temp[2]) {
302                         printk(KERN_INFO "adt746x: Temperature infos:"
303                                          " thermostats: %d,%d,%d;"
304                                          " limits: %d,%d,%d;"
305                                          " fan speed: %d RPM\n",
306                                 temps[0], temps[1], temps[2],
307                                 lims[0],  lims[1],  lims[2],
308                                 mfan_speed);
309                 }
310                 th->cached_temp[0] = temps[0];
311                 th->cached_temp[1] = temps[1];
312                 th->cached_temp[2] = temps[2];
313 #endif          
314         }
315
316         return 0;
317 }
318
319 static void
320 set_limit(struct thermostat *th, int i)
321 {
322                 /* Set CPU limit higher to avoid powerdowns */ 
323                 th->limits[i] = default_limits_chip[i] + limit_adjust;
324                 write_reg(th, LIMIT_REG[i], th->limits[i]);
325                 
326                 /* set our limits to normal */
327                 th->limits[i] = default_limits_local[i] + limit_adjust;
328 }
329         
330 static int
331 attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno)
332 {
333         struct thermostat* th;
334         int rc;
335         int i;
336
337         if (thermostat)
338                 return 0;
339         th = (struct thermostat *)kmalloc(sizeof(struct thermostat), GFP_KERNEL);
340         if (!th)
341                 return -ENOMEM;
342         memset(th, 0, sizeof(*th));
343         th->clt.addr = addr;
344         th->clt.adapter = adapter;
345         th->clt.driver = &thermostat_driver;
346         th->clt.id = 0xDEAD7467;
347         strcpy(th->clt.name, "thermostat");
348
349         rc = read_reg(th, 0);
350         if (rc < 0) {
351                 printk(KERN_ERR "adt746x: Thermostat failed to read config from bus %d !\n",
352                         busno);
353                 kfree(th);
354                 return -ENODEV;
355         }
356         /* force manual control to start the fan quieter */
357         
358         if (fan_speed == -1)
359                 fan_speed=128;
360         
361         if(therm_type == ADT7460) {
362                 printk(KERN_INFO "adt746x: ADT7460 initializing\n");
363                 /* The 7460 needs to be started explicitly */
364                 write_reg(th, CONFIG_REG, 1);
365         } else
366                 printk(KERN_INFO "adt746x: ADT7467 initializing\n");
367
368         for (i = 0; i < 3; i++) {
369                 th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
370                 set_limit(th, i);
371         }
372         
373         printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
374                 " to %d, %d, %d\n",
375                 th->initial_limits[0], th->initial_limits[1], th->initial_limits[2], 
376                 th->limits[0], th->limits[1], th->limits[2]);
377
378         thermostat = th;
379
380         if (i2c_attach_client(&th->clt)) {
381                 printk(KERN_INFO "adt746x: Thermostat failed to attach client !\n");
382                 thermostat = NULL;
383                 kfree(th);
384                 return -ENODEV;
385         }
386
387         /* be sure to really write fan speed the first time */
388         th->last_speed[0] = -2;
389         th->last_speed[1] = -2;
390         
391         if (fan_speed != -1) {
392                 write_both_fan_speed(th, 0);
393         } else {
394                 write_both_fan_speed(th, -1);
395         }
396         
397         thread_therm = kthread_run(monitor_task, th, "kfand");
398
399         if (thread_therm == ERR_PTR(-ENOMEM)) {
400                 printk(KERN_INFO "adt746x: Kthread creation failed\n");
401                 thread_therm = NULL;
402                 return -ENOMEM;
403         }
404
405         return 0;
406 }
407
408 /* 
409  * Now, unfortunately, sysfs doesn't give us a nice void * we could
410  * pass around to the attribute functions, so we don't really have
411  * choice but implement a bunch of them...
412  *
413  */
414 #define BUILD_SHOW_FUNC_INT(name, data)                         \
415 static ssize_t show_##name(struct device *dev, char *buf)       \
416 {                                                               \
417         return sprintf(buf, "%d\n", data);                      \
418 }
419
420 #define BUILD_SHOW_FUNC_FAN(name, data)                         \
421 static ssize_t show_##name(struct device *dev, char *buf)       \
422 {                                                               \
423         return sprintf(buf, "%d (%d rpm)\n",                    \
424                 thermostat->last_speed[data],                   \
425                 read_fan_speed(thermostat, FAN_SPEED[data])     \
426                 );                                              \
427 }
428
429 #define BUILD_STORE_FUNC_DEG(name, data)                        \
430 static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \
431 {                                                               \
432         int val;                                                \
433         int i;                                                  \
434         val = simple_strtol(buf, NULL, 10);                     \
435         printk(KERN_INFO "Adjusting limits by %d°C\n", val);    \
436         limit_adjust = val;                                     \
437         for (i=0; i < 3; i++)                                   \
438                 set_limit(thermostat, i);                       \
439         return n;                                               \
440 }
441
442 #define BUILD_STORE_FUNC_INT(name, data)                        \
443 static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \
444 {                                                               \
445         u32 val;                                                \
446         val = simple_strtoul(buf, NULL, 10);                    \
447         if (val < 0 || val > 255)                               \
448                 return -EINVAL;                                 \
449         printk(KERN_INFO "Setting specified fan speed to %d\n", val);   \
450         data = val;                                             \
451         return n;                                               \
452 }
453
454 BUILD_SHOW_FUNC_INT(cpu_temperature,     (read_reg(thermostat, TEMP_REG[1])))
455 BUILD_SHOW_FUNC_INT(gpu_temperature,     (read_reg(thermostat, TEMP_REG[2])))
456 BUILD_SHOW_FUNC_INT(cpu_limit,           thermostat->limits[1])
457 BUILD_SHOW_FUNC_INT(gpu_limit,           thermostat->limits[2])
458
459 BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed)
460 BUILD_SHOW_FUNC_FAN(cpu_fan_speed,       0)
461 BUILD_SHOW_FUNC_FAN(gpu_fan_speed,       1)
462
463 BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
464 BUILD_SHOW_FUNC_INT(limit_adjust,        limit_adjust)
465 BUILD_STORE_FUNC_DEG(limit_adjust,       thermostat)
466                 
467 static DEVICE_ATTR(cpu_temperature,     S_IRUGO,
468                    show_cpu_temperature,NULL);
469 static DEVICE_ATTR(gpu_temperature,     S_IRUGO,
470                    show_gpu_temperature,NULL);
471 static DEVICE_ATTR(cpu_limit,           S_IRUGO,
472                    show_cpu_limit,      NULL);
473 static DEVICE_ATTR(gpu_limit,           S_IRUGO,
474                    show_gpu_limit,      NULL);
475
476 static DEVICE_ATTR(specified_fan_speed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
477                    show_specified_fan_speed,store_specified_fan_speed);
478
479 static DEVICE_ATTR(cpu_fan_speed,       S_IRUGO,
480                    show_cpu_fan_speed,  NULL);
481 static DEVICE_ATTR(gpu_fan_speed,       S_IRUGO,
482                    show_gpu_fan_speed,  NULL);
483
484 static DEVICE_ATTR(limit_adjust,        S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
485                    show_limit_adjust,   store_limit_adjust);
486
487
488 static int __init
489 thermostat_init(void)
490 {
491         struct device_node* np;
492         u32 *prop;
493         
494         np = of_find_node_by_name(NULL, "fan");
495         if (!np)
496                 return -ENODEV;
497         if (device_is_compatible(np, "adt7460"))
498                 therm_type = ADT7460;
499         else if (device_is_compatible(np, "adt7467"))
500                 therm_type = ADT7467;
501         else
502                 return -ENODEV;
503
504         prop = (u32 *)get_property(np, "reg", NULL);
505         if (!prop)
506                 return -ENODEV;
507         therm_bus = ((*prop) >> 8) & 0x0f;
508         therm_address = ((*prop) & 0xff) >> 1;
509
510         printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, limit_adjust: %d, fan_speed: %d\n",
511                 therm_bus, therm_address, limit_adjust, fan_speed);
512
513         of_dev = of_platform_device_create(np, "temperatures");
514         
515         if (of_dev == NULL) {
516                 printk(KERN_ERR "Can't register temperatures device !\n");
517                 return -ENODEV;
518         }
519         
520         device_create_file(&of_dev->dev, &dev_attr_cpu_temperature);
521         device_create_file(&of_dev->dev, &dev_attr_gpu_temperature);
522         device_create_file(&of_dev->dev, &dev_attr_cpu_limit);
523         device_create_file(&of_dev->dev, &dev_attr_gpu_limit);
524         device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
525         device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
526         device_create_file(&of_dev->dev, &dev_attr_cpu_fan_speed);
527         if(therm_type == ADT7460)
528                 device_create_file(&of_dev->dev, &dev_attr_gpu_fan_speed);
529
530 #ifndef CONFIG_I2C_KEYWEST
531         request_module("i2c-keywest");
532 #endif
533
534         return i2c_add_driver(&thermostat_driver);
535 }
536
537 static void __exit
538 thermostat_exit(void)
539 {
540         if (of_dev) {
541                 device_remove_file(&of_dev->dev, &dev_attr_cpu_temperature);
542                 device_remove_file(&of_dev->dev, &dev_attr_gpu_temperature);
543                 device_remove_file(&of_dev->dev, &dev_attr_cpu_limit);
544                 device_remove_file(&of_dev->dev, &dev_attr_gpu_limit);
545                 device_remove_file(&of_dev->dev, &dev_attr_limit_adjust);
546                 device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed);
547                 device_remove_file(&of_dev->dev, &dev_attr_cpu_fan_speed);
548                 if(therm_type == ADT7460)
549                         device_remove_file(&of_dev->dev, &dev_attr_gpu_fan_speed);
550                 of_device_unregister(of_dev);
551         }
552         i2c_del_driver(&thermostat_driver);
553 }
554
555 module_init(thermostat_init);
556 module_exit(thermostat_exit);