diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 17:15:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 17:15:09 -0400 |
commit | 1259f6ee15c1603dcae41eb6af5a5f9cf932d4d6 (patch) | |
tree | bf85658f7c5a2c86da3bc613d7fea13bbffe4e72 | |
parent | 468f4d1a855f8039dabf441b8bf68cae264033ff (diff) | |
parent | 4573acbc461b8089198500cee06ef0cdc5b70e82 (diff) |
Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck:
"New driver for INA219 and INA226, added support for IT8782F and
IT8783E/F to it87 driver, plus cleanups in a couple of drivers."
* tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
hwmon: (it87) Make temp3 attribute conditional for IT8782F
hwmon: (it87) Convert to use devm_kzalloc and devm_request_region
hwmon: INA219 and INA226 support
hwmon: (it87) Create voltage attributes only if voltage is enabled
hwmon: (ntc_thermistor) Fix checkpatch warning
hwmon: (ntc_thermistor) Optimize and fix build warning
hwmon: (ntc_thermistor) Return error code from hwmon_device_register
hwmon: (ntc_thermistor) Convert to devm_kzalloc
hwmon: (ad7314) Remove unused defines, and rename OFFSET to SHIFT
acpi_power_meter: clean up code around setup_attrs
acpi_power_meter: drop meter_rw_attrs, use common meter_attrs
acpi_power_meter: remove duplicate code between register_{ro,rw}_attrs
acpi_power_meter: use a {RW,RO}_SENSOR_TEMPLATE macro to clean things up
acpi_power_meter: use the same struct {rw,ro}_sensor_template for both
hwmon: use module_pci_driver
hwmon: (it87) Add support for IT8782F and IT8783E/F
-rw-r--r-- | Documentation/hwmon/ina2xx | 29 | ||||
-rw-r--r-- | Documentation/hwmon/it87 | 28 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 13 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/acpi_power_meter.c | 166 | ||||
-rw-r--r-- | drivers/hwmon/ad7314.c | 11 | ||||
-rw-r--r-- | drivers/hwmon/fam15h_power.c | 13 | ||||
-rw-r--r-- | drivers/hwmon/ina2xx.c | 368 | ||||
-rw-r--r-- | drivers/hwmon/it87.c | 384 | ||||
-rw-r--r-- | drivers/hwmon/k10temp.c | 13 | ||||
-rw-r--r-- | drivers/hwmon/k8temp.c | 13 | ||||
-rw-r--r-- | drivers/hwmon/ntc_thermistor.c | 191 | ||||
-rw-r--r-- | include/linux/platform_data/ina2xx.h | 19 |
13 files changed, 902 insertions, 347 deletions
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx new file mode 100644 index 000000000000..f50a6cc27616 --- /dev/null +++ b/Documentation/hwmon/ina2xx | |||
@@ -0,0 +1,29 @@ | |||
1 | Kernel driver ina2xx | ||
2 | ==================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Texas Instruments INA219 | ||
6 | Prefix: 'ina219' | ||
7 | Addresses: I2C 0x40 - 0x4f | ||
8 | Datasheet: Publicly available at the Texas Instruments website | ||
9 | http://www.ti.com/ | ||
10 | |||
11 | * Texas Instruments INA226 | ||
12 | Prefix: 'ina226' | ||
13 | Addresses: I2C 0x40 - 0x4f | ||
14 | Datasheet: Publicly available at the Texas Instruments website | ||
15 | http://www.ti.com/ | ||
16 | |||
17 | Author: Lothar Felten <l-felten@ti.com> | ||
18 | |||
19 | Description | ||
20 | ----------- | ||
21 | |||
22 | The INA219 is a high-side current shunt and power monitor with an I2C | ||
23 | interface. The INA219 monitors both shunt drop and supply voltage, with | ||
24 | programmable conversion times and filtering. | ||
25 | |||
26 | The INA226 is a current shunt and power monitor with an I2C interface. | ||
27 | The INA226 monitors both a shunt voltage drop and bus supply voltage. | ||
28 | |||
29 | The shunt value in micro-ohms can be set via platform data. | ||
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index fba745571684..87850d86c559 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 | |||
@@ -30,6 +30,14 @@ Supported chips: | |||
30 | Prefix: 'it8728' | 30 | Prefix: 'it8728' |
31 | Addresses scanned: from Super I/O config space (8 I/O ports) | 31 | Addresses scanned: from Super I/O config space (8 I/O ports) |
32 | Datasheet: Not publicly available | 32 | Datasheet: Not publicly available |
33 | * IT8782F | ||
34 | Prefix: 'it8782' | ||
35 | Addresses scanned: from Super I/O config space (8 I/O ports) | ||
36 | Datasheet: Not publicly available | ||
37 | * IT8783E/F | ||
38 | Prefix: 'it8783' | ||
39 | Addresses scanned: from Super I/O config space (8 I/O ports) | ||
40 | Datasheet: Not publicly available | ||
33 | * SiS950 [clone of IT8705F] | 41 | * SiS950 [clone of IT8705F] |
34 | Prefix: 'it87' | 42 | Prefix: 'it87' |
35 | Addresses scanned: from Super I/O config space (8 I/O ports) | 43 | Addresses scanned: from Super I/O config space (8 I/O ports) |
@@ -75,7 +83,8 @@ Description | |||
75 | ----------- | 83 | ----------- |
76 | 84 | ||
77 | This driver implements support for the IT8705F, IT8712F, IT8716F, | 85 | This driver implements support for the IT8705F, IT8712F, IT8716F, |
78 | IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E and SiS950 chips. | 86 | IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8781F, IT8782F, |
87 | IT8783E/F, and SiS950 chips. | ||
79 | 88 | ||
80 | These chips are 'Super I/O chips', supporting floppy disks, infrared ports, | 89 | These chips are 'Super I/O chips', supporting floppy disks, infrared ports, |
81 | joysticks and other miscellaneous stuff. For hardware monitoring, they | 90 | joysticks and other miscellaneous stuff. For hardware monitoring, they |
@@ -99,11 +108,11 @@ The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E and later IT8712F revisions | |||
99 | have support for 2 additional fans. The additional fans are supported by the | 108 | have support for 2 additional fans. The additional fans are supported by the |
100 | driver. | 109 | driver. |
101 | 110 | ||
102 | The IT8716F, IT8718F, IT8720F and IT8721F/IT8758E, and late IT8712F and | 111 | The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8782F, IT8783E/F, and late |
103 | IT8705F also have optional 16-bit tachometer counters for fans 1 to 3. This | 112 | IT8712F and IT8705F also have optional 16-bit tachometer counters for fans 1 to |
104 | is better (no more fan clock divider mess) but not compatible with the older | 113 | 3. This is better (no more fan clock divider mess) but not compatible with the |
105 | chips and revisions. The 16-bit tachometer mode is enabled by the driver when | 114 | older chips and revisions. The 16-bit tachometer mode is enabled by the driver |
106 | one of the above chips is detected. | 115 | when one of the above chips is detected. |
107 | 116 | ||
108 | The IT8726F is just bit enhanced IT8716F with additional hardware | 117 | The IT8726F is just bit enhanced IT8716F with additional hardware |
109 | for AMD power sequencing. Therefore the chip will appear as IT8716F | 118 | for AMD power sequencing. Therefore the chip will appear as IT8716F |
@@ -131,9 +140,10 @@ inputs can measure voltages between 0 and 4.08 volts, with a resolution of | |||
131 | 0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery | 140 | 0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery |
132 | voltage in8 does not have limit registers. | 141 | voltage in8 does not have limit registers. |
133 | 142 | ||
134 | On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside | 143 | On the IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs are |
135 | the chip (in7, in8 and optionally in3). The driver handles this transparently | 144 | internal and scaled inside the chip (in7 (optional for IT8782F and IT8783E/F), |
136 | so user-space doesn't have to care. | 145 | in8 and optionally in3). The driver handles this transparently so user-space |
146 | doesn't have to care. | ||
137 | 147 | ||
138 | The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value: | 148 | The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value: |
139 | the voltage level your processor should work with. This is hardcoded by | 149 | the voltage level your processor should work with. This is hardcoded by |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e466ecba8dc1..7cd9bf42108b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -1102,6 +1102,19 @@ config SENSORS_AMC6821 | |||
1102 | This driver can also be build as a module. If so, the module | 1102 | This driver can also be build as a module. If so, the module |
1103 | will be called amc6821. | 1103 | will be called amc6821. |
1104 | 1104 | ||
1105 | config SENSORS_INA2XX | ||
1106 | tristate "Texas Instruments INA219, INA226" | ||
1107 | depends on I2C && EXPERIMENTAL | ||
1108 | help | ||
1109 | If you say yes here you get support for INA219 and INA226 power | ||
1110 | monitor chips. | ||
1111 | |||
1112 | The INA2xx driver is configured for the default configuration of | ||
1113 | the part as described in the datasheet. | ||
1114 | Default value for Rshunt is 10 mOhms. | ||
1115 | This driver can also be built as a module. If so, the module | ||
1116 | will be called ina2xx. | ||
1117 | |||
1105 | config SENSORS_THMC50 | 1118 | config SENSORS_THMC50 |
1106 | tristate "Texas Instruments THMC50 / Analog Devices ADM1022" | 1119 | tristate "Texas Instruments THMC50 / Analog Devices ADM1022" |
1107 | depends on I2C | 1120 | depends on I2C |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 6d3f11f71815..e1eeac13b851 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -62,6 +62,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o | |||
62 | obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o | 62 | obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o |
63 | obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o | 63 | obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o |
64 | obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o | 64 | obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o |
65 | obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o | ||
65 | obj-$(CONFIG_SENSORS_IT87) += it87.o | 66 | obj-$(CONFIG_SENSORS_IT87) += it87.o |
66 | obj-$(CONFIG_SENSORS_JC42) += jc42.o | 67 | obj-$(CONFIG_SENSORS_JC42) += jc42.o |
67 | obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o | 68 | obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o |
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 9140236a0182..34ad5a27a7e9 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c | |||
@@ -107,15 +107,7 @@ struct acpi_power_meter_resource { | |||
107 | struct kobject *holders_dir; | 107 | struct kobject *holders_dir; |
108 | }; | 108 | }; |
109 | 109 | ||
110 | struct ro_sensor_template { | 110 | struct sensor_template { |
111 | char *label; | ||
112 | ssize_t (*show)(struct device *dev, | ||
113 | struct device_attribute *devattr, | ||
114 | char *buf); | ||
115 | int index; | ||
116 | }; | ||
117 | |||
118 | struct rw_sensor_template { | ||
119 | char *label; | 111 | char *label; |
120 | ssize_t (*show)(struct device *dev, | 112 | ssize_t (*show)(struct device *dev, |
121 | struct device_attribute *devattr, | 113 | struct device_attribute *devattr, |
@@ -469,52 +461,67 @@ static ssize_t show_name(struct device *dev, | |||
469 | return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME); | 461 | return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME); |
470 | } | 462 | } |
471 | 463 | ||
464 | #define RO_SENSOR_TEMPLATE(_label, _show, _index) \ | ||
465 | { \ | ||
466 | .label = _label, \ | ||
467 | .show = _show, \ | ||
468 | .index = _index, \ | ||
469 | } | ||
470 | |||
471 | #define RW_SENSOR_TEMPLATE(_label, _show, _set, _index) \ | ||
472 | { \ | ||
473 | .label = _label, \ | ||
474 | .show = _show, \ | ||
475 | .set = _set, \ | ||
476 | .index = _index, \ | ||
477 | } | ||
478 | |||
472 | /* Sensor descriptions. If you add a sensor, update NUM_SENSORS above! */ | 479 | /* Sensor descriptions. If you add a sensor, update NUM_SENSORS above! */ |
473 | static struct ro_sensor_template meter_ro_attrs[] = { | 480 | static struct sensor_template meter_attrs[] = { |
474 | {POWER_AVERAGE_NAME, show_power, 0}, | 481 | RO_SENSOR_TEMPLATE(POWER_AVERAGE_NAME, show_power, 0), |
475 | {"power1_accuracy", show_accuracy, 0}, | 482 | RO_SENSOR_TEMPLATE("power1_accuracy", show_accuracy, 0), |
476 | {"power1_average_interval_min", show_val, 0}, | 483 | RO_SENSOR_TEMPLATE("power1_average_interval_min", show_val, 0), |
477 | {"power1_average_interval_max", show_val, 1}, | 484 | RO_SENSOR_TEMPLATE("power1_average_interval_max", show_val, 1), |
478 | {"power1_is_battery", show_val, 5}, | 485 | RO_SENSOR_TEMPLATE("power1_is_battery", show_val, 5), |
479 | {NULL, NULL, 0}, | 486 | RW_SENSOR_TEMPLATE(POWER_AVG_INTERVAL_NAME, show_avg_interval, |
487 | set_avg_interval, 0), | ||
488 | {}, | ||
480 | }; | 489 | }; |
481 | 490 | ||
482 | static struct rw_sensor_template meter_rw_attrs[] = { | 491 | static struct sensor_template misc_cap_attrs[] = { |
483 | {POWER_AVG_INTERVAL_NAME, show_avg_interval, set_avg_interval, 0}, | 492 | RO_SENSOR_TEMPLATE("power1_cap_min", show_val, 2), |
484 | {NULL, NULL, NULL, 0}, | 493 | RO_SENSOR_TEMPLATE("power1_cap_max", show_val, 3), |
494 | RO_SENSOR_TEMPLATE("power1_cap_hyst", show_val, 4), | ||
495 | RO_SENSOR_TEMPLATE(POWER_ALARM_NAME, show_val, 6), | ||
496 | {}, | ||
485 | }; | 497 | }; |
486 | 498 | ||
487 | static struct ro_sensor_template misc_cap_attrs[] = { | 499 | static struct sensor_template ro_cap_attrs[] = { |
488 | {"power1_cap_min", show_val, 2}, | 500 | RO_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, 0), |
489 | {"power1_cap_max", show_val, 3}, | 501 | {}, |
490 | {"power1_cap_hyst", show_val, 4}, | ||
491 | {POWER_ALARM_NAME, show_val, 6}, | ||
492 | {NULL, NULL, 0}, | ||
493 | }; | 502 | }; |
494 | 503 | ||
495 | static struct ro_sensor_template ro_cap_attrs[] = { | 504 | static struct sensor_template rw_cap_attrs[] = { |
496 | {POWER_CAP_NAME, show_cap, 0}, | 505 | RW_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, set_cap, 0), |
497 | {NULL, NULL, 0}, | 506 | {}, |
498 | }; | 507 | }; |
499 | 508 | ||
500 | static struct rw_sensor_template rw_cap_attrs[] = { | 509 | static struct sensor_template trip_attrs[] = { |
501 | {POWER_CAP_NAME, show_cap, set_cap, 0}, | 510 | RW_SENSOR_TEMPLATE("power1_average_min", show_val, set_trip, 7), |
502 | {NULL, NULL, NULL, 0}, | 511 | RW_SENSOR_TEMPLATE("power1_average_max", show_val, set_trip, 8), |
512 | {}, | ||
503 | }; | 513 | }; |
504 | 514 | ||
505 | static struct rw_sensor_template trip_attrs[] = { | 515 | static struct sensor_template misc_attrs[] = { |
506 | {"power1_average_min", show_val, set_trip, 7}, | 516 | RO_SENSOR_TEMPLATE("name", show_name, 0), |
507 | {"power1_average_max", show_val, set_trip, 8}, | 517 | RO_SENSOR_TEMPLATE("power1_model_number", show_str, 0), |
508 | {NULL, NULL, NULL, 0}, | 518 | RO_SENSOR_TEMPLATE("power1_oem_info", show_str, 2), |
519 | RO_SENSOR_TEMPLATE("power1_serial_number", show_str, 1), | ||
520 | {}, | ||
509 | }; | 521 | }; |
510 | 522 | ||
511 | static struct ro_sensor_template misc_attrs[] = { | 523 | #undef RO_SENSOR_TEMPLATE |
512 | {"name", show_name, 0}, | 524 | #undef RW_SENSOR_TEMPLATE |
513 | {"power1_model_number", show_str, 0}, | ||
514 | {"power1_oem_info", show_str, 2}, | ||
515 | {"power1_serial_number", show_str, 1}, | ||
516 | {NULL, NULL, 0}, | ||
517 | }; | ||
518 | 525 | ||
519 | /* Read power domain data */ | 526 | /* Read power domain data */ |
520 | static void remove_domain_devices(struct acpi_power_meter_resource *resource) | 527 | static void remove_domain_devices(struct acpi_power_meter_resource *resource) |
@@ -619,49 +626,24 @@ end: | |||
619 | } | 626 | } |
620 | 627 | ||
621 | /* Registration and deregistration */ | 628 | /* Registration and deregistration */ |
622 | static int register_ro_attrs(struct acpi_power_meter_resource *resource, | 629 | static int register_attrs(struct acpi_power_meter_resource *resource, |
623 | struct ro_sensor_template *ro) | 630 | struct sensor_template *attrs) |
624 | { | 631 | { |
625 | struct device *dev = &resource->acpi_dev->dev; | 632 | struct device *dev = &resource->acpi_dev->dev; |
626 | struct sensor_device_attribute *sensors = | 633 | struct sensor_device_attribute *sensors = |
627 | &resource->sensors[resource->num_sensors]; | 634 | &resource->sensors[resource->num_sensors]; |
628 | int res = 0; | 635 | int res = 0; |
629 | 636 | ||
630 | while (ro->label) { | 637 | while (attrs->label) { |
631 | sensors->dev_attr.attr.name = ro->label; | 638 | sensors->dev_attr.attr.name = attrs->label; |
632 | sensors->dev_attr.attr.mode = S_IRUGO; | 639 | sensors->dev_attr.attr.mode = S_IRUGO; |
633 | sensors->dev_attr.show = ro->show; | 640 | sensors->dev_attr.show = attrs->show; |
634 | sensors->index = ro->index; | 641 | sensors->index = attrs->index; |
635 | 642 | ||
636 | sysfs_attr_init(&sensors->dev_attr.attr); | 643 | if (attrs->set) { |
637 | res = device_create_file(dev, &sensors->dev_attr); | 644 | sensors->dev_attr.attr.mode |= S_IWUSR; |
638 | if (res) { | 645 | sensors->dev_attr.store = attrs->set; |
639 | sensors->dev_attr.attr.name = NULL; | ||
640 | goto error; | ||
641 | } | 646 | } |
642 | sensors++; | ||
643 | resource->num_sensors++; | ||
644 | ro++; | ||
645 | } | ||
646 | |||
647 | error: | ||
648 | return res; | ||
649 | } | ||
650 | |||
651 | static int register_rw_attrs(struct acpi_power_meter_resource *resource, | ||
652 | struct rw_sensor_template *rw) | ||
653 | { | ||
654 | struct device *dev = &resource->acpi_dev->dev; | ||
655 | struct sensor_device_attribute *sensors = | ||
656 | &resource->sensors[resource->num_sensors]; | ||
657 | int res = 0; | ||
658 | |||
659 | while (rw->label) { | ||
660 | sensors->dev_attr.attr.name = rw->label; | ||
661 | sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR; | ||
662 | sensors->dev_attr.show = rw->show; | ||
663 | sensors->dev_attr.store = rw->set; | ||
664 | sensors->index = rw->index; | ||
665 | 647 | ||
666 | sysfs_attr_init(&sensors->dev_attr.attr); | 648 | sysfs_attr_init(&sensors->dev_attr.attr); |
667 | res = device_create_file(dev, &sensors->dev_attr); | 649 | res = device_create_file(dev, &sensors->dev_attr); |
@@ -671,7 +653,7 @@ static int register_rw_attrs(struct acpi_power_meter_resource *resource, | |||
671 | } | 653 | } |
672 | sensors++; | 654 | sensors++; |
673 | resource->num_sensors++; | 655 | resource->num_sensors++; |
674 | rw++; | 656 | attrs++; |
675 | } | 657 | } |
676 | 658 | ||
677 | error: | 659 | error: |
@@ -703,10 +685,7 @@ static int setup_attrs(struct acpi_power_meter_resource *resource) | |||
703 | return res; | 685 | return res; |
704 | 686 | ||
705 | if (resource->caps.flags & POWER_METER_CAN_MEASURE) { | 687 | if (resource->caps.flags & POWER_METER_CAN_MEASURE) { |
706 | res = register_ro_attrs(resource, meter_ro_attrs); | 688 | res = register_attrs(resource, meter_attrs); |
707 | if (res) | ||
708 | goto error; | ||
709 | res = register_rw_attrs(resource, meter_rw_attrs); | ||
710 | if (res) | 689 | if (res) |
711 | goto error; | 690 | goto error; |
712 | } | 691 | } |
@@ -718,28 +697,27 @@ static int setup_attrs(struct acpi_power_meter_resource *resource) | |||
718 | goto skip_unsafe_cap; | 697 | goto skip_unsafe_cap; |
719 | } | 698 | } |
720 | 699 | ||
721 | if (resource->caps.configurable_cap) { | 700 | if (resource->caps.configurable_cap) |
722 | res = register_rw_attrs(resource, rw_cap_attrs); | 701 | res = register_attrs(resource, rw_cap_attrs); |
723 | if (res) | 702 | else |
724 | goto error; | 703 | res = register_attrs(resource, ro_cap_attrs); |
725 | } else { | 704 | |
726 | res = register_ro_attrs(resource, ro_cap_attrs); | 705 | if (res) |
727 | if (res) | 706 | goto error; |
728 | goto error; | 707 | |
729 | } | 708 | res = register_attrs(resource, misc_cap_attrs); |
730 | res = register_ro_attrs(resource, misc_cap_attrs); | ||
731 | if (res) | 709 | if (res) |
732 | goto error; | 710 | goto error; |
733 | } | 711 | } |
734 | skip_unsafe_cap: | ||
735 | 712 | ||
713 | skip_unsafe_cap: | ||
736 | if (resource->caps.flags & POWER_METER_CAN_TRIP) { | 714 | if (resource->caps.flags & POWER_METER_CAN_TRIP) { |
737 | res = register_rw_attrs(resource, trip_attrs); | 715 | res = register_attrs(resource, trip_attrs); |
738 | if (res) | 716 | if (res) |
739 | goto error; | 717 | goto error; |
740 | } | 718 | } |
741 | 719 | ||
742 | res = register_ro_attrs(resource, misc_attrs); | 720 | res = register_attrs(resource, misc_attrs); |
743 | if (res) | 721 | if (res) |
744 | goto error; | 722 | goto error; |
745 | 723 | ||
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index f85ce70d9677..cfec802cf9ca 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c | |||
@@ -18,21 +18,14 @@ | |||
18 | #include <linux/hwmon-sysfs.h> | 18 | #include <linux/hwmon-sysfs.h> |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * AD7314 power mode | ||
22 | */ | ||
23 | #define AD7314_PD 0x2000 | ||
24 | |||
25 | /* | ||
26 | * AD7314 temperature masks | 21 | * AD7314 temperature masks |
27 | */ | 22 | */ |
28 | #define AD7314_TEMP_SIGN 0x200 | ||
29 | #define AD7314_TEMP_MASK 0x7FE0 | 23 | #define AD7314_TEMP_MASK 0x7FE0 |
30 | #define AD7314_TEMP_OFFSET 5 | 24 | #define AD7314_TEMP_SHIFT 5 |
31 | 25 | ||
32 | /* | 26 | /* |
33 | * ADT7301 and ADT7302 temperature masks | 27 | * ADT7301 and ADT7302 temperature masks |
34 | */ | 28 | */ |
35 | #define ADT7301_TEMP_SIGN 0x2000 | ||
36 | #define ADT7301_TEMP_MASK 0x3FFF | 29 | #define ADT7301_TEMP_MASK 0x3FFF |
37 | 30 | ||
38 | enum ad7314_variant { | 31 | enum ad7314_variant { |
@@ -73,7 +66,7 @@ static ssize_t ad7314_show_temperature(struct device *dev, | |||
73 | return ret; | 66 | return ret; |
74 | switch (spi_get_device_id(chip->spi_dev)->driver_data) { | 67 | switch (spi_get_device_id(chip->spi_dev)->driver_data) { |
75 | case ad7314: | 68 | case ad7314: |
76 | data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET; | 69 | data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT; |
77 | data = (data << 6) >> 6; | 70 | data = (data << 6) >> 6; |
78 | 71 | ||
79 | return sprintf(buf, "%d\n", 250 * data); | 72 | return sprintf(buf, "%d\n", 250 * data); |
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index e8e18cab1fb8..6b13f1a4dc27 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c | |||
@@ -257,15 +257,4 @@ static struct pci_driver fam15h_power_driver = { | |||
257 | .remove = __devexit_p(fam15h_power_remove), | 257 | .remove = __devexit_p(fam15h_power_remove), |
258 | }; | 258 | }; |
259 | 259 | ||
260 | static int __init fam15h_power_init(void) | 260 | module_pci_driver(fam15h_power_driver); |
261 | { | ||
262 | return pci_register_driver(&fam15h_power_driver); | ||
263 | } | ||
264 | |||
265 | static void __exit fam15h_power_exit(void) | ||
266 | { | ||
267 | pci_unregister_driver(&fam15h_power_driver); | ||
268 | } | ||
269 | |||
270 | module_init(fam15h_power_init) | ||
271 | module_exit(fam15h_power_exit) | ||
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c new file mode 100644 index 000000000000..7f3f4a385729 --- /dev/null +++ b/drivers/hwmon/ina2xx.c | |||
@@ -0,0 +1,368 @@ | |||
1 | /* | ||
2 | * Driver for Texas Instruments INA219, INA226 power monitor chips | ||
3 | * | ||
4 | * INA219: | ||
5 | * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface | ||
6 | * Datasheet: http://www.ti.com/product/ina219 | ||
7 | * | ||
8 | * INA226: | ||
9 | * Bi-Directional Current/Power Monitor with I2C Interface | ||
10 | * Datasheet: http://www.ti.com/product/ina226 | ||
11 | * | ||
12 | * Copyright (C) 2012 Lothar Felten <l-felten@ti.com> | ||
13 | * Thanks to Jan Volkering | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; version 2 of the License. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/hwmon.h> | ||
27 | #include <linux/hwmon-sysfs.h> | ||
28 | |||
29 | #include <linux/platform_data/ina2xx.h> | ||
30 | |||
31 | /* common register definitions */ | ||
32 | #define INA2XX_CONFIG 0x00 | ||
33 | #define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */ | ||
34 | #define INA2XX_BUS_VOLTAGE 0x02 /* readonly */ | ||
35 | #define INA2XX_POWER 0x03 /* readonly */ | ||
36 | #define INA2XX_CURRENT 0x04 /* readonly */ | ||
37 | #define INA2XX_CALIBRATION 0x05 | ||
38 | |||
39 | /* INA226 register definitions */ | ||
40 | #define INA226_MASK_ENABLE 0x06 | ||
41 | #define INA226_ALERT_LIMIT 0x07 | ||
42 | #define INA226_DIE_ID 0xFF | ||
43 | |||
44 | |||
45 | /* register count */ | ||
46 | #define INA219_REGISTERS 6 | ||
47 | #define INA226_REGISTERS 8 | ||
48 | |||
49 | #define INA2XX_MAX_REGISTERS 8 | ||
50 | |||
51 | /* settings - depend on use case */ | ||
52 | #define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */ | ||
53 | #define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */ | ||
54 | |||
55 | /* worst case is 68.10 ms (~14.6Hz, ina219) */ | ||
56 | #define INA2XX_CONVERSION_RATE 15 | ||
57 | |||
58 | enum ina2xx_ids { ina219, ina226 }; | ||
59 | |||
60 | struct ina2xx_data { | ||
61 | struct device *hwmon_dev; | ||
62 | |||
63 | struct mutex update_lock; | ||
64 | bool valid; | ||
65 | unsigned long last_updated; | ||
66 | |||
67 | int kind; | ||
68 | int registers; | ||
69 | u16 regs[INA2XX_MAX_REGISTERS]; | ||
70 | }; | ||
71 | |||
72 | int ina2xx_read_word(struct i2c_client *client, int reg) | ||
73 | { | ||
74 | int val = i2c_smbus_read_word_data(client, reg); | ||
75 | if (unlikely(val < 0)) { | ||
76 | dev_dbg(&client->dev, | ||
77 | "Failed to read register: %d\n", reg); | ||
78 | return val; | ||
79 | } | ||
80 | return be16_to_cpu(val); | ||
81 | } | ||
82 | |||
83 | void ina2xx_write_word(struct i2c_client *client, int reg, int data) | ||
84 | { | ||
85 | i2c_smbus_write_word_data(client, reg, cpu_to_be16(data)); | ||
86 | } | ||
87 | |||
88 | static struct ina2xx_data *ina2xx_update_device(struct device *dev) | ||
89 | { | ||
90 | struct i2c_client *client = to_i2c_client(dev); | ||
91 | struct ina2xx_data *data = i2c_get_clientdata(client); | ||
92 | struct ina2xx_data *ret = data; | ||
93 | |||
94 | mutex_lock(&data->update_lock); | ||
95 | |||
96 | if (time_after(jiffies, data->last_updated + | ||
97 | HZ / INA2XX_CONVERSION_RATE) || !data->valid) { | ||
98 | |||
99 | int i; | ||
100 | |||
101 | dev_dbg(&client->dev, "Starting ina2xx update\n"); | ||
102 | |||
103 | /* Read all registers */ | ||
104 | for (i = 0; i < data->registers; i++) { | ||
105 | int rv = ina2xx_read_word(client, i); | ||
106 | if (rv < 0) { | ||
107 | ret = ERR_PTR(rv); | ||
108 | goto abort; | ||
109 | } | ||
110 | data->regs[i] = rv; | ||
111 | } | ||
112 | data->last_updated = jiffies; | ||
113 | data->valid = 1; | ||
114 | } | ||
115 | abort: | ||
116 | mutex_unlock(&data->update_lock); | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static int ina219_get_value(struct ina2xx_data *data, u8 reg) | ||
121 | { | ||
122 | /* | ||
123 | * calculate exact value for the given register | ||
124 | * we assume default power-on reset settings: | ||
125 | * bus voltage range 32V | ||
126 | * gain = /8 | ||
127 | * adc 1 & 2 -> conversion time 532uS | ||
128 | * mode is continuous shunt and bus | ||
129 | * calibration value is INA219_CALIBRATION_VALUE | ||
130 | */ | ||
131 | int val = data->regs[reg]; | ||
132 | |||
133 | switch (reg) { | ||
134 | case INA2XX_SHUNT_VOLTAGE: | ||
135 | /* LSB=10uV. Convert to mV. */ | ||
136 | val = DIV_ROUND_CLOSEST(val, 100); | ||
137 | break; | ||
138 | case INA2XX_BUS_VOLTAGE: | ||
139 | /* LSB=4mV. Register is not right aligned, convert to mV. */ | ||
140 | val = (val >> 3) * 4; | ||
141 | break; | ||
142 | case INA2XX_POWER: | ||
143 | /* LSB=20mW. Convert to uW */ | ||
144 | val = val * 20 * 1000; | ||
145 | break; | ||
146 | case INA2XX_CURRENT: | ||
147 | /* LSB=1mA (selected). Is in mA */ | ||
148 | break; | ||
149 | default: | ||
150 | /* programmer goofed */ | ||
151 | WARN_ON_ONCE(1); | ||
152 | val = 0; | ||
153 | break; | ||
154 | } | ||
155 | |||
156 | return val; | ||
157 | } | ||
158 | |||
159 | static int ina226_get_value(struct ina2xx_data *data, u8 reg) | ||
160 | { | ||
161 | /* | ||
162 | * calculate exact value for the given register | ||
163 | * we assume default power-on reset settings: | ||
164 | * bus voltage range 32V | ||
165 | * gain = /8 | ||
166 | * adc 1 & 2 -> conversion time 532uS | ||
167 | * mode is continuous shunt and bus | ||
168 | * calibration value is INA226_CALIBRATION_VALUE | ||
169 | */ | ||
170 | int val = data->regs[reg]; | ||
171 | |||
172 | switch (reg) { | ||
173 | case INA2XX_SHUNT_VOLTAGE: | ||
174 | /* LSB=2.5uV. Convert to mV. */ | ||
175 | val = DIV_ROUND_CLOSEST(val, 400); | ||
176 | break; | ||
177 | case INA2XX_BUS_VOLTAGE: | ||
178 | /* LSB=1.25mV. Convert to mV. */ | ||
179 | val = val + DIV_ROUND_CLOSEST(val, 4); | ||
180 | break; | ||
181 | case INA2XX_POWER: | ||
182 | /* LSB=25mW. Convert to uW */ | ||
183 | val = val * 25 * 1000; | ||
184 | break; | ||
185 | case INA2XX_CURRENT: | ||
186 | /* LSB=1mA (selected). Is in mA */ | ||
187 | break; | ||
188 | default: | ||
189 | /* programmer goofed */ | ||
190 | WARN_ON_ONCE(1); | ||
191 | val = 0; | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | return val; | ||
196 | } | ||
197 | |||
198 | static ssize_t ina2xx_show_value(struct device *dev, | ||
199 | struct device_attribute *da, char *buf) | ||
200 | { | ||
201 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
202 | struct ina2xx_data *data = ina2xx_update_device(dev); | ||
203 | int value = 0; | ||
204 | |||
205 | if (IS_ERR(data)) | ||
206 | return PTR_ERR(data); | ||
207 | |||
208 | switch (data->kind) { | ||
209 | case ina219: | ||
210 | value = ina219_get_value(data, attr->index); | ||
211 | break; | ||
212 | case ina226: | ||
213 | value = ina226_get_value(data, attr->index); | ||
214 | break; | ||
215 | default: | ||
216 | WARN_ON_ONCE(1); | ||
217 | break; | ||
218 | } | ||
219 | return snprintf(buf, PAGE_SIZE, "%d\n", value); | ||
220 | } | ||
221 | |||
222 | /* shunt voltage */ | ||
223 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \ | ||
224 | ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE); | ||
225 | |||
226 | /* bus voltage */ | ||
227 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \ | ||
228 | ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE); | ||
229 | |||
230 | /* calculated current */ | ||
231 | static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \ | ||
232 | ina2xx_show_value, NULL, INA2XX_CURRENT); | ||
233 | |||
234 | /* calculated power */ | ||
235 | static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \ | ||
236 | ina2xx_show_value, NULL, INA2XX_POWER); | ||
237 | |||
238 | /* pointers to created device attributes */ | ||
239 | static struct attribute *ina2xx_attributes[] = { | ||
240 | &sensor_dev_attr_in0_input.dev_attr.attr, | ||
241 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
242 | &sensor_dev_attr_curr1_input.dev_attr.attr, | ||
243 | &sensor_dev_attr_power1_input.dev_attr.attr, | ||
244 | NULL, | ||
245 | }; | ||
246 | |||
247 | static const struct attribute_group ina2xx_group = { | ||
248 | .attrs = ina2xx_attributes, | ||
249 | }; | ||
250 | |||
251 | static int ina2xx_probe(struct i2c_client *client, | ||
252 | const struct i2c_device_id *id) | ||
253 | { | ||
254 | struct i2c_adapter *adapter = client->adapter; | ||
255 | struct ina2xx_data *data; | ||
256 | struct ina2xx_platform_data *pdata; | ||
257 | int ret = 0; | ||
258 | long shunt = 10000; /* default shunt value 10mOhms */ | ||
259 | |||
260 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) | ||
261 | return -ENODEV; | ||
262 | |||
263 | data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); | ||
264 | if (!data) | ||
265 | return -ENOMEM; | ||
266 | |||
267 | if (client->dev.platform_data) { | ||
268 | pdata = | ||
269 | (struct ina2xx_platform_data *)client->dev.platform_data; | ||
270 | shunt = pdata->shunt_uohms; | ||
271 | } | ||
272 | |||
273 | if (shunt <= 0) | ||
274 | return -ENODEV; | ||
275 | |||
276 | /* set the device type */ | ||
277 | data->kind = id->driver_data; | ||
278 | |||
279 | switch (data->kind) { | ||
280 | case ina219: | ||
281 | /* device configuration */ | ||
282 | ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT); | ||
283 | |||
284 | /* set current LSB to 1mA, shunt is in uOhms */ | ||
285 | /* (equation 13 in datasheet) */ | ||
286 | ina2xx_write_word(client, INA2XX_CALIBRATION, 40960000 / shunt); | ||
287 | dev_info(&client->dev, | ||
288 | "power monitor INA219 (Rshunt = %li uOhm)\n", shunt); | ||
289 | data->registers = INA219_REGISTERS; | ||
290 | break; | ||
291 | case ina226: | ||
292 | /* device configuration */ | ||
293 | ina2xx_write_word(client, INA2XX_CONFIG, INA226_CONFIG_DEFAULT); | ||
294 | |||
295 | /* set current LSB to 1mA, shunt is in uOhms */ | ||
296 | /* (equation 1 in datasheet)*/ | ||
297 | ina2xx_write_word(client, INA2XX_CALIBRATION, 5120000 / shunt); | ||
298 | dev_info(&client->dev, | ||
299 | "power monitor INA226 (Rshunt = %li uOhm)\n", shunt); | ||
300 | data->registers = INA226_REGISTERS; | ||
301 | break; | ||
302 | default: | ||
303 | /* unknown device id */ | ||
304 | return -ENODEV; | ||
305 | } | ||
306 | |||
307 | i2c_set_clientdata(client, data); | ||
308 | mutex_init(&data->update_lock); | ||
309 | |||
310 | ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group); | ||
311 | if (ret) | ||
312 | return ret; | ||
313 | |||
314 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
315 | if (IS_ERR(data->hwmon_dev)) { | ||
316 | ret = PTR_ERR(data->hwmon_dev); | ||
317 | goto out_err_hwmon; | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | |||
322 | out_err_hwmon: | ||
323 | sysfs_remove_group(&client->dev.kobj, &ina2xx_group); | ||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | static int ina2xx_remove(struct i2c_client *client) | ||
328 | { | ||
329 | struct ina2xx_data *data = i2c_get_clientdata(client); | ||
330 | |||
331 | hwmon_device_unregister(data->hwmon_dev); | ||
332 | sysfs_remove_group(&client->dev.kobj, &ina2xx_group); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static const struct i2c_device_id ina2xx_id[] = { | ||
338 | { "ina219", ina219 }, | ||
339 | { "ina226", ina226 }, | ||
340 | { } | ||
341 | }; | ||
342 | MODULE_DEVICE_TABLE(i2c, ina2xx_id); | ||
343 | |||
344 | static struct i2c_driver ina2xx_driver = { | ||
345 | .driver = { | ||
346 | .name = "ina2xx", | ||
347 | }, | ||
348 | .probe = ina2xx_probe, | ||
349 | .remove = ina2xx_remove, | ||
350 | .id_table = ina2xx_id, | ||
351 | }; | ||
352 | |||
353 | static int __init ina2xx_init(void) | ||
354 | { | ||
355 | return i2c_add_driver(&ina2xx_driver); | ||
356 | } | ||
357 | |||
358 | static void __exit ina2xx_exit(void) | ||
359 | { | ||
360 | i2c_del_driver(&ina2xx_driver); | ||
361 | } | ||
362 | |||
363 | MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>"); | ||
364 | MODULE_DESCRIPTION("ina2xx driver"); | ||
365 | MODULE_LICENSE("GPL"); | ||
366 | |||
367 | module_init(ina2xx_init); | ||
368 | module_exit(ina2xx_exit); | ||
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 0b204e4cf51c..e7701d99f8e8 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c | |||
@@ -19,6 +19,8 @@ | |||
19 | * IT8726F Super I/O chip w/LPC interface | 19 | * IT8726F Super I/O chip w/LPC interface |
20 | * IT8728F Super I/O chip w/LPC interface | 20 | * IT8728F Super I/O chip w/LPC interface |
21 | * IT8758E Super I/O chip w/LPC interface | 21 | * IT8758E Super I/O chip w/LPC interface |
22 | * IT8782F Super I/O chip w/LPC interface | ||
23 | * IT8783E/F Super I/O chip w/LPC interface | ||
22 | * Sis950 A clone of the IT8705F | 24 | * Sis950 A clone of the IT8705F |
23 | * | 25 | * |
24 | * Copyright (C) 2001 Chris Gauthron | 26 | * Copyright (C) 2001 Chris Gauthron |
@@ -59,7 +61,8 @@ | |||
59 | 61 | ||
60 | #define DRVNAME "it87" | 62 | #define DRVNAME "it87" |
61 | 63 | ||
62 | enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 }; | 64 | enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782, |
65 | it8783 }; | ||
63 | 66 | ||
64 | static unsigned short force_id; | 67 | static unsigned short force_id; |
65 | module_param(force_id, ushort, 0); | 68 | module_param(force_id, ushort, 0); |
@@ -137,13 +140,18 @@ static inline void superio_exit(void) | |||
137 | #define IT8721F_DEVID 0x8721 | 140 | #define IT8721F_DEVID 0x8721 |
138 | #define IT8726F_DEVID 0x8726 | 141 | #define IT8726F_DEVID 0x8726 |
139 | #define IT8728F_DEVID 0x8728 | 142 | #define IT8728F_DEVID 0x8728 |
143 | #define IT8782F_DEVID 0x8782 | ||
144 | #define IT8783E_DEVID 0x8783 | ||
140 | #define IT87_ACT_REG 0x30 | 145 | #define IT87_ACT_REG 0x30 |
141 | #define IT87_BASE_REG 0x60 | 146 | #define IT87_BASE_REG 0x60 |
142 | 147 | ||
143 | /* Logical device 7 registers (IT8712F and later) */ | 148 | /* Logical device 7 registers (IT8712F and later) */ |
149 | #define IT87_SIO_GPIO1_REG 0x25 | ||
144 | #define IT87_SIO_GPIO3_REG 0x27 | 150 | #define IT87_SIO_GPIO3_REG 0x27 |
145 | #define IT87_SIO_GPIO5_REG 0x29 | 151 | #define IT87_SIO_GPIO5_REG 0x29 |
152 | #define IT87_SIO_PINX1_REG 0x2a /* Pin selection */ | ||
146 | #define IT87_SIO_PINX2_REG 0x2c /* Pin selection */ | 153 | #define IT87_SIO_PINX2_REG 0x2c /* Pin selection */ |
154 | #define IT87_SIO_SPI_REG 0xef /* SPI function pin select */ | ||
147 | #define IT87_SIO_VID_REG 0xfc /* VID value */ | 155 | #define IT87_SIO_VID_REG 0xfc /* VID value */ |
148 | #define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ | 156 | #define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ |
149 | 157 | ||
@@ -210,6 +218,7 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; | |||
210 | 218 | ||
211 | #define IT87_REG_VIN_ENABLE 0x50 | 219 | #define IT87_REG_VIN_ENABLE 0x50 |
212 | #define IT87_REG_TEMP_ENABLE 0x51 | 220 | #define IT87_REG_TEMP_ENABLE 0x51 |
221 | #define IT87_REG_TEMP_EXTRA 0x55 | ||
213 | #define IT87_REG_BEEP_ENABLE 0x5c | 222 | #define IT87_REG_BEEP_ENABLE 0x5c |
214 | 223 | ||
215 | #define IT87_REG_CHIPID 0x58 | 224 | #define IT87_REG_CHIPID 0x58 |
@@ -226,9 +235,11 @@ struct it87_sio_data { | |||
226 | u8 beep_pin; | 235 | u8 beep_pin; |
227 | u8 internal; /* Internal sensors can be labeled */ | 236 | u8 internal; /* Internal sensors can be labeled */ |
228 | /* Features skipped based on config or DMI */ | 237 | /* Features skipped based on config or DMI */ |
238 | u16 skip_in; | ||
229 | u8 skip_vid; | 239 | u8 skip_vid; |
230 | u8 skip_fan; | 240 | u8 skip_fan; |
231 | u8 skip_pwm; | 241 | u8 skip_pwm; |
242 | u8 skip_temp; | ||
232 | }; | 243 | }; |
233 | 244 | ||
234 | /* | 245 | /* |
@@ -253,6 +264,7 @@ struct it87_data { | |||
253 | u8 has_fan; /* Bitfield, fans enabled */ | 264 | u8 has_fan; /* Bitfield, fans enabled */ |
254 | u16 fan[5]; /* Register values, possibly combined */ | 265 | u16 fan[5]; /* Register values, possibly combined */ |
255 | u16 fan_min[5]; /* Register values, possibly combined */ | 266 | u16 fan_min[5]; /* Register values, possibly combined */ |
267 | u8 has_temp; /* Bitfield, temp sensors enabled */ | ||
256 | s8 temp[3]; /* Register value */ | 268 | s8 temp[3]; /* Register value */ |
257 | s8 temp_high[3]; /* Register value */ | 269 | s8 temp_high[3]; /* Register value */ |
258 | s8 temp_low[3]; /* Register value */ | 270 | s8 temp_low[3]; /* Register value */ |
@@ -304,31 +316,23 @@ static inline int has_newer_autopwm(const struct it87_data *data) | |||
304 | || data->type == it8728; | 316 | || data->type == it8728; |
305 | } | 317 | } |
306 | 318 | ||
307 | static u8 in_to_reg(const struct it87_data *data, int nr, long val) | 319 | static int adc_lsb(const struct it87_data *data, int nr) |
308 | { | 320 | { |
309 | long lsb; | 321 | int lsb = has_12mv_adc(data) ? 12 : 16; |
310 | 322 | if (data->in_scaled & (1 << nr)) | |
311 | if (has_12mv_adc(data)) { | 323 | lsb <<= 1; |
312 | if (data->in_scaled & (1 << nr)) | 324 | return lsb; |
313 | lsb = 24; | 325 | } |
314 | else | ||
315 | lsb = 12; | ||
316 | } else | ||
317 | lsb = 16; | ||
318 | 326 | ||
319 | val = DIV_ROUND_CLOSEST(val, lsb); | 327 | static u8 in_to_reg(const struct it87_data *data, int nr, long val) |
328 | { | ||
329 | val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr)); | ||
320 | return SENSORS_LIMIT(val, 0, 255); | 330 | return SENSORS_LIMIT(val, 0, 255); |
321 | } | 331 | } |
322 | 332 | ||
323 | static int in_from_reg(const struct it87_data *data, int nr, int val) | 333 | static int in_from_reg(const struct it87_data *data, int nr, int val) |
324 | { | 334 | { |
325 | if (has_12mv_adc(data)) { | 335 | return val * adc_lsb(data, nr); |
326 | if (data->in_scaled & (1 << nr)) | ||
327 | return val * 24; | ||
328 | else | ||
329 | return val * 12; | ||
330 | } else | ||
331 | return val * 16; | ||
332 | } | 336 | } |
333 | 337 | ||
334 | static inline u8 FAN_TO_REG(long rpm, int div) | 338 | static inline u8 FAN_TO_REG(long rpm, int div) |
@@ -407,7 +411,9 @@ static inline int has_16bit_fans(const struct it87_data *data) | |||
407 | || data->type == it8718 | 411 | || data->type == it8718 |
408 | || data->type == it8720 | 412 | || data->type == it8720 |
409 | || data->type == it8721 | 413 | || data->type == it8721 |
410 | || data->type == it8728; | 414 | || data->type == it8728 |
415 | || data->type == it8782 | ||
416 | || data->type == it8783; | ||
411 | } | 417 | } |
412 | 418 | ||
413 | static inline int has_old_autopwm(const struct it87_data *data) | 419 | static inline int has_old_autopwm(const struct it87_data *data) |
@@ -1369,57 +1375,103 @@ static ssize_t show_name(struct device *dev, struct device_attribute | |||
1369 | } | 1375 | } |
1370 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 1376 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
1371 | 1377 | ||
1372 | static struct attribute *it87_attributes[] = { | 1378 | static struct attribute *it87_attributes_in[9][5] = { |
1379 | { | ||
1373 | &sensor_dev_attr_in0_input.dev_attr.attr, | 1380 | &sensor_dev_attr_in0_input.dev_attr.attr, |
1374 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
1375 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
1376 | &sensor_dev_attr_in3_input.dev_attr.attr, | ||
1377 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
1378 | &sensor_dev_attr_in5_input.dev_attr.attr, | ||
1379 | &sensor_dev_attr_in6_input.dev_attr.attr, | ||
1380 | &sensor_dev_attr_in7_input.dev_attr.attr, | ||
1381 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
1382 | &sensor_dev_attr_in0_min.dev_attr.attr, | 1381 | &sensor_dev_attr_in0_min.dev_attr.attr, |
1383 | &sensor_dev_attr_in1_min.dev_attr.attr, | ||
1384 | &sensor_dev_attr_in2_min.dev_attr.attr, | ||
1385 | &sensor_dev_attr_in3_min.dev_attr.attr, | ||
1386 | &sensor_dev_attr_in4_min.dev_attr.attr, | ||
1387 | &sensor_dev_attr_in5_min.dev_attr.attr, | ||
1388 | &sensor_dev_attr_in6_min.dev_attr.attr, | ||
1389 | &sensor_dev_attr_in7_min.dev_attr.attr, | ||
1390 | &sensor_dev_attr_in0_max.dev_attr.attr, | 1382 | &sensor_dev_attr_in0_max.dev_attr.attr, |
1391 | &sensor_dev_attr_in1_max.dev_attr.attr, | ||
1392 | &sensor_dev_attr_in2_max.dev_attr.attr, | ||
1393 | &sensor_dev_attr_in3_max.dev_attr.attr, | ||
1394 | &sensor_dev_attr_in4_max.dev_attr.attr, | ||
1395 | &sensor_dev_attr_in5_max.dev_attr.attr, | ||
1396 | &sensor_dev_attr_in6_max.dev_attr.attr, | ||
1397 | &sensor_dev_attr_in7_max.dev_attr.attr, | ||
1398 | &sensor_dev_attr_in0_alarm.dev_attr.attr, | 1383 | &sensor_dev_attr_in0_alarm.dev_attr.attr, |
1384 | NULL | ||
1385 | }, { | ||
1386 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
1387 | &sensor_dev_attr_in1_min.dev_attr.attr, | ||
1388 | &sensor_dev_attr_in1_max.dev_attr.attr, | ||
1399 | &sensor_dev_attr_in1_alarm.dev_attr.attr, | 1389 | &sensor_dev_attr_in1_alarm.dev_attr.attr, |
1390 | NULL | ||
1391 | }, { | ||
1392 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
1393 | &sensor_dev_attr_in2_min.dev_attr.attr, | ||
1394 | &sensor_dev_attr_in2_max.dev_attr.attr, | ||
1400 | &sensor_dev_attr_in2_alarm.dev_attr.attr, | 1395 | &sensor_dev_attr_in2_alarm.dev_attr.attr, |
1396 | NULL | ||
1397 | }, { | ||
1398 | &sensor_dev_attr_in3_input.dev_attr.attr, | ||
1399 | &sensor_dev_attr_in3_min.dev_attr.attr, | ||
1400 | &sensor_dev_attr_in3_max.dev_attr.attr, | ||
1401 | &sensor_dev_attr_in3_alarm.dev_attr.attr, | 1401 | &sensor_dev_attr_in3_alarm.dev_attr.attr, |
1402 | NULL | ||
1403 | }, { | ||
1404 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
1405 | &sensor_dev_attr_in4_min.dev_attr.attr, | ||
1406 | &sensor_dev_attr_in4_max.dev_attr.attr, | ||
1402 | &sensor_dev_attr_in4_alarm.dev_attr.attr, | 1407 | &sensor_dev_attr_in4_alarm.dev_attr.attr, |
1408 | NULL | ||
1409 | }, { | ||
1410 | &sensor_dev_attr_in5_input.dev_attr.attr, | ||
1411 | &sensor_dev_attr_in5_min.dev_attr.attr, | ||
1412 | &sensor_dev_attr_in5_max.dev_attr.attr, | ||
1403 | &sensor_dev_attr_in5_alarm.dev_attr.attr, | 1413 | &sensor_dev_attr_in5_alarm.dev_attr.attr, |
1414 | NULL | ||
1415 | }, { | ||
1416 | &sensor_dev_attr_in6_input.dev_attr.attr, | ||
1417 | &sensor_dev_attr_in6_min.dev_attr.attr, | ||
1418 | &sensor_dev_attr_in6_max.dev_attr.attr, | ||
1404 | &sensor_dev_attr_in6_alarm.dev_attr.attr, | 1419 | &sensor_dev_attr_in6_alarm.dev_attr.attr, |
1420 | NULL | ||
1421 | }, { | ||
1422 | &sensor_dev_attr_in7_input.dev_attr.attr, | ||
1423 | &sensor_dev_attr_in7_min.dev_attr.attr, | ||
1424 | &sensor_dev_attr_in7_max.dev_attr.attr, | ||
1405 | &sensor_dev_attr_in7_alarm.dev_attr.attr, | 1425 | &sensor_dev_attr_in7_alarm.dev_attr.attr, |
1426 | NULL | ||
1427 | }, { | ||
1428 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
1429 | NULL | ||
1430 | } }; | ||
1406 | 1431 | ||
1432 | static const struct attribute_group it87_group_in[9] = { | ||
1433 | { .attrs = it87_attributes_in[0] }, | ||
1434 | { .attrs = it87_attributes_in[1] }, | ||
1435 | { .attrs = it87_attributes_in[2] }, | ||
1436 | { .attrs = it87_attributes_in[3] }, | ||
1437 | { .attrs = it87_attributes_in[4] }, | ||
1438 | { .attrs = it87_attributes_in[5] }, | ||
1439 | { .attrs = it87_attributes_in[6] }, | ||
1440 | { .attrs = it87_attributes_in[7] }, | ||
1441 | { .attrs = it87_attributes_in[8] }, | ||
1442 | }; | ||
1443 | |||
1444 | static struct attribute *it87_attributes_temp[3][6] = { | ||
1445 | { | ||
1407 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 1446 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
1408 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
1409 | &sensor_dev_attr_temp3_input.dev_attr.attr, | ||
1410 | &sensor_dev_attr_temp1_max.dev_attr.attr, | 1447 | &sensor_dev_attr_temp1_max.dev_attr.attr, |
1411 | &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
1412 | &sensor_dev_attr_temp3_max.dev_attr.attr, | ||
1413 | &sensor_dev_attr_temp1_min.dev_attr.attr, | 1448 | &sensor_dev_attr_temp1_min.dev_attr.attr, |
1414 | &sensor_dev_attr_temp2_min.dev_attr.attr, | ||
1415 | &sensor_dev_attr_temp3_min.dev_attr.attr, | ||
1416 | &sensor_dev_attr_temp1_type.dev_attr.attr, | 1449 | &sensor_dev_attr_temp1_type.dev_attr.attr, |
1417 | &sensor_dev_attr_temp2_type.dev_attr.attr, | ||
1418 | &sensor_dev_attr_temp3_type.dev_attr.attr, | ||
1419 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, | 1450 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, |
1451 | NULL | ||
1452 | } , { | ||
1453 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
1454 | &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
1455 | &sensor_dev_attr_temp2_min.dev_attr.attr, | ||
1456 | &sensor_dev_attr_temp2_type.dev_attr.attr, | ||
1420 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, | 1457 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, |
1458 | NULL | ||
1459 | } , { | ||
1460 | &sensor_dev_attr_temp3_input.dev_attr.attr, | ||
1461 | &sensor_dev_attr_temp3_max.dev_attr.attr, | ||
1462 | &sensor_dev_attr_temp3_min.dev_attr.attr, | ||
1463 | &sensor_dev_attr_temp3_type.dev_attr.attr, | ||
1421 | &sensor_dev_attr_temp3_alarm.dev_attr.attr, | 1464 | &sensor_dev_attr_temp3_alarm.dev_attr.attr, |
1465 | NULL | ||
1466 | } }; | ||
1467 | |||
1468 | static const struct attribute_group it87_group_temp[3] = { | ||
1469 | { .attrs = it87_attributes_temp[0] }, | ||
1470 | { .attrs = it87_attributes_temp[1] }, | ||
1471 | { .attrs = it87_attributes_temp[2] }, | ||
1472 | }; | ||
1422 | 1473 | ||
1474 | static struct attribute *it87_attributes[] = { | ||
1423 | &dev_attr_alarms.attr, | 1475 | &dev_attr_alarms.attr, |
1424 | &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, | 1476 | &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, |
1425 | &dev_attr_name.attr, | 1477 | &dev_attr_name.attr, |
@@ -1430,7 +1482,7 @@ static const struct attribute_group it87_group = { | |||
1430 | .attrs = it87_attributes, | 1482 | .attrs = it87_attributes, |
1431 | }; | 1483 | }; |
1432 | 1484 | ||
1433 | static struct attribute *it87_attributes_beep[] = { | 1485 | static struct attribute *it87_attributes_in_beep[] = { |
1434 | &sensor_dev_attr_in0_beep.dev_attr.attr, | 1486 | &sensor_dev_attr_in0_beep.dev_attr.attr, |
1435 | &sensor_dev_attr_in1_beep.dev_attr.attr, | 1487 | &sensor_dev_attr_in1_beep.dev_attr.attr, |
1436 | &sensor_dev_attr_in2_beep.dev_attr.attr, | 1488 | &sensor_dev_attr_in2_beep.dev_attr.attr, |
@@ -1439,15 +1491,13 @@ static struct attribute *it87_attributes_beep[] = { | |||
1439 | &sensor_dev_attr_in5_beep.dev_attr.attr, | 1491 | &sensor_dev_attr_in5_beep.dev_attr.attr, |
1440 | &sensor_dev_attr_in6_beep.dev_attr.attr, | 1492 | &sensor_dev_attr_in6_beep.dev_attr.attr, |
1441 | &sensor_dev_attr_in7_beep.dev_attr.attr, | 1493 | &sensor_dev_attr_in7_beep.dev_attr.attr, |
1494 | NULL | ||
1495 | }; | ||
1442 | 1496 | ||
1497 | static struct attribute *it87_attributes_temp_beep[] = { | ||
1443 | &sensor_dev_attr_temp1_beep.dev_attr.attr, | 1498 | &sensor_dev_attr_temp1_beep.dev_attr.attr, |
1444 | &sensor_dev_attr_temp2_beep.dev_attr.attr, | 1499 | &sensor_dev_attr_temp2_beep.dev_attr.attr, |
1445 | &sensor_dev_attr_temp3_beep.dev_attr.attr, | 1500 | &sensor_dev_attr_temp3_beep.dev_attr.attr, |
1446 | NULL | ||
1447 | }; | ||
1448 | |||
1449 | static const struct attribute_group it87_group_beep = { | ||
1450 | .attrs = it87_attributes_beep, | ||
1451 | }; | 1501 | }; |
1452 | 1502 | ||
1453 | static struct attribute *it87_attributes_fan16[5][3+1] = { { | 1503 | static struct attribute *it87_attributes_fan16[5][3+1] = { { |
@@ -1651,6 +1701,12 @@ static int __init it87_find(unsigned short *address, | |||
1651 | case IT8728F_DEVID: | 1701 | case IT8728F_DEVID: |
1652 | sio_data->type = it8728; | 1702 | sio_data->type = it8728; |
1653 | break; | 1703 | break; |
1704 | case IT8782F_DEVID: | ||
1705 | sio_data->type = it8782; | ||
1706 | break; | ||
1707 | case IT8783E_DEVID: | ||
1708 | sio_data->type = it8783; | ||
1709 | break; | ||
1654 | case 0xffff: /* No device at all */ | 1710 | case 0xffff: /* No device at all */ |
1655 | goto exit; | 1711 | goto exit; |
1656 | default: | 1712 | default: |
@@ -1686,16 +1742,86 @@ static int __init it87_find(unsigned short *address, | |||
1686 | /* The IT8705F has a different LD number for GPIO */ | 1742 | /* The IT8705F has a different LD number for GPIO */ |
1687 | superio_select(5); | 1743 | superio_select(5); |
1688 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; | 1744 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; |
1745 | } else if (sio_data->type == it8783) { | ||
1746 | int reg25, reg27, reg2A, reg2C, regEF; | ||
1747 | |||
1748 | sio_data->skip_vid = 1; /* No VID */ | ||
1749 | |||
1750 | superio_select(GPIO); | ||
1751 | |||
1752 | reg25 = superio_inb(IT87_SIO_GPIO1_REG); | ||
1753 | reg27 = superio_inb(IT87_SIO_GPIO3_REG); | ||
1754 | reg2A = superio_inb(IT87_SIO_PINX1_REG); | ||
1755 | reg2C = superio_inb(IT87_SIO_PINX2_REG); | ||
1756 | regEF = superio_inb(IT87_SIO_SPI_REG); | ||
1757 | |||
1758 | /* Check if fan3 is there or not */ | ||
1759 | if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2))) | ||
1760 | sio_data->skip_fan |= (1 << 2); | ||
1761 | if ((reg25 & (1 << 4)) | ||
1762 | || (!(reg2A & (1 << 1)) && (regEF & (1 << 0)))) | ||
1763 | sio_data->skip_pwm |= (1 << 2); | ||
1764 | |||
1765 | /* Check if fan2 is there or not */ | ||
1766 | if (reg27 & (1 << 7)) | ||
1767 | sio_data->skip_fan |= (1 << 1); | ||
1768 | if (reg27 & (1 << 3)) | ||
1769 | sio_data->skip_pwm |= (1 << 1); | ||
1770 | |||
1771 | /* VIN5 */ | ||
1772 | if ((reg27 & (1 << 0)) || (reg2C & (1 << 2))) | ||
1773 | sio_data->skip_in |= (1 << 5); /* No VIN5 */ | ||
1774 | |||
1775 | /* VIN6 */ | ||
1776 | if (reg27 & (1 << 1)) | ||
1777 | sio_data->skip_in |= (1 << 6); /* No VIN6 */ | ||
1778 | |||
1779 | /* | ||
1780 | * VIN7 | ||
1781 | * Does not depend on bit 2 of Reg2C, contrary to datasheet. | ||
1782 | */ | ||
1783 | if (reg27 & (1 << 2)) { | ||
1784 | /* | ||
1785 | * The data sheet is a bit unclear regarding the | ||
1786 | * internal voltage divider for VCCH5V. It says | ||
1787 | * "This bit enables and switches VIN7 (pin 91) to the | ||
1788 | * internal voltage divider for VCCH5V". | ||
1789 | * This is different to other chips, where the internal | ||
1790 | * voltage divider would connect VIN7 to an internal | ||
1791 | * voltage source. Maybe that is the case here as well. | ||
1792 | * | ||
1793 | * Since we don't know for sure, re-route it if that is | ||
1794 | * not the case, and ask the user to report if the | ||
1795 | * resulting voltage is sane. | ||
1796 | */ | ||
1797 | if (!(reg2C & (1 << 1))) { | ||
1798 | reg2C |= (1 << 1); | ||
1799 | superio_outb(IT87_SIO_PINX2_REG, reg2C); | ||
1800 | pr_notice("Routing internal VCCH5V to in7.\n"); | ||
1801 | } | ||
1802 | pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n"); | ||
1803 | pr_notice("Please report if it displays a reasonable voltage.\n"); | ||
1804 | } | ||
1805 | |||
1806 | if (reg2C & (1 << 0)) | ||
1807 | sio_data->internal |= (1 << 0); | ||
1808 | if (reg2C & (1 << 1)) | ||
1809 | sio_data->internal |= (1 << 1); | ||
1810 | |||
1811 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; | ||
1812 | |||
1689 | } else { | 1813 | } else { |
1690 | int reg; | 1814 | int reg; |
1815 | bool uart6; | ||
1691 | 1816 | ||
1692 | superio_select(GPIO); | 1817 | superio_select(GPIO); |
1693 | 1818 | ||
1694 | reg = superio_inb(IT87_SIO_GPIO3_REG); | 1819 | reg = superio_inb(IT87_SIO_GPIO3_REG); |
1695 | if (sio_data->type == it8721 || sio_data->type == it8728) { | 1820 | if (sio_data->type == it8721 || sio_data->type == it8728 || |
1821 | sio_data->type == it8782) { | ||
1696 | /* | 1822 | /* |
1697 | * The IT8721F/IT8758E doesn't have VID pins at all, | 1823 | * IT8721F/IT8758E, and IT8782F don't have VID pins |
1698 | * not sure about the IT8728F. | 1824 | * at all, not sure about the IT8728F. |
1699 | */ | 1825 | */ |
1700 | sio_data->skip_vid = 1; | 1826 | sio_data->skip_vid = 1; |
1701 | } else { | 1827 | } else { |
@@ -1724,6 +1850,9 @@ static int __init it87_find(unsigned short *address, | |||
1724 | sio_data->vid_value = superio_inb(IT87_SIO_VID_REG); | 1850 | sio_data->vid_value = superio_inb(IT87_SIO_VID_REG); |
1725 | 1851 | ||
1726 | reg = superio_inb(IT87_SIO_PINX2_REG); | 1852 | reg = superio_inb(IT87_SIO_PINX2_REG); |
1853 | |||
1854 | uart6 = sio_data->type == it8782 && (reg & (1 << 2)); | ||
1855 | |||
1727 | /* | 1856 | /* |
1728 | * The IT8720F has no VIN7 pin, so VCCH should always be | 1857 | * The IT8720F has no VIN7 pin, so VCCH should always be |
1729 | * routed internally to VIN7 with an internal divider. | 1858 | * routed internally to VIN7 with an internal divider. |
@@ -1733,8 +1862,12 @@ static int __init it87_find(unsigned short *address, | |||
1733 | * configured, even though the IT8720F datasheet claims | 1862 | * configured, even though the IT8720F datasheet claims |
1734 | * that the internal routing of VCCH to VIN7 is the default | 1863 | * that the internal routing of VCCH to VIN7 is the default |
1735 | * setting. So we force the internal routing in this case. | 1864 | * setting. So we force the internal routing in this case. |
1865 | * | ||
1866 | * On IT8782F, VIN7 is multiplexed with one of the UART6 pins. | ||
1867 | * If UART6 is enabled, re-route VIN7 to the internal divider | ||
1868 | * if that is not already the case. | ||
1736 | */ | 1869 | */ |
1737 | if (sio_data->type == it8720 && !(reg & (1 << 1))) { | 1870 | if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) { |
1738 | reg |= (1 << 1); | 1871 | reg |= (1 << 1); |
1739 | superio_outb(IT87_SIO_PINX2_REG, reg); | 1872 | superio_outb(IT87_SIO_PINX2_REG, reg); |
1740 | pr_notice("Routing internal VCCH to in7\n"); | 1873 | pr_notice("Routing internal VCCH to in7\n"); |
@@ -1745,6 +1878,20 @@ static int __init it87_find(unsigned short *address, | |||
1745 | sio_data->type == it8728) | 1878 | sio_data->type == it8728) |
1746 | sio_data->internal |= (1 << 1); | 1879 | sio_data->internal |= (1 << 1); |
1747 | 1880 | ||
1881 | /* | ||
1882 | * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7. | ||
1883 | * While VIN7 can be routed to the internal voltage divider, | ||
1884 | * VIN5 and VIN6 are not available if UART6 is enabled. | ||
1885 | * | ||
1886 | * Also, temp3 is not available if UART6 is enabled and TEMPIN3 | ||
1887 | * is the temperature source. Since we can not read the | ||
1888 | * temperature source here, skip_temp is preliminary. | ||
1889 | */ | ||
1890 | if (uart6) { | ||
1891 | sio_data->skip_in |= (1 << 5) | (1 << 6); | ||
1892 | sio_data->skip_temp |= (1 << 2); | ||
1893 | } | ||
1894 | |||
1748 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; | 1895 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; |
1749 | } | 1896 | } |
1750 | if (sio_data->beep_pin) | 1897 | if (sio_data->beep_pin) |
@@ -1782,8 +1929,22 @@ static void it87_remove_files(struct device *dev) | |||
1782 | int i; | 1929 | int i; |
1783 | 1930 | ||
1784 | sysfs_remove_group(&dev->kobj, &it87_group); | 1931 | sysfs_remove_group(&dev->kobj, &it87_group); |
1785 | if (sio_data->beep_pin) | 1932 | for (i = 0; i < 9; i++) { |
1786 | sysfs_remove_group(&dev->kobj, &it87_group_beep); | 1933 | if (sio_data->skip_in & (1 << i)) |
1934 | continue; | ||
1935 | sysfs_remove_group(&dev->kobj, &it87_group_in[i]); | ||
1936 | if (it87_attributes_in_beep[i]) | ||
1937 | sysfs_remove_file(&dev->kobj, | ||
1938 | it87_attributes_in_beep[i]); | ||
1939 | } | ||
1940 | for (i = 0; i < 3; i++) { | ||
1941 | if (!(data->has_temp & (1 << i))) | ||
1942 | continue; | ||
1943 | sysfs_remove_group(&dev->kobj, &it87_group_temp[i]); | ||
1944 | if (sio_data->beep_pin) | ||
1945 | sysfs_remove_file(&dev->kobj, | ||
1946 | it87_attributes_temp_beep[i]); | ||
1947 | } | ||
1787 | for (i = 0; i < 5; i++) { | 1948 | for (i = 0; i < 5; i++) { |
1788 | if (!(data->has_fan & (1 << i))) | 1949 | if (!(data->has_fan & (1 << i))) |
1789 | continue; | 1950 | continue; |
@@ -1823,22 +1984,22 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1823 | "it8720", | 1984 | "it8720", |
1824 | "it8721", | 1985 | "it8721", |
1825 | "it8728", | 1986 | "it8728", |
1987 | "it8782", | ||
1988 | "it8783", | ||
1826 | }; | 1989 | }; |
1827 | 1990 | ||
1828 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1991 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
1829 | if (!request_region(res->start, IT87_EC_EXTENT, DRVNAME)) { | 1992 | if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT, |
1993 | DRVNAME)) { | ||
1830 | dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", | 1994 | dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", |
1831 | (unsigned long)res->start, | 1995 | (unsigned long)res->start, |
1832 | (unsigned long)(res->start + IT87_EC_EXTENT - 1)); | 1996 | (unsigned long)(res->start + IT87_EC_EXTENT - 1)); |
1833 | err = -EBUSY; | 1997 | return -EBUSY; |
1834 | goto ERROR0; | ||
1835 | } | 1998 | } |
1836 | 1999 | ||
1837 | data = kzalloc(sizeof(struct it87_data), GFP_KERNEL); | 2000 | data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL); |
1838 | if (!data) { | 2001 | if (!data) |
1839 | err = -ENOMEM; | 2002 | return -ENOMEM; |
1840 | goto ERROR1; | ||
1841 | } | ||
1842 | 2003 | ||
1843 | data->addr = res->start; | 2004 | data->addr = res->start; |
1844 | data->type = sio_data->type; | 2005 | data->type = sio_data->type; |
@@ -1847,10 +2008,8 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1847 | 2008 | ||
1848 | /* Now, we do the remaining detection. */ | 2009 | /* Now, we do the remaining detection. */ |
1849 | if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) | 2010 | if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) |
1850 | || it87_read_value(data, IT87_REG_CHIPID) != 0x90) { | 2011 | || it87_read_value(data, IT87_REG_CHIPID) != 0x90) |
1851 | err = -ENODEV; | 2012 | return -ENODEV; |
1852 | goto ERROR2; | ||
1853 | } | ||
1854 | 2013 | ||
1855 | platform_set_drvdata(pdev, data); | 2014 | platform_set_drvdata(pdev, data); |
1856 | 2015 | ||
@@ -1867,6 +2026,18 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1867 | data->in_scaled |= (1 << 7); /* in7 is VSB */ | 2026 | data->in_scaled |= (1 << 7); /* in7 is VSB */ |
1868 | if (sio_data->internal & (1 << 2)) | 2027 | if (sio_data->internal & (1 << 2)) |
1869 | data->in_scaled |= (1 << 8); /* in8 is Vbat */ | 2028 | data->in_scaled |= (1 << 8); /* in8 is Vbat */ |
2029 | } else if (sio_data->type == it8782 || sio_data->type == it8783) { | ||
2030 | if (sio_data->internal & (1 << 0)) | ||
2031 | data->in_scaled |= (1 << 3); /* in3 is VCC5V */ | ||
2032 | if (sio_data->internal & (1 << 1)) | ||
2033 | data->in_scaled |= (1 << 7); /* in7 is VCCH5V */ | ||
2034 | } | ||
2035 | |||
2036 | data->has_temp = 0x07; | ||
2037 | if (sio_data->skip_temp & (1 << 2)) { | ||
2038 | if (sio_data->type == it8782 | ||
2039 | && !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80)) | ||
2040 | data->has_temp &= ~(1 << 2); | ||
1870 | } | 2041 | } |
1871 | 2042 | ||
1872 | /* Initialize the IT87 chip */ | 2043 | /* Initialize the IT87 chip */ |
@@ -1875,12 +2046,34 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1875 | /* Register sysfs hooks */ | 2046 | /* Register sysfs hooks */ |
1876 | err = sysfs_create_group(&dev->kobj, &it87_group); | 2047 | err = sysfs_create_group(&dev->kobj, &it87_group); |
1877 | if (err) | 2048 | if (err) |
1878 | goto ERROR2; | 2049 | return err; |
1879 | 2050 | ||
1880 | if (sio_data->beep_pin) { | 2051 | for (i = 0; i < 9; i++) { |
1881 | err = sysfs_create_group(&dev->kobj, &it87_group_beep); | 2052 | if (sio_data->skip_in & (1 << i)) |
2053 | continue; | ||
2054 | err = sysfs_create_group(&dev->kobj, &it87_group_in[i]); | ||
1882 | if (err) | 2055 | if (err) |
1883 | goto ERROR4; | 2056 | goto error; |
2057 | if (sio_data->beep_pin && it87_attributes_in_beep[i]) { | ||
2058 | err = sysfs_create_file(&dev->kobj, | ||
2059 | it87_attributes_in_beep[i]); | ||
2060 | if (err) | ||
2061 | goto error; | ||
2062 | } | ||
2063 | } | ||
2064 | |||
2065 | for (i = 0; i < 3; i++) { | ||
2066 | if (!(data->has_temp & (1 << i))) | ||
2067 | continue; | ||
2068 | err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]); | ||
2069 | if (err) | ||
2070 | goto error; | ||
2071 | if (sio_data->beep_pin) { | ||
2072 | err = sysfs_create_file(&dev->kobj, | ||
2073 | it87_attributes_temp_beep[i]); | ||
2074 | if (err) | ||
2075 | goto error; | ||
2076 | } | ||
1884 | } | 2077 | } |
1885 | 2078 | ||
1886 | /* Do not create fan files for disabled fans */ | 2079 | /* Do not create fan files for disabled fans */ |
@@ -1891,13 +2084,13 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1891 | continue; | 2084 | continue; |
1892 | err = sysfs_create_group(&dev->kobj, &fan_group[i]); | 2085 | err = sysfs_create_group(&dev->kobj, &fan_group[i]); |
1893 | if (err) | 2086 | if (err) |
1894 | goto ERROR4; | 2087 | goto error; |
1895 | 2088 | ||
1896 | if (sio_data->beep_pin) { | 2089 | if (sio_data->beep_pin) { |
1897 | err = sysfs_create_file(&dev->kobj, | 2090 | err = sysfs_create_file(&dev->kobj, |
1898 | it87_attributes_fan_beep[i]); | 2091 | it87_attributes_fan_beep[i]); |
1899 | if (err) | 2092 | if (err) |
1900 | goto ERROR4; | 2093 | goto error; |
1901 | if (!fan_beep_need_rw) | 2094 | if (!fan_beep_need_rw) |
1902 | continue; | 2095 | continue; |
1903 | 2096 | ||
@@ -1922,14 +2115,14 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1922 | err = sysfs_create_group(&dev->kobj, | 2115 | err = sysfs_create_group(&dev->kobj, |
1923 | &it87_group_pwm[i]); | 2116 | &it87_group_pwm[i]); |
1924 | if (err) | 2117 | if (err) |
1925 | goto ERROR4; | 2118 | goto error; |
1926 | 2119 | ||
1927 | if (!has_old_autopwm(data)) | 2120 | if (!has_old_autopwm(data)) |
1928 | continue; | 2121 | continue; |
1929 | err = sysfs_create_group(&dev->kobj, | 2122 | err = sysfs_create_group(&dev->kobj, |
1930 | &it87_group_autopwm[i]); | 2123 | &it87_group_autopwm[i]); |
1931 | if (err) | 2124 | if (err) |
1932 | goto ERROR4; | 2125 | goto error; |
1933 | } | 2126 | } |
1934 | } | 2127 | } |
1935 | 2128 | ||
@@ -1939,7 +2132,7 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1939 | data->vid = sio_data->vid_value; | 2132 | data->vid = sio_data->vid_value; |
1940 | err = sysfs_create_group(&dev->kobj, &it87_group_vid); | 2133 | err = sysfs_create_group(&dev->kobj, &it87_group_vid); |
1941 | if (err) | 2134 | if (err) |
1942 | goto ERROR4; | 2135 | goto error; |
1943 | } | 2136 | } |
1944 | 2137 | ||
1945 | /* Export labels for internal sensors */ | 2138 | /* Export labels for internal sensors */ |
@@ -1949,25 +2142,19 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1949 | err = sysfs_create_file(&dev->kobj, | 2142 | err = sysfs_create_file(&dev->kobj, |
1950 | it87_attributes_label[i]); | 2143 | it87_attributes_label[i]); |
1951 | if (err) | 2144 | if (err) |
1952 | goto ERROR4; | 2145 | goto error; |
1953 | } | 2146 | } |
1954 | 2147 | ||
1955 | data->hwmon_dev = hwmon_device_register(dev); | 2148 | data->hwmon_dev = hwmon_device_register(dev); |
1956 | if (IS_ERR(data->hwmon_dev)) { | 2149 | if (IS_ERR(data->hwmon_dev)) { |
1957 | err = PTR_ERR(data->hwmon_dev); | 2150 | err = PTR_ERR(data->hwmon_dev); |
1958 | goto ERROR4; | 2151 | goto error; |
1959 | } | 2152 | } |
1960 | 2153 | ||
1961 | return 0; | 2154 | return 0; |
1962 | 2155 | ||
1963 | ERROR4: | 2156 | error: |
1964 | it87_remove_files(dev); | 2157 | it87_remove_files(dev); |
1965 | ERROR2: | ||
1966 | platform_set_drvdata(pdev, NULL); | ||
1967 | kfree(data); | ||
1968 | ERROR1: | ||
1969 | release_region(res->start, IT87_EC_EXTENT); | ||
1970 | ERROR0: | ||
1971 | return err; | 2158 | return err; |
1972 | } | 2159 | } |
1973 | 2160 | ||
@@ -1978,10 +2165,6 @@ static int __devexit it87_remove(struct platform_device *pdev) | |||
1978 | hwmon_device_unregister(data->hwmon_dev); | 2165 | hwmon_device_unregister(data->hwmon_dev); |
1979 | it87_remove_files(&pdev->dev); | 2166 | it87_remove_files(&pdev->dev); |
1980 | 2167 | ||
1981 | release_region(data->addr, IT87_EC_EXTENT); | ||
1982 | platform_set_drvdata(pdev, NULL); | ||
1983 | kfree(data); | ||
1984 | |||
1985 | return 0; | 2168 | return 0; |
1986 | } | 2169 | } |
1987 | 2170 | ||
@@ -2143,8 +2326,9 @@ static void __devinit it87_init_device(struct platform_device *pdev) | |||
2143 | it87_write_value(data, IT87_REG_FAN_16BIT, | 2326 | it87_write_value(data, IT87_REG_FAN_16BIT, |
2144 | tmp | 0x07); | 2327 | tmp | 0x07); |
2145 | } | 2328 | } |
2146 | /* IT8705F only supports three fans. */ | 2329 | /* IT8705F, IT8782F, and IT8783E/F only support three fans. */ |
2147 | if (data->type != it87) { | 2330 | if (data->type != it87 && data->type != it8782 && |
2331 | data->type != it8783) { | ||
2148 | if (tmp & (1 << 4)) | 2332 | if (tmp & (1 << 4)) |
2149 | data->has_fan |= (1 << 3); /* fan4 enabled */ | 2333 | data->has_fan |= (1 << 3); /* fan4 enabled */ |
2150 | if (tmp & (1 << 5)) | 2334 | if (tmp & (1 << 5)) |
@@ -2233,6 +2417,8 @@ static struct it87_data *it87_update_device(struct device *dev) | |||
2233 | } | 2417 | } |
2234 | } | 2418 | } |
2235 | for (i = 0; i < 3; i++) { | 2419 | for (i = 0; i < 3; i++) { |
2420 | if (!(data->has_temp & (1 << i))) | ||
2421 | continue; | ||
2236 | data->temp[i] = | 2422 | data->temp[i] = |
2237 | it87_read_value(data, IT87_REG_TEMP(i)); | 2423 | it87_read_value(data, IT87_REG_TEMP(i)); |
2238 | data->temp_high[i] = | 2424 | data->temp_high[i] = |
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 307bb325dde9..7356b5ec8f67 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c | |||
@@ -225,15 +225,4 @@ static struct pci_driver k10temp_driver = { | |||
225 | .remove = __devexit_p(k10temp_remove), | 225 | .remove = __devexit_p(k10temp_remove), |
226 | }; | 226 | }; |
227 | 227 | ||
228 | static int __init k10temp_init(void) | 228 | module_pci_driver(k10temp_driver); |
229 | { | ||
230 | return pci_register_driver(&k10temp_driver); | ||
231 | } | ||
232 | |||
233 | static void __exit k10temp_exit(void) | ||
234 | { | ||
235 | pci_unregister_driver(&k10temp_driver); | ||
236 | } | ||
237 | |||
238 | module_init(k10temp_init) | ||
239 | module_exit(k10temp_exit) | ||
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 575101988751..35aac82ee8eb 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c | |||
@@ -339,19 +339,8 @@ static struct pci_driver k8temp_driver = { | |||
339 | .remove = __devexit_p(k8temp_remove), | 339 | .remove = __devexit_p(k8temp_remove), |
340 | }; | 340 | }; |
341 | 341 | ||
342 | static int __init k8temp_init(void) | 342 | module_pci_driver(k8temp_driver); |
343 | { | ||
344 | return pci_register_driver(&k8temp_driver); | ||
345 | } | ||
346 | |||
347 | static void __exit k8temp_exit(void) | ||
348 | { | ||
349 | pci_unregister_driver(&k8temp_driver); | ||
350 | } | ||
351 | 343 | ||
352 | MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>"); | 344 | MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>"); |
353 | MODULE_DESCRIPTION("AMD K8 core temperature monitor"); | 345 | MODULE_DESCRIPTION("AMD K8 core temperature monitor"); |
354 | MODULE_LICENSE("GPL"); | 346 | MODULE_LICENSE("GPL"); |
355 | |||
356 | module_init(k8temp_init) | ||
357 | module_exit(k8temp_exit) | ||
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 9b382ec2c3bd..6da9696e1827 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c | |||
@@ -134,8 +134,7 @@ static inline u64 div64_u64_safe(u64 dividend, u64 divisor) | |||
134 | return div64_u64(dividend, divisor); | 134 | return div64_u64(dividend, divisor); |
135 | } | 135 | } |
136 | 136 | ||
137 | static unsigned int get_ohm_of_thermistor(struct ntc_data *data, | 137 | static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV) |
138 | unsigned int uV) | ||
139 | { | 138 | { |
140 | struct ntc_thermistor_platform_data *pdata = data->pdata; | 139 | struct ntc_thermistor_platform_data *pdata = data->pdata; |
141 | u64 mV = uV / 1000; | 140 | u64 mV = uV / 1000; |
@@ -146,12 +145,12 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data, | |||
146 | 145 | ||
147 | if (mV == 0) { | 146 | if (mV == 0) { |
148 | if (pdata->connect == NTC_CONNECTED_POSITIVE) | 147 | if (pdata->connect == NTC_CONNECTED_POSITIVE) |
149 | return UINT_MAX; | 148 | return INT_MAX; |
150 | return 0; | 149 | return 0; |
151 | } | 150 | } |
152 | if (mV >= pmV) | 151 | if (mV >= pmV) |
153 | return (pdata->connect == NTC_CONNECTED_POSITIVE) ? | 152 | return (pdata->connect == NTC_CONNECTED_POSITIVE) ? |
154 | 0 : UINT_MAX; | 153 | 0 : INT_MAX; |
155 | 154 | ||
156 | if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0) | 155 | if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0) |
157 | N = div64_u64_safe(pdO * (pmV - mV), mV); | 156 | N = div64_u64_safe(pdO * (pmV - mV), mV); |
@@ -163,113 +162,109 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data, | |||
163 | else | 162 | else |
164 | N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV); | 163 | N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV); |
165 | 164 | ||
166 | return (unsigned int) N; | 165 | if (N > INT_MAX) |
166 | N = INT_MAX; | ||
167 | return N; | ||
167 | } | 168 | } |
168 | 169 | ||
169 | static int lookup_comp(struct ntc_data *data, | 170 | static void lookup_comp(struct ntc_data *data, unsigned int ohm, |
170 | unsigned int ohm, int *i_low, int *i_high) | 171 | int *i_low, int *i_high) |
171 | { | 172 | { |
172 | int start, end, mid = -1; | 173 | int start, end, mid; |
174 | |||
175 | /* | ||
176 | * Handle special cases: Resistance is higher than or equal to | ||
177 | * resistance in first table entry, or resistance is lower or equal | ||
178 | * to resistance in last table entry. | ||
179 | * In these cases, return i_low == i_high, either pointing to the | ||
180 | * beginning or to the end of the table depending on the condition. | ||
181 | */ | ||
182 | if (ohm >= data->comp[0].ohm) { | ||
183 | *i_low = 0; | ||
184 | *i_high = 0; | ||
185 | return; | ||
186 | } | ||
187 | if (ohm <= data->comp[data->n_comp - 1].ohm) { | ||
188 | *i_low = data->n_comp - 1; | ||
189 | *i_high = data->n_comp - 1; | ||
190 | return; | ||
191 | } | ||
173 | 192 | ||
174 | /* Do a binary search on compensation table */ | 193 | /* Do a binary search on compensation table */ |
175 | start = 0; | 194 | start = 0; |
176 | end = data->n_comp; | 195 | end = data->n_comp; |
177 | 196 | while (start < end) { | |
178 | while (end > start) { | ||
179 | mid = start + (end - start) / 2; | 197 | mid = start + (end - start) / 2; |
180 | if (data->comp[mid].ohm < ohm) | 198 | /* |
199 | * start <= mid < end | ||
200 | * data->comp[start].ohm > ohm >= data->comp[end].ohm | ||
201 | * | ||
202 | * We could check for "ohm == data->comp[mid].ohm" here, but | ||
203 | * that is a quite unlikely condition, and we would have to | ||
204 | * check again after updating start. Check it at the end instead | ||
205 | * for simplicity. | ||
206 | */ | ||
207 | if (ohm >= data->comp[mid].ohm) { | ||
181 | end = mid; | 208 | end = mid; |
182 | else if (data->comp[mid].ohm > ohm) | ||
183 | start = mid + 1; | ||
184 | else | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | if (mid == 0) { | ||
189 | if (data->comp[mid].ohm > ohm) { | ||
190 | *i_high = mid; | ||
191 | *i_low = mid + 1; | ||
192 | return 0; | ||
193 | } else { | ||
194 | *i_low = mid; | ||
195 | *i_high = -1; | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | } | ||
199 | if (mid == (data->n_comp - 1)) { | ||
200 | if (data->comp[mid].ohm <= ohm) { | ||
201 | *i_low = mid; | ||
202 | *i_high = mid - 1; | ||
203 | return 0; | ||
204 | } else { | 209 | } else { |
205 | *i_low = -1; | 210 | start = mid + 1; |
206 | *i_high = mid; | 211 | /* |
207 | return -EINVAL; | 212 | * ohm >= data->comp[start].ohm might be true here, |
213 | * since we set start to mid + 1. In that case, we are | ||
214 | * done. We could keep going, but the condition is quite | ||
215 | * likely to occur, so it is worth checking for it. | ||
216 | */ | ||
217 | if (ohm >= data->comp[start].ohm) | ||
218 | end = start; | ||
208 | } | 219 | } |
220 | /* | ||
221 | * start <= end | ||
222 | * data->comp[start].ohm >= ohm >= data->comp[end].ohm | ||
223 | */ | ||
209 | } | 224 | } |
210 | 225 | /* | |
211 | if (data->comp[mid].ohm <= ohm) { | 226 | * start == end |
212 | *i_low = mid; | 227 | * ohm >= data->comp[end].ohm |
213 | *i_high = mid - 1; | 228 | */ |
214 | } else { | 229 | *i_low = end; |
215 | *i_low = mid + 1; | 230 | if (ohm == data->comp[end].ohm) |
216 | *i_high = mid; | 231 | *i_high = end; |
217 | } | 232 | else |
218 | 233 | *i_high = end - 1; | |
219 | return 0; | ||
220 | } | 234 | } |
221 | 235 | ||
222 | static int get_temp_mC(struct ntc_data *data, unsigned int ohm, int *temp) | 236 | static int get_temp_mC(struct ntc_data *data, unsigned int ohm) |
223 | { | 237 | { |
224 | int low, high; | 238 | int low, high; |
225 | int ret; | 239 | int temp; |
226 | 240 | ||
227 | ret = lookup_comp(data, ohm, &low, &high); | 241 | lookup_comp(data, ohm, &low, &high); |
228 | if (ret) { | 242 | if (low == high) { |
229 | /* Unable to use linear approximation */ | 243 | /* Unable to use linear approximation */ |
230 | if (low != -1) | 244 | temp = data->comp[low].temp_C * 1000; |
231 | *temp = data->comp[low].temp_C * 1000; | ||
232 | else if (high != -1) | ||
233 | *temp = data->comp[high].temp_C * 1000; | ||
234 | else | ||
235 | return ret; | ||
236 | } else { | 245 | } else { |
237 | *temp = data->comp[low].temp_C * 1000 + | 246 | temp = data->comp[low].temp_C * 1000 + |
238 | ((data->comp[high].temp_C - data->comp[low].temp_C) * | 247 | ((data->comp[high].temp_C - data->comp[low].temp_C) * |
239 | 1000 * ((int)ohm - (int)data->comp[low].ohm)) / | 248 | 1000 * ((int)ohm - (int)data->comp[low].ohm)) / |
240 | ((int)data->comp[high].ohm - (int)data->comp[low].ohm); | 249 | ((int)data->comp[high].ohm - (int)data->comp[low].ohm); |
241 | } | 250 | } |
242 | 251 | return temp; | |
243 | return 0; | ||
244 | } | 252 | } |
245 | 253 | ||
246 | static int ntc_thermistor_read(struct ntc_data *data, int *temp) | 254 | static int ntc_thermistor_get_ohm(struct ntc_data *data) |
247 | { | 255 | { |
248 | int ret; | 256 | int read_uV; |
249 | int read_ohm, read_uV; | 257 | |
250 | unsigned int ohm = 0; | 258 | if (data->pdata->read_ohm) |
251 | 259 | return data->pdata->read_ohm(); | |
252 | if (data->pdata->read_ohm) { | ||
253 | read_ohm = data->pdata->read_ohm(); | ||
254 | if (read_ohm < 0) | ||
255 | return read_ohm; | ||
256 | ohm = (unsigned int)read_ohm; | ||
257 | } | ||
258 | 260 | ||
259 | if (data->pdata->read_uV) { | 261 | if (data->pdata->read_uV) { |
260 | read_uV = data->pdata->read_uV(); | 262 | read_uV = data->pdata->read_uV(); |
261 | if (read_uV < 0) | 263 | if (read_uV < 0) |
262 | return read_uV; | 264 | return read_uV; |
263 | ohm = get_ohm_of_thermistor(data, (unsigned int)read_uV); | 265 | return get_ohm_of_thermistor(data, read_uV); |
264 | } | ||
265 | |||
266 | ret = get_temp_mC(data, ohm, temp); | ||
267 | if (ret) { | ||
268 | dev_dbg(data->dev, "Sensor reading function not available.\n"); | ||
269 | return ret; | ||
270 | } | 266 | } |
271 | 267 | return -EINVAL; | |
272 | return 0; | ||
273 | } | 268 | } |
274 | 269 | ||
275 | static ssize_t ntc_show_name(struct device *dev, | 270 | static ssize_t ntc_show_name(struct device *dev, |
@@ -290,12 +285,13 @@ static ssize_t ntc_show_temp(struct device *dev, | |||
290 | struct device_attribute *attr, char *buf) | 285 | struct device_attribute *attr, char *buf) |
291 | { | 286 | { |
292 | struct ntc_data *data = dev_get_drvdata(dev); | 287 | struct ntc_data *data = dev_get_drvdata(dev); |
293 | int temp, ret; | 288 | int ohm; |
294 | 289 | ||
295 | ret = ntc_thermistor_read(data, &temp); | 290 | ohm = ntc_thermistor_get_ohm(data); |
296 | if (ret) | 291 | if (ohm < 0) |
297 | return ret; | 292 | return ohm; |
298 | return sprintf(buf, "%d\n", temp); | 293 | |
294 | return sprintf(buf, "%d\n", get_temp_mC(data, ohm)); | ||
299 | } | 295 | } |
300 | 296 | ||
301 | static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0); | 297 | static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0); |
@@ -326,14 +322,14 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev) | |||
326 | 322 | ||
327 | /* Either one of the two is required. */ | 323 | /* Either one of the two is required. */ |
328 | if (!pdata->read_uV && !pdata->read_ohm) { | 324 | if (!pdata->read_uV && !pdata->read_ohm) { |
329 | dev_err(&pdev->dev, "Both read_uV and read_ohm missing." | 325 | dev_err(&pdev->dev, |
330 | "Need either one of the two.\n"); | 326 | "Both read_uV and read_ohm missing. Need either one of the two.\n"); |
331 | return -EINVAL; | 327 | return -EINVAL; |
332 | } | 328 | } |
333 | 329 | ||
334 | if (pdata->read_uV && pdata->read_ohm) { | 330 | if (pdata->read_uV && pdata->read_ohm) { |
335 | dev_warn(&pdev->dev, "Only one of read_uV and read_ohm " | 331 | dev_warn(&pdev->dev, |
336 | "is needed; ignoring read_uV.\n"); | 332 | "Only one of read_uV and read_ohm is needed; ignoring read_uV.\n"); |
337 | pdata->read_uV = NULL; | 333 | pdata->read_uV = NULL; |
338 | } | 334 | } |
339 | 335 | ||
@@ -344,12 +340,12 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev) | |||
344 | NTC_CONNECTED_POSITIVE) || | 340 | NTC_CONNECTED_POSITIVE) || |
345 | (pdata->connect != NTC_CONNECTED_POSITIVE && | 341 | (pdata->connect != NTC_CONNECTED_POSITIVE && |
346 | pdata->connect != NTC_CONNECTED_GROUND))) { | 342 | pdata->connect != NTC_CONNECTED_GROUND))) { |
347 | dev_err(&pdev->dev, "Required data to use read_uV not " | 343 | dev_err(&pdev->dev, |
348 | "supplied.\n"); | 344 | "Required data to use read_uV not supplied.\n"); |
349 | return -EINVAL; | 345 | return -EINVAL; |
350 | } | 346 | } |
351 | 347 | ||
352 | data = kzalloc(sizeof(struct ntc_data), GFP_KERNEL); | 348 | data = devm_kzalloc(&pdev->dev, sizeof(struct ntc_data), GFP_KERNEL); |
353 | if (!data) | 349 | if (!data) |
354 | return -ENOMEM; | 350 | return -ENOMEM; |
355 | 351 | ||
@@ -370,8 +366,7 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev) | |||
370 | dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n", | 366 | dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n", |
371 | pdev->id_entry->driver_data, | 367 | pdev->id_entry->driver_data, |
372 | pdev->id_entry->name); | 368 | pdev->id_entry->name); |
373 | ret = -EINVAL; | 369 | return -EINVAL; |
374 | goto err; | ||
375 | } | 370 | } |
376 | 371 | ||
377 | platform_set_drvdata(pdev, data); | 372 | platform_set_drvdata(pdev, data); |
@@ -379,13 +374,13 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev) | |||
379 | ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group); | 374 | ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group); |
380 | if (ret) { | 375 | if (ret) { |
381 | dev_err(data->dev, "unable to create sysfs files\n"); | 376 | dev_err(data->dev, "unable to create sysfs files\n"); |
382 | goto err; | 377 | return ret; |
383 | } | 378 | } |
384 | 379 | ||
385 | data->hwmon_dev = hwmon_device_register(data->dev); | 380 | data->hwmon_dev = hwmon_device_register(data->dev); |
386 | if (IS_ERR_OR_NULL(data->hwmon_dev)) { | 381 | if (IS_ERR(data->hwmon_dev)) { |
387 | dev_err(data->dev, "unable to register as hwmon device.\n"); | 382 | dev_err(data->dev, "unable to register as hwmon device.\n"); |
388 | ret = -EINVAL; | 383 | ret = PTR_ERR(data->hwmon_dev); |
389 | goto err_after_sysfs; | 384 | goto err_after_sysfs; |
390 | } | 385 | } |
391 | 386 | ||
@@ -395,8 +390,6 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev) | |||
395 | return 0; | 390 | return 0; |
396 | err_after_sysfs: | 391 | err_after_sysfs: |
397 | sysfs_remove_group(&data->dev->kobj, &ntc_attr_group); | 392 | sysfs_remove_group(&data->dev->kobj, &ntc_attr_group); |
398 | err: | ||
399 | kfree(data); | ||
400 | return ret; | 393 | return ret; |
401 | } | 394 | } |
402 | 395 | ||
@@ -408,8 +401,6 @@ static int __devexit ntc_thermistor_remove(struct platform_device *pdev) | |||
408 | sysfs_remove_group(&data->dev->kobj, &ntc_attr_group); | 401 | sysfs_remove_group(&data->dev->kobj, &ntc_attr_group); |
409 | platform_set_drvdata(pdev, NULL); | 402 | platform_set_drvdata(pdev, NULL); |
410 | 403 | ||
411 | kfree(data); | ||
412 | |||
413 | return 0; | 404 | return 0; |
414 | } | 405 | } |
415 | 406 | ||
diff --git a/include/linux/platform_data/ina2xx.h b/include/linux/platform_data/ina2xx.h new file mode 100644 index 000000000000..9abc0ca7259b --- /dev/null +++ b/include/linux/platform_data/ina2xx.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * Driver for Texas Instruments INA219, INA226 power monitor chips | ||
3 | * | ||
4 | * Copyright (C) 2012 Lothar Felten <l-felten@ti.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * For further information, see the Documentation/hwmon/ina2xx file. | ||
11 | */ | ||
12 | |||
13 | /** | ||
14 | * struct ina2xx_platform_data - ina2xx info | ||
15 | * @shunt_uohms shunt resistance in microohms | ||
16 | */ | ||
17 | struct ina2xx_platform_data { | ||
18 | long shunt_uohms; | ||
19 | }; | ||