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