smsc47m1.c 22.6 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>
40
#include <linux/acpi.h>
L
Linus Torvalds 已提交
41 42
#include <asm/io.h>

43 44 45 46
static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");

47 48 49
static struct platform_device *pdev;

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

/* 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
89
#define SUPERIO_REG_DEVREV	0x21
L
Linus Torvalds 已提交
90 91 92 93 94 95 96 97 98 99

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

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 已提交
111 112 113 114 115 116 117 118 119 120 121

#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 {
122 123
	unsigned short addr;
	const char *name;
124
	enum chips type;
125
	struct device *hwmon_dev;
L
Linus Torvalds 已提交
126

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

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

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

141 142

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

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

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

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

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

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

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

203 204 205 206 207 208 209 210
static ssize_t get_fan_alarm(struct device *dev, struct device_attribute
			     *devattr, char *buf)
{
	int bitnr = to_sensor_dev_attr(devattr)->index;
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
}

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

219 220
static ssize_t get_pwm_en(struct device *dev, struct device_attribute
			  *devattr, char *buf)
L
Linus Torvalds 已提交
221
{
222
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
L
Linus Torvalds 已提交
223
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
224
	return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index]));
L
Linus Torvalds 已提交
225 226
}

227 228
static ssize_t get_alarms(struct device *dev, struct device_attribute
			  *devattr, char *buf)
L
Linus Torvalds 已提交
229 230 231 232 233
{
	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
	return sprintf(buf, "%d\n", data->alarms);
}

234 235
static ssize_t set_fan_min(struct device *dev, struct device_attribute
			   *devattr, const char *buf, size_t count)
L
Linus Torvalds 已提交
236
{
237
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
238
	struct smsc47m1_data *data = dev_get_drvdata(dev);
239
	int nr = attr->index;
L
Linus Torvalds 已提交
240 241
	long rpmdiv, val = simple_strtol(buf, NULL, 10);

242
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
243 244 245
	rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);

	if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
246
		mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
247 248 249 250
		return -EINVAL;
	}

	data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
251
	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
L
Linus Torvalds 已提交
252
			     data->fan_preload[nr]);
253
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
254 255 256 257 258 259

	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 已提交
260
   of least surprise; the user doesn't expect the fan minimum to change just
L
Linus Torvalds 已提交
261
   because the divider changed. */
262 263
static ssize_t set_fan_div(struct device *dev, struct device_attribute
			   *devattr, const char *buf, size_t count)
L
Linus Torvalds 已提交
264
{
265
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
266
	struct smsc47m1_data *data = dev_get_drvdata(dev);
267
	int nr = attr->index;
L
Linus Torvalds 已提交
268 269 270 271 272 273
	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;

274
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
275 276 277 278 279 280
	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:
281
		mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
282 283 284
		return -EINVAL;
	}

285 286 287
	switch (nr) {
	case 0:
	case 1:
288
		tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV)
289 290
		      & ~(0x03 << (4 + 2 * nr));
		tmp |= data->fan_div[nr] << (4 + 2 * nr);
291
		smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp);
292 293
		break;
	case 2:
294
		tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF;
295
		tmp |= data->fan_div[2] << 4;
296
		smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
297 298
		break;
	}
L
Linus Torvalds 已提交
299 300 301 302 303

	/* 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);
304
	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
L
Linus Torvalds 已提交
305
			     data->fan_preload[nr]);
306
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
307 308 309 310

	return count;
}

311 312
static ssize_t set_pwm(struct device *dev, struct device_attribute
		       *devattr, const char *buf, size_t count)
L
Linus Torvalds 已提交
313
{
314
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
315
	struct smsc47m1_data *data = dev_get_drvdata(dev);
316
	int nr = attr->index;
L
Linus Torvalds 已提交
317 318 319 320 321
	long val = simple_strtol(buf, NULL, 10);

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

322
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
323 324
	data->pwm[nr] &= 0x81; /* Preserve additional bits */
	data->pwm[nr] |= PWM_TO_REG(val);
325
	smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
L
Linus Torvalds 已提交
326
			     data->pwm[nr]);
327
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
328 329 330 331

	return count;
}

332 333
static ssize_t set_pwm_en(struct device *dev, struct device_attribute
			  *devattr, const char *buf, size_t count)
