smsc47m1.c 20.4 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
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.
Linus Torvalds's avatar
Linus Torvalds committed
8 9

    Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
10
    Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org>
Linus Torvalds's avatar
Linus Torvalds committed
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
    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>
#include <linux/i2c.h>
34
#include <linux/i2c-isa.h>
35 36
#include <linux/hwmon.h>
#include <linux/err.h>
Linus Torvalds's avatar
Linus Torvalds committed
37
#include <linux/init.h>
38
#include <linux/mutex.h>
39
#include <linux/sysfs.h>
Linus Torvalds's avatar
Linus Torvalds committed
40 41 42
#include <asm/io.h>

/* Address is autodetected, there is no default value */
43
static unsigned short address;
44 45
static u8 devid;
enum chips { smsc47m1, smsc47m2 };
Linus Torvalds's avatar
Linus Torvalds committed
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
Linus Torvalds's avatar
Linus Torvalds committed
105 106 107 108 109 110 111 112 113 114 115 116

#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 {
	struct i2c_client client;
117
	enum chips type;
118
	struct class_device *class_dev;
Linus Torvalds's avatar
Linus Torvalds committed
119

120
	struct mutex update_lock;
Linus Torvalds's avatar
Linus Torvalds committed
121 122
	unsigned long last_updated;	/* In jiffies */

123 124 125
	u8 fan[3];		/* Register value */
	u8 fan_preload[3];	/* Register value */
	u8 fan_div[3];		/* Register encoding, shifted right */
Linus Torvalds's avatar
Linus Torvalds committed
126
	u8 alarms;		/* Register encoding */
127
	u8 pwm[3];		/* Register value (bit 0 is disable) */
Linus Torvalds's avatar
Linus Torvalds committed
128 129 130
};


131
static int smsc47m1_detect(struct i2c_adapter *adapter);
Linus Torvalds's avatar
Linus Torvalds committed
132 133 134 135
static int smsc47m1_detach_client(struct i2c_client *client);
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
		int init);

136 137 138 139 140 141 142 143 144 145
static inline int smsc47m1_read_value(struct i2c_client *client, u8 reg)
{
	return inb_p(client->addr + reg);
}

static inline void smsc47m1_write_value(struct i2c_client *client, u8 reg,
		u8 value)
{
	outb_p(value, client->addr + reg);
}
Linus Torvalds's avatar
Linus Torvalds committed
146 147

static struct i2c_driver smsc47m1_driver = {
148
	.driver = {
Jean Delvare's avatar
Jean Delvare committed
149
		.owner	= THIS_MODULE,
150 151
		.name	= "smsc47m1",
	},
152
	.attach_adapter	= smsc47m1_detect,
Linus Torvalds's avatar
Linus Torvalds committed
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
	.detach_client	= smsc47m1_detach_client,
};

/* nr is 0 or 1 in the callback functions below */

static ssize_t get_fan(struct device *dev, char *buf, int nr)
{
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
	/* 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);
}

static ssize_t get_fan_min(struct device *dev, char *buf, int nr)
{
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
	int rpm = MIN_FROM_REG(data->fan_preload[nr],
			       DIV_FROM_REG(data->fan_div[nr]));
	return sprintf(buf, "%d\n", rpm);
}

static ssize_t get_fan_div(struct device *dev, char *buf, int nr)
{
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
}

static ssize_t get_pwm(struct device *dev, char *buf, int nr)
{
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
}

static ssize_t get_pwm_en(struct device *dev, char *buf, int nr)
{
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
	return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr]));
}

198
static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds's avatar
Linus Torvalds committed
199 200 201 202 203 204 205 206 207 208 209 210
{
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
	return sprintf(buf, "%d\n", data->alarms);
}

static ssize_t set_fan_min(struct device *dev, const char *buf,
		size_t count, int nr)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct smsc47m1_data *data = i2c_get_clientdata(client);
	long rpmdiv, val = simple_strtol(buf, NULL, 10);

211
	mutex_lock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
212 213 214
	rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);

	if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
215
		mutex_unlock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
216 217 218 219
		return -EINVAL;
	}

	data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
220
	smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD[nr],
Linus Torvalds's avatar
Linus Torvalds committed
221
			     data->fan_preload[nr]);
222
	mutex_unlock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
223 224 225 226 227 228

	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
Andreas Mohr's avatar
Andreas Mohr committed
229
   of least surprise; the user doesn't expect the fan minimum to change just
Linus Torvalds's avatar
Linus Torvalds committed
230 231 232 233 234 235 236 237 238 239 240 241 242
   because the divider changed. */
static ssize_t set_fan_div(struct device *dev, const char *buf,
		size_t count, int nr)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct smsc47m1_data *data = i2c_get_clientdata(client);

	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;

243
	mutex_lock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
244 245 246 247 248 249
	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:
250
		mutex_unlock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
251 252 253
		return -EINVAL;
	}

