smsc47m1.c 21.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4
/*
    smsc47m1.c - Part of lm_sensors, Linux kernel modules
                 for hardware monitoring

5
    Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
6 7
    LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997
    Super-I/O chips.
L
Linus Torvalds 已提交
8 9

    Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
10
    Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org>
L
Linus Torvalds 已提交
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
    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.
*/

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/jiffies.h>
33
#include <linux/platform_device.h>
34
#include <linux/hwmon.h>
35
#include <linux/hwmon-sysfs.h>
36
#include <linux/err.h>
L
Linus Torvalds 已提交
37
#include <linux/init.h>
38
#include <linux/mutex.h>
39
#include <linux/sysfs.h>
L
Linus Torvalds 已提交
40 41
#include <asm/io.h>

42 43 44
static struct platform_device *pdev;

#define DRVNAME "smsc47m1"
45
enum chips { smsc47m1, smsc47m2 };
L
Linus Torvalds 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

/* Super-I/0 registers and commands */

#define	REG	0x2e	/* The register to read/write */
#define	VAL	0x2f	/* The value to read/write */

static inline void
superio_outb(int reg, int val)
{
	outb(reg, REG);
	outb(val, VAL);
}

static inline int
superio_inb(int reg)
{
	outb(reg, REG);
	return inb(VAL);
}

/* logical device for fans is 0x0A */
#define superio_select() superio_outb(0x07, 0x0A)

static inline void
superio_enter(void)
{
	outb(0x55, REG);
}

static inline void
superio_exit(void)
{
	outb(0xAA, REG);
}

#define SUPERIO_REG_ACT		0x30
#define SUPERIO_REG_BASE	0x60
#define SUPERIO_REG_DEVID	0x20

/* 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))
#define SMSC47M1_REG_FANDIV		0x58
94 95 96 97 98 99 100 101 102 103 104

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
L
Linus Torvalds 已提交
105 106 107 108 109 110 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)))
#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 {
116 117
	unsigned short addr;
	const char *name;
118
	enum chips type;
119
	struct class_device *class_dev;
L
Linus Torvalds 已提交
120

121
	struct mutex update_lock;
L
Linus Torvalds 已提交
122 123
	unsigned long last_updated;	/* In jiffies */

124 125 126
	u8 fan[3];		/* Register value */
	u8 fan_preload[3];	/* Register value */
	u8 fan_div[3];		/* Register encoding, shifted right */
L
Linus Torvalds 已提交
127
	u8 alarms;		/* Register encoding */
128
	u8 pwm[3];		/* Register value (bit 0 is disable) */
L
Linus Torvalds 已提交
129 130
};

131 132 133
struct smsc47m1_sio_data {
	enum chips type;
};
L
Linus Torvalds 已提交
134

135 136

static int smsc47m1_probe(struct platform_device *pdev);
137
static int __devexit smsc47m1_remove(struct platform_device *pdev);
L
Linus Torvalds 已提交
138 139 140
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
		int init);

141
static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg)
142
{
143
	return inb_p(data->addr + reg);
144 145
}

146
static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg,
147 148
		u8 value)
{
149
	outb_p(value, data->addr + reg);
150
}
L
Linus Torvalds 已提交
151

152
static struct platform_driver smsc47m1_driver = {
153
	.driver = {
J
Jean Delvare 已提交
154
		.owner	= THIS_MODULE,
155
		.name	= DRVNAME,
156
	},
157 158
	.probe		= smsc47m1_probe,
	.remove		= __devexit_p(smsc47m1_remove),
L
Linus Torvalds 已提交
159 160
};

161 162
static ssize_t get_fan(struct device *dev, struct device_attribute
		       *devattr, char *buf)
