aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/smsc47m1.c
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2007-05-08 11:21:59 -0400
committerJean Delvare <khali@hyperion.delvare>2007-05-08 11:21:59 -0400
commit8eccbb6fb97a5b54a9db166399f0d24f33114522 (patch)
tree0eff8bf78f899cb55c59904d1ed3e3430bf742a3 /drivers/hwmon/smsc47m1.c
parentce7ee4e80a72d3b1009ca232be8981de93c015f6 (diff)
hwmon/smsc47m1: Add support for the LPC47M292
The new SMSC LPC47M292 Super-I/O chip is a bit different from the previous ones, it supports a 3rd fan, but unfortunately the pin configuration registers are different. Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/smsc47m1.c')
-rw-r--r--drivers/hwmon/smsc47m1.c160
1 files changed, 126 insertions, 34 deletions
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index beb881c4b2e8..16762cca87e5 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -3,10 +3,11 @@
3 for hardware monitoring 3 for hardware monitoring
4 4
5 Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, 5 Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
6 LPC47M14x, LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips. 6 LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997
7 Super-I/O chips.
7 8
8 Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> 9 Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
9 Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> 10 Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org>
10 Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com> 11 Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
11 and Jean Delvare 12 and Jean Delvare
12 13
@@ -40,6 +41,8 @@
40 41
41/* Address is autodetected, there is no default value */ 42/* Address is autodetected, there is no default value */
42static unsigned short address; 43static unsigned short address;
44static u8 devid;
45enum chips { smsc47m1, smsc47m2 };
43 46
44/* Super-I/0 registers and commands */ 47/* Super-I/0 registers and commands */
45 48
@@ -87,10 +90,18 @@ superio_exit(void)
87#define SMSC47M1_REG_ALARM 0x04 90#define SMSC47M1_REG_ALARM 0x04
88#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr)) 91#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr))
89#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr)) 92#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr))
90#define SMSC47M1_REG_PWM(nr) (0x56 + (nr))
91#define SMSC47M1_REG_FANDIV 0x58 93#define SMSC47M1_REG_FANDIV 0x58
92#define SMSC47M1_REG_FAN(nr) (0x59 + (nr)) 94
93#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr)) 95static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b };
96static const u8 SMSC47M1_REG_FAN_PRELOAD[3] = { 0x5b, 0x5c, 0x6c };
97static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 };
98
99#define SMSC47M2_REG_ALARM6 0x09
100#define SMSC47M2_REG_TPIN1 0x38
101#define SMSC47M2_REG_TPIN2 0x37
102#define SMSC47M2_REG_TPIN3 0x2d
103#define SMSC47M2_REG_PPIN3 0x2c
104#define SMSC47M2_REG_FANDIV3 0x6a
94 105
95#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ 106#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \
96 983040/((192-(reg))*(div))) 107 983040/((192-(reg))*(div)))
@@ -103,17 +114,18 @@ superio_exit(void)
103 114
104struct smsc47m1_data { 115struct smsc47m1_data {
105 struct i2c_client client; 116 struct i2c_client client;
117 enum chips type;
106 struct class_device *class_dev; 118 struct class_device *class_dev;
107 struct mutex lock; 119 struct mutex lock;
108 120
109 struct mutex update_lock; 121 struct mutex update_lock;
110 unsigned long last_updated; /* In jiffies */ 122 unsigned long last_updated; /* In jiffies */
111 123
112 u8 fan[2]; /* Register value */ 124 u8 fan[3]; /* Register value */
113 u8 fan_preload[2]; /* Register value */ 125 u8 fan_preload[3]; /* Register value */
114 u8 fan_div[2]; /* Register encoding, shifted right */ 126 u8 fan_div[3]; /* Register encoding, shifted right */
115 u8 alarms; /* Register encoding */ 127 u8 alarms; /* Register encoding */
116 u8 pwm[2]; /* Register value (bit 7 is enable) */ 128 u8 pwm[3]; /* Register value (bit 0 is disable) */
117}; 129};
118 130
119 131
@@ -200,7 +212,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
200 } 212 }
201 213
202 data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); 214 data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
203 smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), 215 smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD[nr],
204 data->fan_preload[nr]); 216 data->fan_preload[nr]);
205 mutex_unlock(&data->update_lock); 217 mutex_unlock(&data->update_lock);
206 218
@@ -234,15 +246,26 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
234 return -EINVAL; 246 return -EINVAL;
235 } 247 }
236 248
237 tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F; 249 switch (nr) {
238 tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6); 250 case 0:
239 smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp); 251 case 1:
252 tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV)
253 & ~(0x03 << (4 + 2 * nr));
254 tmp |= data->fan_div[nr] << (4 + 2 * nr);
255 smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp);
256 break;
257 case 2:
258 tmp = smsc47m1_read_value(client, SMSC47M2_REG_FANDIV3) & 0xCF;
259 tmp |= data->fan_div[2] << 4;
260 smsc47m1_write_value(client, SMSC47M2_REG_FANDIV3, tmp);
261 break;
262 }
240 263
241 /* Preserve fan min */ 264 /* Preserve fan min */
242 tmp = 192 - (old_div * (192 - data->fan_preload[nr]) 265 tmp = 192 - (old_div * (192 - data->fan_preload[nr])
243 + new_div / 2) / new_div; 266 + new_div / 2) / new_div;
244 data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); 267 data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
245 smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), 268 smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD[nr],
246 data->fan_preload[nr]); 269 data->fan_preload[nr]);
247 mutex_unlock(&data->update_lock); 270 mutex_unlock(&data->update_lock);
248 271
@@ -263,7 +286,7 @@ static ssize_t set_pwm(struct device *dev, const char *buf,
263 mutex_lock(&data->update_lock); 286 mutex_lock(&data->update_lock);
264 data->pwm[nr] &= 0x81; /* Preserve additional bits */ 287 data->pwm[nr] &= 0x81; /* Preserve additional bits */
265 data->pwm[nr] |= PWM_TO_REG(val); 288 data->pwm[nr] |= PWM_TO_REG(val);
266 smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), 289 smsc47m1_write_value(client, SMSC47M1_REG_PWM[nr],
267 data->pwm[nr]); 290 data->pwm[nr]);
268 mutex_unlock(&data->update_lock); 291 mutex_unlock(&data->update_lock);
269 292
@@ -284,7 +307,7 @@ static ssize_t set_pwm_en(struct device *dev, const char *buf,
284 mutex_lock(&data->update_lock); 307 mutex_lock(&data->update_lock);
285 data->pwm[nr] &= 0xFE; /* preserve the other bits */ 308 data->pwm[nr] &= 0xFE; /* preserve the other bits */
286 data->pwm[nr] |= !val; 309 data->pwm[nr] |= !val;
287 smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), 310 smsc47m1_write_value(client, SMSC47M1_REG_PWM[nr],
288 data->pwm[nr]); 311 data->pwm[nr]);
289 mutex_unlock(&data->update_lock); 312 mutex_unlock(&data->update_lock);
290 313
@@ -345,6 +368,7 @@ static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
345 368
346fan_present(1); 369fan_present(1);
347fan_present(2); 370fan_present(2);
371fan_present(3);
348 372
349static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); 373static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
350 374
@@ -358,11 +382,16 @@ static struct attribute *smsc47m1_attributes[] = {
358 &dev_attr_fan2_input.attr, 382 &dev_attr_fan2_input.attr,
359 &dev_attr_fan2_min.attr, 383 &dev_attr_fan2_min.attr,
360 &dev_attr_fan2_div.attr, 384 &dev_attr_fan2_div.attr,
385 &dev_attr_fan3_input.attr,
386 &dev_attr_fan3_min.attr,
387 &dev_attr_fan3_div.attr,
361 388
362 &dev_attr_pwm1.attr, 389 &dev_attr_pwm1.attr,
363 &dev_attr_pwm1_enable.attr, 390 &dev_attr_pwm1_enable.attr,
364 &dev_attr_pwm2.attr, 391 &dev_attr_pwm2.attr,
365 &dev_attr_pwm2_enable.attr, 392 &dev_attr_pwm2_enable.attr,
393 &dev_attr_pwm3.attr,
394 &dev_attr_pwm3_enable.attr,
366 395
367 &dev_attr_alarms.attr, 396 &dev_attr_alarms.attr,
368 NULL 397 NULL
@@ -377,7 +406,7 @@ static int __init smsc47m1_find(unsigned short *addr)
377 u8 val; 406 u8 val;
378 407
379 superio_enter(); 408 superio_enter();
380 val = superio_inb(SUPERIO_REG_DEVID); 409 devid = superio_inb(SUPERIO_REG_DEVID);
381 410
382 /* 411 /*
383 * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x 412 * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
@@ -386,18 +415,29 @@ static int __init smsc47m1_find(unsigned short *addr)
386 * can do much more besides (device id 0x60). 415 * can do much more besides (device id 0x60).
387 * The LPC47M997 is undocumented, but seems to be compatible with 416 * The LPC47M997 is undocumented, but seems to be compatible with
388 * the LPC47M192, and has the same device id. 417 * the LPC47M192, and has the same device id.
418 * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
419 * supports a 3rd fan, and the pin configuration registers are
420 * unfortunately different.
389 */ 421 */
390 if (val == 0x51) 422 switch (devid) {
423 case 0x51:
391 printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); 424 printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n");
392 else if (val == 0x59) 425 break;
426 case 0x59:
393 printk(KERN_INFO "smsc47m1: Found SMSC " 427 printk(KERN_INFO "smsc47m1: Found SMSC "
394 "LPC47M10x/LPC47M112/LPC47M13x\n"); 428 "LPC47M10x/LPC47M112/LPC47M13x\n");
395 else if (val == 0x5F) 429 break;
430 case 0x5F:
396 printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); 431 printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n");
397 else if (val == 0x60) 432 break;
433 case 0x60:
398 printk(KERN_INFO "smsc47m1: Found SMSC " 434 printk(KERN_INFO "smsc47m1: Found SMSC "
399 "LPC47M15x/LPC47M192/LPC47M997\n"); 435 "LPC47M15x/LPC47M192/LPC47M997\n");
400 else { 436 break;
437 case 0x6B:
438 printk(KERN_INFO "smsc47m1: Found SMSC LPC47M292\n");
439 break;
440 default:
401 superio_exit(); 441 superio_exit();
402 return -ENODEV; 442 return -ENODEV;
403 } 443 }
@@ -421,7 +461,7 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
421 struct i2c_client *new_client; 461 struct i2c_client *new_client;
422 struct smsc47m1_data *data; 462 struct smsc47m1_data *data;
423 int err = 0; 463 int err = 0;
424 int fan1, fan2, pwm1, pwm2; 464 int fan1, fan2, fan3, pwm1, pwm2, pwm3;
425 465
426 if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.driver.name)) { 466 if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.driver.name)) {
427 dev_err(&adapter->dev, "Region 0x%x already in use!\n", address); 467 dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
@@ -433,6 +473,7 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
433 goto error_release; 473 goto error_release;
434 } 474 }
435 475
476 data->type = devid == 0x6B ? smsc47m2 : smsc47m1;
436 new_client = &data->client; 477 new_client = &data->client;
437 i2c_set_clientdata(new_client, data); 478 i2c_set_clientdata(new_client, data);
438 new_client->addr = address; 479 new_client->addr = address;
@@ -441,20 +482,35 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
441 new_client->driver = &smsc47m1_driver; 482 new_client->driver = &smsc47m1_driver;
442 new_client->flags = 0; 483 new_client->flags = 0;
443 484
444 strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE); 485 strlcpy(new_client->name,
486 data->type == smsc47m2 ? "smsc47m2" : "smsc47m1",
487 I2C_NAME_SIZE);
445 mutex_init(&data->update_lock); 488 mutex_init(&data->update_lock);
446 489
447 /* If no function is properly configured, there's no point in 490 /* If no function is properly configured, there's no point in
448 actually registering the chip. */ 491 actually registering the chip. */
449 fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05)
450 == 0x05;
451 fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05)
452 == 0x05;
453 pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05) 492 pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05)
454 == 0x04; 493 == 0x04;
455 pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05) 494 pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
456 == 0x04; 495 == 0x04;
457 if (!(fan1 || fan2 || pwm1 || pwm2)) { 496 if (data->type == smsc47m2) {
497 fan1 = (smsc47m1_read_value(new_client, SMSC47M2_REG_TPIN1)
498 & 0x0d) == 0x09;
499 fan2 = (smsc47m1_read_value(new_client, SMSC47M2_REG_TPIN2)
500 & 0x0d) == 0x09;
501 fan3 = (smsc47m1_read_value(new_client, SMSC47M2_REG_TPIN3)
502 & 0x0d) == 0x0d;
503 pwm3 = (smsc47m1_read_value(new_client, SMSC47M2_REG_PPIN3)
504 & 0x0d) == 0x08;
505 } else {
506 fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0))
507 & 0x05) == 0x05;
508 fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1))
509 & 0x05) == 0x05;
510 fan3 = 0;
511 pwm3 = 0;
512 }
513 if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
458 dev_warn(&adapter->dev, "Device at 0x%x is not configured, " 514 dev_warn(&adapter->dev, "Device at 0x%x is not configured, "
459 "will not use\n", new_client->addr); 515 "will not use\n", new_client->addr);
460 err = -ENODEV; 516 err = -ENODEV;
@@ -497,6 +553,18 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
497 dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, " 553 dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
498 "skipping\n"); 554 "skipping\n");
499 555
556 if (fan3) {
557 if ((err = device_create_file(&new_client->dev,
558 &dev_attr_fan3_input))
559 || (err = device_create_file(&new_client->dev,
560 &dev_attr_fan3_min))
561 || (err = device_create_file(&new_client->dev,
562 &dev_attr_fan3_div)))
563 goto error_remove_files;
564 } else
565 dev_dbg(&new_client->dev, "Fan 3 not enabled by hardware, "
566 "skipping\n");
567
500 if (pwm1) { 568 if (pwm1) {
501 if ((err = device_create_file(&new_client->dev, 569 if ((err = device_create_file(&new_client->dev,
502 &dev_attr_pwm1)) 570 &dev_attr_pwm1))
@@ -506,6 +574,7 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
506 } else 574 } else
507 dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, " 575 dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
508 "skipping\n"); 576 "skipping\n");
577
509 if (pwm2) { 578 if (pwm2) {
510 if ((err = device_create_file(&new_client->dev, 579 if ((err = device_create_file(&new_client->dev,
511 &dev_attr_pwm2)) 580 &dev_attr_pwm2))
@@ -516,6 +585,16 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
516 dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, " 585 dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
517 "skipping\n"); 586 "skipping\n");
518 587
588 if (pwm3) {
589 if ((err = device_create_file(&new_client->dev,
590 &dev_attr_pwm3))
591 || (err = device_create_file(&new_client->dev,
592 &dev_attr_pwm3_enable)))
593 goto error_remove_files;
594 } else
595 dev_dbg(&new_client->dev, "PWM 3 not enabled by hardware, "
596 "skipping\n");
597
519 if ((err = device_create_file(&new_client->dev, &dev_attr_alarms))) 598 if ((err = device_create_file(&new_client->dev, &dev_attr_alarms)))
520 goto error_remove_files; 599 goto error_remove_files;
521 600
@@ -580,15 +659,16 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
580 mutex_lock(&data->update_lock); 659 mutex_lock(&data->update_lock);
581 660
582 if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { 661 if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
583 int i; 662 int i, fan_nr;
663 fan_nr = data->type == smsc47m2 ? 3 : 2;
584 664
585 for (i = 0; i < 2; i++) { 665 for (i = 0; i < fan_nr; i++) {
586 data->fan[i] = smsc47m1_read_value(client, 666 data->fan[i] = smsc47m1_read_value(client,
587 SMSC47M1_REG_FAN(i)); 667 SMSC47M1_REG_FAN[i]);
588 data->fan_preload[i] = smsc47m1_read_value(client, 668 data->fan_preload[i] = smsc47m1_read_value(client,
589 SMSC47M1_REG_FAN_PRELOAD(i)); 669 SMSC47M1_REG_FAN_PRELOAD[i]);
590 data->pwm[i] = smsc47m1_read_value(client, 670 data->pwm[i] = smsc47m1_read_value(client,
591 SMSC47M1_REG_PWM(i)); 671 SMSC47M1_REG_PWM[i]);
592 } 672 }
593 673
594 i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); 674 i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
@@ -601,6 +681,18 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
601 if (data->alarms) 681 if (data->alarms)
602 smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0); 682 smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0);
603 683
684 if (fan_nr >= 3) {
685 data->fan_div[2] = (smsc47m1_read_value(client,
686 SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
687 data->alarms |= (smsc47m1_read_value(client,
688 SMSC47M2_REG_ALARM6) & 0x40) >> 4;
689 /* Clear alarm if needed */
690 if (data->alarms & 0x04)
691 smsc47m1_write_value(client,
692 SMSC47M2_REG_ALARM6,
693 0x40);
694 }
695
604 data->last_updated = jiffies; 696 data->last_updated = jiffies;
605 } 697 }
606 698