254 255 256 257 258 259 260 261 262 263 264 265 266 267
	switch (nr) {
	case 0:
	case 1:
		tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV)
		      & ~(0x03 << (4 + 2 * nr));
		tmp |= data->fan_div[nr] << (4 + 2 * nr);
		smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp);
		break;
	case 2:
		tmp = smsc47m1_read_value(client, SMSC47M2_REG_FANDIV3) & 0xCF;
		tmp |= data->fan_div[2] << 4;
		smsc47m1_write_value(client, SMSC47M2_REG_FANDIV3, tmp);
		break;
	}
Linus Torvalds's avatar
Linus Torvalds committed
268 269 270 271 272

	/* 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);
273
	smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD[nr],
Linus Torvalds's avatar
Linus Torvalds committed
274
			     data->fan_preload[nr]);
275
	mutex_unlock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

	return count;
}

static ssize_t set_pwm(struct device *dev, const char *buf,
		size_t count, int nr)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct smsc47m1_data *data = i2c_get_clientdata(client);

	long val = simple_strtol(buf, NULL, 10);

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

291
	mutex_lock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
292 293
	data->pwm[nr] &= 0x81; /* Preserve additional bits */
	data->pwm[nr] |= PWM_TO_REG(val);
294
	smsc47m1_write_value(client, SMSC47M1_REG_PWM[nr],
Linus Torvalds's avatar
Linus Torvalds committed
295
			     data->pwm[nr]);
296
	mutex_unlock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311

	return count;
}

static ssize_t set_pwm_en(struct device *dev, const char *buf,
		size_t count, int nr)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct smsc47m1_data *data = i2c_get_clientdata(client);

	long val = simple_strtol(buf, NULL, 10);
	
	if (val != 0 && val != 1)
		return -EINVAL;

312
	mutex_lock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
313 314
	data->pwm[nr] &= 0xFE; /* preserve the other bits */
	data->pwm[nr] |= !val;
315
	smsc47m1_write_value(client, SMSC47M1_REG_PWM[nr],
Linus Torvalds's avatar
Linus Torvalds committed
316
			     data->pwm[nr]);
317
	mutex_unlock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
318 319 320 321 322

	return count;
}

#define fan_present(offset)						\
323
static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf)		\
Linus Torvalds's avatar
Linus Torvalds committed
324 325 326
{									\
	return get_fan(dev, buf, offset - 1);				\
}									\
327
static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)	\
Linus Torvalds's avatar
Linus Torvalds committed
328 329 330
{									\
	return get_fan_min(dev, buf, offset - 1);			\
}									\
331
static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr,		\
Linus Torvalds's avatar
Linus Torvalds committed
332 333 334 335
		const char *buf, size_t count)				\
{									\
	return set_fan_min(dev, buf, count, offset - 1);		\
}									\
336
static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf)	\
Linus Torvalds's avatar
Linus Torvalds committed
337 338 339
{									\
	return get_fan_div(dev, buf, offset - 1);			\
}									\
340
static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr,		\
Linus Torvalds's avatar
Linus Torvalds committed
341 342 343 344
		const char *buf, size_t count)				\
{									\
	return set_fan_div(dev, buf, count, offset - 1);		\
}									\
345
static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf)		\
Linus Torvalds's avatar
Linus Torvalds committed
346 347 348
{									\
	return get_pwm(dev, buf, offset - 1);				\
}									\
349
static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr,			\
Linus Torvalds's avatar
Linus Torvalds committed
350 351 352 353
		const char *buf, size_t count)				\
{									\
	return set_pwm(dev, buf, count, offset - 1);			\
}									\
354
static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf)	\
Linus Torvalds's avatar
Linus Torvalds committed
355 356 357
{									\
	return get_pwm_en(dev, buf, offset - 1);			\
}									\
358
static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr,		\
Linus Torvalds's avatar
Linus Torvalds committed
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
		const char *buf, size_t count)				\
{									\
	return set_pwm_en(dev, buf, count, offset - 1);			\
}									\
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset,	\
		NULL);							\
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
		get_fan##offset##_min, set_fan##offset##_min);		\