L
Linus Torvalds 已提交
163
{
164
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
L
Linus Torvalds 已提交
165
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
166
	int nr = attr->index;
L
Linus Torvalds 已提交
167 168 169 170 171 172 173 174 175 176 177
	/* This chip (stupidly) stops monitoring fan speed if PWM is
	   enabled and duty cycle is 0%. This is fine if the monitoring
	   and control concern the same fan, but troublesome if they are
	   not (which could as well happen). */
	int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 :
		  FAN_FROM_REG(data->fan[nr],
			       DIV_FROM_REG(data->fan_div[nr]),
			       data->fan_preload[nr]);
	return sprintf(buf, "%d\n", rpm);
}

178 179
static ssize_t get_fan_min(struct device *dev, struct device_attribute
			   *devattr, char *buf)
L
Linus Torvalds 已提交
180
{
181
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
L
Linus Torvalds 已提交
182
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
183
	int nr = attr->index;
L
Linus Torvalds 已提交
184 185 186 187 188
	int rpm = MIN_FROM_REG(data->fan_preload[nr],
			       DIV_FROM_REG(data->fan_div[nr]));
	return sprintf(buf, "%d\n", rpm);
}

189 190
static ssize_t get_fan_div(struct device *dev, struct device_attribute
			   *devattr, char *buf)
L
Linus Torvalds 已提交
191
{
192
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
L
Linus Torvalds 已提交
193
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
194
	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
L
Linus Torvalds 已提交
195 196
}

197 198
static ssize_t get_pwm(struct device *dev, struct device_attribute
		       *devattr, char *buf)
L
Linus Torvalds 已提交
199
{
200
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
L
Linus Torvalds 已提交
201
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
202
	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[attr->index]));
L
Linus Torvalds 已提交
203 204
}

205 206
static ssize_t get_pwm_en(struct device *dev, struct device_attribute
			  *devattr, char *buf)
L
Linus Torvalds 已提交
207
{
208
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
L
Linus Torvalds 已提交
209
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
210
	return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index]));
L
Linus Torvalds 已提交
211 212
}

213 214
static ssize_t get_alarms(struct device *dev, struct device_attribute
			  *devattr, char *buf)
L
Linus Torvalds 已提交
215 216 217 218 219
{
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
	return sprintf(buf, "%d\n", data->alarms);
}

220 221
static ssize_t set_fan_min(struct device *dev, struct device_attribute
			   *devattr, const char *buf, size_t count)
L
Linus Torvalds 已提交
222
{
223
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
224
	struct smsc47m1_data *data = dev_get_drvdata(dev);
225
	int nr = attr->index;
L
Linus Torvalds 已提交
226 227
	long rpmdiv, val = simple_strtol(buf, NULL, 10);

228
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
229 230 231
	rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);

	if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
232
		mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
233 234 235 236
		return -EINVAL;
	}

	data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
237
	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
L
Linus Torvalds 已提交
238
			     data->fan_preload[nr]);
239
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
240 241 242 243 244 245

	return count;
}

/* Note: we save and restore the fan minimum here, because its value is
   determined in part by the fan clock divider.  This follows the principle
A
Andreas Mohr 已提交
246
   of least surprise; the user doesn't expect the fan minimum to change just
L
Linus Torvalds 已提交
247
   because the divider changed. */
248 249
static ssize_t set_fan_div(struct device *dev, struct device_attribute
			   *devattr, const char *buf, size_t count)
L
Linus Torvalds 已提交
250
{
251
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
252
	struct smsc47m1_data *data = dev_get_drvdata(dev);
253
	int nr = attr->index;
L
Linus Torvalds 已提交
254 255 256 257 258 259
	long new_div = simple_strtol(buf, NULL, 10), tmp;
	u8 old_div = DIV_FROM_REG(data->fan_div[nr]);

	if (new_div == old_div) /* No change */
		return count;

260
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
261 262 263 264 265 266
	switch (new_div) {
	case 1: data->fan_div[nr] = 0; break;
	case 2: data->fan_div[nr] = 1; break;
	case 4: data->fan_div[nr] = 2; break;
	case 8: data->fan_div[nr] = 3; break;
	default:
267
		mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
268 269 270
		return -EINVAL;
	}

271 272 273
	switch (nr) {
	case 0:
	case 1:
274
		tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV)
275 276
		      & ~(0x03 << (4 + 2 * nr));
		tmp |= data->fan_div[nr] << (4 + 2 * nr);
277
		smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp);
