Blame view
drivers/hwmon/smsc47m1.c
24.5 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
85a0c0d1a hwmon: (smsc47m1)... |
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
* smsc47m1.c - Part of lm_sensors, Linux kernel modules * for hardware monitoring * * Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, * LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997 * Super-I/O chips. * * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> * Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org> * 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. */ |
1da177e4c Linux-2.6.12-rc2 |
28 |
|
512504e9f hwmon: (smsc47m1)... |
29 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
30 31 32 33 |
#include <linux/module.h> #include <linux/slab.h> #include <linux/ioport.h> #include <linux/jiffies.h> |
51f2cca1f hwmon/smsc47m1: C... |
34 |
#include <linux/platform_device.h> |
943b0830c [PATCH] I2C hwmon... |
35 |
#include <linux/hwmon.h> |
e84cfbcbe hwmon/smsc47m1: U... |
36 |
#include <linux/hwmon-sysfs.h> |
943b0830c [PATCH] I2C hwmon... |
37 |
#include <linux/err.h> |
1da177e4c Linux-2.6.12-rc2 |
38 |
#include <linux/init.h> |
9a61bf630 [PATCH] hwmon: Se... |
39 |
#include <linux/mutex.h> |
ce8c6ce1e hwmon: Fix unchec... |
40 |
#include <linux/sysfs.h> |
b9acb64a3 hwmon: Check for ... |
41 |
#include <linux/acpi.h> |
6055fae8a hwmon: Include <l... |
42 |
#include <linux/io.h> |
1da177e4c Linux-2.6.12-rc2 |
43 |
|
67b671bce hwmon: Let the us... |
44 45 46 |
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... |
47 48 49 |
static struct platform_device *pdev; #define DRVNAME "smsc47m1" |
8eccbb6fb hwmon/smsc47m1: A... |
50 |
enum chips { smsc47m1, smsc47m2 }; |
1da177e4c Linux-2.6.12-rc2 |
51 52 |
/* Super-I/0 registers and commands */ |
85a0c0d1a hwmon: (smsc47m1)... |
53 54 |
#define REG 0x2e /* The register to read/write */ #define VAL 0x2f /* The value to read/write */ |
1da177e4c Linux-2.6.12-rc2 |
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
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)... |
88 |
#define SUPERIO_REG_DEVREV 0x21 |
1da177e4c Linux-2.6.12-rc2 |
89 90 91 92 93 94 95 96 97 |
/* 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 |
98 |
#define SMSC47M1_REG_FANDIV 0x58 |
8eccbb6fb hwmon/smsc47m1: A... |
99 100 101 102 103 104 105 106 107 108 109 |
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 |
110 |
|
85a0c0d1a hwmon: (smsc47m1)... |
111 112 113 114 115 |
#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))) |
1da177e4c Linux-2.6.12-rc2 |
116 117 118 119 120 121 |
#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... |
122 123 |
unsigned short addr; const char *name; |
8eccbb6fb hwmon/smsc47m1: A... |
124 |
enum chips type; |
1beeffe43 hwmon: Convert fr... |
125 |
struct device *hwmon_dev; |
1da177e4c Linux-2.6.12-rc2 |
126 |
|
9a61bf630 [PATCH] hwmon: Se... |
127 |
struct mutex update_lock; |
1da177e4c Linux-2.6.12-rc2 |
128 |
unsigned long last_updated; /* In jiffies */ |
8eccbb6fb hwmon/smsc47m1: A... |
129 130 131 |
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 |
132 |
u8 alarms; /* Register encoding */ |
8eccbb6fb hwmon/smsc47m1: A... |
133 |
u8 pwm[3]; /* Register value (bit 0 is disable) */ |
1da177e4c Linux-2.6.12-rc2 |
134 |
}; |
51f2cca1f hwmon/smsc47m1: C... |
135 136 |
struct smsc47m1_sio_data { enum chips type; |
fa0bff022 hwmon: (smsc47m1)... |
137 |
u8 activate; /* Remember initial device state */ |
51f2cca1f hwmon/smsc47m1: C... |
138 |
}; |
1da177e4c Linux-2.6.12-rc2 |
139 |
|
51f2cca1f hwmon/smsc47m1: C... |
140 |
|
3ecf44b31 hwmon: (smsc47m1)... |
141 |
static int __exit smsc47m1_remove(struct platform_device *pdev); |
1da177e4c Linux-2.6.12-rc2 |
142 143 |
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, int init); |
51f2cca1f hwmon/smsc47m1: C... |
144 |
static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg) |
94e183fd0 hwmon/smsc47m1: G... |
145 |
{ |
51f2cca1f hwmon/smsc47m1: C... |
146 |
return inb_p(data->addr + reg); |
94e183fd0 hwmon/smsc47m1: G... |
147 |
} |
51f2cca1f hwmon/smsc47m1: C... |
148 |
static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg, |
94e183fd0 hwmon/smsc47m1: G... |
149 150 |
u8 value) { |
51f2cca1f hwmon/smsc47m1: C... |
151 |
outb_p(value, data->addr + reg); |
94e183fd0 hwmon/smsc47m1: G... |
152 |
} |
1da177e4c Linux-2.6.12-rc2 |
153 |
|
51f2cca1f hwmon/smsc47m1: C... |
154 |
static struct platform_driver smsc47m1_driver = { |
cdaf79349 [PATCH] i2c: Drop... |
155 |
.driver = { |
872188420 i2c-isa: Restore ... |
156 |
.owner = THIS_MODULE, |
51f2cca1f hwmon/smsc47m1: C... |
157 |
.name = DRVNAME, |
cdaf79349 [PATCH] i2c: Drop... |
158 |
}, |
3ecf44b31 hwmon: (smsc47m1)... |
159 |
.remove = __exit_p(smsc47m1_remove), |
1da177e4c Linux-2.6.12-rc2 |
160 |
}; |
e84cfbcbe hwmon/smsc47m1: U... |
161 162 |
static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
163 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
164 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
165 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
166 |
int nr = attr->index; |
85a0c0d1a hwmon: (smsc47m1)... |
167 168 169 170 171 172 |
/* * 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). */ |
1da177e4c Linux-2.6.12-rc2 |
173 174 175 176 177 178 179 |
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... |
180 181 |
static ssize_t get_fan_min(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
182 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
183 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
184 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
185 |
int nr = attr->index; |
1da177e4c Linux-2.6.12-rc2 |
186 187 188 189 190 |
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... |
191 192 |
static ssize_t get_fan_div(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
193 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
194 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
195 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
196 197 |
return sprintf(buf, "%d ", DIV_FROM_REG(data->fan_div[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
198 |
} |
1f08af7ea hwmon: (smsc47m1)... |
199 200 201 202 203 204 205 206 |
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... |
207 208 |
static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
209 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
210 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
211 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
212 213 |
return sprintf(buf, "%d ", PWM_FROM_REG(data->pwm[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
214 |
} |
e84cfbcbe hwmon/smsc47m1: U... |
215 216 |
static ssize_t get_pwm_en(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
217 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
218 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
1da177e4c Linux-2.6.12-rc2 |
219 |
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
e84cfbcbe hwmon/smsc47m1: U... |
220 221 |
return sprintf(buf, "%d ", PWM_EN_FROM_REG(data->pwm[attr->index])); |
1da177e4c Linux-2.6.12-rc2 |
222 |
} |
e84cfbcbe hwmon/smsc47m1: U... |
223 224 |
static ssize_t get_alarms(struct device *dev, struct device_attribute *devattr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
225 226 227 228 229 |
{ struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); return sprintf(buf, "%d ", data->alarms); } |
e84cfbcbe hwmon/smsc47m1: U... |
230 231 |
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 |
232 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
233 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
51f2cca1f hwmon/smsc47m1: C... |
234 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
e84cfbcbe hwmon/smsc47m1: U... |
235 |
int nr = attr->index; |
85a0c0d1a hwmon: (smsc47m1)... |
236 237 238 239 240 241 242 |
long rpmdiv; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
243 |
|
9a61bf630 [PATCH] hwmon: Se... |
244 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
245 246 247 |
rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) { |
9a61bf630 [PATCH] hwmon: Se... |
248 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
249 250 251 252 |
return -EINVAL; } data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); |
51f2cca1f hwmon/smsc47m1: C... |
253 |
smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr], |
1da177e4c Linux-2.6.12-rc2 |
254 |
data->fan_preload[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
255 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
256 257 258 |
return count; } |
85a0c0d1a hwmon: (smsc47m1)... |
259 260 261 262 263 264 |
/* * 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 * of least surprise; the user doesn't expect the fan minimum to change just * because the divider changed. */ |
e84cfbcbe hwmon/smsc47m1: U... |
265 266 |
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 |
267 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
268 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
51f2cca1f hwmon/smsc47m1: C... |
269 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
e84cfbcbe hwmon/smsc47m1: U... |
270 |
int nr = attr->index; |
85a0c0d1a hwmon: (smsc47m1)... |
271 272 273 |
long new_div; int err; long tmp; |
1da177e4c Linux-2.6.12-rc2 |
274 |
u8 old_div = DIV_FROM_REG(data->fan_div[nr]); |
85a0c0d1a hwmon: (smsc47m1)... |
275 276 277 |
err = kstrtol(buf, 10, &new_div); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
278 279 |
if (new_div == old_div) /* No change */ return count; |
9a61bf630 [PATCH] hwmon: Se... |
280 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
281 |
switch (new_div) { |
85a0c0d1a hwmon: (smsc47m1)... |
282 283 284 285 286 287 288 289 290 291 292 293 |
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; |
1da177e4c Linux-2.6.12-rc2 |
294 |
default: |
9a61bf630 [PATCH] hwmon: Se... |
295 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
296 297 |
return -EINVAL; } |
8eccbb6fb hwmon/smsc47m1: A... |
298 299 300 |
switch (nr) { case 0: case 1: |
51f2cca1f hwmon/smsc47m1: C... |
301 |
tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV) |
8eccbb6fb hwmon/smsc47m1: A... |
302 303 |
& ~(0x03 << (4 + 2 * nr)); tmp |= data->fan_div[nr] << (4 + 2 * nr); |
51f2cca1f hwmon/smsc47m1: C... |
304 |
smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp); |
8eccbb6fb hwmon/smsc47m1: A... |
305 306 |
break; case 2: |
51f2cca1f hwmon/smsc47m1: C... |
307 |
tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF; |
8eccbb6fb hwmon/smsc47m1: A... |
308 |
tmp |= data->fan_div[2] << 4; |
51f2cca1f hwmon/smsc47m1: C... |
309 |
smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp); |
8eccbb6fb hwmon/smsc47m1: A... |
310 311 |
break; } |
1da177e4c Linux-2.6.12-rc2 |
312 313 314 315 |
/* Preserve fan min */ tmp = 192 - (old_div * (192 - data->fan_preload[nr]) + new_div / 2) / new_div; |
2a844c148 hwmon: Replace SE... |
316 |
data->fan_preload[nr] = clamp_val(tmp, 0, 191); |
51f2cca1f hwmon/smsc47m1: C... |
317 |
smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr], |
1da177e4c Linux-2.6.12-rc2 |
318 |
data->fan_preload[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
319 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
320 321 322 |
return count; } |
e84cfbcbe hwmon/smsc47m1: U... |
323 324 |
static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
325 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
326 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
51f2cca1f hwmon/smsc47m1: C... |
327 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
e84cfbcbe hwmon/smsc47m1: U... |
328 |
int nr = attr->index; |
85a0c0d1a hwmon: (smsc47m1)... |
329 330 331 332 333 334 |
long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; |
1da177e4c Linux-2.6.12-rc2 |
335 336 337 |
if (val < 0 || val > 255) return -EINVAL; |
9a61bf630 [PATCH] hwmon: Se... |
338 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
339 340 |
data->pwm[nr] &= 0x81; /* Preserve additional bits */ data->pwm[nr] |= PWM_TO_REG(val); |
51f2cca1f hwmon/smsc47m1: C... |
341 |
smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr], |
1da177e4c Linux-2.6.12-rc2 |
342 |
data->pwm[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
343 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
344 345 346 |
return count; } |
e84cfbcbe hwmon/smsc47m1: U... |
347 348 |
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 |
349 |
{ |
e84cfbcbe hwmon/smsc47m1: U... |
350 |
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
51f2cca1f hwmon/smsc47m1: C... |
351 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
e84cfbcbe hwmon/smsc47m1: U... |
352 |
int nr = attr->index; |
85a0c0d1a hwmon: (smsc47m1)... |
353 354 355 356 357 358 359 360 |
unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; if (val > 1) |
1da177e4c Linux-2.6.12-rc2 |
361 |
return -EINVAL; |
9a61bf630 [PATCH] hwmon: Se... |
362 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
363 364 |
data->pwm[nr] &= 0xFE; /* preserve the other bits */ data->pwm[nr] |= !val; |
51f2cca1f hwmon/smsc47m1: C... |
365 |
smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr], |
1da177e4c Linux-2.6.12-rc2 |
366 |
data->pwm[nr]); |
9a61bf630 [PATCH] hwmon: Se... |
367 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
368 369 370 371 372 |
return count; } #define fan_present(offset) \ |
e84cfbcbe hwmon/smsc47m1: U... |
373 374 375 376 377 378 |
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)... |
379 380 |
static SENSOR_DEVICE_ATTR(fan##offset##_alarm, S_IRUGO, get_fan_alarm, \ NULL, offset - 1); \ |
e84cfbcbe hwmon/smsc47m1: U... |
381 382 383 384 |
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 |
385 386 387 |
fan_present(1); fan_present(2); |
8eccbb6fb hwmon/smsc47m1: A... |
388 |
fan_present(3); |
1da177e4c Linux-2.6.12-rc2 |
389 390 |
static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); |
51f2cca1f hwmon/smsc47m1: C... |
391 392 393 394 395 396 397 398 399 |
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); |
7e612685a hwmon: (smsc47m1)... |
400 |
static struct attribute *smsc47m1_attributes_fan1[] = { |
e84cfbcbe hwmon/smsc47m1: U... |
401 402 403 |
&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)... |
404 |
&sensor_dev_attr_fan1_alarm.dev_attr.attr, |
7e612685a hwmon: (smsc47m1)... |
405 406 407 408 409 410 411 412 |
NULL }; static const struct attribute_group smsc47m1_group_fan1 = { .attrs = smsc47m1_attributes_fan1, }; static struct attribute *smsc47m1_attributes_fan2[] = { |
e84cfbcbe hwmon/smsc47m1: U... |
413 414 415 |
&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)... |
416 |
&sensor_dev_attr_fan2_alarm.dev_attr.attr, |
7e612685a hwmon: (smsc47m1)... |
417 418 419 420 421 422 423 424 |
NULL }; static const struct attribute_group smsc47m1_group_fan2 = { .attrs = smsc47m1_attributes_fan2, }; static struct attribute *smsc47m1_attributes_fan3[] = { |
e84cfbcbe hwmon/smsc47m1: U... |
425 426 427 |
&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)... |
428 |
&sensor_dev_attr_fan3_alarm.dev_attr.attr, |
7e612685a hwmon: (smsc47m1)... |
429 430 |
NULL }; |
e84cfbcbe hwmon/smsc47m1: U... |
431 |
|
7e612685a hwmon: (smsc47m1)... |
432 433 434 435 436 |
static const struct attribute_group smsc47m1_group_fan3 = { .attrs = smsc47m1_attributes_fan3, }; static struct attribute *smsc47m1_attributes_pwm1[] = { |
e84cfbcbe hwmon/smsc47m1: U... |
437 438 |
&sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr, |
7e612685a hwmon: (smsc47m1)... |
439 440 441 442 443 444 445 446 |
NULL }; static const struct attribute_group smsc47m1_group_pwm1 = { .attrs = smsc47m1_attributes_pwm1, }; static struct attribute *smsc47m1_attributes_pwm2[] = { |
e84cfbcbe hwmon/smsc47m1: U... |
447 448 |
&sensor_dev_attr_pwm2.dev_attr.attr, &sensor_dev_attr_pwm2_enable.dev_attr.attr, |
7e612685a hwmon: (smsc47m1)... |
449 450 451 452 453 454 455 456 |
NULL }; static const struct attribute_group smsc47m1_group_pwm2 = { .attrs = smsc47m1_attributes_pwm2, }; static struct attribute *smsc47m1_attributes_pwm3[] = { |
e84cfbcbe hwmon/smsc47m1: U... |
457 458 |
&sensor_dev_attr_pwm3.dev_attr.attr, &sensor_dev_attr_pwm3_enable.dev_attr.attr, |
7e612685a hwmon: (smsc47m1)... |
459 460 |
NULL }; |
ce8c6ce1e hwmon: Fix unchec... |
461 |
|
7e612685a hwmon: (smsc47m1)... |
462 463 464 465 466 |
static const struct attribute_group smsc47m1_group_pwm3 = { .attrs = smsc47m1_attributes_pwm3, }; static struct attribute *smsc47m1_attributes[] = { |
ce8c6ce1e hwmon: Fix unchec... |
467 |
&dev_attr_alarms.attr, |
51f2cca1f hwmon/smsc47m1: C... |
468 |
&dev_attr_name.attr, |
ce8c6ce1e hwmon: Fix unchec... |
469 470 471 472 473 474 |
NULL }; static const struct attribute_group smsc47m1_group = { .attrs = smsc47m1_attributes, }; |
1d0045ee4 hwmon: (smsc47m1)... |
475 |
static int __init smsc47m1_find(struct smsc47m1_sio_data *sio_data) |
1da177e4c Linux-2.6.12-rc2 |
476 477 |
{ u8 val; |
1d0045ee4 hwmon: (smsc47m1)... |
478 |
unsigned short addr; |
1da177e4c Linux-2.6.12-rc2 |
479 480 |
superio_enter(); |
67b671bce hwmon: Let the us... |
481 |
val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID); |
1da177e4c Linux-2.6.12-rc2 |
482 483 |
/* |
6091780eb smsc47m1: List th... |
484 485 |
* 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 |
486 |
* The LPC47M15x and LPC47M192 chips "with hardware monitoring block" |
ec5ce552d [PATCH] I2C: Add ... |
487 |
* can do much more besides (device id 0x60). |
b890a07f7 [PATCH] hwmon: sm... |
488 489 |
* The LPC47M997 is undocumented, but seems to be compatible with * the LPC47M192, and has the same device id. |
8eccbb6fb hwmon/smsc47m1: A... |
490 491 492 |
* 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)... |
493 494 495 |
* 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 |
496 |
*/ |
51f2cca1f hwmon/smsc47m1: C... |
497 |
switch (val) { |
8eccbb6fb hwmon/smsc47m1: A... |
498 |
case 0x51: |
512504e9f hwmon: (smsc47m1)... |
499 500 |
pr_info("Found SMSC LPC47B27x "); |
51f2cca1f hwmon/smsc47m1: C... |
501 |
sio_data->type = smsc47m1; |
8eccbb6fb hwmon/smsc47m1: A... |
502 503 |
break; case 0x59: |
512504e9f hwmon: (smsc47m1)... |
504 505 |
pr_info("Found SMSC LPC47M10x/LPC47M112/LPC47M13x "); |
51f2cca1f hwmon/smsc47m1: C... |
506 |
sio_data->type = smsc47m1; |
8eccbb6fb hwmon/smsc47m1: A... |
507 508 |
break; case 0x5F: |
512504e9f hwmon: (smsc47m1)... |
509 510 |
pr_info("Found SMSC LPC47M14x "); |
51f2cca1f hwmon/smsc47m1: C... |
511 |
sio_data->type = smsc47m1; |
8eccbb6fb hwmon/smsc47m1: A... |
512 513 |
break; case 0x60: |
512504e9f hwmon: (smsc47m1)... |
514 515 |
pr_info("Found SMSC LPC47M15x/LPC47M192/LPC47M997 "); |
51f2cca1f hwmon/smsc47m1: C... |
516 |
sio_data->type = smsc47m1; |
8eccbb6fb hwmon/smsc47m1: A... |
517 518 |
break; case 0x6B: |
1b54ab450 hwmon: (smsc47m1)... |
519 |
if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) { |
512504e9f hwmon: (smsc47m1)... |
520 521 |
pr_debug("Found SMSC LPC47M233, unsupported "); |
1b54ab450 hwmon: (smsc47m1)... |
522 523 524 |
superio_exit(); return -ENODEV; } |
512504e9f hwmon: (smsc47m1)... |
525 526 |
pr_info("Found SMSC LPC47M292 "); |
51f2cca1f hwmon/smsc47m1: C... |
527 |
sio_data->type = smsc47m2; |
8eccbb6fb hwmon/smsc47m1: A... |
528 529 |
break; default: |
1da177e4c Linux-2.6.12-rc2 |
530 531 532 533 534 |
superio_exit(); return -ENODEV; } superio_select(); |
1d0045ee4 hwmon: (smsc47m1)... |
535 |
addr = (superio_inb(SUPERIO_REG_BASE) << 8) |
2d8672c5a [PATCH] I2C: Sepa... |
536 |
| superio_inb(SUPERIO_REG_BASE + 1); |
1d0045ee4 hwmon: (smsc47m1)... |
537 |
if (addr == 0) { |
512504e9f hwmon: (smsc47m1)... |
538 539 |
pr_info("Device address not set, will not use "); |
1da177e4c Linux-2.6.12-rc2 |
540 541 542 |
superio_exit(); return -ENODEV; } |
85a0c0d1a hwmon: (smsc47m1)... |
543 544 545 546 |
/* * Enable only if address is set (needed at least on the * Compaq Presario S4000NX) */ |
fa0bff022 hwmon: (smsc47m1)... |
547 548 |
sio_data->activate = superio_inb(SUPERIO_REG_ACT); if ((sio_data->activate & 0x01) == 0) { |
512504e9f hwmon: (smsc47m1)... |
549 550 |
pr_info("Enabling device "); |
fa0bff022 hwmon: (smsc47m1)... |
551 552 |
superio_outb(SUPERIO_REG_ACT, sio_data->activate | 0x01); } |
1da177e4c Linux-2.6.12-rc2 |
553 |
superio_exit(); |
1d0045ee4 hwmon: (smsc47m1)... |
554 |
return addr; |
1da177e4c Linux-2.6.12-rc2 |
555 |
} |
fa0bff022 hwmon: (smsc47m1)... |
556 |
/* Restore device to its initial state */ |
a00d643a2 hwmon: (smsc47m1)... |
557 |
static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data) |
fa0bff022 hwmon: (smsc47m1)... |
558 559 560 561 |
{ if ((sio_data->activate & 0x01) == 0) { superio_enter(); superio_select(); |
512504e9f hwmon: (smsc47m1)... |
562 563 |
pr_info("Disabling device "); |
fa0bff022 hwmon: (smsc47m1)... |
564 565 566 567 568 |
superio_outb(SUPERIO_REG_ACT, sio_data->activate); superio_exit(); } } |
a0e92d70f hwmon: (smsc47m1)... |
569 570 |
#define CHECK 1 #define REQUEST 2 |
a0e92d70f hwmon: (smsc47m1)... |
571 572 573 574 575 |
/* * This function can be used to: * - test for resource conflicts with ACPI * - request the resources |
a0e92d70f hwmon: (smsc47m1)... |
576 577 578 |
* We only allocate the I/O ports we really need, to minimize the risk of * conflicts with ACPI or with other drivers. */ |
08ad7c952 hwmon: (smsc47m1)... |
579 580 581 |
static int __init smsc47m1_handle_resources(unsigned short address, enum chips type, int action, struct device *dev) |
a0e92d70f hwmon: (smsc47m1)... |
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 |
{ 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 */ |
08ad7c952 hwmon: (smsc47m1)... |
628 629 630 631 632 |
if (!devm_request_region(dev, start, len, DRVNAME)) { dev_err(dev, "Region 0x%hx-0x%hx already in use! ", start, start + len); |
a0e92d70f hwmon: (smsc47m1)... |
633 634 635 |
return -EBUSY; } break; |
a0e92d70f hwmon: (smsc47m1)... |
636 637 638 639 640 |
} } return 0; } |
7e612685a hwmon: (smsc47m1)... |
641 642 643 644 645 646 647 648 649 650 |
static void smsc47m1_remove_files(struct device *dev) { sysfs_remove_group(&dev->kobj, &smsc47m1_group); sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan1); sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan2); sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan3); sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm1); sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm2); sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm3); } |
3ecf44b31 hwmon: (smsc47m1)... |
651 |
static int __init smsc47m1_probe(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
652 |
{ |
51f2cca1f hwmon/smsc47m1: C... |
653 654 |
struct device *dev = &pdev->dev; struct smsc47m1_sio_data *sio_data = dev->platform_data; |
1da177e4c Linux-2.6.12-rc2 |
655 |
struct smsc47m1_data *data; |
51f2cca1f hwmon/smsc47m1: C... |
656 |
struct resource *res; |
a0e92d70f hwmon: (smsc47m1)... |
657 |
int err; |
8eccbb6fb hwmon/smsc47m1: A... |
658 |
int fan1, fan2, fan3, pwm1, pwm2, pwm3; |
1da177e4c Linux-2.6.12-rc2 |
659 |
|
85a0c0d1a hwmon: (smsc47m1)... |
660 |
static const char * const names[] = { |
51f2cca1f hwmon/smsc47m1: C... |
661 662 663 664 665 |
"smsc47m1", "smsc47m2", }; res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
a0e92d70f hwmon: (smsc47m1)... |
666 667 668 669 |
err = smsc47m1_handle_resources(res->start, sio_data->type, REQUEST, dev); if (err < 0) return err; |
1da177e4c Linux-2.6.12-rc2 |
670 |
|
08ad7c952 hwmon: (smsc47m1)... |
671 672 673 |
data = devm_kzalloc(dev, sizeof(struct smsc47m1_data), GFP_KERNEL); if (!data) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
674 |
|
51f2cca1f hwmon/smsc47m1: C... |
675 676 677 |
data->addr = res->start; data->type = sio_data->type; data->name = names[sio_data->type]; |
9a61bf630 [PATCH] hwmon: Se... |
678 |
mutex_init(&data->update_lock); |
51f2cca1f hwmon/smsc47m1: C... |
679 |
platform_set_drvdata(pdev, data); |
1da177e4c Linux-2.6.12-rc2 |
680 |
|
85a0c0d1a hwmon: (smsc47m1)... |
681 682 683 684 |
/* * If no function is properly configured, there's no point in * actually registering the chip. */ |
51f2cca1f hwmon/smsc47m1: C... |
685 |
pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05) |
1da177e4c Linux-2.6.12-rc2 |
686 |
== 0x04; |
51f2cca1f hwmon/smsc47m1: C... |
687 |
pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05) |
1da177e4c Linux-2.6.12-rc2 |
688 |
== 0x04; |
8eccbb6fb hwmon/smsc47m1: A... |
689 |
if (data->type == smsc47m2) { |
51f2cca1f hwmon/smsc47m1: C... |
690 |
fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1) |
8eccbb6fb hwmon/smsc47m1: A... |
691 |
& 0x0d) == 0x09; |
51f2cca1f hwmon/smsc47m1: C... |
692 |
fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2) |
8eccbb6fb hwmon/smsc47m1: A... |
693 |
& 0x0d) == 0x09; |
51f2cca1f hwmon/smsc47m1: C... |
694 |
fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3) |
8eccbb6fb hwmon/smsc47m1: A... |
695 |
& 0x0d) == 0x0d; |
51f2cca1f hwmon/smsc47m1: C... |
696 |
pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3) |
8eccbb6fb hwmon/smsc47m1: A... |
697 698 |
& 0x0d) == 0x08; } else { |
51f2cca1f hwmon/smsc47m1: C... |
699 |
fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0)) |
8eccbb6fb hwmon/smsc47m1: A... |
700 |
& 0x05) == 0x05; |
51f2cca1f hwmon/smsc47m1: C... |
701 |
fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1)) |
8eccbb6fb hwmon/smsc47m1: A... |
702 703 704 705 706 |
& 0x05) == 0x05; fan3 = 0; pwm3 = 0; } if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) { |
51f2cca1f hwmon/smsc47m1: C... |
707 708 |
dev_warn(dev, "Device not configured, will not use "); |
08ad7c952 hwmon: (smsc47m1)... |
709 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
710 |
} |
85a0c0d1a hwmon: (smsc47m1)... |
711 712 713 714 715 716 717 718 |
/* * 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... |
719 |
smsc47m1_update_device(dev, 1); |
1da177e4c Linux-2.6.12-rc2 |
720 |
|
943b0830c [PATCH] I2C hwmon... |
721 |
/* Register sysfs hooks */ |
1da177e4c Linux-2.6.12-rc2 |
722 |
if (fan1) { |
7e612685a hwmon: (smsc47m1)... |
723 724 725 |
err = sysfs_create_group(&dev->kobj, &smsc47m1_group_fan1); if (err) |
ce8c6ce1e hwmon: Fix unchec... |
726 |
goto error_remove_files; |
1da177e4c Linux-2.6.12-rc2 |
727 |
} else |
51f2cca1f hwmon/smsc47m1: C... |
728 729 |
dev_dbg(dev, "Fan 1 not enabled by hardware, skipping "); |
1da177e4c Linux-2.6.12-rc2 |
730 731 |
if (fan2) { |
7e612685a hwmon: (smsc47m1)... |
732 733 734 |
err = sysfs_create_group(&dev->kobj, &smsc47m1_group_fan2); if (err) |
ce8c6ce1e hwmon: Fix unchec... |
735 |
goto error_remove_files; |
1da177e4c Linux-2.6.12-rc2 |
736 |
} else |
51f2cca1f hwmon/smsc47m1: C... |
737 738 |
dev_dbg(dev, "Fan 2 not enabled by hardware, skipping "); |
1da177e4c Linux-2.6.12-rc2 |
739 |
|
8eccbb6fb hwmon/smsc47m1: A... |
740 |
if (fan3) { |
7e612685a hwmon: (smsc47m1)... |
741 742 743 |
err = sysfs_create_group(&dev->kobj, &smsc47m1_group_fan3); if (err) |
8eccbb6fb hwmon/smsc47m1: A... |
744 |
goto error_remove_files; |
8477d0268 hwmon: (smsc47m1)... |
745 |
} else if (data->type == smsc47m2) |
51f2cca1f hwmon/smsc47m1: C... |
746 747 |
dev_dbg(dev, "Fan 3 not enabled by hardware, skipping "); |
8eccbb6fb hwmon/smsc47m1: A... |
748 |
|
1da177e4c Linux-2.6.12-rc2 |
749 |
if (pwm1) { |
7e612685a hwmon: (smsc47m1)... |
750 751 752 |
err = sysfs_create_group(&dev->kobj, &smsc47m1_group_pwm1); if (err) |
ce8c6ce1e hwmon: Fix unchec... |
753 |
goto error_remove_files; |
1da177e4c Linux-2.6.12-rc2 |
754 |
} else |
51f2cca1f hwmon/smsc47m1: C... |
755 756 |
dev_dbg(dev, "PWM 1 not enabled by hardware, skipping "); |
8eccbb6fb hwmon/smsc47m1: A... |
757 |
|
1da177e4c Linux-2.6.12-rc2 |
758 |
if (pwm2) { |
7e612685a hwmon: (smsc47m1)... |
759 760 761 |
err = sysfs_create_group(&dev->kobj, &smsc47m1_group_pwm2); if (err) |
ce8c6ce1e hwmon: Fix unchec... |
762 |
goto error_remove_files; |
1da177e4c Linux-2.6.12-rc2 |
763 |
} else |
51f2cca1f hwmon/smsc47m1: C... |
764 765 |
dev_dbg(dev, "PWM 2 not enabled by hardware, skipping "); |
1da177e4c Linux-2.6.12-rc2 |
766 |
|
8eccbb6fb hwmon/smsc47m1: A... |
767 |
if (pwm3) { |
7e612685a hwmon: (smsc47m1)... |
768 769 770 |
err = sysfs_create_group(&dev->kobj, &smsc47m1_group_pwm3); if (err) |
8eccbb6fb hwmon/smsc47m1: A... |
771 |
goto error_remove_files; |
8477d0268 hwmon: (smsc47m1)... |
772 |
} else if (data->type == smsc47m2) |
51f2cca1f hwmon/smsc47m1: C... |
773 774 |
dev_dbg(dev, "PWM 3 not enabled by hardware, skipping "); |
8eccbb6fb hwmon/smsc47m1: A... |
775 |
|
7e612685a hwmon: (smsc47m1)... |
776 777 |
err = sysfs_create_group(&dev->kobj, &smsc47m1_group); if (err) |
68a50b567 hwmon: (smsc47m1)... |
778 |
goto error_remove_files; |
ce8c6ce1e hwmon: Fix unchec... |
779 |
|
1beeffe43 hwmon: Convert fr... |
780 781 782 |
data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); |
ce8c6ce1e hwmon: Fix unchec... |
783 784 |
goto error_remove_files; } |
1da177e4c Linux-2.6.12-rc2 |
785 786 |
return 0; |
ce8c6ce1e hwmon: Fix unchec... |
787 |
error_remove_files: |
7e612685a hwmon: (smsc47m1)... |
788 |
smsc47m1_remove_files(dev); |
1da177e4c Linux-2.6.12-rc2 |
789 790 |
return err; } |
3ecf44b31 hwmon: (smsc47m1)... |
791 |
static int __exit smsc47m1_remove(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
792 |
{ |
51f2cca1f hwmon/smsc47m1: C... |
793 |
struct smsc47m1_data *data = platform_get_drvdata(pdev); |
1da177e4c Linux-2.6.12-rc2 |
794 |
|
1beeffe43 hwmon: Convert fr... |
795 |
hwmon_device_unregister(data->hwmon_dev); |
7e612685a hwmon: (smsc47m1)... |
796 |
smsc47m1_remove_files(&pdev->dev); |
1da177e4c Linux-2.6.12-rc2 |
797 |
|
1da177e4c Linux-2.6.12-rc2 |
798 799 |
return 0; } |
1da177e4c Linux-2.6.12-rc2 |
800 801 802 |
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, int init) { |
51f2cca1f hwmon/smsc47m1: C... |
803 |
struct smsc47m1_data *data = dev_get_drvdata(dev); |
1da177e4c Linux-2.6.12-rc2 |
804 |
|
9a61bf630 [PATCH] hwmon: Se... |
805 |
mutex_lock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
806 807 |
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { |
8eccbb6fb hwmon/smsc47m1: A... |
808 809 |
int i, fan_nr; fan_nr = data->type == smsc47m2 ? 3 : 2; |
1da177e4c Linux-2.6.12-rc2 |
810 |
|
8eccbb6fb hwmon/smsc47m1: A... |
811 |
for (i = 0; i < fan_nr; i++) { |
51f2cca1f hwmon/smsc47m1: C... |
812 |
data->fan[i] = smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
813 |
SMSC47M1_REG_FAN[i]); |
51f2cca1f hwmon/smsc47m1: C... |
814 |
data->fan_preload[i] = smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
815 |
SMSC47M1_REG_FAN_PRELOAD[i]); |
51f2cca1f hwmon/smsc47m1: C... |
816 |
data->pwm[i] = smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
817 |
SMSC47M1_REG_PWM[i]); |
1da177e4c Linux-2.6.12-rc2 |
818 |
} |
51f2cca1f hwmon/smsc47m1: C... |
819 |
i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV); |
1da177e4c Linux-2.6.12-rc2 |
820 821 |
data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = i >> 6; |
51f2cca1f hwmon/smsc47m1: C... |
822 |
data->alarms = smsc47m1_read_value(data, |
1da177e4c Linux-2.6.12-rc2 |
823 824 825 |
SMSC47M1_REG_ALARM) >> 6; /* Clear alarms if needed */ if (data->alarms) |
51f2cca1f hwmon/smsc47m1: C... |
826 |
smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0); |
1da177e4c Linux-2.6.12-rc2 |
827 |
|
8eccbb6fb hwmon/smsc47m1: A... |
828 |
if (fan_nr >= 3) { |
51f2cca1f hwmon/smsc47m1: C... |
829 |
data->fan_div[2] = (smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
830 |
SMSC47M2_REG_FANDIV3) >> 4) & 0x03; |
51f2cca1f hwmon/smsc47m1: C... |
831 |
data->alarms |= (smsc47m1_read_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
832 833 834 |
SMSC47M2_REG_ALARM6) & 0x40) >> 4; /* Clear alarm if needed */ if (data->alarms & 0x04) |
51f2cca1f hwmon/smsc47m1: C... |
835 |
smsc47m1_write_value(data, |
8eccbb6fb hwmon/smsc47m1: A... |
836 837 838 |
SMSC47M2_REG_ALARM6, 0x40); } |
1da177e4c Linux-2.6.12-rc2 |
839 840 |
data->last_updated = jiffies; } |
9a61bf630 [PATCH] hwmon: Se... |
841 |
mutex_unlock(&data->update_lock); |
1da177e4c Linux-2.6.12-rc2 |
842 843 |
return data; } |
51f2cca1f hwmon/smsc47m1: C... |
844 845 846 847 848 849 850 851 852 853 |
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)... |
854 |
err = smsc47m1_handle_resources(address, sio_data->type, CHECK, NULL); |
b9acb64a3 hwmon: Check for ... |
855 856 |
if (err) goto exit; |
51f2cca1f hwmon/smsc47m1: C... |
857 858 859 |
pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; |
512504e9f hwmon: (smsc47m1)... |
860 861 |
pr_err("Device allocation failed "); |
51f2cca1f hwmon/smsc47m1: C... |
862 863 864 865 866 |
goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { |
512504e9f hwmon: (smsc47m1)... |
867 868 |
pr_err("Device resource addition failed (%d) ", err); |
51f2cca1f hwmon/smsc47m1: C... |
869 870 |
goto exit_device_put; } |
2df6d8115 hwmon: Use platfo... |
871 872 873 |
err = platform_device_add_data(pdev, sio_data, sizeof(struct smsc47m1_sio_data)); if (err) { |
512504e9f hwmon: (smsc47m1)... |
874 875 |
pr_err("Platform data allocation failed "); |
51f2cca1f hwmon/smsc47m1: C... |
876 877 |
goto exit_device_put; } |
51f2cca1f hwmon/smsc47m1: C... |
878 879 880 |
err = platform_device_add(pdev); if (err) { |
512504e9f hwmon: (smsc47m1)... |
881 882 |
pr_err("Device addition failed (%d) ", err); |
51f2cca1f hwmon/smsc47m1: C... |
883 884 885 886 887 888 889 890 891 892 |
goto exit_device_put; } return 0; exit_device_put: platform_device_put(pdev); exit: return err; } |
1da177e4c Linux-2.6.12-rc2 |
893 894 |
static int __init sm_smsc47m1_init(void) { |
51f2cca1f hwmon/smsc47m1: C... |
895 896 897 |
int err; unsigned short address; struct smsc47m1_sio_data sio_data; |
1d0045ee4 hwmon: (smsc47m1)... |
898 899 900 901 |
err = smsc47m1_find(&sio_data); if (err < 0) return err; address = err; |
1da177e4c Linux-2.6.12-rc2 |
902 |
|
3ecf44b31 hwmon: (smsc47m1)... |
903 904 |
/* Sets global pdev as a side effect */ err = smsc47m1_device_add(address, &sio_data); |
51f2cca1f hwmon/smsc47m1: C... |
905 |
if (err) |
1d0045ee4 hwmon: (smsc47m1)... |
906 |
return err; |
51f2cca1f hwmon/smsc47m1: C... |
907 |
|
3ecf44b31 hwmon: (smsc47m1)... |
908 |
err = platform_driver_probe(&smsc47m1_driver, smsc47m1_probe); |
51f2cca1f hwmon/smsc47m1: C... |
909 |
if (err) |
3ecf44b31 hwmon: (smsc47m1)... |
910 |
goto exit_device; |
51f2cca1f hwmon/smsc47m1: C... |
911 912 |
return 0; |
3ecf44b31 hwmon: (smsc47m1)... |
913 914 |
exit_device: platform_device_unregister(pdev); |
fa0bff022 hwmon: (smsc47m1)... |
915 |
smsc47m1_restore(&sio_data); |
51f2cca1f hwmon/smsc47m1: C... |
916 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
917 918 919 920 |
} static void __exit sm_smsc47m1_exit(void) { |
51f2cca1f hwmon/smsc47m1: C... |
921 |
platform_driver_unregister(&smsc47m1_driver); |
fa0bff022 hwmon: (smsc47m1)... |
922 |
smsc47m1_restore(pdev->dev.platform_data); |
3ecf44b31 hwmon: (smsc47m1)... |
923 |
platform_device_unregister(pdev); |
1da177e4c Linux-2.6.12-rc2 |
924 925 926 927 928 929 930 931 |
} 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); |