smsc47m1.c 21.5 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 45
static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");

46 47 48
static struct platform_device *pdev;

#define DRVNAME "smsc47m1"
49
enum chips { smsc47m1, smsc47m2 };
L
Linus Torvalds 已提交
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 94 95 96 97

/* 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
98 99 100 101 102 103 104 105 106 107 108

static const u8 SMSC47M1_REG_FAN[3]		= { 0x59, 0x5a, 0x6b };
static const u8 SMSC47M1_REG_FAN_PRELOAD[3]	= { 0x5b, 0x5c, 0x6c };
static const u8 SMSC47M1_REG_PWM[3]		= { 0x56, 0x57, 0x69 };

#define SMSC47M2_REG_ALARM6		0x09
#define SMSC47M2_REG_TPIN1		0x38
#define SMSC47M2_REG_TPIN2		0x37
#define SMSC47M2_REG_TPIN3		0x2d
#define SMSC47M2_REG_PPIN3		0x2c
#define SMSC47M2_REG_FANDIV3		0x6a
L
Linus Torvalds 已提交
109 110 111 112 113 114 115 116 117 118 119

#define MIN_FROM_REG(reg,div)		((reg)>=192 ? 0 : \
					 983040/((192-(reg))*(div)))
#define FAN_FROM_REG(reg,div,preload)	((reg)<=(preload) || (reg)==255 ? 0 : \
					 983040/(((reg)-(preload))*(div)))
#define DIV_FROM_REG(reg)		(1 << (reg))
#define PWM_FROM_REG(reg)		(((reg) & 0x7E) << 1)
#define PWM_EN_FROM_REG(reg)		((~(reg)) & 0x01)
#define PWM_TO_REG(reg)			(((reg) >> 1) & 0x7E)

struct smsc47m1_data {
120 121
	unsigned short addr;
	const char *name;
122
	enum chips type;
123
	struct device *hwmon_dev;
L
Linus Torvalds 已提交
124

125
	struct mutex update_lock;
L
Linus Torvalds 已提交
126 127
	unsigned long last_updated;	/* In jiffies */

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

135 136 137
struct smsc47m1_sio_data {
	enum chips type;
};
L
Linus Torvalds 已提交
138

139 140

static int smsc47m1_probe(struct platform_device *pdev);
141
static int __devexit smsc47m1_remove(struct platform_device *pdev);
L
Linus Torvalds 已提交
142 143 144
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
		int init);

145
static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg)
146
{
147
	return inb_p(data->addr + reg);
148 149
}

150
static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg,
151 152
		u8 value)
{
153
	outb_p(value, data->addr + reg);
154
}
L
Linus Torvalds 已提交
155

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

165 166
static ssize_t get_fan(struct device *dev, struct device_attribute
		       *devattr, char *buf)
L
Linus Torvalds 已提交
167
{
168
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
L
Linus Torvalds 已提交
169
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
170
	int nr = attr->index;
L
Linus Torvalds 已提交
171 172 173 174 175 176 177 178 179 180 181
	/* 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);
}

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

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

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

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

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

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

232
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
233 234 235
	rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);

	if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
236
		mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
237 238 239 240
		return -EINVAL;
	}

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

	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 已提交
250
   of least surprise; the user doesn't expect the fan minimum to change just
L
Linus Torvalds 已提交
251
   because the divider changed. */
252 253
static ssize_t set_fan_div(struct device *dev, struct device_attribute
			   *devattr, const char *buf, size_t count)
L
Linus Torvalds 已提交
254
{
255
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
256
	struct smsc47m1_data *data = dev_get_drvdata(dev);
257
	int nr = attr->index;
L
Linus Torvalds 已提交
258 259 260 261 262 263
	long new_div = simple_strtol(buf, NULL, 10), tmp;
	u8 old_div = DIV_FROM_REG(data->fan_div[nr]);

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

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

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

	/* 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);
294
	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
L
Linus Torvalds 已提交
295
			     data->fan_preload[nr]);
296
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
297 298 299 300

	return count;
}

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

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

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

	return count;
}

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

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

	return count;
}

#define fan_present(offset)						\
344 345 346 347 348 349 350 351 352 353
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 已提交
354 355 356

fan_present(1);
fan_present(2);
357
fan_present(3);
L
Linus Torvalds 已提交
358 359 360

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

361 362 363 364 365 366 367 368 369
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);

370 371 372 373
/* 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[] = {
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
	&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,
390 391

	&dev_attr_alarms.attr,
392
	&dev_attr_name.attr,
393 394 395 396 397 398 399
	NULL
};

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

400 401
static int __init smsc47m1_find(unsigned short *addr,
				struct smsc47m1_sio_data *sio_data)
L
Linus Torvalds 已提交
402 403 404 405
{
	u8 val;

	superio_enter();
406
	val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
L
Linus Torvalds 已提交
407 408

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

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

	superio_exit();
	return 0;
}

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

468 469 470 471 472 473 474 475 476 477
	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 已提交
478 479 480
		return -EBUSY;
	}

D
Deepak Saxena 已提交
481
	if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
L
Linus Torvalds 已提交
482 483 484 485
		err = -ENOMEM;
		goto error_release;
	}

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

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

529
	/* Register sysfs hooks */
L
Linus Torvalds 已提交
530
	if (fan1) {
531 532 533 534 535 536
		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)))