278 279
		break;
	case 2:
280
		tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF;
281
		tmp |= data->fan_div[2] << 4;
282
		smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
283 284
		break;
	}
L
Linus Torvalds 已提交
285 286 287 288 289

	/* Preserve fan min */
	tmp = 192 - (old_div * (192 - data->fan_preload[nr])
		     + new_div / 2) / new_div;
	data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
290
	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
L
Linus Torvalds 已提交
291
			     data->fan_preload[nr]);
292
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
293 294 295 296

	return count;
}

297 298
static ssize_t set_pwm(struct device *dev, struct device_attribute
		       *devattr, const char *buf, size_t count)
L
Linus Torvalds 已提交
299
{
300
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
301
	struct smsc47m1_data *data = dev_get_drvdata(dev);
302
	int nr = attr->index;
L
Linus Torvalds 已提交
303 304 305 306 307
	long val = simple_strtol(buf, NULL, 10);

	if (val < 0 || val > 255)
		return -EINVAL;

308
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
309 310
	data->pwm[nr] &= 0x81; /* Preserve additional bits */
	data->pwm[nr] |= PWM_TO_REG(val);
311
	smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
L
Linus Torvalds 已提交
312
			     data->pwm[nr]);
313
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
314 315 316 317

	return count;
}

318 319
static ssize_t set_pwm_en(struct device *dev, struct device_attribute
			  *devattr, const char *buf, size_t count)
L
Linus Torvalds 已提交
320
{
321
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
322
	struct smsc47m1_data *data = dev_get_drvdata(dev);
323
	int nr = attr->index;
L
Linus Torvalds 已提交
324 325 326 327 328
	long val = simple_strtol(buf, NULL, 10);
	
	if (val != 0 && val != 1)
		return -EINVAL;

329
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
330 331
	data->pwm[nr] &= 0xFE; /* preserve the other bits */
	data->pwm[nr] |= !val;
332
	smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
L
Linus Torvalds 已提交
333
			     data->pwm[nr]);
334
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
335 336 337 338 339

	return count;
}

#define fan_present(offset)						\
340 341 342 343 344 345 346 347 348 349
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);			\
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)
L
Linus Torvalds 已提交
350 351 352

fan_present(1);
fan_present(2);
353
fan_present(3);
L
Linus Torvalds 已提交
354 355 356

static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);

357 358 359 360 361 362 363 364 365
static ssize_t show_name(struct device *dev, struct device_attribute
			 *devattr, char *buf)
{
	struct smsc47m1_data *data = dev_get_drvdata(dev);

	return sprintf(buf, "%s\n", data->name);
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);

366 367 368 369
/* Almost all sysfs files may or may not be created depending on the chip
   setup so we create them individually. It is still convenient to define a
   group to remove them all at once. */
static struct attribute *smsc47m1_attributes[] = {
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
	&sensor_dev_attr_fan1_input.dev_attr.attr,
	&sensor_dev_attr_fan1_min.dev_attr.attr,
	&sensor_dev_attr_fan1_div.dev_attr.attr,
	&sensor_dev_attr_fan2_input.dev_attr.attr,
	&sensor_dev_attr_fan2_min.dev_attr.attr,
	&sensor_dev_attr_fan2_div.dev_attr.attr,
	&sensor_dev_attr_fan3_input.dev_attr.attr,
	&sensor_dev_attr_fan3_min.dev_attr.attr,
	&sensor_dev_attr_fan3_div.dev_attr.attr,

	&sensor_dev_attr_pwm1.dev_attr.attr,
	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
	&sensor_dev_attr_pwm2.dev_attr.attr,
	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
	&sensor_dev_attr_pwm3.dev_attr.attr,
	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
386 387

	&dev_attr_alarms.attr,
388
	&dev_attr_name.attr,
389 390 391 392 393 394 395
	NULL
};