L
Linus Torvalds 已提交
334
{
335
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
336
	struct smsc47m1_data *data = dev_get_drvdata(dev);
337
	int nr = attr->index;
L
Linus Torvalds 已提交
338 339 340 341 342
	long val = simple_strtol(buf, NULL, 10);
	
	if (val != 0 && val != 1)
		return -EINVAL;

343
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
344 345
	data->pwm[nr] &= 0xFE; /* preserve the other bits */
	data->pwm[nr] |= !val;
346
	smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
L
Linus Torvalds 已提交
347
			     data->pwm[nr]);
348
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
349 350 351 352 353

	return count;
}

#define fan_present(offset)						\
354 355 356 357 358 359
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);			\
360 361
static SENSOR_DEVICE_ATTR(fan##offset##_alarm, S_IRUGO, get_fan_alarm,	\
		NULL, offset - 1);					\
362 363 364 365
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 已提交
366 367 368

fan_present(1);
fan_present(2);
369
fan_present(3);
L
Linus Torvalds 已提交
370 371 372

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

373 374 375 376 377 378 379 380 381
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);

382 383 384 385
/* 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[] = {
386 387 388
	&sensor_dev_attr_fan1_input.dev_attr.attr,
	&sensor_dev_attr_fan1_min.dev_attr.attr,
	&sensor_dev_attr_fan1_div.dev_attr.attr,
389
	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
390 391 392
	&sensor_dev_attr_fan2_input.dev_attr.attr,
	&sensor_dev_attr_fan2_min.dev_attr.attr,
	&sensor_dev_attr_fan2_div.dev_attr.attr,
393
	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
394 395 396
	&sensor_dev_attr_fan3_input.dev_attr.attr,
	&sensor_dev_attr_fan3_min.dev_attr.attr,
	&sensor_dev_attr_fan3_div.dev_attr.attr,
397
	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
398 399 400 401 402 403 404

	&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,
405 406

	&dev_attr_alarms.attr,
407
	&dev_attr_name.attr,
408 409 410 411 412 413 414
	NULL
};

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

415 416
static int __init smsc47m1_find(unsigned short *addr,
				struct smsc47m1_sio_data *sio_data)
L
Linus Torvalds 已提交
417 418 419 420
{
	u8 val;

	superio_enter();
421
	val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
L
Linus Torvalds 已提交
422 423

	/*
424 425
	 * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
	 * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
L
Linus Torvalds 已提交
426
	 * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
427
	 * can do much more besides (device id 0x60).
428 429
	 * The LPC47M997 is undocumented, but seems to be compatible with
	 * the LPC47M192, and has the same device id.
430 431 432
	 * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
	 * supports a 3rd fan, and the pin configuration registers are
	 * unfortunately different.
433 434 435
	 * The LPC47M233 has the same device id (0x6B) but is not compatible.
	 * We check the high bit of the device revision register to
	 * differentiate them.
L
Linus Torvalds 已提交
436
	 */
437
	switch (val) {
438
	case 0x51:
439
		pr_info(DRVNAME ": Found SMSC LPC47B27x\n");
440
		sio_data->type = smsc47m1;
441 442
		break;
	case 0x59:
443
		pr_info(DRVNAME ": Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
444
		sio_data->type = smsc47m1;
445 446
		break;
	case 0x5F:
447
		pr_info(DRVNAME ": Found SMSC LPC47M14x\n");
448
		sio_data->type = smsc47m1;
449 450
		break;
	case 0x60:
451
		pr_info(DRVNAME ": Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
452
		sio_data->type = smsc47m1;
453 454
		break;
	case 0x6B:
455 456 457 458 459 460 461
		if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) {
			pr_debug(DRVNAME ": "
				 "Found SMSC LPC47M233, unsupported\n");
			superio_exit();
			return -ENODEV;
		}

462
		pr_info(DRVNAME ": Found SMSC LPC47M292\n");
463
		sio_data->type = smsc47m2;
464 465
		break;
	default:
L
Linus Torvalds 已提交
466 467 468 469 470
		superio_exit();
		return -ENODEV;
	}

	superio_select();
471 472
	*addr = (superio_inb(SUPERIO_REG_BASE) << 8)
	      |  superio_inb(SUPERIO_REG_BASE + 1);
L
Linus Torvalds 已提交
473
	val = superio_inb(SUPERIO_REG_ACT);
474
	if (*addr == 0 || (val & 0x01) == 0) {
475
		pr_info(DRVNAME ": Device is disabled, will not use\n");
L
Linus Torvalds 已提交
476 477 478 479 480 481 482 483
		superio_exit();
		return -ENODEV;
	}

	superio_exit();
	return 0;
}

