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