static const struct attribute_group smsc47m1_group = {
	.attrs = smsc47m1_attributes,
};

396 397
static int __init smsc47m1_find(unsigned short *addr,
				struct smsc47m1_sio_data *sio_data)
L
Linus Torvalds 已提交
398 399 400 401
{
	u8 val;

	superio_enter();
402
	val = superio_inb(SUPERIO_REG_DEVID);
L
Linus Torvalds 已提交
403 404

	/*
405 406
	 * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
	 * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
L
Linus Torvalds 已提交
407
	 * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
408
	 * can do much more besides (device id 0x60).
409 410
	 * The LPC47M997 is undocumented, but seems to be compatible with
	 * the LPC47M192, and has the same device id.
411 412 413
	 * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
	 * supports a 3rd fan, and the pin configuration registers are
	 * unfortunately different.
L
Linus Torvalds 已提交
414
	 */
415
	switch (val) {
416
	case 0x51:
417
		pr_info(DRVNAME ": Found SMSC LPC47B27x\n");
418
		sio_data->type = smsc47m1;
419 420
		break;
	case 0x59:
421
		pr_info(DRVNAME ": Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
422
		sio_data->type = smsc47m1;
423 424
		break;
	case 0x5F:
425
		pr_info(DRVNAME ": Found SMSC LPC47M14x\n");
426
		sio_data->type = smsc47m1;
427 428
		break;
	case 0x60:
429
		pr_info(DRVNAME ": Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
430
		sio_data->type = smsc47m1;
431 432
		break;
	case 0x6B:
433
		pr_info(DRVNAME ": Found SMSC LPC47M292\n");
434
		sio_data->type = smsc47m2;
435 436
		break;
	default:
L
Linus Torvalds 已提交
437 438 439 440 441
		superio_exit();
		return -ENODEV;
	}

	superio_select();
442 443
	*addr = (superio_inb(SUPERIO_REG_BASE) << 8)
	      |  superio_inb(SUPERIO_REG_BASE + 1);
L
Linus Torvalds 已提交
444
	val = superio_inb(SUPERIO_REG_ACT);
445
	if (*addr == 0 || (val & 0x01) == 0) {
446
		pr_info(DRVNAME ": Device is disabled, will not use\n");
L
Linus Torvalds 已提交
447 448 449 450 451 452 453 454
		superio_exit();
		return -ENODEV;
	}

	superio_exit();
	return 0;
}

455
static int __devinit smsc47m1_probe(struct platform_device *pdev)
L
Linus Torvalds 已提交
456
{
457 458
	struct device *dev = &pdev->dev;
	struct smsc47m1_sio_data *sio_data = dev->platform_data;
L
Linus Torvalds 已提交
459
	struct smsc47m1_data *data;
460
	struct resource *res;
L
Linus Torvalds 已提交
461
	int err = 0;
462
	int fan1, fan2, fan3, pwm1, pwm2, pwm3;
L
Linus Torvalds 已提交
463

464 465 466 467 468 469 470 471 472 473
	static const char *names[] = {
		"smsc47m1",
		"smsc47m2",
	};

	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
	if (!request_region(res->start, SMSC_EXTENT, DRVNAME)) {
		dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
			(unsigned long)res->start,
			(unsigned long)res->end);
L
Linus Torvalds 已提交
474 475 476
		return -EBUSY;
	}

D
Deepak Saxena 已提交
477
	if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
L
Linus Torvalds 已提交
478 479 480 481
		err = -ENOMEM;
		goto error_release;
	}

482 483 484
	data->addr = res->start;
	data->type = sio_data->type;
	data->name = names[sio_data->type];
485
	mutex_init(&data->update_lock);
486
	platform_set_drvdata(pdev, data);
L
Linus Torvalds 已提交
487 488 489

	/* If no function is properly configured, there's no point in
	   actually registering the chip. */
490
	pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05)
L
Linus Torvalds 已提交
491
	       == 0x04;
492
	pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05)
