Blame view
drivers/hwmon/smsc47m1.c
24.7 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 |
/* smsc47m1.c - Part of lm_sensors, Linux kernel modules for hardware monitoring |
6091780eb smsc47m1: List th... |
4 |
Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, |
8eccbb6fb hwmon/smsc47m1: A... |
5 6 |
LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997 Super-I/O chips. |
1da177e4c Linux-2.6.12-rc2 |
7 8 |
Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> |
8eccbb6fb hwmon/smsc47m1: A... |
9 |
Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org> |
1da177e4c Linux-2.6.12-rc2 |
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com> and Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
512504e9f hwmon: (smsc47m1)... |
27 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
28 29 30 31 |
#include <linux/module.h> #include <linux/slab.h> #include <linux/ioport.h> #include <linux/jiffies.h> |
51f2cca1f hwmon/smsc47m1: C... |
32 |
#include <linux/platform_device.h> |
943b0830c [PATCH] I2C hwmon... |
33 |
#include <linux/hwmon.h> |
e84cfbcbe hwmon/smsc47m1: U... |
34 |
#include <linux/hwmon-sysfs.h> |
943b0830c [PATCH] I2C hwmon... |
35 |
#include <linux/err.h> |
1da177e4c Linux-2.6.12-rc2 |
36 |
#include <linux/init.h> |
9a61bf630 [PATCH] hwmon: Se... |
37 |
#include <linux/mutex.h> |
ce8c6ce1e hwmon: Fix unchec... |
38 |
#include <linux/sysfs.h> |
b9acb64a3 hwmon: Check for ... |
39 |
#include <linux/acpi.h> |
6055fae8a hwmon: Include <l... |
40 |
#include <linux/io.h> |
1da177e4c Linux-2.6.12-rc2 |
41 |
|
67b671bce hwmon: Let the us... |
42 43 44 |
static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); |
51f2cca1f hwmon/smsc47m1: C... |
45 46 47 |
static struct platform_device *pdev; #define DRVNAME "smsc47m1" |
8eccbb6fb hwmon/smsc47m1: A... |
48 |
enum chips { smsc47m1, smsc47m2 }; |
1da177e4c Linux-2.6.12-rc2 |
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 |
/* Super-I/0 registers and commands */ #define REG 0x2e /* The register to read/write */ #define VAL 0x2f /* The value to read/write */ static inline void superio_outb(int reg, int val) { outb(reg, REG); outb(val, VAL); } static inline int superio_inb(int reg) { outb(reg, REG); return inb(VAL); } /* logical device for fans is 0x0A */ #define superio_select() superio_outb(0x07, 0x0A) static inline void superio_enter(void) { outb(0x55, REG); } static inline void superio_exit(void) { outb(0xAA, REG); } #define SUPERIO_REG_ACT 0x30 #define SUPERIO_REG_BASE 0x60 #define SUPERIO_REG_DEVID 0x20 |
1b54ab450 hwmon: (smsc47m1)... |
87 |
#define SUPERIO_REG_DEVREV 0x21 |
1da177e4c Linux-2.6.12-rc2 |
88 89 90 91 92 93 94 95 96 |
/* Logical device registers */ #define SMSC_EXTENT 0x80 /* nr is 0 or 1 in the macros below */ #define SMSC47M1_REG_ALARM 0x04 #define SMSC47M1_REG_TPIN(nr) (0x34 - (nr)) #define SMSC47M1_REG_PPIN(nr) (0x36 - (nr)) |
1da177e4c Linux-2.6.12-rc2 |
97 |
#define SMSC47M1_REG_FANDIV 0x58 |
8eccbb6fb hwmon/smsc47m1: A... |
98 99 100 101 102 103 104 105 106 107 108 |
static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b }; static const u8 SMSC47M1_REG_FAN_PRELOAD[3] = { 0x5b, 0x5c, 0x6c }; static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 }; #define SMSC47M2_REG_ALARM6 0x09 #define SMSC47M2_REG_TPIN1 0x38 #define SMSC47M2_REG_TPIN2 0x37 #define SMSC47M2_REG_TPIN3 0x2d #define SMSC47M2_REG_PPIN3 0x2c #define SMSC47M2_REG_FANDIV3 0x6a |
1da177e4c Linux-2.6.12-rc2 |
109 110 111 112 113 114 115 116 117 118 119 |
#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ 983040/((192-(reg))*(div))) #define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \ 983040/(((reg)-(preload))*(div))) #define DIV_FROM_REG(reg) (1 << (reg)) #define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) #define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) #define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E) struct smsc47m1_data { |
51f2cca1f hwmon/smsc47m1: C... |
120 121 |
unsigned short addr; const char *name; |
8eccbb6fb hwmon/smsc47m1: A... |
122 |
enum chips type; |
1beeffe43 hwmon: Convert fr... |
123 |
struct device *hwmon_dev; |
1da177e4c Linux-2.6.12-rc2 |
124 |
|
9a61bf630 [PATCH] hwmon: Se... |
125 |
struct mutex update_lock; |
1da177e4c Linux-2.6.12-rc2 |
126 |
unsigned long last_updated; /* In jiffies */ |
8eccbb6fb hwmon/smsc47m1: A... |
127 128 129 |
u8 fan[3]; /* Register value */ u8 fan_preload[3]; /* Register value */ u8 fan_div[3]; /* Register encoding, shifted right */ |
1da177e4c Linux-2.6.12-rc2 |
130 |
u8 alarms; /* Register encoding */ |
8eccbb6fb hwmon/smsc47m1: A... |
131 |
u8 pwm[3]; /* Register value (bit 0 is disable) */ |
1da177e4c Linux-2.6.12-rc2 |
132 |
}; |
51f2cca1f hwmon/smsc47m1: C... |
133 134 |
struct smsc47m1_sio_data { enum chips type; |
fa0bff022 hwmon: (smsc47m1)... |
135 |
u8 activate; /* Remember initial device state */ |
51f2cca1f hwmon/smsc47m1: C... |
136 |
}; |
1da177e4c Linux-2.6.12-rc2 |
137 |
|
51f2cca1f hwmon/smsc47m1: C... |
138 |
|
3ecf44b31 hwmon: (smsc47m1)... |
139 |
static int __exit smsc47m1_remove(struct platform_device *pdev); |
1da177e4c Linux-2.6.12-rc2 |
140 141 |
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, int init); |
51f2cca1f hwmon/smsc47m1: C... |
142 |
static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg) |
94e183fd0 hwmon/smsc47m1: G... |
143 |
{ |
51f2cca1f hwmon/smsc47m1: C... |
144 |
return inb_p(data->addr + reg); |
94e183fd0 hwmon/smsc47m1: G... |
145 |
} |
51f2cca1f hwmon/smsc47m1: C... |
146 |
static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg, |
94e183fd0 hwmon/smsc47m1: G... |
147 148 |
u8 value) { |
51f2cca1f hwmon/smsc47m1: C... |
149 |
outb_p(value, data->addr + reg); |
94e183fd0 hwmon/smsc47m1: G... |
150 |
} |
1da177e4c Linux-2.6.12-rc2 |
151 |
|
51f2cca1f hwmon/smsc47m1: C... |
152 |
static struct platform_driver smsc47m1_driver = { |
cdaf79349 [PATCH] i2c: Drop... |
153 |
.driver = { |
872188420 i2c-isa: Restore ... |
154 |
.owner = THIS_MODULE, |
51f2cca1f hwmon/smsc47m1: C... |
155 |
.name = DRVNAME, |
cdaf79349 [PATCH] i2c: Drop... |
156 |
}, |
3ecf44b31 hwmon: (smsc47m1)... |
157 |
.remove = __exit_p(smsc47m1_remove), |
1da177e4c Linux-2.6.12-rc2 |
158 |
}; |
e84cfbcbe hwmon/smsc47m1: U... |
159 160 |
static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
161 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
162 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
163 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
164 |
int nr = attr->index; |
1da177e4c Linux-2.6.12-rc2 |
165 166 167 168 169 170 171 172 173 174 175 |
/* This chip (stupidly) stops monitoring fan speed if PWM is enabled and duty cycle is 0%. This is fine if the monitoring and control concern the same fan, but troublesome if they are not (which could as well happen). */ int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]), data->fan_preload[nr]); return sprintf(buf, "%d ", rpm); } |
e84cfbcbe hwmon/smsc47m1: U... |
176 177 |
static ssize_t get_fan_min(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
178 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
179 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
180 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
181 |
int nr = attr->index; |
1da177e4c Linux-2.6.12-rc2 |
182 183 184 185 186 |
int rpm = MIN_FROM_REG(data->fan_preload[nr], DIV_FROM_REG(data->fan_div[nr])); return sprintf(buf, "%d ", rpm); } |
e84cfbcbe hwmon/smsc47m1: U... |
187 188 |
static ssize_t get_fan_div(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
189 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
190 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
191 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
192 193 |
return sprintf(buf, "%d ", DIV_FROM_REG(data->fan_div[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
194 |
} |
1f08af7ea hwmon: (smsc47m1)... |
195 196 197 198 199 200 201 202 |
static ssize_t get_fan_alarm(struct device *dev, struct device_attribute *devattr, char *buf) { int bitnr = to_sensor_dev_attr(devattr)->index; struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); return sprintf(buf, "%u ", (data->alarms >> bitnr) & 1); } |
e84cfbcbe hwmon/smsc47m1: U... |
203 204 |
static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
205 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
206 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
207 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
208 209 |
return sprintf(buf, "%d ", PWM_FROM_REG(data->pwm[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
210 |
} |
e84cfbcbe hwmon/smsc47m1: U... |
211 212 |
static ssize_t get_pwm_en(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
213 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
214 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
215 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
216 217 |
return sprintf(buf, "%d ", PWM_EN_FROM_REG(data->pwm[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
218 |
} |
e84cfbcbe hwmon/smsc47m1: U... |
219 220 |
static ssize_t get_alarms(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
221 222 223 224 225 |
{ struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); return sprintf(buf, "%d ", data->alarms); } |
e84cfbcbe hwmon/smsc47m1: U... |
226 227 |
static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
228 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
229 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
51f2cca1f hwmon/smsc47m1: C... |
230 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
e84cfbcbe hwmon/smsc47m1: U... |
231 |
int nr = attr->index; |
1da177e4c Linux-2.6.12-rc2 |
232 |
long rpmdiv, val = simple_strtol(buf, NULL, 10); |
9a61bf630 [PATCH] hwmon: Se... |
233 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
234 235 236 |
rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) { |
9a61bf630 [PATCH] hwmon: Se... |
237 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
238 239 240 241 |
return -EINVAL; } data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); |
51f2cca1f hwmon/smsc47m1: C... |
242 |
smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr], |
1da177e4c Linux-2.6.12-rc2 |
243 |
data->fan_preload[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
244 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
245 246 247 248 249 250 |
return count; } /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan clock divider. This follows the principle |
d6e05edc5 spelling fixes |
251 |
of least surprise; the user doesn't expect the fan minimum to change just |
1da177e4c Linux-2.6.12-rc2 |
252 |
because the divider changed. */ |
e84cfbcbe hwmon/smsc47m1: U... |
253 254 |
static ssize_t set_fan_div(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
255 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
256 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
51f2cca1f hwmon/smsc47m1: C... |
257 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
e84cfbcbe hwmon/smsc47m1: U... |
258 |
int nr = attr->index; |
1da177e4c Linux-2.6.12-rc2 |
259 260 261 262 263 |
long new_div = simple_strtol(buf, NULL, 10), tmp; u8 old_div = DIV_FROM_REG(data->fan_div[nr]); if (new_div == old_div) /* No change */ return count; |
9a61bf630 [PATCH] hwmon: Se... |
264 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
265 266 267 268 269 270 |
switch (new_div) { case 1: data->fan_div[nr] = 0; break; case 2: data->fan_div[nr] = 1; break; case 4: data->fan_div[nr] = 2; break; case 8: data->fan_div[nr] = 3; break; default: |
9a61bf630 [PATCH] hwmon: Se... |
271 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
272 273 |
return -EINVAL; } |
8eccbb6fb hwmon/smsc47m1: A... |
274 275 276 |
switch (nr) { case 0: case 1: |
51f2cca1f hwmon/smsc47m1: C... |
277 |
tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV) |
8eccbb6fb hwmon/smsc47m1: A... |
278 279 |
& ~(0x03 << (4 + 2 * nr)); tmp |= data->fan_div[nr] << (4 + 2 * nr); |
51f2cca1f hwmon/smsc47m1: C... |
280 |
smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp); |
8eccbb6fb hwmon/smsc47m1: A... |
281 282 |
break; case 2: |
51f2cca1f hwmon/smsc47m1: C... |
283 |
tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF; |
8eccbb6fb hwmon/smsc47m1: A... |
284 |
tmp |= data->fan_div[2] << 4; |
51f2cca1f hwmon/smsc47m1: C... |
285 |
smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp); |
8eccbb6fb hwmon/smsc47m1: A... |
286 287 |
break; } |
1da177e4c Linux-2.6.12-rc2 |
288 289 290 291 292 |
/* Preserve fan min */ tmp = 192 - (old_div * (192 - data->fan_preload[nr]) + new_div / 2) / new_div; data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); |
51f2cca1f hwmon/smsc47m1: C... |
293 |
smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr], |
1da177e4c Linux-2.6.12-rc2 |
294 |
data->fan_preload[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
295 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
296 297 298 |
return count; } |
e84cfbcbe hwmon/smsc47m1: U... |
299 300 |
static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
301 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
302 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
51f2cca1f hwmon/smsc47m1: C... |
303 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
e84cfbcbe hwmon/smsc47m1: U... |
304 |
int nr = attr->index; |
1da177e4c Linux-2.6.12-rc2 |
305 306 307 308 |
long val = simple_strtol(buf, NULL, 10); if (val < 0 || val > 255) return -EINVAL; |
9a61bf630 [PATCH] hwmon: Se... |
309 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
310 311 |
data->pwm[nr] &= 0x81; /* Preserve additional bits */ data->pwm[nr] |= PWM_TO_REG(val); |
51f2cca1f hwmon/smsc47m1: C... |
312 |
smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr], |
1da177e4c Linux-2.6.12-rc2 |
313 |
data->pwm[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
314 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
315 316 317 |
return count; } |
e84cfbcbe hwmon/smsc47m1: U... |
318 319 |
static ssize_t set_pwm_en(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
320 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
321 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
51f2cca1f hwmon/smsc47m1: C... |
322 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
e84cfbcbe hwmon/smsc47m1: U... |
323 |
int nr = attr->index; |
1da177e4c Linux-2.6.12-rc2 |
324 325 326 327 |
long val = simple_strtol(buf, NULL, 10); if (val != 0 && val != 1) return -EINVAL; |
9a61bf630 [PATCH] hwmon: Se... |
328 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
329 330 |
data->pwm[nr] &= 0xFE; /* preserve the other bits */ data->pwm[nr] |= !val; |
51f2cca1f hwmon/smsc47m1: C... |
331 |
smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr], |
1da177e4c Linux-2.6.12-rc2 |
332 |
data->pwm[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
333 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
334 335 336 337 338 |
return count; } #define fan_present(offset) \ |
e84cfbcbe hwmon/smsc47m1: U... |
339 340 341 342 343 344 |
static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan, \ NULL, offset - 1); \ static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ get_fan_min, set_fan_min, offset - 1); \ static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ get_fan_div, set_fan_div, offset - 1); \ |
1f08af7ea hwmon: (smsc47m1)... |
345 346 |
static SENSOR_DEVICE_ATTR(fan##offset##_alarm, S_IRUGO, get_fan_alarm, \ NULL, offset - 1); \ |
e84cfbcbe hwmon/smsc47m1: U... |
347 348 349 350 |
static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ get_pwm, set_pwm, offset - 1); \ static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ get_pwm_en, set_pwm_en, offset - 1) |
1da177e4c Linux-2.6.12-rc2 |
351 352 353 |
fan_present(1); fan_present(2); |
8eccbb6fb hwmon/smsc47m1: A... |
354 |
fan_present(3); |
1da177e4c Linux-2.6.12-rc2 |
355 356 |
static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); |
51f2cca1f hwmon/smsc47m1: C... |
357 358 359 360 361 362 363 364 365 |
static ssize_t show_name(struct device *dev, struct device_attribute *devattr, char *buf) { struct smsc47m1_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s ", data->name); } static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
ce8c6ce1e hwmon: Fix unchec... |
366 367 368 369 |
/* Almost all sysfs files may or may not be created depending on the chip setup so we create them individually. It is still convenient to define a group to remove them all at once. */ static struct attribute *smsc47m1_attributes[] = { |
e84cfbcbe hwmon/smsc47m1: U... |
370 371 372 |
&sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, |
1f08af7ea hwmon: (smsc47m1)... |
373 |
&sensor_dev_attr_fan1_alarm.dev_attr.attr, |
e84cfbcbe hwmon/smsc47m1: U... |
374 375 376 |
&sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, |
1f08af7ea hwmon: (smsc47m1)... |
377 |
&sensor_dev_attr_fan2_alarm.dev_attr.attr, |
e84cfbcbe hwmon/smsc47m1: U... |
378 379 380 |
&sensor_dev_attr_fan3_input.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, |
1f08af7ea hwmon: (smsc47m1)... |
381 |
&sensor_dev_attr_fan3_alarm.dev_attr.attr, |
e84cfbcbe hwmon/smsc47m1: U... |
382 383 384 385 386 387 388 |
&sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, &sensor_dev_attr_pwm2_enable.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr, &sensor_dev_attr_pwm3_enable.dev_attr.attr, |
ce8c6ce1e hwmon: Fix unchec... |
389 390 |
&dev_attr_alarms.attr, |
51f2cca1f hwmon/smsc47m1: C... |
391 |
&dev_attr_name.attr, |
ce8c6ce1e hwmon: Fix unchec... |
392 393 394 395 396 397 |
NULL }; static const struct attribute_group smsc47m1_group = { .attrs = smsc47m1_attributes, }; |
51f2cca1f hwmon/smsc47m1: C... |
398 399 |
static int __init smsc47m1_find(unsigned short *addr, struct smsc47m1_sio_data *sio_data) |
1da177e4c Linux-2.6.12-rc2 |
400 401 402 403 |
{ u8 val; superio_enter(); |
67b671bce hwmon: Let the us... |
404 |
val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID); |
1da177e4c Linux-2.6.12-rc2 |
405 406 |
/* |
6091780eb smsc47m1: List th... |
407 408 |
* SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control. |
1da177e4c Linux-2.6.12-rc2 |
409 |
* The LPC47M15x and LPC47M192 chips "with hardware monitoring block" |
ec5ce552d [PATCH] I2C: Add ... |
410 |
* can do much more besides (device id 0x60). |
b890a07f7 [PATCH] hwmon: sm... |
411 412 |
* The LPC47M997 is undocumented, but seems to be compatible with * the LPC47M192, and has the same device id. |
8eccbb6fb hwmon/smsc47m1: A... |
413 414 415 |
* The LPC47M292 (device id 0x6B) is somewhat compatible, but it * supports a 3rd fan, and the pin configuration registers are * unfortunately different. |
1b54ab450 hwmon: (smsc47m1)... |
416 417 418 |
* The LPC47M233 has the same device id (0x6B) but is not compatible. * We check the high bit of the device revision register to * differentiate them. |
1da177e4c Linux-2.6.12-rc2 |
419 |
*/ |
51f2cca1f hwmon/smsc47m1: C... |
420 |
switch (val) { |
8eccbb6fb hwmon/smsc47m1: A... |
421 |
case 0x51: |
512504e9f hwmon: (smsc47m1)... |
422 423 |
pr_info("Found SMSC LPC47B27x "); |
51f2cca1f hwmon/smsc47m1: C... |
424 |
sio_data->type = smsc47m1; |
8eccbb6fb hwmon/smsc47m1: A... |
425 426 |
break; case 0x59: |
512504e9f hwmon: (smsc47m1)... |
427 428 |
pr_info("Found SMSC LPC47M10x/LPC47M112/LPC47M13x "); |
51f2cca1f hwmon/smsc47m1: C... |
429 |
sio_data->type = smsc47m1; |
8eccbb6fb hwmon/smsc47m1: A... |
430 431 |
break; case 0x5F: |
512504e9f hwmon: (smsc47m1)... |
432 433 |
pr_info("Found SMSC LPC47M14x "); |
51f2cca1f hwmon/smsc47m1: C... |
434 |
sio_data->type = smsc47m1; |
8eccbb6fb hwmon/smsc47m1: A... |
435 436 |
break; case 0x60: |
512504e9f hwmon: (smsc47m1)... |
437 438 |
pr_info("Found SMSC LPC47M15x/LPC47M192/LPC47M997 "); |
51f2cca1f hwmon/smsc47m1: C... |
439 |
sio_data->type = smsc47m1; |
8eccbb6fb hwmon/smsc47m1: A... |
440 441 |
break; case 0x6B: |
1b54ab450 hwmon: (smsc47m1)... |
442 |
if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) { |
512504e9f hwmon: (smsc47m1)... |
443 444 |
pr_debug("Found SMSC LPC47M233, unsupported "); |
1b54ab450 hwmon: (smsc47m1)... |
445 446 447 |
superio_exit(); return -ENODEV; } |
512504e9f hwmon: (smsc47m1)... |
448 449 |
pr_info("Found SMSC LPC47M292 "); |
51f2cca1f hwmon/smsc47m1: C... |
450 |
sio_data->type = smsc47m2; |
8eccbb6fb hwmon/smsc47m1: A... |
451 452 |
break; default: |
1da177e4c Linux-2.6.12-rc2 |
453 454 455 456 457 |
superio_exit(); return -ENODEV; } superio_select(); |
2d8672c5a [PATCH] I2C: Sepa... |
458 459 |
*addr = (superio_inb(SUPERIO_REG_BASE) << 8) | superio_inb(SUPERIO_REG_BASE + 1); |
fa0bff022 hwmon: (smsc47m1)... |
460 |
if (*addr == 0) { |
512504e9f hwmon: (smsc47m1)... |
461 462 |
pr_info("Device address not set, will not use "); |
1da177e4c Linux-2.6.12-rc2 |
463 464 465 |
superio_exit(); return -ENODEV; } |
fa0bff022 hwmon: (smsc47m1)... |
466 467 468 469 |
/* Enable only if address is set (needed at least on the * Compaq Presario S4000NX) */ sio_data->activate = superio_inb(SUPERIO_REG_ACT); if ((sio_data->activate & 0x01) == 0) { |
512504e9f hwmon: (smsc47m1)... |
470 471 |
pr_info("Enabling device "); |
fa0bff022 hwmon: (smsc47m1)... |
472 473 |
superio_outb(SUPERIO_REG_ACT, sio_data->activate | 0x01); } |
1da177e4c Linux-2.6.12-rc2 |
474 475 476 |
superio_exit(); return 0; } |
fa0bff022 hwmon: (smsc47m1)... |
477 |
/* Restore device to its initial state */ |
a00d643a2 hwmon: (smsc47m1)... |
478 |
static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data) |
fa0bff022 hwmon: (smsc47m1)... |
479 480 481 482 |
{ if ((sio_data->activate & 0x01) == 0) { superio_enter(); superio_select(); |
512504e9f hwmon: (smsc47m1)... |
483 484 |
pr_info("Disabling device "); |
fa0bff022 hwmon: (smsc47m1)... |
485 486 487 488 489 |
superio_outb(SUPERIO_REG_ACT, sio_data->activate); superio_exit(); } } |
a0e92d70f hwmon: (smsc47m1)... |
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
#define CHECK 1 #define REQUEST 2 #define RELEASE 3 /* * This function can be used to: * - test for resource conflicts with ACPI * - request the resources * - release the resources * We only allocate the I/O ports we really need, to minimize the risk of * conflicts with ACPI or with other drivers. */ static int smsc47m1_handle_resources(unsigned short address, enum chips type, int action, struct device *dev) { static const u8 ports_m1[] = { /* register, region length */ 0x04, 1, 0x33, 4, 0x56, 7, }; static const u8 ports_m2[] = { /* register, region length */ 0x04, 1, 0x09, 1, 0x2c, 2, 0x35, 4, 0x56, 7, 0x69, 4, }; int i, ports_size, err; const u8 *ports; switch (type) { case smsc47m1: default: ports = ports_m1; ports_size = ARRAY_SIZE(ports_m1); break; case smsc47m2: ports = ports_m2; ports_size = ARRAY_SIZE(ports_m2); break; } for (i = 0; i + 1 < ports_size; i += 2) { unsigned short start = address + ports[i]; unsigned short len = ports[i + 1]; switch (action) { case CHECK: /* Only check for conflicts */ err = acpi_check_region(start, len, DRVNAME); if (err) return err; break; case REQUEST: /* Request the resources */ if (!request_region(start, len, DRVNAME)) { dev_err(dev, "Region 0x%hx-0x%hx already in " "use! ", start, start + len); /* Undo all requests */ for (i -= 2; i >= 0; i -= 2) release_region(address + ports[i], ports[i + 1]); return -EBUSY; } break; case RELEASE: /* Release the resources */ release_region(start, len); break; } } return 0; } |
3ecf44b31 hwmon: (smsc47m1)... |
571 |
static int __init smsc47m1_probe(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
572 |
{ |
51f2cca1f hwmon/smsc47m1: C... |
573 574 |
struct device *dev = &pdev->dev; struct smsc47m1_sio_data *sio_data = dev->platform_data; |
1da177e4c Linux-2.6.12-rc2 |
575 |
struct smsc47m1_data *data; |
51f2cca1f hwmon/smsc47m1: C... |
576 |
struct resource *res; |
a0e92d70f hwmon: (smsc47m1)... |
577 |
int err; |
8eccbb6fb hwmon/smsc47m1: A... |
578 |
int fan1, fan2, fan3, pwm1, pwm2, pwm3; |
1da177e4c Linux-2.6.12-rc2 |
579 |
|
51f2cca1f hwmon/smsc47m1: C... |
580 581 582 583 584 585 |
static const char *names[] = { "smsc47m1", "smsc47m2", }; res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
a0e92d70f hwmon: (smsc47m1)... |
586 587 588 589 |
err = smsc47m1_handle_resources(res->start, sio_data->type, REQUEST, dev); if (err < 0) return err; |
1da177e4c Linux-2.6.12-rc2 |
590 |
|
ba9c2e8d1 [PATCH] hwmon: kz... |
591 |
if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { |
1da177e4c Linux-2.6.12-rc2 |
592 593 594 |
err = -ENOMEM; goto error_release; } |
1da177e4c Linux-2.6.12-rc2 |
595 |
|
51f2cca1f hwmon/smsc47m1: C... |
596 597 598 |
data->addr = res->start; data->type = sio_data->type; data->name = names[sio_data->type]; |
9a61bf630 [PATCH] hwmon: Se... |
599 |
mutex_init(&data->update_lock); |
51f2cca1f hwmon/smsc47m1: C... |
600 |
platform_set_drvdata(pdev, data); |
1da177e4c Linux-2.6.12-rc2 |
601 602 603 |
/* If no function is properly configured, there's no point in actually registering the chip. */ |
51f2cca1f hwmon/smsc47m1: C... |
604 |
pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05) |
1da177e4c Linux-2.6.12-rc2 |
605 |
== 0x04; |
51f2cca1f hwmon/smsc47m1: C... |
606 |
pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05) |
1da177e4c Linux-2.6.12-rc2 |
607 |
== 0x04; |
8eccbb6fb hwmon/smsc47m1: A... |
608 |
if (data->type == smsc47m2) { |
51f2cca1f hwmon/smsc47m1: C... |
609 |
fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1) |
8eccbb6fb hwmon/smsc47m1: A... |
610 |
& 0x0d) == 0x09; |
51f2cca1f hwmon/smsc47m1: C... |
611 |
fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2) |
8eccbb6fb hwmon/smsc47m1: A... |
612 |
& 0x0d) == 0x09; |
51f2cca1f hwmon/smsc47m1: C... |
613 |
fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3) |
8eccbb6fb hwmon/smsc47m1: A... |
614 |
& 0x0d) == 0x0d; |
51f2cca1f hwmon/smsc47m1: C... |
615 |
pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3) |
8eccbb6fb hwmon/smsc47m1: A... |
616 617 |
& 0x0d) == 0x08; } else { |
51f2cca1f hwmon/smsc47m1: C... |
618 |
fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0)) |
8eccbb6fb hwmon/smsc47m1: A... |
619 |
& 0x05) == 0x05; |
51f2cca1f hwmon/smsc47m1: C... |
620 |
fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1)) |
8eccbb6fb hwmon/smsc47m1: A... |
621 622 623 624 625 |
& 0x05) == 0x05; fan3 = 0; pwm3 = 0; } if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) { |
51f2cca1f hwmon/smsc47m1: C... |
626 627 |
dev_warn(dev, "Device not configured, will not use "); |
1da177e4c Linux-2.6.12-rc2 |
628 629 630 |
err = -ENODEV; goto error_free; } |
1da177e4c Linux-2.6.12-rc2 |
631 632 633 634 635 636 |
/* Some values (fan min, clock dividers, pwm registers) may be needed before any update is triggered, so we better read them at least once here. We don't usually do it that way, but in this particular case, manually reading 5 registers out of 8 doesn't make much sense and we're better using the existing function. */ |
51f2cca1f hwmon/smsc47m1: C... |
637 |
smsc47m1_update_device(dev, 1); |
1da177e4c Linux-2.6.12-rc2 |
638 |
|
943b0830c [PATCH] I2C hwmon... |
639 |
/* Register sysfs hooks */ |
1da177e4c Linux-2.6.12-rc2 |
640 |
if (fan1) { |
e84cfbcbe hwmon/smsc47m1: U... |
641 642 643 644 645 |
if ((err = device_create_file(dev, &sensor_dev_attr_fan1_input.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_fan1_min.dev_attr)) || (err = device_create_file(dev, |
1f08af7ea hwmon: (smsc47m1)... |
646 647 648 |
&sensor_dev_attr_fan1_div.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_fan1_alarm.dev_attr))) |
ce8c6ce1e hwmon: Fix unchec... |
649 |
goto error_remove_files; |
1da177e4c Linux-2.6.12-rc2 |
650 |
} else |
51f2cca1f hwmon/smsc47m1: C... |
651 652 |
dev_dbg(dev, "Fan 1 not enabled by hardware, skipping "); |
1da177e4c Linux-2.6.12-rc2 |
653 654 |
if (fan2) { |
e84cfbcbe hwmon/smsc47m1: U... |
655 656 657 658 659 |
if ((err = device_create_file(dev, &sensor_dev_attr_fan2_input.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_fan2_min.dev_attr)) || (err = device_create_file(dev, |
1f08af7ea hwmon: (smsc47m1)... |
660 661 662 |
&sensor_dev_attr_fan2_div.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_fan2_alarm.dev_attr))) |
ce8c6ce1e hwmon: Fix unchec... |
663 |
goto error_remove_files; |
1da177e4c Linux-2.6.12-rc2 |
664 |
} else |
51f2cca1f hwmon/smsc47m1: C... |
665 666 |
dev_dbg(dev, "Fan 2 not enabled by hardware, skipping "); |
1da177e4c Linux-2.6.12-rc2 |
667 |
|
8eccbb6fb hwmon/smsc47m1: A... |
668 |
if (fan3) { |
e84cfbcbe hwmon/smsc47m1: U... |
669 670 671 672 673 |
if ((err = device_create_file(dev, &sensor_dev_attr_fan3_input.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_fan3_min.dev_attr)) || (err = device_create_file(dev, |
1f08af7ea hwmon: (smsc47m1)... |
674 675 676 |
&sensor_dev_attr_fan3_div.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_fan3_alarm.dev_attr))) |
8eccbb6fb hwmon/smsc47m1: A... |
677 |
goto error_remove_files; |
8477d0268 hwmon: (smsc47m1)... |
678 |
} else if (data->type == smsc47m2) |
51f2cca1f hwmon/smsc47m1: C... |
679 680 |
dev_dbg(dev, "Fan 3 not enabled by hardware, skipping "); |
8eccbb6fb hwmon/smsc47m1: A... |
681 |
|
1da177e4c Linux-2.6.12-rc2 |
682 |
if (pwm1) { |
e84cfbcbe hwmon/smsc47m1: U... |
683 684 685 686 |
if ((err = device_create_file(dev, &sensor_dev_attr_pwm1.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_pwm1_enable.dev_attr))) |
ce8c6ce1e hwmon: Fix unchec... |
687 |
goto error_remove_files; |
1da177e4c Linux-2.6.12-rc2 |
688 |
} else |
51f2cca1f hwmon/smsc47m1: C... |
689 690 |
dev_dbg(dev, "PWM 1 not enabled by hardware, skipping "); |
8eccbb6fb hwmon/smsc47m1: A... |
691 |
|
1da177e4c Linux-2.6.12-rc2 |
692 |
if (pwm2) { |
e84cfbcbe hwmon/smsc47m1: U... |
693 694 695 696 |
if ((err = device_create_file(dev, &sensor_dev_attr_pwm2.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_pwm2_enable.dev_attr))) |
ce8c6ce1e hwmon: Fix unchec... |
697 |
goto error_remove_files; |
1da177e4c Linux-2.6.12-rc2 |
698 |
} else |
51f2cca1f hwmon/smsc47m1: C... |
699 700 |
dev_dbg(dev, "PWM 2 not enabled by hardware, skipping "); |
1da177e4c Linux-2.6.12-rc2 |
701 |
|
8eccbb6fb hwmon/smsc47m1: A... |
702 |
if (pwm3) { |
e84cfbcbe hwmon/smsc47m1: U... |
703 704 705 706 |
if ((err = device_create_file(dev, &sensor_dev_attr_pwm3.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_pwm3_enable.dev_attr))) |
8eccbb6fb hwmon/smsc47m1: A... |
707 |
goto error_remove_files; |
8477d0268 hwmon: (smsc47m1)... |
708 |
} else if (data->type == smsc47m2) |
51f2cca1f hwmon/smsc47m1: C... |
709 710 |
dev_dbg(dev, "PWM 3 not enabled by hardware, skipping "); |
8eccbb6fb hwmon/smsc47m1: A... |
711 |
|
51f2cca1f hwmon/smsc47m1: C... |
712 |
if ((err = device_create_file(dev, &dev_attr_alarms))) |
ce8c6ce1e hwmon: Fix unchec... |
713 |
goto error_remove_files; |
68a50b567 hwmon: (smsc47m1)... |
714 715 |
if ((err = device_create_file(dev, &dev_attr_name))) goto error_remove_files; |
ce8c6ce1e hwmon: Fix unchec... |
716 |
|
1beeffe43 hwmon: Convert fr... |
717 718 719 |
data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); |
ce8c6ce1e hwmon: Fix unchec... |
720 721 |
goto error_remove_files; } |
1da177e4c Linux-2.6.12-rc2 |
722 723 |
return 0; |
ce8c6ce1e hwmon: Fix unchec... |
724 |
error_remove_files: |
51f2cca1f hwmon/smsc47m1: C... |
725 |
sysfs_remove_group(&dev->kobj, &smsc47m1_group); |
1da177e4c Linux-2.6.12-rc2 |
726 |
error_free: |
04a6217df hwmon: Fix a pote... |
727 |
platform_set_drvdata(pdev, NULL); |
1f57ff89f [PATCH] drivers/h... |
728 |
kfree(data); |
1da177e4c Linux-2.6.12-rc2 |
729 |
error_release: |
a0e92d70f hwmon: (smsc47m1)... |
730 |
smsc47m1_handle_resources(res->start, sio_data->type, RELEASE, dev); |
1da177e4c Linux-2.6.12-rc2 |
731 732 |
return err; } |
3ecf44b31 hwmon: (smsc47m1)... |
733 |
static int __exit smsc47m1_remove(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
734 |
{ |
51f2cca1f hwmon/smsc47m1: C... |
735 736 |
struct smsc47m1_data *data = platform_get_drvdata(pdev); struct resource *res; |
1da177e4c Linux-2.6.12-rc2 |
737 |
|
1beeffe43 hwmon: Convert fr... |
738 |
hwmon_device_unregister(data->hwmon_dev); |
51f2cca1f hwmon/smsc47m1: C... |
739 |
sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group); |
1da177e4c Linux-2.6.12-rc2 |
740 |
|
51f2cca1f hwmon/smsc47m1: C... |
741 |
res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
a0e92d70f hwmon: (smsc47m1)... |
742 |
smsc47m1_handle_resources(res->start, data->type, RELEASE, &pdev->dev); |
04a6217df hwmon: Fix a pote... |
743 |
platform_set_drvdata(pdev, NULL); |
943b0830c [PATCH] I2C hwmon... |
744 |
kfree(data); |
1da177e4c Linux-2.6.12-rc2 |
745 746 747 |
return 0; } |
1da177e4c Linux-2.6.12-rc2 |
748 749 750 |
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, int init) { |
51f2cca1f hwmon/smsc47m1: C... |
751 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
1da177e4c Linux-2.6.12-rc2 |
752 |
|
9a61bf630 [PATCH] hwmon: Se... |
753 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
754 755 |
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { |
8eccbb6fb hwmon/smsc47m1: A... |
756 757 |
int i, fan_nr; fan_nr = data->type == smsc47m2 ? 3 : 2; |
1da177e4c Linux-2.6.12-rc2 |
758 |
|
8eccbb6fb hwmon/smsc47m1: A... |
759 |
for (i = 0; i < fan_nr; i++) { |
51f2cca1f hwmon/smsc47m1: C... |
760 |
data->fan[i] = smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
761 |
SMSC47M1_REG_FAN[i]); |
51f2cca1f hwmon/smsc47m1: C... |
762 |
data->fan_preload[i] = smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
763 |
SMSC47M1_REG_FAN_PRELOAD[i]); |
51f2cca1f hwmon/smsc47m1: C... |
764 |
data->pwm[i] = smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
765 |
SMSC47M1_REG_PWM[i]); |
1da177e4c Linux-2.6.12-rc2 |
766 |
} |
51f2cca1f hwmon/smsc47m1: C... |
767 |
i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV); |
1da177e4c Linux-2.6.12-rc2 |
768 769 |
data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = i >> 6; |
51f2cca1f hwmon/smsc47m1: C... |
770 |
data->alarms = smsc47m1_read_value(data, |
1da177e4c Linux-2.6.12-rc2 |
771 772 773 |
SMSC47M1_REG_ALARM) >> 6; /* Clear alarms if needed */ if (data->alarms) |
51f2cca1f hwmon/smsc47m1: C... |
774 |
smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0); |
1da177e4c Linux-2.6.12-rc2 |
775 |
|
8eccbb6fb hwmon/smsc47m1: A... |
776 |
if (fan_nr >= 3) { |
51f2cca1f hwmon/smsc47m1: C... |
777 |
data->fan_div[2] = (smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
778 |
SMSC47M2_REG_FANDIV3) >> 4) & 0x03; |
51f2cca1f hwmon/smsc47m1: C... |
779 |
data->alarms |= (smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
780 781 782 |
SMSC47M2_REG_ALARM6) & 0x40) >> 4; /* Clear alarm if needed */ if (data->alarms & 0x04) |
51f2cca1f hwmon/smsc47m1: C... |
783 |
smsc47m1_write_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
784 785 786 |
SMSC47M2_REG_ALARM6, 0x40); } |
1da177e4c Linux-2.6.12-rc2 |
787 788 |
data->last_updated = jiffies; } |
9a61bf630 [PATCH] hwmon: Se... |
789 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
790 791 |
return data; } |
51f2cca1f hwmon/smsc47m1: C... |
792 793 794 795 796 797 798 799 800 801 |
static int __init smsc47m1_device_add(unsigned short address, const struct smsc47m1_sio_data *sio_data) { struct resource res = { .start = address, .end = address + SMSC_EXTENT - 1, .name = DRVNAME, .flags = IORESOURCE_IO, }; int err; |
a0e92d70f hwmon: (smsc47m1)... |
802 |
err = smsc47m1_handle_resources(address, sio_data->type, CHECK, NULL); |
b9acb64a3 hwmon: Check for ... |
803 804 |
if (err) goto exit; |
51f2cca1f hwmon/smsc47m1: C... |
805 806 807 |
pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; |
512504e9f hwmon: (smsc47m1)... |
808 809 |
pr_err("Device allocation failed "); |
51f2cca1f hwmon/smsc47m1: C... |
810 811 812 813 814 |
goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { |
512504e9f hwmon: (smsc47m1)... |
815 816 |
pr_err("Device resource addition failed (%d) ", err); |
51f2cca1f hwmon/smsc47m1: C... |
817 818 |
goto exit_device_put; } |
2df6d8115 hwmon: Use platfo... |
819 820 821 |
err = platform_device_add_data(pdev, sio_data, sizeof(struct smsc47m1_sio_data)); if (err) { |
512504e9f hwmon: (smsc47m1)... |
822 823 |
pr_err("Platform data allocation failed "); |
51f2cca1f hwmon/smsc47m1: C... |
824 825 |
goto exit_device_put; } |
51f2cca1f hwmon/smsc47m1: C... |
826 827 828 |
err = platform_device_add(pdev); if (err) { |
512504e9f hwmon: (smsc47m1)... |
829 830 |
pr_err("Device addition failed (%d) ", err); |
51f2cca1f hwmon/smsc47m1: C... |
831 832 833 834 835 836 837 838 839 840 |
goto exit_device_put; } return 0; exit_device_put: platform_device_put(pdev); exit: return err; } |
1da177e4c Linux-2.6.12-rc2 |
841 842 |
static int __init sm_smsc47m1_init(void) { |
51f2cca1f hwmon/smsc47m1: C... |
843 844 845 846 847 |
int err; unsigned short address; struct smsc47m1_sio_data sio_data; if (smsc47m1_find(&address, &sio_data)) |
1da177e4c Linux-2.6.12-rc2 |
848 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
849 |
|
3ecf44b31 hwmon: (smsc47m1)... |
850 851 |
/* Sets global pdev as a side effect */ err = smsc47m1_device_add(address, &sio_data); |
51f2cca1f hwmon/smsc47m1: C... |
852 853 |
if (err) goto exit; |
3ecf44b31 hwmon: (smsc47m1)... |
854 |
err = platform_driver_probe(&smsc47m1_driver, smsc47m1_probe); |
51f2cca1f hwmon/smsc47m1: C... |
855 |
if (err) |
3ecf44b31 hwmon: (smsc47m1)... |
856 |
goto exit_device; |
51f2cca1f hwmon/smsc47m1: C... |
857 858 |
return 0; |
3ecf44b31 hwmon: (smsc47m1)... |
859 860 |
exit_device: platform_device_unregister(pdev); |
fa0bff022 hwmon: (smsc47m1)... |
861 |
smsc47m1_restore(&sio_data); |
51f2cca1f hwmon/smsc47m1: C... |
862 863 |
exit: return err; |
1da177e4c Linux-2.6.12-rc2 |
864 865 866 867 |
} static void __exit sm_smsc47m1_exit(void) { |
51f2cca1f hwmon/smsc47m1: C... |
868 |
platform_driver_unregister(&smsc47m1_driver); |
fa0bff022 hwmon: (smsc47m1)... |
869 |
smsc47m1_restore(pdev->dev.platform_data); |
3ecf44b31 hwmon: (smsc47m1)... |
870 |
platform_device_unregister(pdev); |
1da177e4c Linux-2.6.12-rc2 |
871 872 873 874 875 876 877 878 |
} MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>"); MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver"); MODULE_LICENSE("GPL"); module_init(sm_smsc47m1_init); module_exit(sm_smsc47m1_exit); |