484
static int __devinit smsc47m1_probe(struct platform_device *pdev)
L
Linus Torvalds 已提交
485
{
486 487
	struct device *dev = &pdev->dev;
	struct smsc47m1_sio_data *sio_data = dev->platform_data;
L
Linus Torvalds 已提交
488
	struct smsc47m1_data *data;
489
	struct resource *res;
L
Linus Torvalds 已提交
490
	int err = 0;
491
	int fan1, fan2, fan3, pwm1, pwm2, pwm3;
L
Linus Torvalds 已提交
492

493 494 495 496 497 498 499 500 501 502
	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 已提交
503 504 505
		return -EBUSY;
	}

D
Deepak Saxena 已提交
506
	if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
L
Linus Torvalds 已提交
507 508 509 510
		err = -ENOMEM;
		goto error_release;
	}

511 512 513
	data->addr = res->start;
	data->type = sio_data->type;
	data->name = names[sio_data->type];
514
	mutex_init(&data->update_lock);
515
	platform_set_drvdata(pdev, data);
L
Linus Torvalds 已提交
516 517 518

	/* If no function is properly configured, there's no point in
	   actually registering the chip. */
519
	pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05)
L
Linus Torvalds 已提交
520
	       == 0x04;
521
	pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05)
L
Linus Torvalds 已提交
522
	       == 0x04;
523
	if (data->type == smsc47m2) {
524
		fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1)
525
			& 0x0d) == 0x09;
526
		fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2)
527
			& 0x0d) == 0x09;
528
		fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3)
529
			& 0x0d) == 0x0d;
530
		pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3)
531 532
			& 0x0d) == 0x08;
	} else {
533
		fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0))
534
			& 0x05) == 0x05;
535
		fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1))
536 537 538 539 540
			& 0x05) == 0x05;
		fan3 = 0;
		pwm3 = 0;
	}
	if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
541
		dev_warn(dev, "Device not configured, will not use\n");
L
Linus Torvalds 已提交
542 543 544 545 546 547 548 549 550 551
		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. */
552
	smsc47m1_update_device(dev, 1);
L
Linus Torvalds 已提交
553

554
	/* Register sysfs hooks */
L
Linus Torvalds 已提交
555
	if (fan1) {
556 557 558 559 560
		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,
561 562 563
				&sensor_dev_attr_fan1_div.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_fan1_alarm.dev_attr)))
564
			goto error_remove_files;
L
Linus Torvalds 已提交
565
	} else
566
		dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
L
Linus Torvalds 已提交
567 568

	if (fan2) {
569 570 571 572 573
		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,
574 575 576
				&sensor_dev_attr_fan2_div.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_fan2_alarm.dev_attr)))
577
			goto error_remove_files;
L
Linus Torvalds 已提交
578
	} else
579
		dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
L
Linus Torvalds 已提交
580

581
	if (fan3) {
582 583 584 585 586
		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,
587 588 589
				&sensor_dev_attr_fan3_div.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_fan3_alarm.dev_attr)))
590
			goto error_remove_files;
591
	} else if (data->type == smsc47m2)
592
		dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
593

L
Linus Torvalds 已提交
594
	if (pwm1) {
595 596 597 598
		if ((err = device_create_file(dev,
				&sensor_dev_attr_pwm1.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_pwm1_enable.dev_attr)))
599
			goto error_remove_files;
L
Linus Torvalds 已提交
600
	} else
601
		dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n");
602

L
Linus Torvalds 已提交
603
	if (pwm2) {
604 605 606 607
		if ((err = device_create_file(dev,
				&sensor_dev_attr_pwm2.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_pwm2_enable.dev_attr)))
608
			goto error_remove_files;
L
Linus Torvalds 已提交
609
	} else
610
		dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n");
L
Linus Torvalds 已提交
611

612
	if (pwm3) {
613 614 615 616
		if ((err = device_create_file(dev,
				&sensor_dev_attr_pwm3.dev_attr))
		 || (err = device_create_file(dev,
				&sensor_dev_attr_pwm3_enable.dev_attr)))
617
			goto error_remove_files;
618
	} else if (data->type == smsc47m2)