L
Linus Torvalds 已提交
493
	       == 0x04;
494
	if (data->type == smsc47m2) {
495
		fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1)
496
			& 0x0d) == 0x09;
497
		fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2)
498
			& 0x0d) == 0x09;
499
		fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3)
500
			& 0x0d) == 0x0d;
501
		pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3)
502 503
			& 0x0d) == 0x08;
	} else {
504
		fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0))
505
			& 0x05) == 0x05;
506
		fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1))
507 508 509 510 511
			& 0x05) == 0x05;
		fan3 = 0;
		pwm3 = 0;
	}
	if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
512
		dev_warn(dev, "Device not configured, will not use\n");
L
Linus Torvalds 已提交
513 514 515 516 517 518 519 520 521 522
		err = -ENODEV;
		goto error_free;
	}

	/* 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. */
523
	smsc47m1_update_device(dev, 1);
L
Linus Torvalds 已提交
524

525
	/* Register sysfs hooks */
L
Linus Torvalds 已提交
526
	if (fan1) {
527 528 529 530 531 532
		if ((err = device_create_file(dev,
				&sensor_dev_attr_fan1_input.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_fan1_min.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_fan1_div.dev_attr)))
533
			goto error_remove_files;
L
Linus Torvalds 已提交
534
	} else
535
		dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
L
Linus Torvalds 已提交
536 537

	if (fan2) {
538 539 540 541 542 543
		if ((err = device_create_file(dev,
				&sensor_dev_attr_fan2_input.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_fan2_min.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_fan2_div.dev_attr)))
544
			goto error_remove_files;
L
Linus Torvalds 已提交
545
	} else
546
		dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
L
Linus Torvalds 已提交
547

548
	if (fan3) {
549 550 551 552 553 554
		if ((err = device_create_file(dev,
				&sensor_dev_attr_fan3_input.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_fan3_min.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_fan3_div.dev_attr)))
555 556
			goto error_remove_files;
	} else
557
		dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
558

L
Linus Torvalds 已提交
559
	if (pwm1) {
560 561 562 563
		if ((err = device_create_file(dev,
				&sensor_dev_attr_pwm1.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_pwm1_enable.dev_attr)))
564
			goto error_remove_files;
L
Linus Torvalds 已提交
565
	} else
566
		dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n");
567

L
Linus Torvalds 已提交
568
	if (pwm2) {
569 570 571 572
		if ((err = device_create_file(dev,
				&sensor_dev_attr_pwm2.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_pwm2_enable.dev_attr)))
573
			goto error_remove_files;
L
Linus Torvalds 已提交
574
	} else
575
		dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n");
L
Linus Torvalds 已提交
576

577
	if (pwm3) {
578 579 580 581
		if ((err = device_create_file(dev,
				&sensor_dev_attr_pwm3.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_pwm3_enable.dev_attr)))
582 583
			goto error_remove_files;
	} else
584
		dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
585

586
	if ((err = device_create_file(dev, &dev_attr_alarms)))
587 588
		goto error_remove_files;

589
	data->class_dev = hwmon_device_register(dev);
590 591 592 593
	if (IS_ERR(data->class_dev)) {
		err = PTR_ERR(data->class_dev);
		goto error_remove_files;
	}
L
Linus Torvalds 已提交
594 595 596

	return 0;

597
error_remove_files:
598
	sysfs_remove_group(&dev->kobj, &smsc47m1_group);
L
Linus Torvalds 已提交
599
error_free:
600
	platform_set_drvdata(pdev, NULL);
601
	kfree(data);
L
Linus Torvalds 已提交
602
error_release:
603
	release_region(res->start, SMSC_EXTENT);
L
Linus Torvalds 已提交
604 605 606
	return err;
}