static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
		get_fan##offset##_div, set_fan##offset##_div);		\
static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,			\
		get_pwm##offset, set_pwm##offset);			\
static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,		\
		get_pwm##offset##_en, set_pwm##offset##_en);

fan_present(1);
fan_present(2);
376
fan_present(3);
Linus Torvalds's avatar
Linus Torvalds committed
377 378 379

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

380 381 382 383 384 385 386 387 388 389
/* 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[] = {
	&dev_attr_fan1_input.attr,
	&dev_attr_fan1_min.attr,
	&dev_attr_fan1_div.attr,
	&dev_attr_fan2_input.attr,
	&dev_attr_fan2_min.attr,
	&dev_attr_fan2_div.attr,
390 391 392
	&dev_attr_fan3_input.attr,
	&dev_attr_fan3_min.attr,
	&dev_attr_fan3_div.attr,
393 394 395 396 397

	&dev_attr_pwm1.attr,
	&dev_attr_pwm1_enable.attr,
	&dev_attr_pwm2.attr,
	&dev_attr_pwm2_enable.attr,
398 399
	&dev_attr_pwm3.attr,
	&dev_attr_pwm3_enable.attr,
400 401 402 403 404 405 406 407 408

	&dev_attr_alarms.attr,
	NULL
};

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

409
static int __init smsc47m1_find(unsigned short *addr)
Linus Torvalds's avatar
Linus Torvalds committed
410 411 412 413
{
	u8 val;

	superio_enter();
414
	devid = superio_inb(SUPERIO_REG_DEVID);
Linus Torvalds's avatar
Linus Torvalds committed
415 416

	/*
417 418
	 * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
	 * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
Linus Torvalds's avatar
Linus Torvalds committed
419
	 * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
420
	 * can do much more besides (device id 0x60).
421 422
	 * The LPC47M997 is undocumented, but seems to be compatible with
	 * the LPC47M192, and has the same device id.
423 424 425
	 * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
	 * supports a 3rd fan, and the pin configuration registers are
	 * unfortunately different.
Linus Torvalds's avatar
Linus Torvalds committed
426
	 */
427 428
	switch (devid) {
	case 0x51:
429
		printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n");
430 431
		break;
	case 0x59:
432 433
		printk(KERN_INFO "smsc47m1: Found SMSC "
		       "LPC47M10x/LPC47M112/LPC47M13x\n");
434 435
		break;
	case 0x5F:
436
		printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n");
437 438
		break;
	case 0x60:
439 440
		printk(KERN_INFO "smsc47m1: Found SMSC "
		       "LPC47M15x/LPC47M192/LPC47M997\n");
441 442 443 444 445
		break;
	case 0x6B:
		printk(KERN_INFO "smsc47m1: Found SMSC LPC47M292\n");
		break;
	default:
Linus Torvalds's avatar
Linus Torvalds committed
446 447 448 449 450
		superio_exit();
		return -ENODEV;
	}

	superio_select();
451 452
	*addr = (superio_inb(SUPERIO_REG_BASE) << 8)
	      |  superio_inb(SUPERIO_REG_BASE + 1);
Linus Torvalds's avatar
Linus Torvalds committed
453
	val = superio_inb(SUPERIO_REG_ACT);
454
	if (*addr == 0 || (val & 0x01) == 0) {
Linus Torvalds's avatar
Linus Torvalds committed
455 456 457 458 459 460 461 462 463
		printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n");
		superio_exit();
		return -ENODEV;
	}

	superio_exit();
	return 0;
}

464
static int smsc47m1_detect(struct i2c_adapter *adapter)
Linus Torvalds's avatar
Linus Torvalds committed
465 466 467 468
{
	struct i2c_client *new_client;
	struct smsc47m1_data *data;
	int err = 0;
469
	int fan1, fan2, fan3, pwm1, pwm2, pwm3;
Linus Torvalds's avatar
Linus Torvalds committed
470

471
	if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.driver.name)) {
Linus Torvalds's avatar
Linus Torvalds committed
472 473 474 475
		dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
		return -EBUSY;
	}

476
	if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
Linus Torvalds's avatar
Linus Torvalds committed
477 478 479 480
		err = -ENOMEM;
		goto error_release;
	}

481
	data->type = devid == 0x6B ? smsc47m2 : smsc47m1;