619
		dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
620

621
	if ((err = device_create_file(dev, &dev_attr_alarms)))
622
		goto error_remove_files;
623 624
	if ((err = device_create_file(dev, &dev_attr_name)))
		goto error_remove_files;
625

626 627 628
	data->hwmon_dev = hwmon_device_register(dev);
	if (IS_ERR(data->hwmon_dev)) {
		err = PTR_ERR(data->hwmon_dev);
629 630
		goto error_remove_files;
	}
L
Linus Torvalds 已提交
631 632 633

	return 0;

634
error_remove_files:
635
	sysfs_remove_group(&dev->kobj, &smsc47m1_group);
L
Linus Torvalds 已提交
636
error_free:
637
	platform_set_drvdata(pdev, NULL);
638
	kfree(data);
L
Linus Torvalds 已提交
639
error_release:
640
	release_region(res->start, SMSC_EXTENT);
L
Linus Torvalds 已提交
641 642 643
	return err;
}

644
static int __devexit smsc47m1_remove(struct platform_device *pdev)
L
Linus Torvalds 已提交
645
{
646 647
	struct smsc47m1_data *data = platform_get_drvdata(pdev);
	struct resource *res;
L
Linus Torvalds 已提交
648

649
	hwmon_device_unregister(data->hwmon_dev);
650
	sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
L
Linus Torvalds 已提交
651

652 653
	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
	release_region(res->start, SMSC_EXTENT);
654
	platform_set_drvdata(pdev, NULL);
655
	kfree(data);
L
Linus Torvalds 已提交
656 657 658 659 660 661 662

	return 0;
}

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

665
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
666 667

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

671
		for (i = 0; i < fan_nr; i++) {
672
			data->fan[i] = smsc47m1_read_value(data,
673
				       SMSC47M1_REG_FAN[i]);
674
			data->fan_preload[i] = smsc47m1_read_value(data,
675
					       SMSC47M1_REG_FAN_PRELOAD[i]);
676
			data->pwm[i] = smsc47m1_read_value(data,
677
				       SMSC47M1_REG_PWM[i]);
L
Linus Torvalds 已提交
678 679
		}

680
		i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
L
Linus Torvalds 已提交
681 682 683
		data->fan_div[0] = (i >> 4) & 0x03;
		data->fan_div[1] = i >> 6;

684
		data->alarms = smsc47m1_read_value(data,
L
Linus Torvalds 已提交
685 686 687
			       SMSC47M1_REG_ALARM) >> 6;
		/* Clear alarms if needed */
		if (data->alarms)
688
			smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
L
Linus Torvalds 已提交
689

690
		if (fan_nr >= 3) {
691
			data->fan_div[2] = (smsc47m1_read_value(data,
692
					    SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
693
			data->alarms |= (smsc47m1_read_value(data,
694 695 696
					 SMSC47M2_REG_ALARM6) & 0x40) >> 4;
			/* Clear alarm if needed */
			if (data->alarms & 0x04)
697
				smsc47m1_write_value(data,
698 699 700 701
						     SMSC47M2_REG_ALARM6,
						     0x40);
		}

L
Linus Torvalds 已提交
702 703 704
		data->last_updated = jiffies;
	}

705
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
706 707 708
	return data;
}

709 710 711 712 713 714 715 716 717 718 719
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;

720 721 722 723
	err = acpi_check_resource_conflict(&res);
	if (err)
		goto exit;

724 725 726 727 728 729 730 731 732 733 734 735 736 737
	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;
	}

738 739 740
	err = platform_device_add_data(pdev, sio_data,
				       sizeof(struct smsc47m1_sio_data));
	if (err) {
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
		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 已提交
760 761
static int __init sm_smsc47m1_init(void)
{
762 763 764 765 766
	int err;
	unsigned short address;
	struct smsc47m1_sio_data sio_data;

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

769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
	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 已提交
784 785 786 787
}

static void __exit sm_smsc47m1_exit(void)
{
788 789
	platform_device_unregister(pdev);
	platform_driver_unregister(&smsc47m1_driver);
L
Linus Torvalds 已提交
790 791 792 793 794 795 796 797
}

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