607
static int __devexit smsc47m1_remove(struct platform_device *pdev)
L
Linus Torvalds 已提交
608
{
609 610
	struct smsc47m1_data *data = platform_get_drvdata(pdev);
	struct resource *res;
L
Linus Torvalds 已提交
611

612
	hwmon_device_unregister(data->class_dev);
613
	sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
L
Linus Torvalds 已提交
614

615 616
	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
	release_region(res->start, SMSC_EXTENT);
617
	platform_set_drvdata(pdev, NULL);
618
	kfree(data);
L
Linus Torvalds 已提交
619 620 621 622 623 624 625

	return 0;
}

static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
		int init)
{
626
	struct smsc47m1_data *data = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
627

628
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
629 630

	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
631 632
		int i, fan_nr;
		fan_nr = data->type == smsc47m2 ? 3 : 2;
L
Linus Torvalds 已提交
633

634
		for (i = 0; i < fan_nr; i++) {
635
			data->fan[i] = smsc47m1_read_value(data,
636
				       SMSC47M1_REG_FAN[i]);
637
			data->fan_preload[i] = smsc47m1_read_value(data,
638
					       SMSC47M1_REG_FAN_PRELOAD[i]);
639
			data->pwm[i] = smsc47m1_read_value(data,
640
				       SMSC47M1_REG_PWM[i]);
L
Linus Torvalds 已提交
641 642
		}

643
		i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
L
Linus Torvalds 已提交
644 645 646
		data->fan_div[0] = (i >> 4) & 0x03;
		data->fan_div[1] = i >> 6;

647
		data->alarms = smsc47m1_read_value(data,
L
Linus Torvalds 已提交
648 649 650
			       SMSC47M1_REG_ALARM) >> 6;
		/* Clear alarms if needed */
		if (data->alarms)
651
			smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
L
Linus Torvalds 已提交
652

653
		if (fan_nr >= 3) {
654
			data->fan_div[2] = (smsc47m1_read_value(data,
655
					    SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
656
			data->alarms |= (smsc47m1_read_value(data,
657 658 659
					 SMSC47M2_REG_ALARM6) & 0x40) >> 4;
			/* Clear alarm if needed */
			if (data->alarms & 0x04)
660
				smsc47m1_write_value(data,
661 662 663 664
						     SMSC47M2_REG_ALARM6,
						     0x40);
		}

L
Linus Torvalds 已提交
665 666 667
		data->last_updated = jiffies;
	}

668
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
669 670 671
	return data;
}

672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
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;

	pdev = platform_device_alloc(DRVNAME, address);
	if (!pdev) {
		err = -ENOMEM;
		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
		goto exit;
	}

	err = platform_device_add_resources(pdev, &res, 1);
	if (err) {
		printk(KERN_ERR DRVNAME ": Device resource addition failed "
		       "(%d)\n", err);
		goto exit_device_put;
	}

697 698 699
	err = platform_device_add_data(pdev, sio_data,
				       sizeof(struct smsc47m1_sio_data));
	if (err) {
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
		goto exit_device_put;
	}

	err = platform_device_add(pdev);
	if (err) {
		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
		       err);
		goto exit_device_put;
	}

	return 0;

exit_device_put:
	platform_device_put(pdev);
exit:
	return err;
}

L
Linus Torvalds 已提交
719 720
static int __init sm_smsc47m1_init(void)
{
721 722 723 724 725
	int err;
	unsigned short address;
	struct smsc47m1_sio_data sio_data;

	if (smsc47m1_find(&address, &sio_data))
L
Linus Torvalds 已提交
726 727
		return -ENODEV;

728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
	err = platform_driver_register(&smsc47m1_driver);
	if (err)
		goto exit;

	/* Sets global pdev as a side effect */
	err = smsc47m1_device_add(address, &sio_data);
	if (err)
		goto exit_driver;

	return 0;

exit_driver:
	platform_driver_unregister(&smsc47m1_driver);
exit:
	return err;
L
Linus Torvalds 已提交
743 744 745 746
}

static void __exit sm_smsc47m1_exit(void)
{
747 748
	platform_device_unregister(pdev);
	platform_driver_unregister(&smsc47m1_driver);
L
Linus Torvalds 已提交
749 750 751 752 753 754 755 756
}

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);