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