Linus Torvalds's avatar
Linus Torvalds committed
482 483 484 485 486 487 488
	new_client = &data->client;
	i2c_set_clientdata(new_client, data);
	new_client->addr = address;
	new_client->adapter = adapter;
	new_client->driver = &smsc47m1_driver;
	new_client->flags = 0;

489 490 491
	strlcpy(new_client->name,
		data->type == smsc47m2 ? "smsc47m2" : "smsc47m1",
		I2C_NAME_SIZE);
492
	mutex_init(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
493 494 495 496 497 498 499

	/* If no function is properly configured, there's no point in
	   actually registering the chip. */
	pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05)
	       == 0x04;
	pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
	       == 0x04;
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
	if (data->type == smsc47m2) {
		fan1 = (smsc47m1_read_value(new_client, SMSC47M2_REG_TPIN1)
			& 0x0d) == 0x09;
		fan2 = (smsc47m1_read_value(new_client, SMSC47M2_REG_TPIN2)
			& 0x0d) == 0x09;
		fan3 = (smsc47m1_read_value(new_client, SMSC47M2_REG_TPIN3)
			& 0x0d) == 0x0d;
		pwm3 = (smsc47m1_read_value(new_client, SMSC47M2_REG_PPIN3)
			& 0x0d) == 0x08;
	} else {
		fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0))
			& 0x05) == 0x05;
		fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1))
			& 0x05) == 0x05;
		fan3 = 0;
		pwm3 = 0;
	}
	if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
Jean Delvare's avatar
Jean Delvare committed
518 519
		dev_warn(&adapter->dev, "Device at 0x%x is not configured, "
			 "will not use\n", new_client->addr);
Linus Torvalds's avatar
Linus Torvalds committed
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
		err = -ENODEV;
		goto error_free;
	}

	if ((err = i2c_attach_client(new_client)))
		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. */
	smsc47m1_update_device(&new_client->dev, 1);

535
	/* Register sysfs hooks */
Linus Torvalds's avatar
Linus Torvalds committed
536
	if (fan1) {
537 538 539 540 541 542 543
		if ((err = device_create_file(&new_client->dev,
					      &dev_attr_fan1_input))
		 || (err = device_create_file(&new_client->dev,
					      &dev_attr_fan1_min))
		 || (err = device_create_file(&new_client->dev,
					      &dev_attr_fan1_div)))
			goto error_remove_files;
Linus Torvalds's avatar
Linus Torvalds committed
544 545 546 547 548
	} else
		dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
			"skipping\n");

	if (fan2) {
549 550 551 552 553 554 555
		if ((err = device_create_file(&new_client->dev,
					      &dev_attr_fan2_input))
		 || (err = device_create_file(&new_client->dev,
					      &dev_attr_fan2_min))
		 || (err = device_create_file(&new_client->dev,
					      &dev_attr_fan2_div)))
			goto error_remove_files;
Linus Torvalds's avatar
Linus Torvalds committed
556 557 558 559
	} else
		dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
			"skipping\n");

560 561 562 563 564 565 566 567 568 569 570 571
	if (fan3) {
		if ((err = device_create_file(&new_client->dev,
					      &dev_attr_fan3_input))
		 || (err = device_create_file(&new_client->dev,
					      &dev_attr_fan3_min))
		 || (err = device_create_file(&new_client->dev,
					      &dev_attr_fan3_div)))
			goto error_remove_files;
	} else
		dev_dbg(&new_client->dev, "Fan 3 not enabled by hardware, "
			"skipping\n");

Linus Torvalds's avatar
Linus Torvalds committed
572
	if (pwm1) {
573 574 575 576 577
		if ((err = device_create_file(&new_client->dev,
					      &dev_attr_pwm1))
		 || (err = device_create_file(&new_client->dev,
					      &dev_attr_pwm1_enable)))
			goto error_remove_files;
Linus Torvalds's avatar
Linus Torvalds committed
578 579 580
	} else
		dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
			"skipping\n");
581

Linus Torvalds's avatar
Linus Torvalds committed
582
	if (pwm2) {
583 584 585 586 587
		if ((err = device_create_file(&new_client->dev,
					      &dev_attr_pwm2))
		 || (err = device_create_file(&new_client->dev,
					      &dev_attr_pwm2_enable)))
			goto error_remove_files;
Linus Torvalds's avatar
Linus Torvalds committed
588 589 590 591
	} else
		dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
			"skipping\n");