537
			goto error_remove_files;
L
Linus Torvalds 已提交
538
	} else
539
		dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
L
Linus Torvalds 已提交
540 541

	if (fan2) {
542 543 544 545 546 547
		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)))
548
			goto error_remove_files;
L
Linus Torvalds 已提交
549
	} else
550
		dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
L
Linus Torvalds 已提交
551

552
	if (fan3) {
553 554 555 556 557 558
		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)))
559
			goto error_remove_files;
560
	} else if (data->type == smsc47m2)
561
		dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
562

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

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

581
	if (pwm3) {
582 583 584 585
		if ((err = device_create_file(dev,
				&sensor_dev_attr_pwm3.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_pwm3_enable.dev_attr)))
586
			goto error_remove_files;
587
	} else if (data->type == smsc47m2)
588
		dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
589

590
	if ((err = device_create_file(dev, &dev_attr_alarms)))
591
		goto error_remove_files;
592 593
	if ((err = device_create_file(dev, &dev_attr_name)))
		goto error_remove_files;
594

595 596 597
	data->hwmon_dev = hwmon_device_register(dev);
	if (IS_ERR(data->hwmon_dev)) {
		err = PTR_ERR(data->hwmon_dev);
598 599
		goto error_remove_files;
	}
L
Linus Torvalds 已提交
600 601 602

	return 0;

603
error_remove_files:
604
	sysfs_remove_group(&dev->kobj, &smsc47m1_group);
L
Linus Torvalds 已提交
605
error_free:
606
	platform_set_drvdata(pdev, NULL);
607
	kfree(data);
L
Linus Torvalds 已提交
608
error_release:
609
	release_region(res->start, SMSC_EXTENT);
L
Linus Torvalds 已提交
610 611 612
	return err;
}

613
static int __devexit smsc47m1_remove(struct platform_device *pdev)
L
Linus Torvalds 已提交
614
{
615 616
	struct smsc47m1_data *data = platform_get_drvdata(pdev);
	struct resource *res;
L
Linus Torvalds 已提交
617

618
	hwmon_device_unregister(data->hwmon_dev);
619
	sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
L
Linus Torvalds 已提交
620

621 622
	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
	release_region(res->start, SMSC_EXTENT);
623
	platform_set_drvdata(pdev, NULL);
624
	kfree(data);
L
Linus Torvalds 已提交
625 626 627 628 629 630 631

	return 0;
}

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

634
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
635 636

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

640
		for (i = 0; i < fan_nr; i++) {
641
			data->fan[i] = smsc47m1_read_value(data,
642
				       SMSC47M1_REG_FAN[i]);
643
			data->fan_preload[i] = smsc47m1_read_value(data,
644
					       SMSC47M1_REG_FAN_PRELOAD[i]);
645
			data->pwm[i] = smsc47m1_read_value(data,
646
				       SMSC47M1_REG_PWM[i]);
L
Linus Torvalds 已提交
647 648
		}

649
		i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
L
Linus Torvalds 已提交
650 651 652
		data->fan_div[0] = (i >> 4) & 0x03;
		data->fan_div[1] = i >> 6;

653
		data->alarms = smsc47m1_read_value(data,
L
Linus Torvalds 已提交
654 655 656
			       SMSC47M1_REG_ALARM) >> 6;
		/* Clear alarms if needed */
		if (data->alarms)
657
			smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
L
Linus Torvalds 已提交
658

659
		if (fan_nr >= 3) {
660
			data->fan_div[2] = (smsc47m1_read_value(data,
661
					    SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
662
			data->alarms |= (smsc47m1_read_value(data,
663 664 665
					 SMSC47M2_REG_ALARM6) & 0x40) >> 4;
			/* Clear alarm if needed */
			if (data->alarms & 0x04)
666
				smsc47m1_write_value(data,
667 668 669 670
						     SMSC47M2_REG_ALARM6,
						     0x40);
		}

L
Linus Torvalds 已提交
671 672 673
		data->last_updated = jiffies;
	}

674
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
675 676 677
	return data;
}

678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
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;
	}

703 704 705
	err = platform_device_add_data(pdev, sio_data,
				       sizeof(struct smsc47m1_sio_data));
	if (err) {
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
		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 已提交
725 726
static int __init sm_smsc47m1_init(void)
{
727 728 729 730 731
	int err;
	unsigned short address;
	struct smsc47m1_sio_data sio_data;

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

734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
	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 已提交
749 750 751 752
}

static void __exit sm_smsc47m1_exit(void)
{
753 754
	platform_device_unregister(pdev);
	platform_driver_unregister(&smsc47m1_driver);
L
Linus Torvalds 已提交
755 756 757 758 759 760 761 762
}

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