aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/i8k.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/i8k.c')
-rw-r--r--drivers/char/i8k.c123
1 files changed, 82 insertions, 41 deletions
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 93dcad0c1cbe..65525c7e903c 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -65,6 +65,8 @@ static char bios_version[4];
65static struct device *i8k_hwmon_dev; 65static struct device *i8k_hwmon_dev;
66static u32 i8k_hwmon_flags; 66static u32 i8k_hwmon_flags;
67static int i8k_fan_mult; 67static int i8k_fan_mult;
68static int i8k_pwm_mult;
69static int i8k_fan_max = I8K_FAN_HIGH;
68 70
69#define I8K_HWMON_HAVE_TEMP1 (1 << 0) 71#define I8K_HWMON_HAVE_TEMP1 (1 << 0)
70#define I8K_HWMON_HAVE_TEMP2 (1 << 1) 72#define I8K_HWMON_HAVE_TEMP2 (1 << 1)
@@ -97,6 +99,10 @@ static int fan_mult = I8K_FAN_MULT;
97module_param(fan_mult, int, 0); 99module_param(fan_mult, int, 0);
98MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); 100MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
99 101
102static int fan_max = I8K_FAN_HIGH;
103module_param(fan_max, int, 0);
104MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed");
105
100static int i8k_open_fs(struct inode *inode, struct file *file); 106static int i8k_open_fs(struct inode *inode, struct file *file);
101static long i8k_ioctl(struct file *, unsigned int, unsigned long); 107static long i8k_ioctl(struct file *, unsigned int, unsigned long);
102 108
@@ -276,7 +282,7 @@ static int i8k_set_fan(int fan, int speed)
276{ 282{
277 struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; 283 struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
278 284
279 speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); 285 speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);
280 regs.ebx = (fan & 0xff) | (speed << 8); 286 regs.ebx = (fan & 0xff) | (speed << 8);
281 287
282 return i8k_smm(&regs) ? : i8k_get_fan_status(fan); 288 return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
@@ -521,7 +527,7 @@ static ssize_t i8k_hwmon_show_pwm(struct device *dev,
521 status = i8k_get_fan_status(index); 527 status = i8k_get_fan_status(index);
522 if (status < 0) 528 if (status < 0)
523 return -EIO; 529 return -EIO;
524 return sprintf(buf, "%d\n", clamp_val(status * 128, 0, 255)); 530 return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255));
525} 531}
526 532
527static ssize_t i8k_hwmon_set_pwm(struct device *dev, 533static ssize_t i8k_hwmon_set_pwm(struct device *dev,
@@ -535,7 +541,7 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev,
535 err = kstrtoul(buf, 10, &val); 541 err = kstrtoul(buf, 10, &val);
536 if (err) 542 if (err)
537 return err; 543 return err;
538 val = clamp_val(DIV_ROUND_CLOSEST(val, 128), 0, 2); 544 val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max);
539 545
540 mutex_lock(&i8k_mutex); 546 mutex_lock(&i8k_mutex);
541 err = i8k_set_fan(index, val); 547 err = i8k_set_fan(index, val);
@@ -544,20 +550,6 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev,
544 return err < 0 ? -EIO : count; 550 return err < 0 ? -EIO : count;
545} 551}
546 552
547static ssize_t i8k_hwmon_show_label(struct device *dev,
548 struct device_attribute *devattr,
549 char *buf)
550{
551 static const char *labels[3] = {
552 "CPU",
553 "Left Fan",
554 "Right Fan",
555 };
556 int index = to_sensor_dev_attr(devattr)->index;
557
558 return sprintf(buf, "%s\n", labels[index]);
559}
560
561static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); 553static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0);
562static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1); 554static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1);
563static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2); 555static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2);
@@ -570,41 +562,34 @@ static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
570 I8K_FAN_RIGHT); 562 I8K_FAN_RIGHT);
571static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, 563static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
572 i8k_hwmon_set_pwm, I8K_FAN_RIGHT); 564 i8k_hwmon_set_pwm, I8K_FAN_RIGHT);
573static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 0);
574static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1);
575static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2);
576 565
577static struct attribute *i8k_attrs[] = { 566static struct attribute *i8k_attrs[] = {
578 &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ 567 &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */
579 &sensor_dev_attr_temp1_label.dev_attr.attr, /* 1 */ 568 &sensor_dev_attr_temp2_input.dev_attr.attr, /* 1 */
580 &sensor_dev_attr_temp2_input.dev_attr.attr, /* 2 */ 569 &sensor_dev_attr_temp3_input.dev_attr.attr, /* 2 */
581 &sensor_dev_attr_temp3_input.dev_attr.attr, /* 3 */ 570 &sensor_dev_attr_temp4_input.dev_attr.attr, /* 3 */
582 &sensor_dev_attr_temp4_input.dev_attr.attr, /* 4 */ 571 &sensor_dev_attr_fan1_input.dev_attr.attr, /* 4 */
583 &sensor_dev_attr_fan1_input.dev_attr.attr, /* 5 */ 572 &sensor_dev_attr_pwm1.dev_attr.attr, /* 5 */
584 &sensor_dev_attr_pwm1.dev_attr.attr, /* 6 */ 573 &sensor_dev_attr_fan2_input.dev_attr.attr, /* 6 */
585 &sensor_dev_attr_fan1_label.dev_attr.attr, /* 7 */ 574 &sensor_dev_attr_pwm2.dev_attr.attr, /* 7 */
586 &sensor_dev_attr_fan2_input.dev_attr.attr, /* 8 */
587 &sensor_dev_attr_pwm2.dev_attr.attr, /* 9 */
588 &sensor_dev_attr_fan2_label.dev_attr.attr, /* 10 */
589 NULL 575 NULL
590}; 576};
591 577
592static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, 578static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
593 int index) 579 int index)
594{ 580{
595 if ((index == 0 || index == 1) && 581 if (index == 0 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
596 !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
597 return 0; 582 return 0;
598 if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) 583 if (index == 1 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
599 return 0; 584 return 0;
600 if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) 585 if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
601 return 0; 586 return 0;
602 if (index == 4 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) 587 if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
603 return 0; 588 return 0;
604 if (index >= 5 && index <= 7 && 589 if (index >= 4 && index <= 5 &&
605 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) 590 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
606 return 0; 591 return 0;
607 if (index >= 8 && index <= 10 && 592 if (index >= 6 && index <= 7 &&
608 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) 593 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
609 return 0; 594 return 0;
610 595
@@ -659,6 +644,37 @@ static int __init i8k_init_hwmon(void)
659 return 0; 644 return 0;
660} 645}
661 646
647struct i8k_config_data {
648 int fan_mult;
649 int fan_max;
650};
651
652enum i8k_configs {
653 DELL_LATITUDE_D520,
654 DELL_PRECISION_490,
655 DELL_STUDIO,
656 DELL_XPS_M140,
657};
658
659static const struct i8k_config_data i8k_config_data[] = {
660 [DELL_LATITUDE_D520] = {
661 .fan_mult = 1,
662 .fan_max = I8K_FAN_TURBO,
663 },
664 [DELL_PRECISION_490] = {
665 .fan_mult = 1,
666 .fan_max = I8K_FAN_TURBO,
667 },
668 [DELL_STUDIO] = {
669 .fan_mult = 1,
670 .fan_max = I8K_FAN_HIGH,
671 },
672 [DELL_XPS_M140] = {
673 .fan_mult = 1,
674 .fan_max = I8K_FAN_HIGH,
675 },
676};
677
662static struct dmi_system_id i8k_dmi_table[] __initdata = { 678static struct dmi_system_id i8k_dmi_table[] __initdata = {
663 { 679 {
664 .ident = "Dell Inspiron", 680 .ident = "Dell Inspiron",
@@ -682,6 +698,14 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
682 }, 698 },
683 }, 699 },
684 { 700 {
701 .ident = "Dell Latitude D520",
702 .matches = {
703 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
704 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D520"),
705 },
706 .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],
707 },
708 {
685 .ident = "Dell Latitude 2", 709 .ident = "Dell Latitude 2",
686 .matches = { 710 .matches = {
687 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 711 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
@@ -703,6 +727,15 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
703 }, 727 },
704 }, 728 },
705 { 729 {
730 .ident = "Dell Precision 490",
731 .matches = {
732 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
733 DMI_MATCH(DMI_PRODUCT_NAME,
734 "Precision WorkStation 490"),
735 },
736 .driver_data = (void *)&i8k_config_data[DELL_PRECISION_490],
737 },
738 {
706 .ident = "Dell Precision", 739 .ident = "Dell Precision",
707 .matches = { 740 .matches = {
708 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 741 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
@@ -729,7 +762,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
729 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 762 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
730 DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), 763 DMI_MATCH(DMI_PRODUCT_NAME, "Studio"),
731 }, 764 },
732 .driver_data = (void *)1, /* fan multiplier override */ 765 .driver_data = (void *)&i8k_config_data[DELL_STUDIO],
733 }, 766 },
734 { 767 {
735 .ident = "Dell XPS M140", 768 .ident = "Dell XPS M140",
@@ -737,7 +770,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
737 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 770 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
738 DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), 771 DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"),
739 }, 772 },
740 .driver_data = (void *)1, /* fan multiplier override */ 773 .driver_data = (void *)&i8k_config_data[DELL_XPS_M140],
741 }, 774 },
742 { } 775 { }
743}; 776};
@@ -777,9 +810,17 @@ static int __init i8k_probe(void)
777 } 810 }
778 811
779 i8k_fan_mult = fan_mult; 812 i8k_fan_mult = fan_mult;
813 i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
780 id = dmi_first_match(i8k_dmi_table); 814 id = dmi_first_match(i8k_dmi_table);
781 if (id && fan_mult == I8K_FAN_MULT && id->driver_data) 815 if (id && id->driver_data) {
782 i8k_fan_mult = (unsigned long)id->driver_data; 816 const struct i8k_config_data *conf = id->driver_data;
817
818 if (fan_mult == I8K_FAN_MULT && conf->fan_mult)
819 i8k_fan_mult = conf->fan_mult;
820 if (fan_max == I8K_FAN_HIGH && conf->fan_max)
821 i8k_fan_max = conf->fan_max;
822 }
823 i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
783 824
784 return 0; 825 return 0;
785} 826}