592 593 594 595 596 597 598 599 600 601
	if (pwm3) {
		if ((err = device_create_file(&new_client->dev,
					      &dev_attr_pwm3))
		 || (err = device_create_file(&new_client->dev,
					      &dev_attr_pwm3_enable)))
			goto error_remove_files;
	} else
		dev_dbg(&new_client->dev, "PWM 3 not enabled by hardware, "
			"skipping\n");

602 603 604 605 606 607 608 609
	if ((err = device_create_file(&new_client->dev, &dev_attr_alarms)))
		goto error_remove_files;

	data->class_dev = hwmon_device_register(&new_client->dev);
	if (IS_ERR(data->class_dev)) {
		err = PTR_ERR(data->class_dev);
		goto error_remove_files;
	}
Linus Torvalds's avatar
Linus Torvalds committed
610 611 612

	return 0;

613 614
error_remove_files:
	sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group);
615
	i2c_detach_client(new_client);
Linus Torvalds's avatar
Linus Torvalds committed
616
error_free:
617
	kfree(data);
Linus Torvalds's avatar
Linus Torvalds committed
618 619 620 621 622 623 624
error_release:
	release_region(address, SMSC_EXTENT);
	return err;
}

static int smsc47m1_detach_client(struct i2c_client *client)
{
625
	struct smsc47m1_data *data = i2c_get_clientdata(client);
Linus Torvalds's avatar
Linus Torvalds committed
626 627
	int err;

628
	hwmon_device_unregister(data->class_dev);
629
	sysfs_remove_group(&client->dev.kobj, &smsc47m1_group);
630

631
	if ((err = i2c_detach_client(client)))
Linus Torvalds's avatar
Linus Torvalds committed
632 633 634
		return err;

	release_region(client->addr, SMSC_EXTENT);
635
	kfree(data);
Linus Torvalds's avatar
Linus Torvalds committed
636 637 638 639 640 641 642 643 644 645

	return 0;
}

static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
		int init)
{
 	struct i2c_client *client = to_i2c_client(dev);
	struct smsc47m1_data *data = i2c_get_clientdata(client);

646
	mutex_lock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
647 648

	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
649 650
		int i, fan_nr;
		fan_nr = data->type == smsc47m2 ? 3 : 2;
Linus Torvalds's avatar
Linus Torvalds committed
651

652
		for (i = 0; i < fan_nr; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
653
			data->fan[i] = smsc47m1_read_value(client,
654
				       SMSC47M1_REG_FAN[i]);
Linus Torvalds's avatar
Linus Torvalds committed
655
			data->fan_preload[i] = smsc47m1_read_value(client,
656
					       SMSC47M1_REG_FAN_PRELOAD[i]);
Linus Torvalds's avatar
Linus Torvalds committed
657
			data->pwm[i] = smsc47m1_read_value(client,
658
				       SMSC47M1_REG_PWM[i]);
Linus Torvalds's avatar
Linus Torvalds committed
659 660 661 662 663 664 665 666 667 668 669 670
		}

		i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
		data->fan_div[0] = (i >> 4) & 0x03;
		data->fan_div[1] = i >> 6;

		data->alarms = smsc47m1_read_value(client,
			       SMSC47M1_REG_ALARM) >> 6;
		/* Clear alarms if needed */
		if (data->alarms)
			smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0);

671 672 673 674 675 676 677 678 679 680 681 682
		if (fan_nr >= 3) {
			data->fan_div[2] = (smsc47m1_read_value(client,
					    SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
			data->alarms |= (smsc47m1_read_value(client,
					 SMSC47M2_REG_ALARM6) & 0x40) >> 4;
			/* Clear alarm if needed */
			if (data->alarms & 0x04)
				smsc47m1_write_value(client,
						     SMSC47M2_REG_ALARM6,
						     0x40);
		}

Linus Torvalds's avatar
Linus Torvalds committed
683 684 685
		data->last_updated = jiffies;
	}

686
	mutex_unlock(&data->update_lock);
Linus Torvalds's avatar
Linus Torvalds committed
687 688 689 690 691
	return data;
}

static int __init sm_smsc47m1_init(void)
{
692
	if (smsc47m1_find(&address)) {
Linus Torvalds's avatar
Linus Torvalds committed
693 694 695
		return -ENODEV;
	}

696
	return i2c_isa_add_driver(&smsc47m1_driver);
Linus Torvalds's avatar
Linus Torvalds committed
697 698 699 700
}

static void __exit sm_smsc47m1_exit(void)
{
701
	i2c_isa_del_driver(&smsc47m1_driver);
Linus Torvalds's avatar
Linus Torvalds committed
702 703 704 705 706 707 708 709
}

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