Update DEP-5 uri
[debian/omnibook.git] / fan.c
1 /*
2  * fan.c -- fan status/control
3  * 
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2, or (at your option) any
7  * later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * Written by Soós Péter <sp@osb.hu>, 2002-2004
15  * Modified by Mathieu Bérard <mathieu.berard@crans.org>, 2006
16  */
17
18 #include "omnibook.h"
19
20 #include <linux/delay.h>
21 #include <asm/io.h>
22 #include "hardware.h"
23
24 static const struct omnibook_operation ctmp_io_op = { EC, XE3GF_CTMP, 0, 0, 0, 0 };
25 static const struct omnibook_operation fot_io_op = { EC, XE3GF_FOT, XE3GF_FOT, 0, 0, 0 };
26
27 static int omnibook_get_fan(struct omnibook_operation *io_op)
28 {
29         u8 fan;
30         int retval;
31
32         if ((retval = backend_byte_read(io_op, &fan)))
33                 return retval;
34
35         /*
36          * For most models the reading is a bool
37          * It as to be inverted on all but OB6000|OB6100|OB4150|AMILOD
38          * TSP10|XE3GF|TSX205 return an integer
39          */
40
41         if (omnibook_ectype & (TSP10 | XE3GF | TSX205))
42                 retval = fan;
43         else if (omnibook_ectype & (OB6000 | OB6100 | OB4150 | AMILOD))
44                 retval = !!fan;
45         else
46                 retval = !fan;
47
48         return retval;
49 }
50
51 static int omnibook_fan_on(struct omnibook_operation *io_op)
52 {
53         return omnibook_apply_write_mask(io_op, 1);
54 }
55
56 static int omnibook_fan_off(struct omnibook_operation *io_op)
57 {
58         int i, retval = 0;
59
60         if (!(omnibook_ectype & (XE3GF | TSP10 | TSX205))) {
61                 retval = omnibook_apply_write_mask(io_op, 0);
62                 return retval;
63         } else {
64         /*
65          * Special handling for XE3GF & TSP10
66          */
67                 u8 fot, temp, fan;
68
69                 if(mutex_lock_interruptible(&io_op->backend->mutex))
70                         return -ERESTARTSYS;    
71
72                 retval = __backend_byte_read(io_op, &fan);
73
74                 /* error or fan is already off */
75                 if (retval || !fan)
76                         goto out;
77
78                 /* now we set FOT to current temp, then reset to initial value */
79                 if ((retval = __backend_byte_read(&fot_io_op, &fot)))
80                         goto out;
81                 if ((retval = __backend_byte_read(&ctmp_io_op, &temp)))
82                         goto out;
83
84                 /* Wait for no longer than 250ms (this is arbitrary). */
85                 for (i = 0; i < 250; i++) {
86                         __backend_byte_write(&fot_io_op, temp);
87                         mdelay(1);
88                         __backend_byte_read(io_op, &fan);
89                         if (!fan) /* Fan is off */
90                                 break;
91                 }
92                 __backend_byte_write(&fot_io_op, fot);
93
94                 if(i == 250 ) {
95                         printk(O_ERR "Attempt to switch off the fan failed.\n");
96                         retval = -EIO;
97                 }
98
99                 out:            
100                 mutex_unlock(&io_op->backend->mutex);
101         }
102                 
103
104         return retval;
105 }
106
107 static int omnibook_fan_read(char *buffer, struct omnibook_operation *io_op)
108 {
109         int fan;
110         int len = 0;
111         char *str;
112
113         fan = omnibook_get_fan(io_op);
114         if (fan < 0)
115                 return fan;
116         str = (fan) ? "on" : "off";
117
118         if (fan > 1)
119                 len += sprintf(buffer + len, "Fan is %s (level %d)\n", str, fan);
120         else
121                 len += sprintf(buffer + len, "Fan is %s\n", str);
122
123         return len;
124 }
125
126 static int omnibook_fan_write(char *buffer, struct omnibook_operation *io_op)
127 {
128         int retval;
129
130         switch (*buffer) {
131         case '0':
132                 retval = omnibook_fan_off(io_op);
133                 break;
134         case '1':
135                 retval = omnibook_fan_on(io_op);
136                 break;
137         default:
138                 retval = -EINVAL;
139         }
140         return retval;
141 }
142
143 static struct omnibook_feature fan_driver;
144
145 static int __init omnibook_fan_init(struct omnibook_operation *io_op)
146 {
147         /*
148          * OB4150
149          * XE2
150          * AMILOD
151          * They only support fan reading 
152          */
153         if (omnibook_ectype & (OB4150 | XE2 | AMILOD))
154                 fan_driver.write = NULL;
155         return 0;
156 }
157
158 static struct omnibook_tbl fan_table[] __initdata = {
159         {XE3GF | TSP10 | TSM70 | TSX205, {EC, XE3GF_FSRD, XE3GF_FSRD, 0, XE3GF_FAN_ON_MASK, 0}},
160         {OB500,
161          {PIO, OB500_GPO1, OB500_GPO1, OB500_FAN_OFF_MASK, -OB500_FAN_ON_MASK, OB500_FAN_OFF_MASK}},
162         {OB510,
163          {PIO, OB510_GPIO, OB510_GPIO, OB510_FAN_OFF_MASK, -OB510_FAN_ON_MASK, OB510_FAN_OFF_MASK}},
164         {OB6000 | OB6100,
165          {EC, OB6000_STA1, OB6000_STA1, OB6000_FAN_MASK, OB6000_FAN_MASK, -OB6000_FAN_MASK}},
166         {OB4150 | AMILOD, {EC, OB4150_STA1, 0, OB4150_FAN_MASK, 0, 0}},
167         {XE2, {PIO, OB500_GPO1, 0, XE2_FAN_MASK, 0, 0}},
168         {0,}
169 };
170
171 static struct omnibook_feature __declared_feature fan_driver = {
172         .name = "fan",
173         .enabled = 1,
174         .read = omnibook_fan_read,
175         .write = omnibook_fan_write,
176         .init = omnibook_fan_init,
177         .ectypes = XE3GF | OB500 | OB510 | OB6000 | OB6100 | OB4150 | XE2 | AMILOD | TSP10 | TSX205,
178         .tbl = fan_table,
179 };
180
181 module_param_named(fan, fan_driver.enabled, int, S_IRUGO);
182 MODULE_PARM_DESC(fan, "Use 0 to disable, 1 to enable fan status monitor and control");
183 /* End of file */