diff options
32 files changed, 1695 insertions, 594 deletions
diff --git a/Documentation/devicetree/bindings/hwmon/mcp3021.txt b/Documentation/devicetree/bindings/hwmon/mcp3021.txt new file mode 100644 index 000000000000..294318ba6914 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/mcp3021.txt | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | mcp3021 properties | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Must be one of the following: | ||
| 5 | - "microchip,mcp3021" for mcp3021 | ||
| 6 | - "microchip,mcp3221" for mcp3221 | ||
| 7 | - reg: I2C address | ||
| 8 | |||
| 9 | Optional properties: | ||
| 10 | |||
| 11 | - reference-voltage-microvolt | ||
| 12 | Reference voltage in microvolt (uV) | ||
| 13 | |||
| 14 | Example: | ||
| 15 | |||
| 16 | mcp3021@4d { | ||
| 17 | compatible = "microchip,mcp3021"; | ||
| 18 | reg = <0x4d>; | ||
| 19 | |||
| 20 | reference-voltage-microvolt = <4500000>; /* 4.5 V */ | ||
| 21 | }; | ||
diff --git a/Documentation/devicetree/bindings/hwmon/tmp108.txt b/Documentation/devicetree/bindings/hwmon/tmp108.txt new file mode 100644 index 000000000000..8c4b10df86d9 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/tmp108.txt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | TMP108 temperature sensor | ||
| 2 | ------------------------- | ||
| 3 | |||
| 4 | This device supports I2C only. | ||
| 5 | |||
| 6 | Requires node properties: | ||
| 7 | - compatible : "ti,tmp108" | ||
| 8 | - reg : the I2C address of the device. This is 0x48, 0x49, 0x4a, or 0x4b. | ||
| 9 | |||
| 10 | Example: | ||
| 11 | tmp108@48 { | ||
| 12 | compatible = "ti,tmp108"; | ||
| 13 | reg = <0x48>; | ||
| 14 | }; | ||
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 03349ad5abfa..df720ca00fcf 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt | |||
| @@ -124,6 +124,8 @@ microchip,mcp4662-502 Microchip 8-bit Dual I2C Digital Potentiometer with NV Mem | |||
| 124 | microchip,mcp4662-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k) | 124 | microchip,mcp4662-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k) |
| 125 | microchip,mcp4662-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k) | 125 | microchip,mcp4662-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k) |
| 126 | microchip,mcp4662-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k) | 126 | microchip,mcp4662-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k) |
| 127 | microchip,tc654 PWM Fan Speed Controller With Fan Fault Detection | ||
| 128 | microchip,tc655 PWM Fan Speed Controller With Fan Fault Detection | ||
| 127 | miramems,da226 MiraMEMS DA226 2-axis 14-bit digital accelerometer | 129 | miramems,da226 MiraMEMS DA226 2-axis 14-bit digital accelerometer |
| 128 | miramems,da280 MiraMEMS DA280 3-axis 14-bit digital accelerometer | 130 | miramems,da280 MiraMEMS DA280 3-axis 14-bit digital accelerometer |
| 129 | miramems,da311 MiraMEMS DA311 3-axis 12-bit digital accelerometer | 131 | miramems,da311 MiraMEMS DA311 3-axis 12-bit digital accelerometer |
diff --git a/Documentation/hwmon/hwmon-kernel-api.txt b/Documentation/hwmon/hwmon-kernel-api.txt index ef9d74947f5c..2505ae67e2b6 100644 --- a/Documentation/hwmon/hwmon-kernel-api.txt +++ b/Documentation/hwmon/hwmon-kernel-api.txt | |||
| @@ -23,7 +23,6 @@ Each hardware monitoring driver must #include <linux/hwmon.h> and, in most | |||
| 23 | cases, <linux/hwmon-sysfs.h>. linux/hwmon.h declares the following | 23 | cases, <linux/hwmon-sysfs.h>. linux/hwmon.h declares the following |
| 24 | register/unregister functions: | 24 | register/unregister functions: |
| 25 | 25 | ||
| 26 | struct device *hwmon_device_register(struct device *dev); | ||
| 27 | struct device * | 26 | struct device * |
| 28 | hwmon_device_register_with_groups(struct device *dev, const char *name, | 27 | hwmon_device_register_with_groups(struct device *dev, const char *name, |
| 29 | void *drvdata, | 28 | void *drvdata, |
| @@ -38,36 +37,31 @@ struct device * | |||
| 38 | hwmon_device_register_with_info(struct device *dev, | 37 | hwmon_device_register_with_info(struct device *dev, |
| 39 | const char *name, void *drvdata, | 38 | const char *name, void *drvdata, |
| 40 | const struct hwmon_chip_info *info, | 39 | const struct hwmon_chip_info *info, |
| 41 | const struct attribute_group **groups); | 40 | const struct attribute_group **extra_groups); |
| 42 | 41 | ||
| 43 | struct device * | 42 | struct device * |
| 44 | devm_hwmon_device_register_with_info(struct device *dev, | 43 | devm_hwmon_device_register_with_info(struct device *dev, |
| 45 | const char *name, | 44 | const char *name, |
| 46 | void *drvdata, | 45 | void *drvdata, |
| 47 | const struct hwmon_chip_info *info, | 46 | const struct hwmon_chip_info *info, |
| 48 | const struct attribute_group **groups); | 47 | const struct attribute_group **extra_groups); |
| 49 | 48 | ||
| 50 | void hwmon_device_unregister(struct device *dev); | 49 | void hwmon_device_unregister(struct device *dev); |
| 51 | void devm_hwmon_device_unregister(struct device *dev); | 50 | void devm_hwmon_device_unregister(struct device *dev); |
| 52 | 51 | ||
| 53 | hwmon_device_register registers a hardware monitoring device. The parameter | 52 | hwmon_device_register_with_groups registers a hardware monitoring device. |
| 54 | of this function is a pointer to the parent device. | 53 | The first parameter of this function is a pointer to the parent device. |
| 55 | This function returns a pointer to the newly created hardware monitoring device | 54 | The name parameter is a pointer to the hwmon device name. The registration |
| 56 | or PTR_ERR for failure. If this registration function is used, hardware | 55 | function wil create a name sysfs attribute pointing to this name. |
| 57 | monitoring sysfs attributes are expected to have been created and attached to | 56 | The drvdata parameter is the pointer to the local driver data. |
| 58 | the parent device prior to calling hwmon_device_register. A name attribute must | 57 | hwmon_device_register_with_groups will attach this pointer to the newly |
| 59 | have been created by the caller. | 58 | allocated hwmon device. The pointer can be retrieved by the driver using |
| 60 | 59 | dev_get_drvdata() on the hwmon device pointer. The groups parameter is | |
| 61 | hwmon_device_register_with_groups is similar to hwmon_device_register. However, | ||
| 62 | it has additional parameters. The name parameter is a pointer to the hwmon | ||
| 63 | device name. The registration function wil create a name sysfs attribute | ||
| 64 | pointing to this name. The drvdata parameter is the pointer to the local | ||
| 65 | driver data. hwmon_device_register_with_groups will attach this pointer | ||
| 66 | to the newly allocated hwmon device. The pointer can be retrieved by the driver | ||
| 67 | using dev_get_drvdata() on the hwmon device pointer. The groups parameter is | ||
| 68 | a pointer to a list of sysfs attribute groups. The list must be NULL terminated. | 60 | a pointer to a list of sysfs attribute groups. The list must be NULL terminated. |
| 69 | hwmon_device_register_with_groups creates the hwmon device with name attribute | 61 | hwmon_device_register_with_groups creates the hwmon device with name attribute |
| 70 | as well as all sysfs attributes attached to the hwmon device. | 62 | as well as all sysfs attributes attached to the hwmon device. |
| 63 | This function returns a pointer to the newly created hardware monitoring device | ||
| 64 | or PTR_ERR for failure. | ||
| 71 | 65 | ||
| 72 | devm_hwmon_device_register_with_groups is similar to | 66 | devm_hwmon_device_register_with_groups is similar to |
| 73 | hwmon_device_register_with_groups. However, it is device managed, meaning the | 67 | hwmon_device_register_with_groups. However, it is device managed, meaning the |
| @@ -87,13 +81,13 @@ hwmon_device_unregister deregisters a registered hardware monitoring device. | |||
| 87 | The parameter of this function is the pointer to the registered hardware | 81 | The parameter of this function is the pointer to the registered hardware |
| 88 | monitoring device structure. This function must be called from the driver | 82 | monitoring device structure. This function must be called from the driver |
| 89 | remove function if the hardware monitoring device was registered with | 83 | remove function if the hardware monitoring device was registered with |
| 90 | hwmon_device_register, hwmon_device_register_with_groups, or | 84 | hwmon_device_register_with_groups or hwmon_device_register_with_info. |
| 91 | hwmon_device_register_with_info. | ||
| 92 | 85 | ||
| 93 | devm_hwmon_device_unregister does not normally have to be called. It is only | 86 | devm_hwmon_device_unregister does not normally have to be called. It is only |
| 94 | needed for error handling, and only needed if the driver probe fails after | 87 | needed for error handling, and only needed if the driver probe fails after |
| 95 | the call to devm_hwmon_device_register_with_groups and if the automatic | 88 | the call to devm_hwmon_device_register_with_groups or |
| 96 | (device managed) removal would be too late. | 89 | hwmon_device_register_with_info and if the automatic (device managed) |
| 90 | removal would be too late. | ||
| 97 | 91 | ||
| 98 | Using devm_hwmon_device_register_with_info() | 92 | Using devm_hwmon_device_register_with_info() |
| 99 | -------------------------------------------- | 93 | -------------------------------------------- |
| @@ -106,9 +100,9 @@ const char *name Device name | |||
| 106 | void *drvdata Driver private data | 100 | void *drvdata Driver private data |
| 107 | const struct hwmon_chip_info *info | 101 | const struct hwmon_chip_info *info |
| 108 | Pointer to chip description. | 102 | Pointer to chip description. |
| 109 | const struct attribute_group **groups | 103 | const struct attribute_group **extra_groups |
| 110 | Null-terminated list of additional sysfs attribute | 104 | Null-terminated list of additional non-standard |
| 111 | groups. | 105 | sysfs attribute groups. |
| 112 | 106 | ||
| 113 | This function returns a pointer to the created hardware monitoring device | 107 | This function returns a pointer to the created hardware monitoring device |
| 114 | on success and a negative error code for failure. | 108 | on success and a negative error code for failure. |
| @@ -160,7 +154,7 @@ It contains following fields: | |||
| 160 | * type: The hardware monitoring sensor type. | 154 | * type: The hardware monitoring sensor type. |
| 161 | Supported sensor types are | 155 | Supported sensor types are |
| 162 | * hwmon_chip A virtual sensor type, used to describe attributes | 156 | * hwmon_chip A virtual sensor type, used to describe attributes |
| 163 | which apply to the entire chip. | 157 | * which are not bound to a specific input or output |
| 164 | * hwmon_temp Temperature sensor | 158 | * hwmon_temp Temperature sensor |
| 165 | * hwmon_in Voltage sensor | 159 | * hwmon_in Voltage sensor |
| 166 | * hwmon_curr Current sensor | 160 | * hwmon_curr Current sensor |
| @@ -293,9 +287,9 @@ Driver-provided sysfs attributes | |||
| 293 | 287 | ||
| 294 | If the hardware monitoring device is registered with | 288 | If the hardware monitoring device is registered with |
| 295 | hwmon_device_register_with_info or devm_hwmon_device_register_with_info, | 289 | hwmon_device_register_with_info or devm_hwmon_device_register_with_info, |
| 296 | it is most likely not necessary to provide sysfs attributes. Only non-standard | 290 | it is most likely not necessary to provide sysfs attributes. Only additional |
| 297 | sysfs attributes need to be provided when one of those registration functions | 291 | non-standard sysfs attributes need to be provided when one of those registration |
| 298 | is used. | 292 | functions is used. |
| 299 | 293 | ||
| 300 | The header file linux/hwmon-sysfs.h provides a number of useful macros to | 294 | The header file linux/hwmon-sysfs.h provides a number of useful macros to |
| 301 | declare and use hardware monitoring sysfs attributes. | 295 | declare and use hardware monitoring sysfs attributes. |
diff --git a/Documentation/hwmon/tc654 b/Documentation/hwmon/tc654 new file mode 100644 index 000000000000..91a2843f5f98 --- /dev/null +++ b/Documentation/hwmon/tc654 | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | Kernel driver tc654 | ||
| 2 | =================== | ||
| 3 | |||
| 4 | Supported chips: | ||
| 5 | * Microship TC654 and TC655 | ||
| 6 | Prefix: 'tc654' | ||
| 7 | Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/20001734C.pdf | ||
| 8 | |||
| 9 | Authors: | ||
| 10 | Chris Packham <chris.packham@alliedtelesis.co.nz> | ||
| 11 | Masahiko Iwamoto <iwamoto@allied-telesis.co.jp> | ||
| 12 | |||
| 13 | Description | ||
| 14 | ----------- | ||
| 15 | This driver implements support for the Microchip TC654 and TC655. | ||
| 16 | |||
| 17 | The TC654 uses the 2-wire interface compatible with the SMBUS 2.0 | ||
| 18 | specification. The TC654 has two (2) inputs for measuring fan RPM and | ||
| 19 | one (1) PWM output which can be used for fan control. | ||
| 20 | |||
| 21 | Configuration Notes | ||
| 22 | ------------------- | ||
| 23 | Ordinarily the pwm1_mode ABI is used for controlling the pwm output | ||
| 24 | mode. However, for this chip the output is always pwm, and the | ||
| 25 | pwm1_mode determines if the pwm output is controlled via the pwm1 value | ||
| 26 | or via the Vin analog input. | ||
| 27 | |||
| 28 | |||
| 29 | Setting pwm1_mode to 1 will cause the pwm output to be driven based on | ||
| 30 | the pwm1 value. Setting pwm1_mode to 0 will cause the pwm output to be | ||
| 31 | driven based on the Vin input. | ||
diff --git a/Documentation/hwmon/tmp108 b/Documentation/hwmon/tmp108 new file mode 100644 index 000000000000..25802df23010 --- /dev/null +++ b/Documentation/hwmon/tmp108 | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | Kernel driver tmp108 | ||
| 2 | ==================== | ||
| 3 | |||
| 4 | Supported chips: | ||
| 5 | * Texas Instruments TMP108 | ||
| 6 | Prefix: 'tmp108' | ||
| 7 | Addresses scanned: none | ||
| 8 | Datasheet: http://www.ti.com/product/tmp108 | ||
| 9 | |||
| 10 | Author: | ||
| 11 | John Muir <john@jmuir.com> | ||
| 12 | |||
| 13 | Description | ||
| 14 | ----------- | ||
| 15 | |||
| 16 | The Texas Instruments TMP108 implements one temperature sensor. An alert pin | ||
| 17 | can be set when temperatures exceed minimum or maximum values plus or minus a | ||
| 18 | hysteresis value. (This driver does not support interrupts for the alert pin, | ||
| 19 | and the device runs in comparator mode.) | ||
| 20 | |||
| 21 | The sensor is accurate to 0.75C over the range of -25 to +85 C, and to 1.0 | ||
| 22 | degree from -40 to +125 C. Resolution of the sensor is 0.0625 degree. The | ||
| 23 | operating temperature has a minimum of -55 C and a maximum of +150 C. | ||
| 24 | Hysteresis values can be set to 0, 1, 2, or 4C. | ||
| 25 | |||
| 26 | The TMP108 has a programmable update rate that can select between 8, 4, 1, and | ||
| 27 | 0.5 Hz. | ||
| 28 | |||
| 29 | By default the TMP108 reads the temperature continuously. To conserve power, | ||
| 30 | the TMP108 has a one-shot mode where the device is normally shut-down. When a | ||
| 31 | one shot is requested the temperature is read, the result can be retrieved, | ||
| 32 | and then the device is shut down automatically. (This driver only supports | ||
| 33 | continuous mode.) | ||
| 34 | |||
| 35 | The driver provides the common sysfs-interface for temperatures (see | ||
| 36 | Documentation/hwmon/sysfs-interface under Temperatures). | ||
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 45cef3d2c75c..190d270b20a2 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
| @@ -907,6 +907,17 @@ config SENSORS_MCP3021 | |||
| 907 | This driver can also be built as a module. If so, the module | 907 | This driver can also be built as a module. If so, the module |
| 908 | will be called mcp3021. | 908 | will be called mcp3021. |
| 909 | 909 | ||
| 910 | config SENSORS_TC654 | ||
| 911 | tristate "Microchip TC654/TC655 and compatibles" | ||
| 912 | depends on I2C | ||
| 913 | help | ||
| 914 | If you say yes here you get support for TC654 and TC655. | ||
| 915 | The TC654 and TC655 are PWM mode fan speed controllers with | ||
| 916 | FanSense technology for use with brushless DC fans. | ||
| 917 | |||
| 918 | This driver can also be built as a module. If so, the module | ||
| 919 | will be called tc654. | ||
| 920 | |||
| 910 | config SENSORS_MENF21BMC_HWMON | 921 | config SENSORS_MENF21BMC_HWMON |
| 911 | tristate "MEN 14F021P00 BMC Hardware Monitoring" | 922 | tristate "MEN 14F021P00 BMC Hardware Monitoring" |
| 912 | depends on MFD_MENF21BMC | 923 | depends on MFD_MENF21BMC |
| @@ -1068,8 +1079,8 @@ config SENSORS_LM90 | |||
| 1068 | LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A, | 1079 | LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A, |
| 1069 | Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, | 1080 | Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, |
| 1070 | MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008, | 1081 | MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008, |
| 1071 | Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, and GMT G781 | 1082 | Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, GMT G781, and |
| 1072 | sensor chips. | 1083 | Texas Instruments TMP451 sensor chips. |
| 1073 | 1084 | ||
| 1074 | This driver can also be built as a module. If so, the module | 1085 | This driver can also be built as a module. If so, the module |
| 1075 | will be called lm90. | 1086 | will be called lm90. |
| @@ -1591,6 +1602,17 @@ config SENSORS_TMP103 | |||
| 1591 | This driver can also be built as a module. If so, the module | 1602 | This driver can also be built as a module. If so, the module |
| 1592 | will be called tmp103. | 1603 | will be called tmp103. |
| 1593 | 1604 | ||
| 1605 | config SENSORS_TMP108 | ||
| 1606 | tristate "Texas Instruments TMP108" | ||
| 1607 | depends on I2C | ||
| 1608 | select REGMAP_I2C | ||
| 1609 | help | ||
| 1610 | If you say yes here you get support for Texas Instruments TMP108 | ||
| 1611 | sensor chips. | ||
| 1612 | |||
| 1613 | This driver can also be built as a module. If so, the module | ||
| 1614 | will be called tmp108. | ||
| 1615 | |||
| 1594 | config SENSORS_TMP401 | 1616 | config SENSORS_TMP401 |
| 1595 | tristate "Texas Instruments TMP401 and compatibles" | 1617 | tristate "Texas Instruments TMP401 and compatibles" |
| 1596 | depends on I2C | 1618 | depends on I2C |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index aecf4ba17460..d2cb7e804a0f 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
| @@ -122,6 +122,7 @@ obj-$(CONFIG_SENSORS_MAX6697) += max6697.o | |||
| 122 | obj-$(CONFIG_SENSORS_MAX31790) += max31790.o | 122 | obj-$(CONFIG_SENSORS_MAX31790) += max31790.o |
| 123 | obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o | 123 | obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o |
| 124 | obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o | 124 | obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o |
| 125 | obj-$(CONFIG_SENSORS_TC654) += tc654.o | ||
| 125 | obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o | 126 | obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o |
| 126 | obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o | 127 | obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o |
| 127 | obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o | 128 | obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o |
| @@ -152,6 +153,7 @@ obj-$(CONFIG_SENSORS_TC74) += tc74.o | |||
| 152 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o | 153 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o |
| 153 | obj-$(CONFIG_SENSORS_TMP102) += tmp102.o | 154 | obj-$(CONFIG_SENSORS_TMP102) += tmp102.o |
| 154 | obj-$(CONFIG_SENSORS_TMP103) += tmp103.o | 155 | obj-$(CONFIG_SENSORS_TMP103) += tmp103.o |
| 156 | obj-$(CONFIG_SENSORS_TMP108) += tmp108.o | ||
| 155 | obj-$(CONFIG_SENSORS_TMP401) += tmp401.o | 157 | obj-$(CONFIG_SENSORS_TMP401) += tmp401.o |
| 156 | obj-$(CONFIG_SENSORS_TMP421) += tmp421.o | 158 | obj-$(CONFIG_SENSORS_TMP421) += tmp421.o |
| 157 | obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o | 159 | obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o |
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index d6c767ace916..1abb4609b412 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c | |||
| @@ -93,7 +93,7 @@ static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; | |||
| 93 | 93 | ||
| 94 | #define IN_FROM_REG(reg, scale) (((reg) * (scale) + 96) / 192) | 94 | #define IN_FROM_REG(reg, scale) (((reg) * (scale) + 96) / 192) |
| 95 | #define IN_TO_REG(val, scale) ((val) <= 0 ? 0 : \ | 95 | #define IN_TO_REG(val, scale) ((val) <= 0 ? 0 : \ |
| 96 | (val) * 192 >= (scale) * 255 ? 255 : \ | 96 | (val) >= (scale) * 255 / 192 ? 255 : \ |
| 97 | ((val) * 192 + (scale) / 2) / (scale)) | 97 | ((val) * 192 + (scale) / 2) / (scale)) |
| 98 | 98 | ||
| 99 | #define TEMP_FROM_REG(reg) ((reg) * 1000) | 99 | #define TEMP_FROM_REG(reg) ((reg) * 1000) |
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index e67b9a50ac7c..b2a5d9e5c590 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c | |||
| @@ -197,8 +197,9 @@ static int adm1026_scaling[] = { /* .001 Volts */ | |||
| 197 | }; | 197 | }; |
| 198 | #define NEG12_OFFSET 16000 | 198 | #define NEG12_OFFSET 16000 |
| 199 | #define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from)) | 199 | #define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from)) |
| 200 | #define INS_TO_REG(n, val) (clamp_val(SCALE(val, adm1026_scaling[n], 192),\ | 200 | #define INS_TO_REG(n, val) \ |
| 201 | 0, 255)) | 201 | SCALE(clamp_val(val, 0, 255 * adm1026_scaling[n] / 192), \ |
| 202 | adm1026_scaling[n], 192) | ||
| 202 | #define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n])) | 203 | #define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n])) |
| 203 | 204 | ||
| 204 | /* | 205 | /* |
| @@ -215,11 +216,11 @@ static int adm1026_scaling[] = { /* .001 Volts */ | |||
| 215 | #define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0) | 216 | #define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0) |
| 216 | 217 | ||
| 217 | /* Temperature is reported in 1 degC increments */ | 218 | /* Temperature is reported in 1 degC increments */ |
| 218 | #define TEMP_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \ | 219 | #define TEMP_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), \ |
| 219 | / 1000, -127, 127)) | 220 | 1000) |
| 220 | #define TEMP_FROM_REG(val) ((val) * 1000) | 221 | #define TEMP_FROM_REG(val) ((val) * 1000) |
| 221 | #define OFFSET_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \ | 222 | #define OFFSET_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), \ |
| 222 | / 1000, -127, 127)) | 223 | 1000) |
| 223 | #define OFFSET_FROM_REG(val) ((val) * 1000) | 224 | #define OFFSET_FROM_REG(val) ((val) * 1000) |
| 224 | 225 | ||
| 225 | #define PWM_TO_REG(val) (clamp_val(val, 0, 255)) | 226 | #define PWM_TO_REG(val) (clamp_val(val, 0, 255)) |
| @@ -233,7 +234,8 @@ static int adm1026_scaling[] = { /* .001 Volts */ | |||
| 233 | * indicates that the DAC could be used to drive the fans, but in our | 234 | * indicates that the DAC could be used to drive the fans, but in our |
| 234 | * example board (Arima HDAMA) it isn't connected to the fans at all. | 235 | * example board (Arima HDAMA) it isn't connected to the fans at all. |
| 235 | */ | 236 | */ |
| 236 | #define DAC_TO_REG(val) (clamp_val(((((val) * 255) + 500) / 2500), 0, 255)) | 237 | #define DAC_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val(val, 0, 2500) * 255, \ |
| 238 | 2500) | ||
| 237 | #define DAC_FROM_REG(val) (((val) * 2500) / 255) | 239 | #define DAC_FROM_REG(val) (((val) * 2500) / 255) |
| 238 | 240 | ||
| 239 | /* | 241 | /* |
| @@ -593,7 +595,10 @@ static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, | |||
| 593 | return err; | 595 | return err; |
| 594 | 596 | ||
| 595 | mutex_lock(&data->update_lock); | 597 | mutex_lock(&data->update_lock); |
| 596 | data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET); | 598 | data->in_min[16] = INS_TO_REG(16, |
| 599 | clamp_val(val, INT_MIN, | ||
| 600 | INT_MAX - NEG12_OFFSET) + | ||
| 601 | NEG12_OFFSET); | ||
| 597 | adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]); | 602 | adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]); |
| 598 | mutex_unlock(&data->update_lock); | 603 | mutex_unlock(&data->update_lock); |
| 599 | return count; | 604 | return count; |
| @@ -618,7 +623,10 @@ static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, | |||
| 618 | return err; | 623 | return err; |
| 619 | 624 | ||
| 620 | mutex_lock(&data->update_lock); | 625 | mutex_lock(&data->update_lock); |
| 621 | data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET); | 626 | data->in_max[16] = INS_TO_REG(16, |
| 627 | clamp_val(val, INT_MIN, | ||
| 628 | INT_MAX - NEG12_OFFSET) + | ||
| 629 | NEG12_OFFSET); | ||
| 622 | adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]); | 630 | adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]); |
| 623 | mutex_unlock(&data->update_lock); | 631 | mutex_unlock(&data->update_lock); |
| 624 | return count; | 632 | return count; |
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 2fe1828bd10b..72bf2489511e 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c | |||
| @@ -98,13 +98,15 @@ static inline unsigned int IN_FROM_REG(u8 reg, int n) | |||
| 98 | 98 | ||
| 99 | static inline u8 IN_TO_REG(unsigned long val, int n) | 99 | static inline u8 IN_TO_REG(unsigned long val, int n) |
| 100 | { | 100 | { |
| 101 | return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255); | 101 | val = clamp_val(val, 0, nom_mv[n] * 255 / 192); |
| 102 | return SCALE(val, 192, nom_mv[n]); | ||
| 102 | } | 103 | } |
| 103 | 104 | ||
| 104 | /* temperature range: -40..125, 127 disables temperature alarm */ | 105 | /* temperature range: -40..125, 127 disables temperature alarm */ |
| 105 | static inline s8 TEMP_TO_REG(long val) | 106 | static inline s8 TEMP_TO_REG(long val) |
| 106 | { | 107 | { |
| 107 | return clamp_val(SCALE(val, 1, 1000), -40, 127); | 108 | val = clamp_val(val, -40000, 127000); |
| 109 | return SCALE(val, 1, 1000); | ||
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | /* two fans, each with low fan speed limit */ | 112 | /* two fans, each with low fan speed limit */ |
| @@ -122,7 +124,8 @@ static inline unsigned int FAN_FROM_REG(u8 reg, u8 div) | |||
| 122 | /* analog out 0..1250mV */ | 124 | /* analog out 0..1250mV */ |
| 123 | static inline u8 AOUT_TO_REG(unsigned long val) | 125 | static inline u8 AOUT_TO_REG(unsigned long val) |
| 124 | { | 126 | { |
| 125 | return clamp_val(SCALE(val, 255, 1250), 0, 255); | 127 | val = clamp_val(val, 0, 1250); |
| 128 | return SCALE(val, 255, 1250); | ||
| 126 | } | 129 | } |
| 127 | 130 | ||
| 128 | static inline unsigned int AOUT_FROM_REG(u8 reg) | 131 | static inline unsigned int AOUT_FROM_REG(u8 reg) |
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 812fbc00f693..bdeaece9641d 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c | |||
| @@ -55,7 +55,7 @@ struct adt7411_data { | |||
| 55 | struct mutex device_lock; /* for "atomic" device accesses */ | 55 | struct mutex device_lock; /* for "atomic" device accesses */ |
| 56 | struct mutex update_lock; | 56 | struct mutex update_lock; |
| 57 | unsigned long next_update; | 57 | unsigned long next_update; |
| 58 | int vref_cached; | 58 | long vref_cached; |
| 59 | struct i2c_client *client; | 59 | struct i2c_client *client; |
| 60 | bool use_ext_temp; | 60 | bool use_ext_temp; |
| 61 | }; | 61 | }; |
| @@ -114,85 +114,6 @@ static int adt7411_modify_bit(struct i2c_client *client, u8 reg, u8 bit, | |||
| 114 | return ret; | 114 | return ret; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | static ssize_t adt7411_show_vdd(struct device *dev, | ||
| 118 | struct device_attribute *attr, char *buf) | ||
| 119 | { | ||
| 120 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
| 121 | struct i2c_client *client = data->client; | ||
| 122 | int ret = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB, | ||
| 123 | ADT7411_REG_VDD_MSB, 2); | ||
| 124 | |||
| 125 | return ret < 0 ? ret : sprintf(buf, "%u\n", ret * 7000 / 1024); | ||
| 126 | } | ||
| 127 | |||
| 128 | static ssize_t adt7411_show_temp(struct device *dev, | ||
| 129 | struct device_attribute *attr, char *buf) | ||
| 130 | { | ||
| 131 | int nr = to_sensor_dev_attr(attr)->index; | ||
| 132 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
| 133 | struct i2c_client *client = data->client; | ||
| 134 | int val; | ||
| 135 | struct { | ||
| 136 | u8 low; | ||
| 137 | u8 high; | ||
| 138 | } reg[2] = { | ||
| 139 | { ADT7411_REG_INT_TEMP_VDD_LSB, ADT7411_REG_INT_TEMP_MSB }, | ||
| 140 | { ADT7411_REG_EXT_TEMP_AIN14_LSB, | ||
| 141 | ADT7411_REG_EXT_TEMP_AIN1_MSB }, | ||
| 142 | }; | ||
| 143 | |||
| 144 | val = adt7411_read_10_bit(client, reg[nr].low, reg[nr].high, 0); | ||
| 145 | if (val < 0) | ||
| 146 | return val; | ||
| 147 | |||
| 148 | val = val & 0x200 ? val - 0x400 : val; /* 10 bit signed */ | ||
| 149 | |||
| 150 | return sprintf(buf, "%d\n", val * 250); | ||
| 151 | } | ||
| 152 | |||
| 153 | static ssize_t adt7411_show_input(struct device *dev, | ||
| 154 | struct device_attribute *attr, char *buf) | ||
| 155 | { | ||
| 156 | int nr = to_sensor_dev_attr(attr)->index; | ||
| 157 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
| 158 | struct i2c_client *client = data->client; | ||
| 159 | int val; | ||
| 160 | u8 lsb_reg, lsb_shift; | ||
| 161 | |||
| 162 | mutex_lock(&data->update_lock); | ||
| 163 | if (time_after_eq(jiffies, data->next_update)) { | ||
| 164 | val = i2c_smbus_read_byte_data(client, ADT7411_REG_CFG3); | ||
| 165 | if (val < 0) | ||
| 166 | goto exit_unlock; | ||
| 167 | |||
| 168 | if (val & ADT7411_CFG3_REF_VDD) { | ||
| 169 | val = adt7411_read_10_bit(client, | ||
| 170 | ADT7411_REG_INT_TEMP_VDD_LSB, | ||
| 171 | ADT7411_REG_VDD_MSB, 2); | ||
| 172 | if (val < 0) | ||
| 173 | goto exit_unlock; | ||
| 174 | |||
| 175 | data->vref_cached = val * 7000 / 1024; | ||
| 176 | } else { | ||
| 177 | data->vref_cached = 2250; | ||
| 178 | } | ||
| 179 | |||
| 180 | data->next_update = jiffies + HZ; | ||
| 181 | } | ||
| 182 | |||
| 183 | lsb_reg = ADT7411_REG_EXT_TEMP_AIN14_LSB + (nr >> 2); | ||
| 184 | lsb_shift = 2 * (nr & 0x03); | ||
| 185 | val = adt7411_read_10_bit(client, lsb_reg, | ||
| 186 | ADT7411_REG_EXT_TEMP_AIN1_MSB + nr, lsb_shift); | ||
| 187 | if (val < 0) | ||
| 188 | goto exit_unlock; | ||
| 189 | |||
| 190 | val = sprintf(buf, "%u\n", val * data->vref_cached / 1024); | ||
| 191 | exit_unlock: | ||
| 192 | mutex_unlock(&data->update_lock); | ||
| 193 | return val; | ||
| 194 | } | ||
| 195 | |||
| 196 | static ssize_t adt7411_show_bit(struct device *dev, | 117 | static ssize_t adt7411_show_bit(struct device *dev, |
| 197 | struct device_attribute *attr, char *buf) | 118 | struct device_attribute *attr, char *buf) |
| 198 | { | 119 | { |
| @@ -228,65 +149,157 @@ static ssize_t adt7411_set_bit(struct device *dev, | |||
| 228 | return ret < 0 ? ret : count; | 149 | return ret < 0 ? ret : count; |
| 229 | } | 150 | } |
| 230 | 151 | ||
| 231 | |||
| 232 | #define ADT7411_BIT_ATTR(__name, __reg, __bit) \ | 152 | #define ADT7411_BIT_ATTR(__name, __reg, __bit) \ |
| 233 | SENSOR_DEVICE_ATTR_2(__name, S_IRUGO | S_IWUSR, adt7411_show_bit, \ | 153 | SENSOR_DEVICE_ATTR_2(__name, S_IRUGO | S_IWUSR, adt7411_show_bit, \ |
| 234 | adt7411_set_bit, __bit, __reg) | 154 | adt7411_set_bit, __bit, __reg) |
| 235 | 155 | ||
| 236 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7411_show_temp, NULL, 0); | ||
| 237 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, adt7411_show_temp, NULL, 1); | ||
| 238 | static DEVICE_ATTR(in0_input, S_IRUGO, adt7411_show_vdd, NULL); | ||
| 239 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, adt7411_show_input, NULL, 0); | ||
| 240 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, adt7411_show_input, NULL, 1); | ||
| 241 | static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, adt7411_show_input, NULL, 2); | ||
| 242 | static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, adt7411_show_input, NULL, 3); | ||
| 243 | static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, adt7411_show_input, NULL, 4); | ||
| 244 | static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, adt7411_show_input, NULL, 5); | ||
| 245 | static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, adt7411_show_input, NULL, 6); | ||
| 246 | static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, adt7411_show_input, NULL, 7); | ||
| 247 | static ADT7411_BIT_ATTR(no_average, ADT7411_REG_CFG2, ADT7411_CFG2_DISABLE_AVG); | 156 | static ADT7411_BIT_ATTR(no_average, ADT7411_REG_CFG2, ADT7411_CFG2_DISABLE_AVG); |
| 248 | static ADT7411_BIT_ATTR(fast_sampling, ADT7411_REG_CFG3, ADT7411_CFG3_ADC_CLK_225); | 157 | static ADT7411_BIT_ATTR(fast_sampling, ADT7411_REG_CFG3, ADT7411_CFG3_ADC_CLK_225); |
| 249 | static ADT7411_BIT_ATTR(adc_ref_vdd, ADT7411_REG_CFG3, ADT7411_CFG3_REF_VDD); | 158 | static ADT7411_BIT_ATTR(adc_ref_vdd, ADT7411_REG_CFG3, ADT7411_CFG3_REF_VDD); |
| 250 | 159 | ||
| 251 | static struct attribute *adt7411_attrs[] = { | 160 | static struct attribute *adt7411_attrs[] = { |
| 252 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
| 253 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
| 254 | &dev_attr_in0_input.attr, | ||
| 255 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
| 256 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
| 257 | &sensor_dev_attr_in3_input.dev_attr.attr, | ||
| 258 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
| 259 | &sensor_dev_attr_in5_input.dev_attr.attr, | ||
| 260 | &sensor_dev_attr_in6_input.dev_attr.attr, | ||
| 261 | &sensor_dev_attr_in7_input.dev_attr.attr, | ||
| 262 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
| 263 | &sensor_dev_attr_no_average.dev_attr.attr, | 161 | &sensor_dev_attr_no_average.dev_attr.attr, |
| 264 | &sensor_dev_attr_fast_sampling.dev_attr.attr, | 162 | &sensor_dev_attr_fast_sampling.dev_attr.attr, |
| 265 | &sensor_dev_attr_adc_ref_vdd.dev_attr.attr, | 163 | &sensor_dev_attr_adc_ref_vdd.dev_attr.attr, |
| 266 | NULL | 164 | NULL |
| 267 | }; | 165 | }; |
| 166 | ATTRIBUTE_GROUPS(adt7411); | ||
| 268 | 167 | ||
| 269 | static umode_t adt7411_attrs_visible(struct kobject *kobj, | 168 | static int adt7411_read_in_vdd(struct device *dev, u32 attr, long *val) |
| 270 | struct attribute *attr, int index) | ||
| 271 | { | 169 | { |
| 272 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 273 | struct adt7411_data *data = dev_get_drvdata(dev); | 170 | struct adt7411_data *data = dev_get_drvdata(dev); |
| 274 | bool visible = true; | 171 | struct i2c_client *client = data->client; |
| 172 | int ret; | ||
| 275 | 173 | ||
| 276 | if (attr == &sensor_dev_attr_temp2_input.dev_attr.attr) | 174 | switch (attr) { |
| 277 | visible = data->use_ext_temp; | 175 | case hwmon_in_input: |
| 278 | else if (attr == &sensor_dev_attr_in1_input.dev_attr.attr || | 176 | ret = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB, |
| 279 | attr == &sensor_dev_attr_in2_input.dev_attr.attr) | 177 | ADT7411_REG_VDD_MSB, 2); |
| 280 | visible = !data->use_ext_temp; | 178 | if (ret < 0) |
| 179 | return ret; | ||
| 180 | *val = ret * 7000 / 1024; | ||
| 181 | return 0; | ||
| 182 | default: | ||
| 183 | return -EOPNOTSUPP; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, | ||
| 188 | long *val) | ||
| 189 | { | ||
| 190 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
| 191 | struct i2c_client *client = data->client; | ||
| 281 | 192 | ||
| 282 | return visible ? attr->mode : 0; | 193 | int ret; |
| 194 | int lsb_reg, lsb_shift; | ||
| 195 | int nr = channel - 1; | ||
| 196 | |||
| 197 | mutex_lock(&data->update_lock); | ||
| 198 | if (time_after_eq(jiffies, data->next_update)) { | ||
| 199 | ret = i2c_smbus_read_byte_data(client, ADT7411_REG_CFG3); | ||
| 200 | if (ret < 0) | ||
| 201 | goto exit_unlock; | ||
| 202 | |||
| 203 | if (ret & ADT7411_CFG3_REF_VDD) { | ||
| 204 | ret = adt7411_read_in_vdd(dev, hwmon_in_input, | ||
| 205 | &data->vref_cached); | ||
| 206 | if (ret < 0) | ||
| 207 | goto exit_unlock; | ||
| 208 | } else { | ||
| 209 | data->vref_cached = 2250; | ||
| 210 | } | ||
| 211 | |||
| 212 | data->next_update = jiffies + HZ; | ||
| 213 | } | ||
| 214 | |||
| 215 | switch (attr) { | ||
| 216 | case hwmon_in_input: | ||
| 217 | lsb_reg = ADT7411_REG_EXT_TEMP_AIN14_LSB + (nr >> 2); | ||
| 218 | lsb_shift = 2 * (nr & 0x03); | ||
| 219 | ret = adt7411_read_10_bit(client, lsb_reg, | ||
| 220 | ADT7411_REG_EXT_TEMP_AIN1_MSB + nr, | ||
| 221 | lsb_shift); | ||
| 222 | if (ret < 0) | ||
| 223 | goto exit_unlock; | ||
| 224 | *val = ret * data->vref_cached / 1024; | ||
| 225 | ret = 0; | ||
| 226 | break; | ||
| 227 | default: | ||
| 228 | ret = -EOPNOTSUPP; | ||
| 229 | break; | ||
| 230 | } | ||
| 231 | exit_unlock: | ||
| 232 | mutex_unlock(&data->update_lock); | ||
| 233 | return ret; | ||
| 283 | } | 234 | } |
| 284 | 235 | ||
| 285 | static const struct attribute_group adt7411_group = { | 236 | static int adt7411_read_in(struct device *dev, u32 attr, int channel, |
| 286 | .attrs = adt7411_attrs, | 237 | long *val) |
| 287 | .is_visible = adt7411_attrs_visible, | 238 | { |
| 288 | }; | 239 | if (channel == 0) |
| 289 | __ATTRIBUTE_GROUPS(adt7411); | 240 | return adt7411_read_in_vdd(dev, attr, val); |
| 241 | else | ||
| 242 | return adt7411_read_in_chan(dev, attr, channel, val); | ||
| 243 | } | ||
| 244 | |||
| 245 | static int adt7411_read_temp(struct device *dev, u32 attr, int channel, | ||
| 246 | long *val) | ||
| 247 | { | ||
| 248 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
| 249 | struct i2c_client *client = data->client; | ||
| 250 | int ret, regl, regh; | ||
| 251 | |||
| 252 | switch (attr) { | ||
| 253 | case hwmon_temp_input: | ||
| 254 | regl = channel ? ADT7411_REG_EXT_TEMP_AIN14_LSB : | ||
| 255 | ADT7411_REG_INT_TEMP_VDD_LSB; | ||
| 256 | regh = channel ? ADT7411_REG_EXT_TEMP_AIN1_MSB : | ||
| 257 | ADT7411_REG_INT_TEMP_MSB; | ||
| 258 | ret = adt7411_read_10_bit(client, regl, regh, 0); | ||
| 259 | if (ret < 0) | ||
| 260 | return ret; | ||
| 261 | ret = ret & 0x200 ? ret - 0x400 : ret; /* 10 bit signed */ | ||
| 262 | *val = ret * 250; | ||
| 263 | return 0; | ||
| 264 | default: | ||
| 265 | return -EOPNOTSUPP; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | static int adt7411_read(struct device *dev, enum hwmon_sensor_types type, | ||
| 270 | u32 attr, int channel, long *val) | ||
| 271 | { | ||
| 272 | switch (type) { | ||
| 273 | case hwmon_in: | ||
| 274 | return adt7411_read_in(dev, attr, channel, val); | ||
| 275 | case hwmon_temp: | ||
| 276 | return adt7411_read_temp(dev, attr, channel, val); | ||
| 277 | default: | ||
| 278 | return -EOPNOTSUPP; | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | static umode_t adt7411_is_visible(const void *_data, | ||
| 283 | enum hwmon_sensor_types type, | ||
| 284 | u32 attr, int channel) | ||
| 285 | { | ||
| 286 | const struct adt7411_data *data = _data; | ||
| 287 | |||
| 288 | switch (type) { | ||
| 289 | case hwmon_in: | ||
| 290 | if (channel > 0 && channel < 3) | ||
| 291 | return data->use_ext_temp ? 0 : S_IRUGO; | ||
| 292 | else | ||
| 293 | return S_IRUGO; | ||
| 294 | case hwmon_temp: | ||
| 295 | if (channel == 1) | ||
| 296 | return data->use_ext_temp ? S_IRUGO : 0; | ||
| 297 | else | ||
| 298 | return S_IRUGO; | ||
| 299 | default: | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | } | ||
| 290 | 303 | ||
| 291 | static int adt7411_detect(struct i2c_client *client, | 304 | static int adt7411_detect(struct i2c_client *client, |
| 292 | struct i2c_board_info *info) | 305 | struct i2c_board_info *info) |
| @@ -358,6 +371,51 @@ static int adt7411_init_device(struct adt7411_data *data) | |||
| 358 | return i2c_smbus_write_byte_data(data->client, ADT7411_REG_CFG1, val); | 371 | return i2c_smbus_write_byte_data(data->client, ADT7411_REG_CFG1, val); |
| 359 | } | 372 | } |
| 360 | 373 | ||
| 374 | static const u32 adt7411_in_config[] = { | ||
| 375 | HWMON_I_INPUT, | ||
| 376 | HWMON_I_INPUT, | ||
| 377 | HWMON_I_INPUT, | ||
| 378 | HWMON_I_INPUT, | ||
| 379 | HWMON_I_INPUT, | ||
| 380 | HWMON_I_INPUT, | ||
| 381 | HWMON_I_INPUT, | ||
| 382 | HWMON_I_INPUT, | ||
| 383 | HWMON_I_INPUT, | ||
| 384 | 0 | ||
| 385 | }; | ||
| 386 | |||
| 387 | static const struct hwmon_channel_info adt7411_in = { | ||
| 388 | .type = hwmon_in, | ||
| 389 | .config = adt7411_in_config, | ||
| 390 | }; | ||
| 391 | |||
| 392 | static const u32 adt7411_temp_config[] = { | ||
| 393 | HWMON_T_INPUT, | ||
| 394 | HWMON_T_INPUT, | ||
| 395 | 0 | ||
| 396 | }; | ||
| 397 | |||
| 398 | static const struct hwmon_channel_info adt7411_temp = { | ||
| 399 | .type = hwmon_temp, | ||
| 400 | .config = adt7411_temp_config, | ||
| 401 | }; | ||
| 402 | |||
| 403 | static const struct hwmon_channel_info *adt7411_info[] = { | ||
| 404 | &adt7411_in, | ||
| 405 | &adt7411_temp, | ||
| 406 | NULL | ||
| 407 | }; | ||
| 408 | |||
| 409 | static const struct hwmon_ops adt7411_hwmon_ops = { | ||
| 410 | .is_visible = adt7411_is_visible, | ||
| 411 | .read = adt7411_read, | ||
| 412 | }; | ||
| 413 | |||
| 414 | static const struct hwmon_chip_info adt7411_chip_info = { | ||
| 415 | .ops = &adt7411_hwmon_ops, | ||
| 416 | .info = adt7411_info, | ||
| 417 | }; | ||
| 418 | |||
| 361 | static int adt7411_probe(struct i2c_client *client, | 419 | static int adt7411_probe(struct i2c_client *client, |
| 362 | const struct i2c_device_id *id) | 420 | const struct i2c_device_id *id) |
| 363 | { | 421 | { |
| @@ -382,9 +440,10 @@ static int adt7411_probe(struct i2c_client *client, | |||
| 382 | /* force update on first occasion */ | 440 | /* force update on first occasion */ |
| 383 | data->next_update = jiffies; | 441 | data->next_update = jiffies; |
| 384 | 442 | ||
| 385 | hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, | 443 | hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, |
| 386 | data, | 444 | data, |
| 387 | adt7411_groups); | 445 | &adt7411_chip_info, |
| 446 | adt7411_groups); | ||
| 388 | return PTR_ERR_OR_ZERO(hwmon_dev); | 447 | return PTR_ERR_OR_ZERO(hwmon_dev); |
| 389 | } | 448 | } |
| 390 | 449 | ||
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 5929e126da63..19f2a6d48bac 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c | |||
| @@ -810,8 +810,8 @@ static ssize_t set_temp_min(struct device *dev, | |||
| 810 | if (kstrtol(buf, 10, &temp) || !temp_enabled(data, attr->index)) | 810 | if (kstrtol(buf, 10, &temp) || !temp_enabled(data, attr->index)) |
| 811 | return -EINVAL; | 811 | return -EINVAL; |
| 812 | 812 | ||
| 813 | temp = clamp_val(temp, -64000, 191000); | ||
| 813 | temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; | 814 | temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; |
| 814 | temp = clamp_val(temp, 0, 255); | ||
| 815 | 815 | ||
| 816 | mutex_lock(&data->lock); | 816 | mutex_lock(&data->lock); |
| 817 | data->temp_min[attr->index] = temp; | 817 | data->temp_min[attr->index] = temp; |
| @@ -848,8 +848,8 @@ static ssize_t set_temp_max(struct device *dev, | |||
| 848 | if (kstrtol(buf, 10, &temp) || !temp_enabled(data, attr->index)) | 848 | if (kstrtol(buf, 10, &temp) || !temp_enabled(data, attr->index)) |
| 849 | return -EINVAL; | 849 | return -EINVAL; |
| 850 | 850 | ||
| 851 | temp = clamp_val(temp, -64000, 191000); | ||
| 851 | temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; | 852 | temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; |
| 852 | temp = clamp_val(temp, 0, 255); | ||
| 853 | 853 | ||
| 854 | mutex_lock(&data->lock); | 854 | mutex_lock(&data->lock); |
| 855 | data->temp_max[attr->index] = temp; | 855 | data->temp_max[attr->index] = temp; |
| @@ -912,9 +912,9 @@ static ssize_t set_volt_max(struct device *dev, | |||
| 912 | if (kstrtol(buf, 10, &temp) || !x) | 912 | if (kstrtol(buf, 10, &temp) || !x) |
| 913 | return -EINVAL; | 913 | return -EINVAL; |
| 914 | 914 | ||
| 915 | temp = clamp_val(temp, 0, 255 * x / 1000); | ||
| 915 | temp *= 1000; /* convert mV to uV */ | 916 | temp *= 1000; /* convert mV to uV */ |
| 916 | temp = DIV_ROUND_CLOSEST(temp, x); | 917 | temp = DIV_ROUND_CLOSEST(temp, x); |
| 917 | temp = clamp_val(temp, 0, 255); | ||
| 918 | 918 | ||
| 919 | mutex_lock(&data->lock); | 919 | mutex_lock(&data->lock); |
| 920 | data->volt_max[attr->index] = temp; | 920 | data->volt_max[attr->index] = temp; |
| @@ -954,9 +954,9 @@ static ssize_t set_volt_min(struct device *dev, | |||
| 954 | if (kstrtol(buf, 10, &temp) || !x) | 954 | if (kstrtol(buf, 10, &temp) || !x) |
| 955 | return -EINVAL; | 955 | return -EINVAL; |
| 956 | 956 | ||
| 957 | temp = clamp_val(temp, 0, 255 * x / 1000); | ||
| 957 | temp *= 1000; /* convert mV to uV */ | 958 | temp *= 1000; /* convert mV to uV */ |
| 958 | temp = DIV_ROUND_CLOSEST(temp, x); | 959 | temp = DIV_ROUND_CLOSEST(temp, x); |
| 959 | temp = clamp_val(temp, 0, 255); | ||
| 960 | 960 | ||
| 961 | mutex_lock(&data->lock); | 961 | mutex_lock(&data->lock); |
| 962 | data->volt_min[attr->index] = temp; | 962 | data->volt_min[attr->index] = temp; |
| @@ -1220,8 +1220,8 @@ static ssize_t set_pwm_hyst(struct device *dev, | |||
| 1220 | if (kstrtol(buf, 10, &temp)) | 1220 | if (kstrtol(buf, 10, &temp)) |
| 1221 | return -EINVAL; | 1221 | return -EINVAL; |
| 1222 | 1222 | ||
| 1223 | temp = clamp_val(temp, 0, 15000); | ||
| 1223 | temp = DIV_ROUND_CLOSEST(temp, 1000); | 1224 | temp = DIV_ROUND_CLOSEST(temp, 1000); |
| 1224 | temp = clamp_val(temp, 0, 15); | ||
| 1225 | 1225 | ||
| 1226 | /* package things up */ | 1226 | /* package things up */ |
| 1227 | temp &= ADT7462_PWM_HYST_MASK; | 1227 | temp &= ADT7462_PWM_HYST_MASK; |
| @@ -1306,8 +1306,8 @@ static ssize_t set_pwm_tmin(struct device *dev, | |||
| 1306 | if (kstrtol(buf, 10, &temp)) | 1306 | if (kstrtol(buf, 10, &temp)) |
| 1307 | return -EINVAL; | 1307 | return -EINVAL; |
| 1308 | 1308 | ||
| 1309 | temp = clamp_val(temp, -64000, 191000); | ||
| 1309 | temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; | 1310 | temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; |
| 1310 | temp = clamp_val(temp, 0, 255); | ||
| 1311 | 1311 | ||
| 1312 | mutex_lock(&data->lock); | 1312 | mutex_lock(&data->lock); |
| 1313 | data->pwm_tmin[attr->index] = temp; | 1313 | data->pwm_tmin[attr->index] = temp; |
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 6e60ca53406e..c9a1d9c25572 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c | |||
| @@ -483,8 +483,8 @@ static ssize_t set_temp_min(struct device *dev, | |||
| 483 | if (kstrtol(buf, 10, &temp)) | 483 | if (kstrtol(buf, 10, &temp)) |
| 484 | return -EINVAL; | 484 | return -EINVAL; |
| 485 | 485 | ||
| 486 | temp = clamp_val(temp, -128000, 127000); | ||
| 486 | temp = DIV_ROUND_CLOSEST(temp, 1000); | 487 | temp = DIV_ROUND_CLOSEST(temp, 1000); |
| 487 | temp = clamp_val(temp, -128, 127); | ||
| 488 | 488 | ||
| 489 | mutex_lock(&data->lock); | 489 | mutex_lock(&data->lock); |
| 490 | data->temp_min[attr->index] = temp; | 490 | data->temp_min[attr->index] = temp; |
| @@ -517,8 +517,8 @@ static ssize_t set_temp_max(struct device *dev, | |||
| 517 | if (kstrtol(buf, 10, &temp)) | 517 | if (kstrtol(buf, 10, &temp)) |
| 518 | return -EINVAL; | 518 | return -EINVAL; |
| 519 | 519 | ||
| 520 | temp = clamp_val(temp, -128000, 127000); | ||
| 520 | temp = DIV_ROUND_CLOSEST(temp, 1000); | 521 | temp = DIV_ROUND_CLOSEST(temp, 1000); |
| 521 | temp = clamp_val(temp, -128, 127); | ||
| 522 | 522 | ||
| 523 | mutex_lock(&data->lock); | 523 | mutex_lock(&data->lock); |
| 524 | data->temp_max[attr->index] = temp; | 524 | data->temp_max[attr->index] = temp; |
| @@ -880,8 +880,8 @@ static ssize_t set_pwm_tmin(struct device *dev, | |||
| 880 | if (kstrtol(buf, 10, &temp)) | 880 | if (kstrtol(buf, 10, &temp)) |
| 881 | return -EINVAL; | 881 | return -EINVAL; |
| 882 | 882 | ||
| 883 | temp = clamp_val(temp, -128000, 127000); | ||
| 883 | temp = DIV_ROUND_CLOSEST(temp, 1000); | 884 | temp = DIV_ROUND_CLOSEST(temp, 1000); |
| 884 | temp = clamp_val(temp, -128, 127); | ||
| 885 | 885 | ||
| 886 | mutex_lock(&data->lock); | 886 | mutex_lock(&data->lock); |
| 887 | data->pwm_tmin[attr->index] = temp; | 887 | data->pwm_tmin[attr->index] = temp; |
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 12e851a5af48..46b4e35fd555 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c | |||
| @@ -188,8 +188,8 @@ static struct amc6821_data *amc6821_update_device(struct device *dev) | |||
| 188 | !data->valid) { | 188 | !data->valid) { |
| 189 | 189 | ||
| 190 | for (i = 0; i < TEMP_IDX_LEN; i++) | 190 | for (i = 0; i < TEMP_IDX_LEN; i++) |
| 191 | data->temp[i] = i2c_smbus_read_byte_data(client, | 191 | data->temp[i] = (int8_t)i2c_smbus_read_byte_data( |
| 192 | temp_reg[i]); | 192 | client, temp_reg[i]); |
| 193 | 193 | ||
| 194 | data->stat1 = i2c_smbus_read_byte_data(client, | 194 | data->stat1 = i2c_smbus_read_byte_data(client, |
| 195 | AMC6821_REG_STAT1); | 195 | AMC6821_REG_STAT1); |
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 6a27eb2fed17..3ac4c03ba77b 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c | |||
| @@ -51,6 +51,7 @@ static int force_tjmax; | |||
| 51 | module_param_named(tjmax, force_tjmax, int, 0444); | 51 | module_param_named(tjmax, force_tjmax, int, 0444); |
| 52 | MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); | 52 | MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); |
| 53 | 53 | ||
| 54 | #define PKG_SYSFS_ATTR_NO 1 /* Sysfs attribute for package temp */ | ||
| 54 | #define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */ | 55 | #define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */ |
| 55 | #define NUM_REAL_CORES 128 /* Number of Real cores per cpu */ | 56 | #define NUM_REAL_CORES 128 /* Number of Real cores per cpu */ |
| 56 | #define CORETEMP_NAME_LENGTH 19 /* String Length of attrs */ | 57 | #define CORETEMP_NAME_LENGTH 19 /* String Length of attrs */ |
| @@ -58,7 +59,6 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); | |||
| 58 | #define TOTAL_ATTRS (MAX_CORE_ATTRS + 1) | 59 | #define TOTAL_ATTRS (MAX_CORE_ATTRS + 1) |
| 59 | #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) | 60 | #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) |
| 60 | 61 | ||
| 61 | #define TO_PHYS_ID(cpu) (cpu_data(cpu).phys_proc_id) | ||
| 62 | #define TO_CORE_ID(cpu) (cpu_data(cpu).cpu_core_id) | 62 | #define TO_CORE_ID(cpu) (cpu_data(cpu).cpu_core_id) |
| 63 | #define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) | 63 | #define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) |
| 64 | 64 | ||
| @@ -102,20 +102,17 @@ struct temp_data { | |||
| 102 | 102 | ||
| 103 | /* Platform Data per Physical CPU */ | 103 | /* Platform Data per Physical CPU */ |
| 104 | struct platform_data { | 104 | struct platform_data { |
| 105 | struct device *hwmon_dev; | 105 | struct device *hwmon_dev; |
| 106 | u16 phys_proc_id; | 106 | u16 pkg_id; |
| 107 | struct temp_data *core_data[MAX_CORE_DATA]; | 107 | struct cpumask cpumask; |
| 108 | struct temp_data *core_data[MAX_CORE_DATA]; | ||
| 108 | struct device_attribute name_attr; | 109 | struct device_attribute name_attr; |
| 109 | }; | 110 | }; |
| 110 | 111 | ||
| 111 | struct pdev_entry { | 112 | /* Keep track of how many package pointers we allocated in init() */ |
| 112 | struct list_head list; | 113 | static int max_packages __read_mostly; |
| 113 | struct platform_device *pdev; | 114 | /* Array of package pointers. Serialized by cpu hotplug lock */ |
| 114 | u16 phys_proc_id; | 115 | static struct platform_device **pkg_devices; |
| 115 | }; | ||
| 116 | |||
| 117 | static LIST_HEAD(pdev_list); | ||
| 118 | static DEFINE_MUTEX(pdev_list_mutex); | ||
| 119 | 116 | ||
| 120 | static ssize_t show_label(struct device *dev, | 117 | static ssize_t show_label(struct device *dev, |
| 121 | struct device_attribute *devattr, char *buf) | 118 | struct device_attribute *devattr, char *buf) |
| @@ -125,7 +122,7 @@ static ssize_t show_label(struct device *dev, | |||
| 125 | struct temp_data *tdata = pdata->core_data[attr->index]; | 122 | struct temp_data *tdata = pdata->core_data[attr->index]; |
| 126 | 123 | ||
| 127 | if (tdata->is_pkg_data) | 124 | if (tdata->is_pkg_data) |
| 128 | return sprintf(buf, "Physical id %u\n", pdata->phys_proc_id); | 125 | return sprintf(buf, "Package id %u\n", pdata->pkg_id); |
| 129 | 126 | ||
| 130 | return sprintf(buf, "Core %u\n", tdata->cpu_core_id); | 127 | return sprintf(buf, "Core %u\n", tdata->cpu_core_id); |
| 131 | } | 128 | } |
| @@ -138,7 +135,9 @@ static ssize_t show_crit_alarm(struct device *dev, | |||
| 138 | struct platform_data *pdata = dev_get_drvdata(dev); | 135 | struct platform_data *pdata = dev_get_drvdata(dev); |
| 139 | struct temp_data *tdata = pdata->core_data[attr->index]; | 136 | struct temp_data *tdata = pdata->core_data[attr->index]; |
| 140 | 137 | ||
| 138 | mutex_lock(&tdata->update_lock); | ||
| 141 | rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); | 139 | rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); |
| 140 | mutex_unlock(&tdata->update_lock); | ||
| 142 | 141 | ||
| 143 | return sprintf(buf, "%d\n", (eax >> 5) & 1); | 142 | return sprintf(buf, "%d\n", (eax >> 5) & 1); |
| 144 | } | 143 | } |
| @@ -435,18 +434,10 @@ static int chk_ucode_version(unsigned int cpu) | |||
| 435 | 434 | ||
| 436 | static struct platform_device *coretemp_get_pdev(unsigned int cpu) | 435 | static struct platform_device *coretemp_get_pdev(unsigned int cpu) |
| 437 | { | 436 | { |
| 438 | u16 phys_proc_id = TO_PHYS_ID(cpu); | 437 | int pkgid = topology_logical_package_id(cpu); |
| 439 | struct pdev_entry *p; | ||
| 440 | |||
| 441 | mutex_lock(&pdev_list_mutex); | ||
| 442 | 438 | ||
| 443 | list_for_each_entry(p, &pdev_list, list) | 439 | if (pkgid >= 0 && pkgid < max_packages) |
| 444 | if (p->phys_proc_id == phys_proc_id) { | 440 | return pkg_devices[pkgid]; |
| 445 | mutex_unlock(&pdev_list_mutex); | ||
| 446 | return p->pdev; | ||
| 447 | } | ||
| 448 | |||
| 449 | mutex_unlock(&pdev_list_mutex); | ||
| 450 | return NULL; | 441 | return NULL; |
| 451 | } | 442 | } |
| 452 | 443 | ||
| @@ -483,21 +474,11 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, | |||
| 483 | * The attr number is always core id + 2 | 474 | * The attr number is always core id + 2 |
| 484 | * The Pkgtemp will always show up as temp1_*, if available | 475 | * The Pkgtemp will always show up as temp1_*, if available |
| 485 | */ | 476 | */ |
| 486 | attr_no = pkg_flag ? 1 : TO_ATTR_NO(cpu); | 477 | attr_no = pkg_flag ? PKG_SYSFS_ATTR_NO : TO_ATTR_NO(cpu); |
| 487 | 478 | ||
| 488 | if (attr_no > MAX_CORE_DATA - 1) | 479 | if (attr_no > MAX_CORE_DATA - 1) |
| 489 | return -ERANGE; | 480 | return -ERANGE; |
| 490 | 481 | ||
| 491 | /* | ||
| 492 | * Provide a single set of attributes for all HT siblings of a core | ||
| 493 | * to avoid duplicate sensors (the processor ID and core ID of all | ||
| 494 | * HT siblings of a core are the same). | ||
| 495 | * Skip if a HT sibling of this core is already registered. | ||
| 496 | * This is not an error. | ||
| 497 | */ | ||
| 498 | if (pdata->core_data[attr_no] != NULL) | ||
| 499 | return 0; | ||
| 500 | |||
| 501 | tdata = init_temp_data(cpu, pkg_flag); | 482 | tdata = init_temp_data(cpu, pkg_flag); |
| 502 | if (!tdata) | 483 | if (!tdata) |
| 503 | return -ENOMEM; | 484 | return -ENOMEM; |
| @@ -539,21 +520,14 @@ exit_free: | |||
| 539 | return err; | 520 | return err; |
| 540 | } | 521 | } |
| 541 | 522 | ||
| 542 | static void coretemp_add_core(unsigned int cpu, int pkg_flag) | 523 | static void |
| 524 | coretemp_add_core(struct platform_device *pdev, unsigned int cpu, int pkg_flag) | ||
| 543 | { | 525 | { |
| 544 | struct platform_device *pdev = coretemp_get_pdev(cpu); | 526 | if (create_core_data(pdev, cpu, pkg_flag)) |
| 545 | int err; | ||
| 546 | |||
| 547 | if (!pdev) | ||
| 548 | return; | ||
| 549 | |||
| 550 | err = create_core_data(pdev, cpu, pkg_flag); | ||
| 551 | if (err) | ||
| 552 | dev_err(&pdev->dev, "Adding Core %u failed\n", cpu); | 527 | dev_err(&pdev->dev, "Adding Core %u failed\n", cpu); |
| 553 | } | 528 | } |
| 554 | 529 | ||
| 555 | static void coretemp_remove_core(struct platform_data *pdata, | 530 | static void coretemp_remove_core(struct platform_data *pdata, int indx) |
| 556 | int indx) | ||
| 557 | { | 531 | { |
| 558 | struct temp_data *tdata = pdata->core_data[indx]; | 532 | struct temp_data *tdata = pdata->core_data[indx]; |
| 559 | 533 | ||
| @@ -574,7 +548,7 @@ static int coretemp_probe(struct platform_device *pdev) | |||
| 574 | if (!pdata) | 548 | if (!pdata) |
| 575 | return -ENOMEM; | 549 | return -ENOMEM; |
| 576 | 550 | ||
| 577 | pdata->phys_proc_id = pdev->id; | 551 | pdata->pkg_id = pdev->id; |
| 578 | platform_set_drvdata(pdev, pdata); | 552 | platform_set_drvdata(pdev, pdata); |
| 579 | 553 | ||
| 580 | pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME, | 554 | pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME, |
| @@ -602,85 +576,33 @@ static struct platform_driver coretemp_driver = { | |||
| 602 | .remove = coretemp_remove, | 576 | .remove = coretemp_remove, |
| 603 | }; | 577 | }; |
| 604 | 578 | ||
| 605 | static int coretemp_device_add(unsigned int cpu) | 579 | static struct platform_device *coretemp_device_add(unsigned int cpu) |
| 606 | { | 580 | { |
| 607 | int err; | 581 | int err, pkgid = topology_logical_package_id(cpu); |
| 608 | struct platform_device *pdev; | 582 | struct platform_device *pdev; |
| 609 | struct pdev_entry *pdev_entry; | ||
| 610 | 583 | ||
| 611 | mutex_lock(&pdev_list_mutex); | 584 | if (pkgid < 0) |
| 585 | return ERR_PTR(-ENOMEM); | ||
| 612 | 586 | ||
| 613 | pdev = platform_device_alloc(DRVNAME, TO_PHYS_ID(cpu)); | 587 | pdev = platform_device_alloc(DRVNAME, pkgid); |
| 614 | if (!pdev) { | 588 | if (!pdev) |
| 615 | err = -ENOMEM; | 589 | return ERR_PTR(-ENOMEM); |
| 616 | pr_err("Device allocation failed\n"); | ||
| 617 | goto exit; | ||
| 618 | } | ||
| 619 | |||
| 620 | pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL); | ||
| 621 | if (!pdev_entry) { | ||
| 622 | err = -ENOMEM; | ||
| 623 | goto exit_device_put; | ||
| 624 | } | ||
| 625 | 590 | ||
| 626 | err = platform_device_add(pdev); | 591 | err = platform_device_add(pdev); |
| 627 | if (err) { | 592 | if (err) { |
| 628 | pr_err("Device addition failed (%d)\n", err); | 593 | platform_device_put(pdev); |
| 629 | goto exit_device_free; | 594 | return ERR_PTR(err); |
| 630 | } | ||
| 631 | |||
| 632 | pdev_entry->pdev = pdev; | ||
| 633 | pdev_entry->phys_proc_id = pdev->id; | ||
| 634 | |||
| 635 | list_add_tail(&pdev_entry->list, &pdev_list); | ||
| 636 | mutex_unlock(&pdev_list_mutex); | ||
| 637 | |||
| 638 | return 0; | ||
| 639 | |||
| 640 | exit_device_free: | ||
| 641 | kfree(pdev_entry); | ||
| 642 | exit_device_put: | ||
| 643 | platform_device_put(pdev); | ||
| 644 | exit: | ||
| 645 | mutex_unlock(&pdev_list_mutex); | ||
| 646 | return err; | ||
| 647 | } | ||
| 648 | |||
| 649 | static void coretemp_device_remove(unsigned int cpu) | ||
| 650 | { | ||
| 651 | struct pdev_entry *p, *n; | ||
| 652 | u16 phys_proc_id = TO_PHYS_ID(cpu); | ||
| 653 | |||
| 654 | mutex_lock(&pdev_list_mutex); | ||
| 655 | list_for_each_entry_safe(p, n, &pdev_list, list) { | ||
| 656 | if (p->phys_proc_id != phys_proc_id) | ||
| 657 | continue; | ||
| 658 | platform_device_unregister(p->pdev); | ||
| 659 | list_del(&p->list); | ||
| 660 | kfree(p); | ||
| 661 | } | 595 | } |
| 662 | mutex_unlock(&pdev_list_mutex); | ||
| 663 | } | ||
| 664 | |||
| 665 | static bool is_any_core_online(struct platform_data *pdata) | ||
| 666 | { | ||
| 667 | int i; | ||
| 668 | 596 | ||
| 669 | /* Find online cores, except pkgtemp data */ | 597 | pkg_devices[pkgid] = pdev; |
| 670 | for (i = MAX_CORE_DATA - 1; i >= 0; --i) { | 598 | return pdev; |
| 671 | if (pdata->core_data[i] && | ||
| 672 | !pdata->core_data[i]->is_pkg_data) { | ||
| 673 | return true; | ||
| 674 | } | ||
| 675 | } | ||
| 676 | return false; | ||
| 677 | } | 599 | } |
| 678 | 600 | ||
| 679 | static void get_core_online(unsigned int cpu) | 601 | static int coretemp_cpu_online(unsigned int cpu) |
| 680 | { | 602 | { |
| 681 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
| 682 | struct platform_device *pdev = coretemp_get_pdev(cpu); | 603 | struct platform_device *pdev = coretemp_get_pdev(cpu); |
| 683 | int err; | 604 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
| 605 | struct platform_data *pdata; | ||
| 684 | 606 | ||
| 685 | /* | 607 | /* |
| 686 | * CPUID.06H.EAX[0] indicates whether the CPU has thermal | 608 | * CPUID.06H.EAX[0] indicates whether the CPU has thermal |
| @@ -688,12 +610,12 @@ static void get_core_online(unsigned int cpu) | |||
| 688 | * without thermal sensors will be filtered out. | 610 | * without thermal sensors will be filtered out. |
| 689 | */ | 611 | */ |
| 690 | if (!cpu_has(c, X86_FEATURE_DTHERM)) | 612 | if (!cpu_has(c, X86_FEATURE_DTHERM)) |
| 691 | return; | 613 | return -ENODEV; |
| 692 | 614 | ||
| 693 | if (!pdev) { | 615 | if (!pdev) { |
| 694 | /* Check the microcode version of the CPU */ | 616 | /* Check the microcode version of the CPU */ |
| 695 | if (chk_ucode_version(cpu)) | 617 | if (chk_ucode_version(cpu)) |
| 696 | return; | 618 | return -EINVAL; |
| 697 | 619 | ||
| 698 | /* | 620 | /* |
| 699 | * Alright, we have DTS support. | 621 | * Alright, we have DTS support. |
| @@ -701,101 +623,100 @@ static void get_core_online(unsigned int cpu) | |||
| 701 | * online. So, initialize per-pkg data structures and | 623 | * online. So, initialize per-pkg data structures and |
| 702 | * then bring this core online. | 624 | * then bring this core online. |
| 703 | */ | 625 | */ |
| 704 | err = coretemp_device_add(cpu); | 626 | pdev = coretemp_device_add(cpu); |
| 705 | if (err) | 627 | if (IS_ERR(pdev)) |
| 706 | return; | 628 | return PTR_ERR(pdev); |
| 629 | |||
| 707 | /* | 630 | /* |
| 708 | * Check whether pkgtemp support is available. | 631 | * Check whether pkgtemp support is available. |
| 709 | * If so, add interfaces for pkgtemp. | 632 | * If so, add interfaces for pkgtemp. |
| 710 | */ | 633 | */ |
| 711 | if (cpu_has(c, X86_FEATURE_PTS)) | 634 | if (cpu_has(c, X86_FEATURE_PTS)) |
| 712 | coretemp_add_core(cpu, 1); | 635 | coretemp_add_core(pdev, cpu, 1); |
| 713 | } | 636 | } |
| 637 | |||
| 638 | pdata = platform_get_drvdata(pdev); | ||
| 714 | /* | 639 | /* |
| 715 | * Physical CPU device already exists. | 640 | * Check whether a thread sibling is already online. If not add the |
| 716 | * So, just add interfaces for this core. | 641 | * interface for this CPU core. |
| 717 | */ | 642 | */ |
| 718 | coretemp_add_core(cpu, 0); | 643 | if (!cpumask_intersects(&pdata->cpumask, topology_sibling_cpumask(cpu))) |
| 644 | coretemp_add_core(pdev, cpu, 0); | ||
| 645 | |||
| 646 | cpumask_set_cpu(cpu, &pdata->cpumask); | ||
| 647 | return 0; | ||
| 719 | } | 648 | } |
| 720 | 649 | ||
| 721 | static void put_core_offline(unsigned int cpu) | 650 | static int coretemp_cpu_offline(unsigned int cpu) |
| 722 | { | 651 | { |
| 723 | int i, indx; | ||
| 724 | struct platform_data *pdata; | ||
| 725 | struct platform_device *pdev = coretemp_get_pdev(cpu); | 652 | struct platform_device *pdev = coretemp_get_pdev(cpu); |
| 653 | struct platform_data *pd; | ||
| 654 | struct temp_data *tdata; | ||
| 655 | int indx, target; | ||
| 726 | 656 | ||
| 727 | /* If the physical CPU device does not exist, just return */ | 657 | /* If the physical CPU device does not exist, just return */ |
| 728 | if (!pdev) | 658 | if (!pdev) |
| 729 | return; | 659 | return 0; |
| 730 | |||
| 731 | pdata = platform_get_drvdata(pdev); | ||
| 732 | |||
| 733 | indx = TO_ATTR_NO(cpu); | ||
| 734 | 660 | ||
| 735 | /* The core id is too big, just return */ | 661 | /* The core id is too big, just return */ |
| 662 | indx = TO_ATTR_NO(cpu); | ||
| 736 | if (indx > MAX_CORE_DATA - 1) | 663 | if (indx > MAX_CORE_DATA - 1) |
| 737 | return; | 664 | return 0; |
| 738 | 665 | ||
| 739 | if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu) | 666 | pd = platform_get_drvdata(pdev); |
| 740 | coretemp_remove_core(pdata, indx); | 667 | tdata = pd->core_data[indx]; |
| 668 | |||
| 669 | cpumask_clear_cpu(cpu, &pd->cpumask); | ||
| 741 | 670 | ||
| 742 | /* | 671 | /* |
| 743 | * If a HT sibling of a core is taken offline, but another HT sibling | 672 | * If this is the last thread sibling, remove the CPU core |
| 744 | * of the same core is still online, register the alternate sibling. | 673 | * interface, If there is still a sibling online, transfer the |
| 745 | * This ensures that exactly one set of attributes is provided as long | 674 | * target cpu of that core interface to it. |
| 746 | * as at least one HT sibling of a core is online. | ||
| 747 | */ | 675 | */ |
| 748 | for_each_sibling(i, cpu) { | 676 | target = cpumask_any_and(&pd->cpumask, topology_sibling_cpumask(cpu)); |
| 749 | if (i != cpu) { | 677 | if (target >= nr_cpu_ids) { |
| 750 | get_core_online(i); | 678 | coretemp_remove_core(pd, indx); |
| 751 | /* | 679 | } else if (tdata && tdata->cpu == cpu) { |
| 752 | * Display temperature sensor data for one HT sibling | 680 | mutex_lock(&tdata->update_lock); |
| 753 | * per core only, so abort the loop after one such | 681 | tdata->cpu = target; |
| 754 | * sibling has been found. | 682 | mutex_unlock(&tdata->update_lock); |
| 755 | */ | ||
| 756 | break; | ||
| 757 | } | ||
| 758 | } | 683 | } |
| 684 | |||
| 759 | /* | 685 | /* |
| 760 | * If all cores in this pkg are offline, remove the device. | 686 | * If all cores in this pkg are offline, remove the device. This |
| 761 | * coretemp_device_remove calls unregister_platform_device, | 687 | * will invoke the platform driver remove function, which cleans up |
| 762 | * which in turn calls coretemp_remove. This removes the | 688 | * the rest. |
| 763 | * pkgtemp entry and does other clean ups. | ||
| 764 | */ | 689 | */ |
| 765 | if (!is_any_core_online(pdata)) | 690 | if (cpumask_empty(&pd->cpumask)) { |
| 766 | coretemp_device_remove(cpu); | 691 | pkg_devices[topology_logical_package_id(cpu)] = NULL; |
| 767 | } | 692 | platform_device_unregister(pdev); |
| 693 | return 0; | ||
| 694 | } | ||
| 768 | 695 | ||
| 769 | static int coretemp_cpu_callback(struct notifier_block *nfb, | 696 | /* |
| 770 | unsigned long action, void *hcpu) | 697 | * Check whether this core is the target for the package |
| 771 | { | 698 | * interface. We need to assign it to some other cpu. |
| 772 | unsigned int cpu = (unsigned long) hcpu; | 699 | */ |
| 773 | 700 | tdata = pd->core_data[PKG_SYSFS_ATTR_NO]; | |
| 774 | switch (action) { | 701 | if (tdata && tdata->cpu == cpu) { |
| 775 | case CPU_ONLINE: | 702 | target = cpumask_first(&pd->cpumask); |
| 776 | case CPU_DOWN_FAILED: | 703 | mutex_lock(&tdata->update_lock); |
| 777 | get_core_online(cpu); | 704 | tdata->cpu = target; |
| 778 | break; | 705 | mutex_unlock(&tdata->update_lock); |
| 779 | case CPU_DOWN_PREPARE: | ||
| 780 | put_core_offline(cpu); | ||
| 781 | break; | ||
| 782 | } | 706 | } |
| 783 | return NOTIFY_OK; | 707 | return 0; |
| 784 | } | 708 | } |
| 785 | |||
| 786 | static struct notifier_block coretemp_cpu_notifier __refdata = { | ||
| 787 | .notifier_call = coretemp_cpu_callback, | ||
| 788 | }; | ||
| 789 | |||
| 790 | static const struct x86_cpu_id __initconst coretemp_ids[] = { | 709 | static const struct x86_cpu_id __initconst coretemp_ids[] = { |
| 791 | { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM }, | 710 | { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM }, |
| 792 | {} | 711 | {} |
| 793 | }; | 712 | }; |
| 794 | MODULE_DEVICE_TABLE(x86cpu, coretemp_ids); | 713 | MODULE_DEVICE_TABLE(x86cpu, coretemp_ids); |
| 795 | 714 | ||
| 715 | static enum cpuhp_state coretemp_hp_online; | ||
| 716 | |||
| 796 | static int __init coretemp_init(void) | 717 | static int __init coretemp_init(void) |
| 797 | { | 718 | { |
| 798 | int i, err; | 719 | int err; |
| 799 | 720 | ||
| 800 | /* | 721 | /* |
| 801 | * CPUID.06H.EAX[0] indicates whether the CPU has thermal | 722 | * CPUID.06H.EAX[0] indicates whether the CPU has thermal |
| @@ -805,54 +726,38 @@ static int __init coretemp_init(void) | |||
| 805 | if (!x86_match_cpu(coretemp_ids)) | 726 | if (!x86_match_cpu(coretemp_ids)) |
| 806 | return -ENODEV; | 727 | return -ENODEV; |
| 807 | 728 | ||
| 729 | max_packages = topology_max_packages(); | ||
| 730 | pkg_devices = kzalloc(max_packages * sizeof(struct platform_device *), | ||
| 731 | GFP_KERNEL); | ||
| 732 | if (!pkg_devices) | ||
| 733 | return -ENOMEM; | ||
| 734 | |||
| 808 | err = platform_driver_register(&coretemp_driver); | 735 | err = platform_driver_register(&coretemp_driver); |
| 809 | if (err) | 736 | if (err) |
| 810 | goto exit; | 737 | return err; |
| 811 | 738 | ||
| 812 | cpu_notifier_register_begin(); | 739 | err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online", |
| 813 | for_each_online_cpu(i) | 740 | coretemp_cpu_online, coretemp_cpu_offline); |
| 814 | get_core_online(i); | 741 | if (err < 0) |
| 815 | 742 | goto outdrv; | |
| 816 | #ifndef CONFIG_HOTPLUG_CPU | 743 | coretemp_hp_online = err; |
| 817 | if (list_empty(&pdev_list)) { | ||
| 818 | cpu_notifier_register_done(); | ||
| 819 | err = -ENODEV; | ||
| 820 | goto exit_driver_unreg; | ||
| 821 | } | ||
| 822 | #endif | ||
| 823 | |||
| 824 | __register_hotcpu_notifier(&coretemp_cpu_notifier); | ||
| 825 | cpu_notifier_register_done(); | ||
| 826 | return 0; | 744 | return 0; |
| 827 | 745 | ||
| 828 | #ifndef CONFIG_HOTPLUG_CPU | 746 | outdrv: |
| 829 | exit_driver_unreg: | ||
| 830 | platform_driver_unregister(&coretemp_driver); | 747 | platform_driver_unregister(&coretemp_driver); |
| 831 | #endif | 748 | kfree(pkg_devices); |
| 832 | exit: | ||
| 833 | return err; | 749 | return err; |
| 834 | } | 750 | } |
| 751 | module_init(coretemp_init) | ||
| 835 | 752 | ||
| 836 | static void __exit coretemp_exit(void) | 753 | static void __exit coretemp_exit(void) |
| 837 | { | 754 | { |
| 838 | struct pdev_entry *p, *n; | 755 | cpuhp_remove_state(coretemp_hp_online); |
| 839 | |||
| 840 | cpu_notifier_register_begin(); | ||
| 841 | __unregister_hotcpu_notifier(&coretemp_cpu_notifier); | ||
| 842 | mutex_lock(&pdev_list_mutex); | ||
| 843 | list_for_each_entry_safe(p, n, &pdev_list, list) { | ||
| 844 | platform_device_unregister(p->pdev); | ||
| 845 | list_del(&p->list); | ||
| 846 | kfree(p); | ||
| 847 | } | ||
| 848 | mutex_unlock(&pdev_list_mutex); | ||
| 849 | cpu_notifier_register_done(); | ||
| 850 | platform_driver_unregister(&coretemp_driver); | 756 | platform_driver_unregister(&coretemp_driver); |
| 757 | kfree(pkg_devices); | ||
| 851 | } | 758 | } |
| 759 | module_exit(coretemp_exit) | ||
| 852 | 760 | ||
| 853 | MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>"); | 761 | MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>"); |
| 854 | MODULE_DESCRIPTION("Intel Core temperature monitor"); | 762 | MODULE_DESCRIPTION("Intel Core temperature monitor"); |
| 855 | MODULE_LICENSE("GPL"); | 763 | MODULE_LICENSE("GPL"); |
| 856 | |||
| 857 | module_init(coretemp_init) | ||
| 858 | module_exit(coretemp_exit) | ||
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c index edf550fc4eef..0043a4c02b85 100644 --- a/drivers/hwmon/ds620.c +++ b/drivers/hwmon/ds620.c | |||
| @@ -166,7 +166,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, | |||
| 166 | if (res) | 166 | if (res) |
| 167 | return res; | 167 | return res; |
| 168 | 168 | ||
| 169 | val = (val * 10 / 625) * 8; | 169 | val = (clamp_val(val, -128000, 128000) * 10 / 625) * 8; |
| 170 | 170 | ||
| 171 | mutex_lock(&data->update_lock); | 171 | mutex_lock(&data->update_lock); |
| 172 | data->temp[attr->index] = val; | 172 | data->temp[attr->index] = val; |
diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 24e395c5907d..4b870ee9b0d3 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c | |||
| @@ -251,7 +251,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *da, | |||
| 251 | if (result < 0) | 251 | if (result < 0) |
| 252 | return result; | 252 | return result; |
| 253 | 253 | ||
| 254 | val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127); | 254 | val = DIV_ROUND_CLOSEST(clamp_val(val, -63000, 127000), 1000); |
| 255 | 255 | ||
| 256 | mutex_lock(&data->update_lock); | 256 | mutex_lock(&data->update_lock); |
| 257 | data->temp_min[nr] = val; | 257 | data->temp_min[nr] = val; |
| @@ -273,7 +273,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *da, | |||
| 273 | if (result < 0) | 273 | if (result < 0) |
| 274 | return result; | 274 | return result; |
| 275 | 275 | ||
| 276 | val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127); | 276 | val = DIV_ROUND_CLOSEST(clamp_val(val, -63000, 127000), 1000); |
| 277 | 277 | ||
| 278 | mutex_lock(&data->update_lock); | 278 | mutex_lock(&data->update_lock); |
| 279 | data->temp_max[nr] = val; | 279 | data->temp_max[nr] = val; |
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c index f37fe2011640..4aee5adf9ef2 100644 --- a/drivers/hwmon/emc6w201.c +++ b/drivers/hwmon/emc6w201.c | |||
| @@ -215,12 +215,13 @@ static ssize_t set_in(struct device *dev, struct device_attribute *devattr, | |||
| 215 | if (err < 0) | 215 | if (err < 0) |
| 216 | return err; | 216 | return err; |
| 217 | 217 | ||
| 218 | val = DIV_ROUND_CLOSEST(val * 0xC0, nominal_mv[nr]); | 218 | val = clamp_val(val, 0, 255 * nominal_mv[nr] / 192); |
| 219 | val = DIV_ROUND_CLOSEST(val * 192, nominal_mv[nr]); | ||
| 219 | reg = (sf == min) ? EMC6W201_REG_IN_LOW(nr) | 220 | reg = (sf == min) ? EMC6W201_REG_IN_LOW(nr) |
| 220 | : EMC6W201_REG_IN_HIGH(nr); | 221 | : EMC6W201_REG_IN_HIGH(nr); |
| 221 | 222 | ||
| 222 | mutex_lock(&data->update_lock); | 223 | mutex_lock(&data->update_lock); |
| 223 | data->in[sf][nr] = clamp_val(val, 0, 255); | 224 | data->in[sf][nr] = val; |
| 224 | err = emc6w201_write8(client, reg, data->in[sf][nr]); | 225 | err = emc6w201_write8(client, reg, data->in[sf][nr]); |
| 225 | mutex_unlock(&data->update_lock); | 226 | mutex_unlock(&data->update_lock); |
| 226 | 227 | ||
| @@ -252,12 +253,13 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, | |||
| 252 | if (err < 0) | 253 | if (err < 0) |
| 253 | return err; | 254 | return err; |
| 254 | 255 | ||
| 256 | val = clamp_val(val, -127000, 127000); | ||
| 255 | val = DIV_ROUND_CLOSEST(val, 1000); | 257 | val = DIV_ROUND_CLOSEST(val, 1000); |
| 256 | reg = (sf == min) ? EMC6W201_REG_TEMP_LOW(nr) | 258 | reg = (sf == min) ? EMC6W201_REG_TEMP_LOW(nr) |
| 257 | : EMC6W201_REG_TEMP_HIGH(nr); | 259 | : EMC6W201_REG_TEMP_HIGH(nr); |
| 258 | 260 | ||
| 259 | mutex_lock(&data->update_lock); | 261 | mutex_lock(&data->update_lock); |
| 260 | data->temp[sf][nr] = clamp_val(val, -127, 127); | 262 | data->temp[sf][nr] = val; |
| 261 | err = emc6w201_write8(client, reg, data->temp[sf][nr]); | 263 | err = emc6w201_write8(client, reg, data->temp[sf][nr]); |
| 262 | mutex_unlock(&data->update_lock); | 264 | mutex_unlock(&data->update_lock); |
| 263 | 265 | ||
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index b96a2a9e4df7..628be9c95ff9 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c | |||
| @@ -193,14 +193,17 @@ static inline unsigned int rpm_from_cnt(u8 cnt, u32 clk_freq, u16 p, | |||
| 193 | * Convert fan RPM value from sysfs into count value for fan controller | 193 | * Convert fan RPM value from sysfs into count value for fan controller |
| 194 | * register (FAN_SET_CNT). | 194 | * register (FAN_SET_CNT). |
| 195 | */ | 195 | */ |
| 196 | static inline unsigned char cnt_from_rpm(u32 rpm, u32 clk_freq, u16 p, | 196 | static inline unsigned char cnt_from_rpm(unsigned long rpm, u32 clk_freq, u16 p, |
| 197 | u8 clk_div, u8 gear_mult) | 197 | u8 clk_div, u8 gear_mult) |
| 198 | { | 198 | { |
| 199 | if (!rpm) /* to stop the fan, set cnt to 255 */ | 199 | unsigned long f1 = clk_freq * 30 * gear_mult; |
| 200 | unsigned long f2 = p * clk_div; | ||
| 201 | |||
| 202 | if (!rpm) /* to stop the fan, set cnt to 255 */ | ||
| 200 | return 0xff; | 203 | return 0xff; |
| 201 | 204 | ||
| 202 | return clamp_val(((clk_freq * 30 * gear_mult) / (rpm * p * clk_div)), | 205 | rpm = clamp_val(rpm, f1 / (255 * f2), ULONG_MAX / f2); |
| 203 | 0, 255); | 206 | return DIV_ROUND_CLOSEST(f1, rpm * f2); |
| 204 | } | 207 | } |
| 205 | 208 | ||
| 206 | /* helper to grab and cache data, at most one time per second */ | 209 | /* helper to grab and cache data, at most one time per second */ |
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index a74c075a30ec..3932f9276c07 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c | |||
| @@ -38,12 +38,15 @@ struct hwmon_device { | |||
| 38 | 38 | ||
| 39 | #define to_hwmon_device(d) container_of(d, struct hwmon_device, dev) | 39 | #define to_hwmon_device(d) container_of(d, struct hwmon_device, dev) |
| 40 | 40 | ||
| 41 | #define MAX_SYSFS_ATTR_NAME_LENGTH 32 | ||
| 42 | |||
| 41 | struct hwmon_device_attribute { | 43 | struct hwmon_device_attribute { |
| 42 | struct device_attribute dev_attr; | 44 | struct device_attribute dev_attr; |
| 43 | const struct hwmon_ops *ops; | 45 | const struct hwmon_ops *ops; |
| 44 | enum hwmon_sensor_types type; | 46 | enum hwmon_sensor_types type; |
| 45 | u32 attr; | 47 | u32 attr; |
| 46 | int index; | 48 | int index; |
| 49 | char name[MAX_SYSFS_ATTR_NAME_LENGTH]; | ||
| 47 | }; | 50 | }; |
| 48 | 51 | ||
| 49 | #define to_hwmon_attr(d) \ | 52 | #define to_hwmon_attr(d) \ |
| @@ -178,6 +181,22 @@ static ssize_t hwmon_attr_show(struct device *dev, | |||
| 178 | return sprintf(buf, "%ld\n", val); | 181 | return sprintf(buf, "%ld\n", val); |
| 179 | } | 182 | } |
| 180 | 183 | ||
| 184 | static ssize_t hwmon_attr_show_string(struct device *dev, | ||
| 185 | struct device_attribute *devattr, | ||
| 186 | char *buf) | ||
| 187 | { | ||
| 188 | struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); | ||
| 189 | char *s; | ||
| 190 | int ret; | ||
| 191 | |||
| 192 | ret = hattr->ops->read_string(dev, hattr->type, hattr->attr, | ||
| 193 | hattr->index, &s); | ||
| 194 | if (ret < 0) | ||
| 195 | return ret; | ||
| 196 | |||
| 197 | return sprintf(buf, "%s\n", s); | ||
| 198 | } | ||
| 199 | |||
| 181 | static ssize_t hwmon_attr_store(struct device *dev, | 200 | static ssize_t hwmon_attr_store(struct device *dev, |
| 182 | struct device_attribute *devattr, | 201 | struct device_attribute *devattr, |
| 183 | const char *buf, size_t count) | 202 | const char *buf, size_t count) |
| @@ -205,6 +224,17 @@ static int hwmon_attr_base(enum hwmon_sensor_types type) | |||
| 205 | return 1; | 224 | return 1; |
| 206 | } | 225 | } |
| 207 | 226 | ||
| 227 | static bool is_string_attr(enum hwmon_sensor_types type, u32 attr) | ||
| 228 | { | ||
| 229 | return (type == hwmon_temp && attr == hwmon_temp_label) || | ||
| 230 | (type == hwmon_in && attr == hwmon_in_label) || | ||
| 231 | (type == hwmon_curr && attr == hwmon_curr_label) || | ||
| 232 | (type == hwmon_power && attr == hwmon_power_label) || | ||
| 233 | (type == hwmon_energy && attr == hwmon_energy_label) || | ||
| 234 | (type == hwmon_humidity && attr == hwmon_humidity_label) || | ||
| 235 | (type == hwmon_fan && attr == hwmon_fan_label); | ||
| 236 | } | ||
| 237 | |||
| 208 | static struct attribute *hwmon_genattr(struct device *dev, | 238 | static struct attribute *hwmon_genattr(struct device *dev, |
| 209 | const void *drvdata, | 239 | const void *drvdata, |
| 210 | enum hwmon_sensor_types type, | 240 | enum hwmon_sensor_types type, |
| @@ -218,6 +248,7 @@ static struct attribute *hwmon_genattr(struct device *dev, | |||
| 218 | struct attribute *a; | 248 | struct attribute *a; |
| 219 | umode_t mode; | 249 | umode_t mode; |
| 220 | char *name; | 250 | char *name; |
| 251 | bool is_string = is_string_attr(type, attr); | ||
| 221 | 252 | ||
| 222 | /* The attribute is invisible if there is no template string */ | 253 | /* The attribute is invisible if there is no template string */ |
| 223 | if (!template) | 254 | if (!template) |
| @@ -227,32 +258,31 @@ static struct attribute *hwmon_genattr(struct device *dev, | |||
| 227 | if (!mode) | 258 | if (!mode) |
| 228 | return ERR_PTR(-ENOENT); | 259 | return ERR_PTR(-ENOENT); |
| 229 | 260 | ||
| 230 | if ((mode & S_IRUGO) && !ops->read) | 261 | if ((mode & S_IRUGO) && ((is_string && !ops->read_string) || |
| 262 | (!is_string && !ops->read))) | ||
| 231 | return ERR_PTR(-EINVAL); | 263 | return ERR_PTR(-EINVAL); |
| 232 | if ((mode & S_IWUGO) && !ops->write) | 264 | if ((mode & S_IWUGO) && !ops->write) |
| 233 | return ERR_PTR(-EINVAL); | 265 | return ERR_PTR(-EINVAL); |
| 234 | 266 | ||
| 267 | hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL); | ||
| 268 | if (!hattr) | ||
| 269 | return ERR_PTR(-ENOMEM); | ||
| 270 | |||
| 235 | if (type == hwmon_chip) { | 271 | if (type == hwmon_chip) { |
| 236 | name = (char *)template; | 272 | name = (char *)template; |
| 237 | } else { | 273 | } else { |
| 238 | name = devm_kzalloc(dev, strlen(template) + 16, GFP_KERNEL); | 274 | scnprintf(hattr->name, sizeof(hattr->name), template, |
| 239 | if (!name) | ||
| 240 | return ERR_PTR(-ENOMEM); | ||
| 241 | scnprintf(name, strlen(template) + 16, template, | ||
| 242 | index + hwmon_attr_base(type)); | 275 | index + hwmon_attr_base(type)); |
| 276 | name = hattr->name; | ||
| 243 | } | 277 | } |
| 244 | 278 | ||
| 245 | hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL); | ||
| 246 | if (!hattr) | ||
| 247 | return ERR_PTR(-ENOMEM); | ||
| 248 | |||
| 249 | hattr->type = type; | 279 | hattr->type = type; |
| 250 | hattr->attr = attr; | 280 | hattr->attr = attr; |
| 251 | hattr->index = index; | 281 | hattr->index = index; |
| 252 | hattr->ops = ops; | 282 | hattr->ops = ops; |
| 253 | 283 | ||
| 254 | dattr = &hattr->dev_attr; | 284 | dattr = &hattr->dev_attr; |
| 255 | dattr->show = hwmon_attr_show; | 285 | dattr->show = is_string ? hwmon_attr_show_string : hwmon_attr_show; |
| 256 | dattr->store = hwmon_attr_store; | 286 | dattr->store = hwmon_attr_store; |
| 257 | 287 | ||
| 258 | a = &dattr->attr; | 288 | a = &dattr->attr; |
| @@ -263,7 +293,11 @@ static struct attribute *hwmon_genattr(struct device *dev, | |||
| 263 | return a; | 293 | return a; |
| 264 | } | 294 | } |
| 265 | 295 | ||
| 266 | static const char * const hwmon_chip_attr_templates[] = { | 296 | /* |
| 297 | * Chip attributes are not attribute templates but actual sysfs attributes. | ||
| 298 | * See hwmon_genattr() for special handling. | ||
| 299 | */ | ||
| 300 | static const char * const hwmon_chip_attrs[] = { | ||
| 267 | [hwmon_chip_temp_reset_history] = "temp_reset_history", | 301 | [hwmon_chip_temp_reset_history] = "temp_reset_history", |
| 268 | [hwmon_chip_in_reset_history] = "in_reset_history", | 302 | [hwmon_chip_in_reset_history] = "in_reset_history", |
| 269 | [hwmon_chip_curr_reset_history] = "curr_reset_history", | 303 | [hwmon_chip_curr_reset_history] = "curr_reset_history", |
| @@ -400,7 +434,7 @@ static const char * const hwmon_pwm_attr_templates[] = { | |||
| 400 | }; | 434 | }; |
| 401 | 435 | ||
| 402 | static const char * const *__templates[] = { | 436 | static const char * const *__templates[] = { |
| 403 | [hwmon_chip] = hwmon_chip_attr_templates, | 437 | [hwmon_chip] = hwmon_chip_attrs, |
| 404 | [hwmon_temp] = hwmon_temp_attr_templates, | 438 | [hwmon_temp] = hwmon_temp_attr_templates, |
| 405 | [hwmon_in] = hwmon_in_attr_templates, | 439 | [hwmon_in] = hwmon_in_attr_templates, |
| 406 | [hwmon_curr] = hwmon_curr_attr_templates, | 440 | [hwmon_curr] = hwmon_curr_attr_templates, |
| @@ -412,7 +446,7 @@ static const char * const *__templates[] = { | |||
| 412 | }; | 446 | }; |
| 413 | 447 | ||
| 414 | static const int __templates_size[] = { | 448 | static const int __templates_size[] = { |
| 415 | [hwmon_chip] = ARRAY_SIZE(hwmon_chip_attr_templates), | 449 | [hwmon_chip] = ARRAY_SIZE(hwmon_chip_attrs), |
| 416 | [hwmon_temp] = ARRAY_SIZE(hwmon_temp_attr_templates), | 450 | [hwmon_temp] = ARRAY_SIZE(hwmon_temp_attr_templates), |
| 417 | [hwmon_in] = ARRAY_SIZE(hwmon_in_attr_templates), | 451 | [hwmon_in] = ARRAY_SIZE(hwmon_in_attr_templates), |
| 418 | [hwmon_curr] = ARRAY_SIZE(hwmon_curr_attr_templates), | 452 | [hwmon_curr] = ARRAY_SIZE(hwmon_curr_attr_templates), |
| @@ -526,9 +560,9 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, | |||
| 526 | 560 | ||
| 527 | hdev = &hwdev->dev; | 561 | hdev = &hwdev->dev; |
| 528 | 562 | ||
| 529 | if (chip && chip->ops->is_visible) { | 563 | if (chip) { |
| 530 | struct attribute **attrs; | 564 | struct attribute **attrs; |
| 531 | int ngroups = 2; | 565 | int ngroups = 2; /* terminating NULL plus &hwdev->groups */ |
| 532 | 566 | ||
| 533 | if (groups) | 567 | if (groups) |
| 534 | for (i = 0; groups[i]; i++) | 568 | for (i = 0; groups[i]; i++) |
| @@ -572,7 +606,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, | |||
| 572 | if (err) | 606 | if (err) |
| 573 | goto free_hwmon; | 607 | goto free_hwmon; |
| 574 | 608 | ||
| 575 | if (chip && chip->ops->is_visible && chip->ops->read && | 609 | if (chip && chip->ops->read && |
| 576 | chip->info[0]->type == hwmon_chip && | 610 | chip->info[0]->type == hwmon_chip && |
| 577 | (chip->info[0]->config[0] & HWMON_C_REGISTER_TZ)) { | 611 | (chip->info[0]->config[0] & HWMON_C_REGISTER_TZ)) { |
| 578 | const struct hwmon_channel_info **info = chip->info; | 612 | const struct hwmon_channel_info **info = chip->info; |
| @@ -626,8 +660,8 @@ EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups); | |||
| 626 | * @dev: the parent device | 660 | * @dev: the parent device |
| 627 | * @name: hwmon name attribute | 661 | * @name: hwmon name attribute |
| 628 | * @drvdata: driver data to attach to created device | 662 | * @drvdata: driver data to attach to created device |
| 629 | * @info: Pointer to hwmon chip information | 663 | * @info: pointer to hwmon chip information |
| 630 | * @groups - pointer to list of driver specific attribute groups | 664 | * @extra_groups: pointer to list of additional non-standard attribute groups |
| 631 | * | 665 | * |
| 632 | * hwmon_device_unregister() must be called when the device is no | 666 | * hwmon_device_unregister() must be called when the device is no |
| 633 | * longer needed. | 667 | * longer needed. |
| @@ -638,12 +672,12 @@ struct device * | |||
| 638 | hwmon_device_register_with_info(struct device *dev, const char *name, | 672 | hwmon_device_register_with_info(struct device *dev, const char *name, |
| 639 | void *drvdata, | 673 | void *drvdata, |
| 640 | const struct hwmon_chip_info *chip, | 674 | const struct hwmon_chip_info *chip, |
| 641 | const struct attribute_group **groups) | 675 | const struct attribute_group **extra_groups) |
| 642 | { | 676 | { |
| 643 | if (chip && (!chip->ops || !chip->info)) | 677 | if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info)) |
| 644 | return ERR_PTR(-EINVAL); | 678 | return ERR_PTR(-EINVAL); |
| 645 | 679 | ||
| 646 | return __hwmon_device_register(dev, name, drvdata, chip, groups); | 680 | return __hwmon_device_register(dev, name, drvdata, chip, extra_groups); |
| 647 | } | 681 | } |
| 648 | EXPORT_SYMBOL_GPL(hwmon_device_register_with_info); | 682 | EXPORT_SYMBOL_GPL(hwmon_device_register_with_info); |
| 649 | 683 | ||
| @@ -658,6 +692,9 @@ EXPORT_SYMBOL_GPL(hwmon_device_register_with_info); | |||
| 658 | */ | 692 | */ |
| 659 | struct device *hwmon_device_register(struct device *dev) | 693 | struct device *hwmon_device_register(struct device *dev) |
| 660 | { | 694 | { |
| 695 | dev_warn(dev, | ||
| 696 | "hwmon_device_register() is deprecated. Please convert the driver to use hwmon_device_register_with_info().\n"); | ||
| 697 | |||
| 661 | return hwmon_device_register_with_groups(dev, NULL, NULL, NULL); | 698 | return hwmon_device_register_with_groups(dev, NULL, NULL, NULL); |
| 662 | } | 699 | } |
| 663 | EXPORT_SYMBOL_GPL(hwmon_device_register); | 700 | EXPORT_SYMBOL_GPL(hwmon_device_register); |
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 6ff773fcaefb..29c8136ce9c5 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c | |||
| @@ -136,7 +136,8 @@ static const int lm85_scaling[] = { /* .001 Volts */ | |||
| 136 | #define SCALE(val, from, to) (((val) * (to) + ((from) / 2)) / (from)) | 136 | #define SCALE(val, from, to) (((val) * (to) + ((from) / 2)) / (from)) |
| 137 | 137 | ||
| 138 | #define INS_TO_REG(n, val) \ | 138 | #define INS_TO_REG(n, val) \ |
| 139 | clamp_val(SCALE(val, lm85_scaling[n], 192), 0, 255) | 139 | SCALE(clamp_val(val, 0, 255 * lm85_scaling[n] / 192), \ |
| 140 | lm85_scaling[n], 192) | ||
| 140 | 141 | ||
| 141 | #define INSEXT_FROM_REG(n, val, ext) \ | 142 | #define INSEXT_FROM_REG(n, val, ext) \ |
| 142 | SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n]) | 143 | SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n]) |
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index a5e295826aea..13cca3606e06 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c | |||
| @@ -121,7 +121,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; | |||
| 121 | 121 | ||
| 122 | #define IN_FROM_REG(reg, scale) (((reg) * (scale) + 96) / 192) | 122 | #define IN_FROM_REG(reg, scale) (((reg) * (scale) + 96) / 192) |
| 123 | #define IN_TO_REG(val, scale) ((val) <= 0 ? 0 : \ | 123 | #define IN_TO_REG(val, scale) ((val) <= 0 ? 0 : \ |
| 124 | (val) * 192 >= (scale) * 255 ? 255 : \ | 124 | (val) >= (scale) * 255 / 192 ? 255 : \ |
| 125 | ((val) * 192 + (scale) / 2) / (scale)) | 125 | ((val) * 192 + (scale) / 2) / (scale)) |
| 126 | 126 | ||
| 127 | #define TEMP_FROM_REG(reg) ((reg) * 1000) | 127 | #define TEMP_FROM_REG(reg) ((reg) * 1000) |
| @@ -154,7 +154,6 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; | |||
| 154 | */ | 154 | */ |
| 155 | 155 | ||
| 156 | struct lm87_data { | 156 | struct lm87_data { |
| 157 | struct device *hwmon_dev; | ||
| 158 | struct mutex update_lock; | 157 | struct mutex update_lock; |
| 159 | char valid; /* zero until following fields are valid */ | 158 | char valid; /* zero until following fields are valid */ |
| 160 | unsigned long last_updated; /* In jiffies */ | 159 | unsigned long last_updated; /* In jiffies */ |
| @@ -181,6 +180,8 @@ struct lm87_data { | |||
| 181 | u16 alarms; /* register values, combined */ | 180 | u16 alarms; /* register values, combined */ |
| 182 | u8 vid; /* register values, combined */ | 181 | u8 vid; /* register values, combined */ |
| 183 | u8 vrm; | 182 | u8 vrm; |
| 183 | |||
| 184 | const struct attribute_group *attr_groups[6]; | ||
| 184 | }; | 185 | }; |
| 185 | 186 | ||
| 186 | static inline int lm87_read_value(struct i2c_client *client, u8 reg) | 187 | static inline int lm87_read_value(struct i2c_client *client, u8 reg) |
| @@ -195,7 +196,7 @@ static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) | |||
| 195 | 196 | ||
| 196 | static struct lm87_data *lm87_update_device(struct device *dev) | 197 | static struct lm87_data *lm87_update_device(struct device *dev) |
| 197 | { | 198 | { |
| 198 | struct i2c_client *client = to_i2c_client(dev); | 199 | struct i2c_client *client = dev_get_drvdata(dev); |
| 199 | struct lm87_data *data = i2c_get_clientdata(client); | 200 | struct lm87_data *data = i2c_get_clientdata(client); |
| 200 | 201 | ||
| 201 | mutex_lock(&data->update_lock); | 202 | mutex_lock(&data->update_lock); |
| @@ -309,7 +310,7 @@ static ssize_t show_in_max(struct device *dev, | |||
| 309 | static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, | 310 | static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, |
| 310 | const char *buf, size_t count) | 311 | const char *buf, size_t count) |
| 311 | { | 312 | { |
| 312 | struct i2c_client *client = to_i2c_client(dev); | 313 | struct i2c_client *client = dev_get_drvdata(dev); |
| 313 | struct lm87_data *data = i2c_get_clientdata(client); | 314 | struct lm87_data *data = i2c_get_clientdata(client); |
| 314 | int nr = to_sensor_dev_attr(attr)->index; | 315 | int nr = to_sensor_dev_attr(attr)->index; |
| 315 | long val; | 316 | long val; |
| @@ -330,7 +331,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, | |||
| 330 | static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, | 331 | static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, |
| 331 | const char *buf, size_t count) | 332 | const char *buf, size_t count) |
| 332 | { | 333 | { |
| 333 | struct i2c_client *client = to_i2c_client(dev); | 334 | struct i2c_client *client = dev_get_drvdata(dev); |
| 334 | struct lm87_data *data = i2c_get_clientdata(client); | 335 | struct lm87_data *data = i2c_get_clientdata(client); |
| 335 | int nr = to_sensor_dev_attr(attr)->index; | 336 | int nr = to_sensor_dev_attr(attr)->index; |
| 336 | long val; | 337 | long val; |
| @@ -396,7 +397,7 @@ static ssize_t show_temp_high(struct device *dev, | |||
| 396 | static ssize_t set_temp_low(struct device *dev, struct device_attribute *attr, | 397 | static ssize_t set_temp_low(struct device *dev, struct device_attribute *attr, |
| 397 | const char *buf, size_t count) | 398 | const char *buf, size_t count) |
| 398 | { | 399 | { |
| 399 | struct i2c_client *client = to_i2c_client(dev); | 400 | struct i2c_client *client = dev_get_drvdata(dev); |
| 400 | struct lm87_data *data = i2c_get_clientdata(client); | 401 | struct lm87_data *data = i2c_get_clientdata(client); |
| 401 | int nr = to_sensor_dev_attr(attr)->index; | 402 | int nr = to_sensor_dev_attr(attr)->index; |
| 402 | long val; | 403 | long val; |
| @@ -416,7 +417,7 @@ static ssize_t set_temp_low(struct device *dev, struct device_attribute *attr, | |||
| 416 | static ssize_t set_temp_high(struct device *dev, struct device_attribute *attr, | 417 | static ssize_t set_temp_high(struct device *dev, struct device_attribute *attr, |
| 417 | const char *buf, size_t count) | 418 | const char *buf, size_t count) |
| 418 | { | 419 | { |
| 419 | struct i2c_client *client = to_i2c_client(dev); | 420 | struct i2c_client *client = dev_get_drvdata(dev); |
| 420 | struct lm87_data *data = i2c_get_clientdata(client); | 421 | struct lm87_data *data = i2c_get_clientdata(client); |
| 421 | int nr = to_sensor_dev_attr(attr)->index; | 422 | int nr = to_sensor_dev_attr(attr)->index; |
| 422 | long val; | 423 | long val; |
| @@ -495,7 +496,7 @@ static ssize_t show_fan_div(struct device *dev, | |||
| 495 | static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, | 496 | static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, |
| 496 | const char *buf, size_t count) | 497 | const char *buf, size_t count) |
| 497 | { | 498 | { |
| 498 | struct i2c_client *client = to_i2c_client(dev); | 499 | struct i2c_client *client = dev_get_drvdata(dev); |
| 499 | struct lm87_data *data = i2c_get_clientdata(client); | 500 | struct lm87_data *data = i2c_get_clientdata(client); |
| 500 | int nr = to_sensor_dev_attr(attr)->index; | 501 | int nr = to_sensor_dev_attr(attr)->index; |
| 501 | long val; | 502 | long val; |
| @@ -522,7 +523,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, | |||
| 522 | static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, | 523 | static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, |
| 523 | const char *buf, size_t count) | 524 | const char *buf, size_t count) |
| 524 | { | 525 | { |
| 525 | struct i2c_client *client = to_i2c_client(dev); | 526 | struct i2c_client *client = dev_get_drvdata(dev); |
| 526 | struct lm87_data *data = i2c_get_clientdata(client); | 527 | struct lm87_data *data = i2c_get_clientdata(client); |
| 527 | int nr = to_sensor_dev_attr(attr)->index; | 528 | int nr = to_sensor_dev_attr(attr)->index; |
| 528 | long val; | 529 | long val; |
| @@ -635,7 +636,7 @@ static ssize_t show_aout(struct device *dev, struct device_attribute *attr, | |||
| 635 | static ssize_t set_aout(struct device *dev, struct device_attribute *attr, | 636 | static ssize_t set_aout(struct device *dev, struct device_attribute *attr, |
| 636 | const char *buf, size_t count) | 637 | const char *buf, size_t count) |
| 637 | { | 638 | { |
| 638 | struct i2c_client *client = to_i2c_client(dev); | 639 | struct i2c_client *client = dev_get_drvdata(dev); |
| 639 | struct lm87_data *data = i2c_get_clientdata(client); | 640 | struct lm87_data *data = i2c_get_clientdata(client); |
| 640 | long val; | 641 | long val; |
| 641 | int err; | 642 | int err; |
| @@ -841,23 +842,18 @@ static int lm87_detect(struct i2c_client *client, struct i2c_board_info *info) | |||
| 841 | return 0; | 842 | return 0; |
| 842 | } | 843 | } |
| 843 | 844 | ||
| 844 | static void lm87_remove_files(struct i2c_client *client) | 845 | static void lm87_restore_config(void *arg) |
| 845 | { | 846 | { |
| 846 | struct device *dev = &client->dev; | 847 | struct i2c_client *client = arg; |
| 847 | 848 | struct lm87_data *data = i2c_get_clientdata(client); | |
| 848 | sysfs_remove_group(&dev->kobj, &lm87_group); | 849 | |
| 849 | sysfs_remove_group(&dev->kobj, &lm87_group_in6); | 850 | lm87_write_value(client, LM87_REG_CONFIG, data->config); |
| 850 | sysfs_remove_group(&dev->kobj, &lm87_group_fan1); | ||
| 851 | sysfs_remove_group(&dev->kobj, &lm87_group_in7); | ||
| 852 | sysfs_remove_group(&dev->kobj, &lm87_group_fan2); | ||
| 853 | sysfs_remove_group(&dev->kobj, &lm87_group_temp3); | ||
| 854 | sysfs_remove_group(&dev->kobj, &lm87_group_in0_5); | ||
| 855 | sysfs_remove_group(&dev->kobj, &lm87_group_vid); | ||
| 856 | } | 851 | } |
| 857 | 852 | ||
| 858 | static void lm87_init_client(struct i2c_client *client) | 853 | static int lm87_init_client(struct i2c_client *client) |
| 859 | { | 854 | { |
| 860 | struct lm87_data *data = i2c_get_clientdata(client); | 855 | struct lm87_data *data = i2c_get_clientdata(client); |
| 856 | int rc; | ||
| 861 | 857 | ||
| 862 | if (dev_get_platdata(&client->dev)) { | 858 | if (dev_get_platdata(&client->dev)) { |
| 863 | data->channel = *(u8 *)dev_get_platdata(&client->dev); | 859 | data->channel = *(u8 *)dev_get_platdata(&client->dev); |
| @@ -868,6 +864,10 @@ static void lm87_init_client(struct i2c_client *client) | |||
| 868 | } | 864 | } |
| 869 | data->config = lm87_read_value(client, LM87_REG_CONFIG) & 0x6F; | 865 | data->config = lm87_read_value(client, LM87_REG_CONFIG) & 0x6F; |
| 870 | 866 | ||
| 867 | rc = devm_add_action(&client->dev, lm87_restore_config, client); | ||
| 868 | if (rc) | ||
| 869 | return rc; | ||
| 870 | |||
| 871 | if (!(data->config & 0x01)) { | 871 | if (!(data->config & 0x01)) { |
| 872 | int i; | 872 | int i; |
| 873 | 873 | ||
| @@ -895,12 +895,15 @@ static void lm87_init_client(struct i2c_client *client) | |||
| 895 | if ((data->config & 0x09) != 0x01) | 895 | if ((data->config & 0x09) != 0x01) |
| 896 | lm87_write_value(client, LM87_REG_CONFIG, | 896 | lm87_write_value(client, LM87_REG_CONFIG, |
| 897 | (data->config & 0x77) | 0x01); | 897 | (data->config & 0x77) | 0x01); |
| 898 | return 0; | ||
| 898 | } | 899 | } |
| 899 | 900 | ||
| 900 | static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id) | 901 | static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id) |
| 901 | { | 902 | { |
| 902 | struct lm87_data *data; | 903 | struct lm87_data *data; |
| 904 | struct device *hwmon_dev; | ||
| 903 | int err; | 905 | int err; |
| 906 | unsigned int group_tail = 0; | ||
| 904 | 907 | ||
| 905 | data = devm_kzalloc(&client->dev, sizeof(struct lm87_data), GFP_KERNEL); | 908 | data = devm_kzalloc(&client->dev, sizeof(struct lm87_data), GFP_KERNEL); |
| 906 | if (!data) | 909 | if (!data) |
| @@ -910,7 +913,9 @@ static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 910 | mutex_init(&data->update_lock); | 913 | mutex_init(&data->update_lock); |
| 911 | 914 | ||
| 912 | /* Initialize the LM87 chip */ | 915 | /* Initialize the LM87 chip */ |
| 913 | lm87_init_client(client); | 916 | err = lm87_init_client(client); |
| 917 | if (err) | ||
| 918 | return err; | ||
| 914 | 919 | ||
| 915 | data->in_scale[0] = 2500; | 920 | data->in_scale[0] = 2500; |
| 916 | data->in_scale[1] = 2700; | 921 | data->in_scale[1] = 2700; |
| @@ -921,72 +926,34 @@ static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 921 | data->in_scale[6] = 1875; | 926 | data->in_scale[6] = 1875; |
| 922 | data->in_scale[7] = 1875; | 927 | data->in_scale[7] = 1875; |
| 923 | 928 | ||
| 924 | /* Register sysfs hooks */ | 929 | /* |
| 925 | err = sysfs_create_group(&client->dev.kobj, &lm87_group); | 930 | * Construct the list of attributes, the list depends on the |
| 926 | if (err) | 931 | * configuration of the chip |
| 927 | goto exit_stop; | 932 | */ |
| 928 | 933 | data->attr_groups[group_tail++] = &lm87_group; | |
| 929 | if (data->channel & CHAN_NO_FAN(0)) { | 934 | if (data->channel & CHAN_NO_FAN(0)) |
| 930 | err = sysfs_create_group(&client->dev.kobj, &lm87_group_in6); | 935 | data->attr_groups[group_tail++] = &lm87_group_in6; |
| 931 | if (err) | 936 | else |
| 932 | goto exit_remove; | 937 | data->attr_groups[group_tail++] = &lm87_group_fan1; |
| 933 | } else { | 938 | |
| 934 | err = sysfs_create_group(&client->dev.kobj, &lm87_group_fan1); | 939 | if (data->channel & CHAN_NO_FAN(1)) |
| 935 | if (err) | 940 | data->attr_groups[group_tail++] = &lm87_group_in7; |
| 936 | goto exit_remove; | 941 | else |
| 937 | } | 942 | data->attr_groups[group_tail++] = &lm87_group_fan2; |
| 938 | 943 | ||
| 939 | if (data->channel & CHAN_NO_FAN(1)) { | 944 | if (data->channel & CHAN_TEMP3) |
| 940 | err = sysfs_create_group(&client->dev.kobj, &lm87_group_in7); | 945 | data->attr_groups[group_tail++] = &lm87_group_temp3; |
| 941 | if (err) | 946 | else |
| 942 | goto exit_remove; | 947 | data->attr_groups[group_tail++] = &lm87_group_in0_5; |
| 943 | } else { | ||
| 944 | err = sysfs_create_group(&client->dev.kobj, &lm87_group_fan2); | ||
| 945 | if (err) | ||
| 946 | goto exit_remove; | ||
| 947 | } | ||
| 948 | |||
| 949 | if (data->channel & CHAN_TEMP3) { | ||
| 950 | err = sysfs_create_group(&client->dev.kobj, &lm87_group_temp3); | ||
| 951 | if (err) | ||
| 952 | goto exit_remove; | ||
| 953 | } else { | ||
| 954 | err = sysfs_create_group(&client->dev.kobj, &lm87_group_in0_5); | ||
| 955 | if (err) | ||
| 956 | goto exit_remove; | ||
| 957 | } | ||
| 958 | 948 | ||
| 959 | if (!(data->channel & CHAN_NO_VID)) { | 949 | if (!(data->channel & CHAN_NO_VID)) { |
| 960 | data->vrm = vid_which_vrm(); | 950 | data->vrm = vid_which_vrm(); |
| 961 | err = sysfs_create_group(&client->dev.kobj, &lm87_group_vid); | 951 | data->attr_groups[group_tail++] = &lm87_group_vid; |
| 962 | if (err) | ||
| 963 | goto exit_remove; | ||
| 964 | } | ||
| 965 | |||
| 966 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
| 967 | if (IS_ERR(data->hwmon_dev)) { | ||
| 968 | err = PTR_ERR(data->hwmon_dev); | ||
| 969 | goto exit_remove; | ||
| 970 | } | 952 | } |
| 971 | 953 | ||
| 972 | return 0; | 954 | hwmon_dev = devm_hwmon_device_register_with_groups( |
| 973 | 955 | &client->dev, client->name, client, data->attr_groups); | |
| 974 | exit_remove: | 956 | return PTR_ERR_OR_ZERO(hwmon_dev); |
| 975 | lm87_remove_files(client); | ||
| 976 | exit_stop: | ||
| 977 | lm87_write_value(client, LM87_REG_CONFIG, data->config); | ||
| 978 | return err; | ||
| 979 | } | ||
| 980 | |||
| 981 | static int lm87_remove(struct i2c_client *client) | ||
| 982 | { | ||
| 983 | struct lm87_data *data = i2c_get_clientdata(client); | ||
| 984 | |||
| 985 | hwmon_device_unregister(data->hwmon_dev); | ||
| 986 | lm87_remove_files(client); | ||
| 987 | |||
| 988 | lm87_write_value(client, LM87_REG_CONFIG, data->config); | ||
| 989 | return 0; | ||
| 990 | } | 957 | } |
| 991 | 958 | ||
| 992 | /* | 959 | /* |
| @@ -1006,7 +973,6 @@ static struct i2c_driver lm87_driver = { | |||
| 1006 | .name = "lm87", | 973 | .name = "lm87", |
| 1007 | }, | 974 | }, |
| 1008 | .probe = lm87_probe, | 975 | .probe = lm87_probe, |
| 1009 | .remove = lm87_remove, | ||
| 1010 | .id_table = lm87_id, | 976 | .id_table = lm87_id, |
| 1011 | .detect = lm87_detect, | 977 | .detect = lm87_detect, |
| 1012 | .address_list = normal_i2c, | 978 | .address_list = normal_i2c, |
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index 972444a14cca..1929734c3b1d 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc. | 4 | * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc. |
| 5 | * Author: Mingkai Hu <Mingkai.hu@freescale.com> | 5 | * Author: Mingkai Hu <Mingkai.hu@freescale.com> |
| 6 | * Reworked by Sven Schuchmann <schuchmann@schleissheimer.de> | 6 | * Reworked by Sven Schuchmann <schuchmann@schleissheimer.de> |
| 7 | * DT support added by Clemens Gruber <clemens.gruber@pqgruber.com> | ||
| 7 | * | 8 | * |
| 8 | * This driver export the value of analog input voltage to sysfs, the | 9 | * This driver export the value of analog input voltage to sysfs, the |
| 9 | * voltage unit is mV. Through the sysfs interface, lm-sensors tool | 10 | * voltage unit is mV. Through the sysfs interface, lm-sensors tool |
| @@ -22,11 +23,13 @@ | |||
| 22 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
| 23 | #include <linux/err.h> | 24 | #include <linux/err.h> |
| 24 | #include <linux/device.h> | 25 | #include <linux/device.h> |
| 26 | #include <linux/of.h> | ||
| 27 | #include <linux/of_device.h> | ||
| 25 | 28 | ||
| 26 | /* Vdd info */ | 29 | /* Vdd / reference voltage in millivolt */ |
| 27 | #define MCP3021_VDD_MAX 5500 | 30 | #define MCP3021_VDD_REF_MAX 5500 |
| 28 | #define MCP3021_VDD_MIN 2700 | 31 | #define MCP3021_VDD_REF_MIN 2700 |
| 29 | #define MCP3021_VDD_REF 3300 | 32 | #define MCP3021_VDD_REF_DEFAULT 3300 |
| 30 | 33 | ||
| 31 | /* output format */ | 34 | /* output format */ |
| 32 | #define MCP3021_SAR_SHIFT 2 | 35 | #define MCP3021_SAR_SHIFT 2 |
| @@ -47,7 +50,7 @@ enum chips { | |||
| 47 | */ | 50 | */ |
| 48 | struct mcp3021_data { | 51 | struct mcp3021_data { |
| 49 | struct device *hwmon_dev; | 52 | struct device *hwmon_dev; |
| 50 | u32 vdd; /* device power supply */ | 53 | u32 vdd; /* supply and reference voltage in millivolt */ |
| 51 | u16 sar_shift; | 54 | u16 sar_shift; |
| 52 | u16 sar_mask; | 55 | u16 sar_mask; |
| 53 | u8 output_res; | 56 | u8 output_res; |
| @@ -99,13 +102,14 @@ static ssize_t show_in_input(struct device *dev, struct device_attribute *attr, | |||
| 99 | return sprintf(buf, "%d\n", in_input); | 102 | return sprintf(buf, "%d\n", in_input); |
| 100 | } | 103 | } |
| 101 | 104 | ||
| 102 | static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL); | 105 | static DEVICE_ATTR(in0_input, 0444, show_in_input, NULL); |
| 103 | 106 | ||
| 104 | static int mcp3021_probe(struct i2c_client *client, | 107 | static int mcp3021_probe(struct i2c_client *client, |
| 105 | const struct i2c_device_id *id) | 108 | const struct i2c_device_id *id) |
| 106 | { | 109 | { |
| 107 | int err; | 110 | int err; |
| 108 | struct mcp3021_data *data = NULL; | 111 | struct mcp3021_data *data = NULL; |
| 112 | struct device_node *np = client->dev.of_node; | ||
| 109 | 113 | ||
| 110 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | 114 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) |
| 111 | return -ENODEV; | 115 | return -ENODEV; |
| @@ -117,6 +121,21 @@ static int mcp3021_probe(struct i2c_client *client, | |||
| 117 | 121 | ||
| 118 | i2c_set_clientdata(client, data); | 122 | i2c_set_clientdata(client, data); |
| 119 | 123 | ||
| 124 | if (np) { | ||
| 125 | if (!of_property_read_u32(np, "reference-voltage-microvolt", | ||
| 126 | &data->vdd)) | ||
| 127 | data->vdd /= 1000; | ||
| 128 | else | ||
| 129 | data->vdd = MCP3021_VDD_REF_DEFAULT; | ||
| 130 | } else { | ||
| 131 | u32 *pdata = dev_get_platdata(&client->dev); | ||
| 132 | |||
| 133 | if (pdata) | ||
| 134 | data->vdd = *pdata; | ||
| 135 | else | ||
| 136 | data->vdd = MCP3021_VDD_REF_DEFAULT; | ||
| 137 | } | ||
| 138 | |||
| 120 | switch (id->driver_data) { | 139 | switch (id->driver_data) { |
| 121 | case mcp3021: | 140 | case mcp3021: |
| 122 | data->sar_shift = MCP3021_SAR_SHIFT; | 141 | data->sar_shift = MCP3021_SAR_SHIFT; |
| @@ -131,13 +150,8 @@ static int mcp3021_probe(struct i2c_client *client, | |||
| 131 | break; | 150 | break; |
| 132 | } | 151 | } |
| 133 | 152 | ||
| 134 | if (dev_get_platdata(&client->dev)) { | 153 | if (data->vdd > MCP3021_VDD_REF_MAX || data->vdd < MCP3021_VDD_REF_MIN) |
| 135 | data->vdd = *(u32 *)dev_get_platdata(&client->dev); | 154 | return -EINVAL; |
| 136 | if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN) | ||
| 137 | return -EINVAL; | ||
| 138 | } else { | ||
| 139 | data->vdd = MCP3021_VDD_REF; | ||
| 140 | } | ||
| 141 | 155 | ||
| 142 | err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr); | 156 | err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr); |
| 143 | if (err) | 157 | if (err) |
| @@ -173,9 +187,19 @@ static const struct i2c_device_id mcp3021_id[] = { | |||
| 173 | }; | 187 | }; |
| 174 | MODULE_DEVICE_TABLE(i2c, mcp3021_id); | 188 | MODULE_DEVICE_TABLE(i2c, mcp3021_id); |
| 175 | 189 | ||
| 190 | #ifdef CONFIG_OF | ||
| 191 | static const struct of_device_id of_mcp3021_match[] = { | ||
| 192 | { .compatible = "microchip,mcp3021", .data = (void *)mcp3021 }, | ||
| 193 | { .compatible = "microchip,mcp3221", .data = (void *)mcp3221 }, | ||
| 194 | { } | ||
| 195 | }; | ||
| 196 | MODULE_DEVICE_TABLE(of, of_mcp3021_match); | ||
| 197 | #endif | ||
| 198 | |||
| 176 | static struct i2c_driver mcp3021_driver = { | 199 | static struct i2c_driver mcp3021_driver = { |
| 177 | .driver = { | 200 | .driver = { |
| 178 | .name = "mcp3021", | 201 | .name = "mcp3021", |
| 202 | .of_match_table = of_match_ptr(of_mcp3021_match), | ||
| 179 | }, | 203 | }, |
| 180 | .probe = mcp3021_probe, | 204 | .probe = mcp3021_probe, |
| 181 | .remove = mcp3021_remove, | 205 | .remove = mcp3021_remove, |
diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 3ce33d244cc0..12b94b094c0d 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c | |||
| @@ -259,13 +259,15 @@ static int nct7802_read_fan_min(struct nct7802_data *data, u8 reg_fan_low, | |||
| 259 | ret = 0; | 259 | ret = 0; |
| 260 | else if (ret) | 260 | else if (ret) |
| 261 | ret = DIV_ROUND_CLOSEST(1350000U, ret); | 261 | ret = DIV_ROUND_CLOSEST(1350000U, ret); |
| 262 | else | ||
| 263 | ret = 1350000U; | ||
| 262 | abort: | 264 | abort: |
| 263 | mutex_unlock(&data->access_lock); | 265 | mutex_unlock(&data->access_lock); |
| 264 | return ret; | 266 | return ret; |
| 265 | } | 267 | } |
| 266 | 268 | ||
| 267 | static int nct7802_write_fan_min(struct nct7802_data *data, u8 reg_fan_low, | 269 | static int nct7802_write_fan_min(struct nct7802_data *data, u8 reg_fan_low, |
| 268 | u8 reg_fan_high, unsigned int limit) | 270 | u8 reg_fan_high, unsigned long limit) |
| 269 | { | 271 | { |
| 270 | int err; | 272 | int err; |
| 271 | 273 | ||
| @@ -326,8 +328,8 @@ static int nct7802_write_voltage(struct nct7802_data *data, int nr, int index, | |||
| 326 | int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr]; | 328 | int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr]; |
| 327 | int err; | 329 | int err; |
| 328 | 330 | ||
| 331 | voltage = clamp_val(voltage, 0, 0x3ff * nct7802_vmul[nr]); | ||
| 329 | voltage = DIV_ROUND_CLOSEST(voltage, nct7802_vmul[nr]); | 332 | voltage = DIV_ROUND_CLOSEST(voltage, nct7802_vmul[nr]); |
| 330 | voltage = clamp_val(voltage, 0, 0x3ff); | ||
| 331 | 333 | ||
| 332 | mutex_lock(&data->access_lock); | 334 | mutex_lock(&data->access_lock); |
| 333 | err = regmap_write(data->regmap, | 335 | err = regmap_write(data->regmap, |
| @@ -402,7 +404,7 @@ static ssize_t store_temp(struct device *dev, struct device_attribute *attr, | |||
| 402 | if (err < 0) | 404 | if (err < 0) |
| 403 | return err; | 405 | return err; |
| 404 | 406 | ||
| 405 | val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127); | 407 | val = DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), 1000); |
| 406 | 408 | ||
| 407 | err = regmap_write(data->regmap, nr, val & 0xff); | 409 | err = regmap_write(data->regmap, nr, val & 0xff); |
| 408 | return err ? : count; | 410 | return err ? : count; |
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 3baa4f4a8c5e..4ab5293c7bf0 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c | |||
| @@ -499,15 +499,27 @@ static int adm1275_probe(struct i2c_client *client, | |||
| 499 | pindex = 2; | 499 | pindex = 2; |
| 500 | tindex = 3; | 500 | tindex = 3; |
| 501 | 501 | ||
| 502 | info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT; | 502 | info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | |
| 503 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | ||
| 504 | |||
| 505 | /* Enable VOUT if not enabled (it is disabled by default) */ | ||
| 506 | if (!(config & ADM1278_VOUT_EN)) { | ||
| 507 | config |= ADM1278_VOUT_EN; | ||
| 508 | ret = i2c_smbus_write_byte_data(client, | ||
| 509 | ADM1275_PMON_CONFIG, | ||
| 510 | config); | ||
| 511 | if (ret < 0) { | ||
| 512 | dev_err(&client->dev, | ||
| 513 | "Failed to enable VOUT monitoring\n"); | ||
| 514 | return -ENODEV; | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 503 | if (config & ADM1278_TEMP1_EN) | 518 | if (config & ADM1278_TEMP1_EN) |
| 504 | info->func[0] |= | 519 | info->func[0] |= |
| 505 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; | 520 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; |
| 506 | if (config & ADM1278_VIN_EN) | 521 | if (config & ADM1278_VIN_EN) |
| 507 | info->func[0] |= PMBUS_HAVE_VIN; | 522 | info->func[0] |= PMBUS_HAVE_VIN; |
| 508 | if (config & ADM1278_VOUT_EN) | ||
| 509 | info->func[0] |= | ||
| 510 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | ||
| 511 | break; | 523 | break; |
| 512 | case adm1293: | 524 | case adm1293: |
| 513 | case adm1294: | 525 | case adm1294: |
diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c index 559a3dcd64d8..094f948f99ff 100644 --- a/drivers/hwmon/scpi-hwmon.c +++ b/drivers/hwmon/scpi-hwmon.c | |||
| @@ -251,6 +251,7 @@ static const struct of_device_id scpi_of_match[] = { | |||
| 251 | {.compatible = "arm,scpi-sensors"}, | 251 | {.compatible = "arm,scpi-sensors"}, |
| 252 | {}, | 252 | {}, |
| 253 | }; | 253 | }; |
| 254 | MODULE_DEVICE_TABLE(of, scpi_of_match); | ||
| 254 | 255 | ||
| 255 | static struct platform_driver scpi_hwmon_platdrv = { | 256 | static struct platform_driver scpi_hwmon_platdrv = { |
| 256 | .driver = { | 257 | .driver = { |
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index 6ac7cda72d4c..15650f247679 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c | |||
| @@ -77,14 +77,15 @@ static inline unsigned int IN_FROM_REG(u8 reg, int n) | |||
| 77 | 77 | ||
| 78 | static inline u8 IN_TO_REG(unsigned long val, int n) | 78 | static inline u8 IN_TO_REG(unsigned long val, int n) |
| 79 | { | 79 | { |
| 80 | return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255); | 80 | val = clamp_val(val, 0, nom_mv[n] * 255 / 192); |
| 81 | return SCALE(val, 192, nom_mv[n]); | ||
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | /* | 84 | /* |
| 84 | * TEMP: 0.001 degC units (-128C to +127C) | 85 | * TEMP: 0.001 degC units (-128C to +127C) |
| 85 | * REG: 1C/bit, two's complement | 86 | * REG: 1C/bit, two's complement |
| 86 | */ | 87 | */ |
| 87 | static inline s8 TEMP_TO_REG(int val) | 88 | static inline s8 TEMP_TO_REG(long val) |
| 88 | { | 89 | { |
| 89 | return SCALE(clamp_val(val, -128000, 127000), 1, 1000); | 90 | return SCALE(clamp_val(val, -128000, 127000), 1, 1000); |
| 90 | } | 91 | } |
diff --git a/drivers/hwmon/tc654.c b/drivers/hwmon/tc654.c new file mode 100644 index 000000000000..18136e1f95fd --- /dev/null +++ b/drivers/hwmon/tc654.c | |||
| @@ -0,0 +1,514 @@ | |||
| 1 | /* | ||
| 2 | * tc654.c - Linux kernel modules for fan speed controller | ||
| 3 | * | ||
| 4 | * Copyright (C) 2016 Allied Telesis Labs NZ | ||
| 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 as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/bitops.h> | ||
| 18 | #include <linux/err.h> | ||
| 19 | #include <linux/hwmon.h> | ||
| 20 | #include <linux/hwmon-sysfs.h> | ||
| 21 | #include <linux/i2c.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/jiffies.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/mutex.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | #include <linux/util_macros.h> | ||
| 28 | |||
| 29 | enum tc654_regs { | ||
| 30 | TC654_REG_RPM1 = 0x00, /* RPM Output 1 */ | ||
| 31 | TC654_REG_RPM2 = 0x01, /* RPM Output 2 */ | ||
| 32 | TC654_REG_FAN_FAULT1 = 0x02, /* Fan Fault 1 Threshold */ | ||
| 33 | TC654_REG_FAN_FAULT2 = 0x03, /* Fan Fault 2 Threshold */ | ||
| 34 | TC654_REG_CONFIG = 0x04, /* Configuration */ | ||
| 35 | TC654_REG_STATUS = 0x05, /* Status */ | ||
| 36 | TC654_REG_DUTY_CYCLE = 0x06, /* Fan Speed Duty Cycle */ | ||
| 37 | TC654_REG_MFR_ID = 0x07, /* Manufacturer Identification */ | ||
| 38 | TC654_REG_VER_ID = 0x08, /* Version Identification */ | ||
| 39 | }; | ||
| 40 | |||
| 41 | /* Macros to easily index the registers */ | ||
| 42 | #define TC654_REG_RPM(idx) (TC654_REG_RPM1 + (idx)) | ||
| 43 | #define TC654_REG_FAN_FAULT(idx) (TC654_REG_FAN_FAULT1 + (idx)) | ||
| 44 | |||
| 45 | /* Config register bits */ | ||
| 46 | #define TC654_REG_CONFIG_RES BIT(6) /* Resolution Selection */ | ||
| 47 | #define TC654_REG_CONFIG_DUTYC BIT(5) /* Duty Cycle Control */ | ||
| 48 | #define TC654_REG_CONFIG_SDM BIT(0) /* Shutdown Mode */ | ||
| 49 | |||
| 50 | /* Status register bits */ | ||
| 51 | #define TC654_REG_STATUS_F2F BIT(1) /* Fan 2 Fault */ | ||
| 52 | #define TC654_REG_STATUS_F1F BIT(0) /* Fan 1 Fault */ | ||
| 53 | |||
| 54 | /* RPM resolution for RPM Output registers */ | ||
| 55 | #define TC654_HIGH_RPM_RESOLUTION 25 /* 25 RPM resolution */ | ||
| 56 | #define TC654_LOW_RPM_RESOLUTION 50 /* 50 RPM resolution */ | ||
| 57 | |||
| 58 | /* Convert to the fan fault RPM threshold from register value */ | ||
| 59 | #define TC654_FAN_FAULT_FROM_REG(val) ((val) * 50) /* 50 RPM resolution */ | ||
| 60 | |||
| 61 | /* Convert to register value from the fan fault RPM threshold */ | ||
| 62 | #define TC654_FAN_FAULT_TO_REG(val) (((val) / 50) & 0xff) | ||
| 63 | |||
| 64 | /* Register data is read (and cached) at most once per second. */ | ||
| 65 | #define TC654_UPDATE_INTERVAL HZ | ||
| 66 | |||
| 67 | struct tc654_data { | ||
| 68 | struct i2c_client *client; | ||
| 69 | |||
| 70 | /* update mutex */ | ||
| 71 | struct mutex update_lock; | ||
| 72 | |||
| 73 | /* tc654 register cache */ | ||
| 74 | bool valid; | ||
| 75 | unsigned long last_updated; /* in jiffies */ | ||
| 76 | |||
| 77 | u8 rpm_output[2]; /* The fan RPM data for fans 1 and 2 is then | ||
| 78 | * written to registers RPM1 and RPM2 | ||
| 79 | */ | ||
| 80 | u8 fan_fault[2]; /* The Fan Fault Threshold Registers are used to | ||
| 81 | * set the fan fault threshold levels for fan 1 | ||
| 82 | * and fan 2 | ||
| 83 | */ | ||
| 84 | u8 config; /* The Configuration Register is an 8-bit read/ | ||
| 85 | * writable multi-function control register | ||
| 86 | * 7: Fan Fault Clear | ||
| 87 | * 1 = Clear Fan Fault | ||
| 88 | * 0 = Normal Operation (default) | ||
| 89 | * 6: Resolution Selection for RPM Output Registers | ||
| 90 | * RPM Output Registers (RPM1 and RPM2) will be | ||
| 91 | * set for | ||
| 92 | * 1 = 25 RPM (9-bit) resolution | ||
| 93 | * 0 = 50 RPM (8-bit) resolution (default) | ||
| 94 | * 5: Duty Cycle Control Method | ||
| 95 | * The V OUT duty cycle will be controlled via | ||
| 96 | * 1 = the SMBus interface. | ||
| 97 | * 0 = via the V IN analog input pin. (default) | ||
| 98 | * 4,3: Fan 2 Pulses Per Rotation | ||
| 99 | * 00 = 1 | ||
| 100 | * 01 = 2 (default) | ||
| 101 | * 10 = 4 | ||
| 102 | * 11 = 8 | ||
| 103 | * 2,1: Fan 1 Pulses Per Rotation | ||
| 104 | * 00 = 1 | ||
| 105 | * 01 = 2 (default) | ||
| 106 | * 10 = 4 | ||
| 107 | * 11 = 8 | ||
| 108 | * 0: Shutdown Mode | ||
| 109 | * 1 = Shutdown mode. | ||
| 110 | * 0 = Normal operation. (default) | ||
| 111 | */ | ||
| 112 | u8 status; /* The Status register provides all the information | ||
| 113 | * about what is going on within the TC654/TC655 | ||
| 114 | * devices. | ||
| 115 | * 7,6: Unimplemented, Read as '0' | ||
| 116 | * 5: Over-Temperature Fault Condition | ||
| 117 | * 1 = Over-Temperature condition has occurred | ||
| 118 | * 0 = Normal operation. V IN is less than 2.6V | ||
| 119 | * 4: RPM2 Counter Overflow | ||
| 120 | * 1 = Fault condition | ||
| 121 | * 0 = Normal operation | ||
| 122 | * 3: RPM1 Counter Overflow | ||
| 123 | * 1 = Fault condition | ||
| 124 | * 0 = Normal operation | ||
| 125 | * 2: V IN Input Status | ||
| 126 | * 1 = V IN is open | ||
| 127 | * 0 = Normal operation. voltage present at V IN | ||
| 128 | * 1: Fan 2 Fault | ||
| 129 | * 1 = Fault condition | ||
| 130 | * 0 = Normal operation | ||
| 131 | * 0: Fan 1 Fault | ||
| 132 | * 1 = Fault condition | ||
| 133 | * 0 = Normal operation | ||
| 134 | */ | ||
| 135 | u8 duty_cycle; /* The DUTY_CYCLE register is a 4-bit read/ | ||
| 136 | * writable register used to control the duty | ||
| 137 | * cycle of the V OUT output. | ||
| 138 | */ | ||
| 139 | }; | ||
| 140 | |||
| 141 | /* helper to grab and cache data, at most one time per second */ | ||
| 142 | static struct tc654_data *tc654_update_client(struct device *dev) | ||
| 143 | { | ||
| 144 | struct tc654_data *data = dev_get_drvdata(dev); | ||
| 145 | struct i2c_client *client = data->client; | ||
| 146 | int ret = 0; | ||
| 147 | |||
| 148 | mutex_lock(&data->update_lock); | ||
| 149 | if (time_before(jiffies, data->last_updated + TC654_UPDATE_INTERVAL) && | ||
| 150 | likely(data->valid)) | ||
| 151 | goto out; | ||
| 152 | |||
| 153 | ret = i2c_smbus_read_byte_data(client, TC654_REG_RPM(0)); | ||
| 154 | if (ret < 0) | ||
| 155 | goto out; | ||
| 156 | data->rpm_output[0] = ret; | ||
| 157 | |||
| 158 | ret = i2c_smbus_read_byte_data(client, TC654_REG_RPM(1)); | ||
| 159 | if (ret < 0) | ||
| 160 | goto out; | ||
| 161 | data->rpm_output[1] = ret; | ||
| 162 | |||
| 163 | ret = i2c_smbus_read_byte_data(client, TC654_REG_FAN_FAULT(0)); | ||
| 164 | if (ret < 0) | ||
| 165 | goto out; | ||
| 166 | data->fan_fault[0] = ret; | ||
| 167 | |||
| 168 | ret = i2c_smbus_read_byte_data(client, TC654_REG_FAN_FAULT(1)); | ||
| 169 | if (ret < 0) | ||
| 170 | goto out; | ||
| 171 | data->fan_fault[1] = ret; | ||
| 172 | |||
| 173 | ret = i2c_smbus_read_byte_data(client, TC654_REG_CONFIG); | ||
| 174 | if (ret < 0) | ||
| 175 | goto out; | ||
| 176 | data->config = ret; | ||
| 177 | |||
| 178 | ret = i2c_smbus_read_byte_data(client, TC654_REG_STATUS); | ||
| 179 | if (ret < 0) | ||
| 180 | goto out; | ||
| 181 | data->status = ret; | ||
| 182 | |||
| 183 | ret = i2c_smbus_read_byte_data(client, TC654_REG_DUTY_CYCLE); | ||
| 184 | if (ret < 0) | ||
| 185 | goto out; | ||
| 186 | data->duty_cycle = ret & 0x0f; | ||
| 187 | |||
| 188 | data->last_updated = jiffies; | ||
| 189 | data->valid = true; | ||
| 190 | out: | ||
| 191 | mutex_unlock(&data->update_lock); | ||
| 192 | |||
| 193 | if (ret < 0) /* upon error, encode it in return value */ | ||
| 194 | data = ERR_PTR(ret); | ||
| 195 | |||
| 196 | return data; | ||
| 197 | } | ||
| 198 | |||
| 199 | /* | ||
| 200 | * sysfs attributes | ||
| 201 | */ | ||
| 202 | |||
| 203 | static ssize_t show_fan(struct device *dev, struct device_attribute *da, | ||
| 204 | char *buf) | ||
| 205 | { | ||
| 206 | int nr = to_sensor_dev_attr(da)->index; | ||
| 207 | struct tc654_data *data = tc654_update_client(dev); | ||
| 208 | int val; | ||
| 209 | |||
| 210 | if (IS_ERR(data)) | ||
| 211 | return PTR_ERR(data); | ||
| 212 | |||
| 213 | if (data->config & TC654_REG_CONFIG_RES) | ||
| 214 | val = data->rpm_output[nr] * TC654_HIGH_RPM_RESOLUTION; | ||
| 215 | else | ||
| 216 | val = data->rpm_output[nr] * TC654_LOW_RPM_RESOLUTION; | ||
| 217 | |||
| 218 | return sprintf(buf, "%d\n", val); | ||
| 219 | } | ||
| 220 | |||
| 221 | static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, | ||
| 222 | char *buf) | ||
| 223 | { | ||
| 224 | int nr = to_sensor_dev_attr(da)->index; | ||
| 225 | struct tc654_data *data = tc654_update_client(dev); | ||
| 226 | |||
| 227 | if (IS_ERR(data)) | ||
| 228 | return PTR_ERR(data); | ||
| 229 | |||
| 230 | return sprintf(buf, "%d\n", | ||
| 231 | TC654_FAN_FAULT_FROM_REG(data->fan_fault[nr])); | ||
| 232 | } | ||
| 233 | |||
| 234 | static ssize_t set_fan_min(struct device *dev, struct device_attribute *da, | ||
| 235 | const char *buf, size_t count) | ||
| 236 | { | ||
| 237 | int nr = to_sensor_dev_attr(da)->index; | ||
| 238 | struct tc654_data *data = dev_get_drvdata(dev); | ||
| 239 | struct i2c_client *client = data->client; | ||
| 240 | unsigned long val; | ||
| 241 | int ret; | ||
| 242 | |||
| 243 | if (kstrtoul(buf, 10, &val)) | ||
| 244 | return -EINVAL; | ||
| 245 | |||
| 246 | val = clamp_val(val, 0, 12750); | ||
| 247 | |||
| 248 | mutex_lock(&data->update_lock); | ||
| 249 | |||
| 250 | data->fan_fault[nr] = TC654_FAN_FAULT_TO_REG(val); | ||
| 251 | ret = i2c_smbus_write_byte_data(client, TC654_REG_FAN_FAULT(nr), | ||
| 252 | data->fan_fault[nr]); | ||
| 253 | |||
| 254 | mutex_unlock(&data->update_lock); | ||
| 255 | return ret < 0 ? ret : count; | ||
| 256 | } | ||
| 257 | |||
| 258 | static ssize_t show_fan_alarm(struct device *dev, struct device_attribute *da, | ||
| 259 | char *buf) | ||
| 260 | { | ||
| 261 | int nr = to_sensor_dev_attr(da)->index; | ||
| 262 | struct tc654_data *data = tc654_update_client(dev); | ||
| 263 | int val; | ||
| 264 | |||
| 265 | if (IS_ERR(data)) | ||
| 266 | return PTR_ERR(data); | ||
| 267 | |||
| 268 | if (nr == 0) | ||
| 269 | val = !!(data->status & TC654_REG_STATUS_F1F); | ||
| 270 | else | ||
| 271 | val = !!(data->status & TC654_REG_STATUS_F2F); | ||
| 272 | |||
| 273 | return sprintf(buf, "%d\n", val); | ||
| 274 | } | ||
| 275 | |||
| 276 | static const u8 TC654_FAN_PULSE_SHIFT[] = { 1, 3 }; | ||
| 277 | |||
| 278 | static ssize_t show_fan_pulses(struct device *dev, struct device_attribute *da, | ||
| 279 | char *buf) | ||
| 280 | { | ||
| 281 | int nr = to_sensor_dev_attr(da)->index; | ||
| 282 | struct tc654_data *data = tc654_update_client(dev); | ||
| 283 | u8 val; | ||
| 284 | |||
| 285 | if (IS_ERR(data)) | ||
| 286 | return PTR_ERR(data); | ||
| 287 | |||
| 288 | val = BIT((data->config >> TC654_FAN_PULSE_SHIFT[nr]) & 0x03); | ||
| 289 | return sprintf(buf, "%d\n", val); | ||
| 290 | } | ||
| 291 | |||
| 292 | static ssize_t set_fan_pulses(struct device *dev, struct device_attribute *da, | ||
| 293 | const char *buf, size_t count) | ||
| 294 | { | ||
| 295 | int nr = to_sensor_dev_attr(da)->index; | ||
| 296 | struct tc654_data *data = dev_get_drvdata(dev); | ||
| 297 | struct i2c_client *client = data->client; | ||
| 298 | u8 config; | ||
| 299 | unsigned long val; | ||
| 300 | int ret; | ||
| 301 | |||
| 302 | if (kstrtoul(buf, 10, &val)) | ||
| 303 | return -EINVAL; | ||
| 304 | |||
| 305 | switch (val) { | ||
| 306 | case 1: | ||
| 307 | config = 0; | ||
| 308 | break; | ||
| 309 | case 2: | ||
| 310 | config = 1; | ||
| 311 | break; | ||
| 312 | case 4: | ||
| 313 | config = 2; | ||
| 314 | break; | ||
| 315 | case 8: | ||
| 316 | config = 3; | ||
| 317 | break; | ||
| 318 | default: | ||
| 319 | return -EINVAL; | ||
| 320 | } | ||
| 321 | |||
| 322 | mutex_lock(&data->update_lock); | ||
| 323 | |||
| 324 | data->config &= ~(0x03 << TC654_FAN_PULSE_SHIFT[nr]); | ||
| 325 | data->config |= (config << TC654_FAN_PULSE_SHIFT[nr]); | ||
| 326 | ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config); | ||
| 327 | |||
| 328 | mutex_unlock(&data->update_lock); | ||
| 329 | return ret < 0 ? ret : count; | ||
| 330 | } | ||
| 331 | |||
| 332 | static ssize_t show_pwm_mode(struct device *dev, | ||
| 333 | struct device_attribute *da, char *buf) | ||
| 334 | { | ||
| 335 | struct tc654_data *data = tc654_update_client(dev); | ||
| 336 | |||
| 337 | if (IS_ERR(data)) | ||
| 338 | return PTR_ERR(data); | ||
| 339 | |||
| 340 | return sprintf(buf, "%d\n", !!(data->config & TC654_REG_CONFIG_DUTYC)); | ||
| 341 | } | ||
| 342 | |||
| 343 | static ssize_t set_pwm_mode(struct device *dev, | ||
| 344 | struct device_attribute *da, | ||
| 345 | const char *buf, size_t count) | ||
| 346 | { | ||
| 347 | struct tc654_data *data = dev_get_drvdata(dev); | ||
| 348 | struct i2c_client *client = data->client; | ||
| 349 | unsigned long val; | ||
| 350 | int ret; | ||
| 351 | |||
| 352 | if (kstrtoul(buf, 10, &val)) | ||
| 353 | return -EINVAL; | ||
| 354 | |||
| 355 | if (val != 0 && val != 1) | ||
| 356 | return -EINVAL; | ||
| 357 | |||
| 358 | mutex_lock(&data->update_lock); | ||
| 359 | |||
| 360 | if (val) | ||
| 361 | data->config |= TC654_REG_CONFIG_DUTYC; | ||
| 362 | else | ||
| 363 | data->config &= ~TC654_REG_CONFIG_DUTYC; | ||
| 364 | |||
| 365 | ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config); | ||
| 366 | |||
| 367 | mutex_unlock(&data->update_lock); | ||
| 368 | return ret < 0 ? ret : count; | ||
| 369 | } | ||
| 370 | |||
| 371 | static const int tc654_pwm_map[16] = { 77, 88, 102, 112, 124, 136, 148, 160, | ||
| 372 | 172, 184, 196, 207, 219, 231, 243, 255}; | ||
| 373 | |||
| 374 | static ssize_t show_pwm(struct device *dev, struct device_attribute *da, | ||
| 375 | char *buf) | ||
| 376 | { | ||
| 377 | struct tc654_data *data = tc654_update_client(dev); | ||
| 378 | int pwm; | ||
| 379 | |||
| 380 | if (IS_ERR(data)) | ||
| 381 | return PTR_ERR(data); | ||
| 382 | |||
| 383 | if (data->config & TC654_REG_CONFIG_SDM) | ||
| 384 | pwm = 0; | ||
| 385 | else | ||
| 386 | pwm = tc654_pwm_map[data->duty_cycle]; | ||
| 387 | |||
| 388 | return sprintf(buf, "%d\n", pwm); | ||
| 389 | } | ||
| 390 | |||
| 391 | static ssize_t set_pwm(struct device *dev, struct device_attribute *da, | ||
| 392 | const char *buf, size_t count) | ||
| 393 | { | ||
| 394 | struct tc654_data *data = dev_get_drvdata(dev); | ||
| 395 | struct i2c_client *client = data->client; | ||
| 396 | unsigned long val; | ||
| 397 | int ret; | ||
| 398 | |||
| 399 | if (kstrtoul(buf, 10, &val)) | ||
| 400 | return -EINVAL; | ||
| 401 | if (val > 255) | ||
| 402 | return -EINVAL; | ||
| 403 | |||
| 404 | mutex_lock(&data->update_lock); | ||
| 405 | |||
| 406 | if (val == 0) | ||
| 407 | data->config |= TC654_REG_CONFIG_SDM; | ||
| 408 | else | ||
| 409 | data->config &= ~TC654_REG_CONFIG_SDM; | ||
| 410 | |||
| 411 | data->duty_cycle = find_closest(val, tc654_pwm_map, | ||
| 412 | ARRAY_SIZE(tc654_pwm_map)); | ||
| 413 | |||
| 414 | ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config); | ||
| 415 | if (ret < 0) | ||
| 416 | goto out; | ||
| 417 | |||
| 418 | ret = i2c_smbus_write_byte_data(client, TC654_REG_DUTY_CYCLE, | ||
| 419 | data->duty_cycle); | ||
| 420 | |||
| 421 | out: | ||
| 422 | mutex_unlock(&data->update_lock); | ||
| 423 | return ret < 0 ? ret : count; | ||
| 424 | } | ||
| 425 | |||
| 426 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); | ||
| 427 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); | ||
| 428 | static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, | ||
| 429 | set_fan_min, 0); | ||
| 430 | static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, | ||
| 431 | set_fan_min, 1); | ||
| 432 | static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0); | ||
| 433 | static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1); | ||
| 434 | static SENSOR_DEVICE_ATTR(fan1_pulses, S_IWUSR | S_IRUGO, show_fan_pulses, | ||
| 435 | set_fan_pulses, 0); | ||
| 436 | static SENSOR_DEVICE_ATTR(fan2_pulses, S_IWUSR | S_IRUGO, show_fan_pulses, | ||
| 437 | set_fan_pulses, 1); | ||
| 438 | static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, | ||
| 439 | show_pwm_mode, set_pwm_mode, 0); | ||
| 440 | static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, | ||
| 441 | set_pwm, 0); | ||
| 442 | |||
| 443 | /* Driver data */ | ||
| 444 | static struct attribute *tc654_attrs[] = { | ||
| 445 | &sensor_dev_attr_fan1_input.dev_attr.attr, | ||
| 446 | &sensor_dev_attr_fan2_input.dev_attr.attr, | ||
| 447 | &sensor_dev_attr_fan1_min.dev_attr.attr, | ||
| 448 | &sensor_dev_attr_fan2_min.dev_attr.attr, | ||
| 449 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, | ||
| 450 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, | ||
| 451 | &sensor_dev_attr_fan1_pulses.dev_attr.attr, | ||
| 452 | &sensor_dev_attr_fan2_pulses.dev_attr.attr, | ||
| 453 | &sensor_dev_attr_pwm1_mode.dev_attr.attr, | ||
| 454 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
| 455 | NULL | ||
| 456 | }; | ||
| 457 | |||
| 458 | ATTRIBUTE_GROUPS(tc654); | ||
| 459 | |||
| 460 | /* | ||
| 461 | * device probe and removal | ||
| 462 | */ | ||
| 463 | |||
| 464 | static int tc654_probe(struct i2c_client *client, | ||
| 465 | const struct i2c_device_id *id) | ||
| 466 | { | ||
| 467 | struct device *dev = &client->dev; | ||
| 468 | struct tc654_data *data; | ||
| 469 | struct device *hwmon_dev; | ||
| 470 | int ret; | ||
| 471 | |||
| 472 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
| 473 | return -ENODEV; | ||
| 474 | |||
| 475 | data = devm_kzalloc(dev, sizeof(struct tc654_data), GFP_KERNEL); | ||
| 476 | if (!data) | ||
| 477 | return -ENOMEM; | ||
| 478 | |||
| 479 | data->client = client; | ||
| 480 | mutex_init(&data->update_lock); | ||
| 481 | |||
| 482 | ret = i2c_smbus_read_byte_data(client, TC654_REG_CONFIG); | ||
| 483 | if (ret < 0) | ||
| 484 | return ret; | ||
| 485 | |||
| 486 | data->config = ret; | ||
| 487 | |||
| 488 | hwmon_dev = | ||
| 489 | devm_hwmon_device_register_with_groups(dev, client->name, data, | ||
| 490 | tc654_groups); | ||
| 491 | return PTR_ERR_OR_ZERO(hwmon_dev); | ||
| 492 | } | ||
| 493 | |||
| 494 | static const struct i2c_device_id tc654_id[] = { | ||
| 495 | {"tc654", 0}, | ||
| 496 | {"tc655", 0}, | ||
| 497 | {} | ||
| 498 | }; | ||
| 499 | |||
| 500 | MODULE_DEVICE_TABLE(i2c, tc654_id); | ||
| 501 | |||
| 502 | static struct i2c_driver tc654_driver = { | ||
| 503 | .driver = { | ||
| 504 | .name = "tc654", | ||
| 505 | }, | ||
| 506 | .probe = tc654_probe, | ||
| 507 | .id_table = tc654_id, | ||
| 508 | }; | ||
| 509 | |||
| 510 | module_i2c_driver(tc654_driver); | ||
| 511 | |||
| 512 | MODULE_AUTHOR("Allied Telesis Labs"); | ||
| 513 | MODULE_DESCRIPTION("Microchip TC654/TC655 driver"); | ||
| 514 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c new file mode 100644 index 000000000000..91bb94639286 --- /dev/null +++ b/drivers/hwmon/tmp108.c | |||
| @@ -0,0 +1,469 @@ | |||
| 1 | /* Texas Instruments TMP108 SMBus temperature sensor driver | ||
| 2 | * | ||
| 3 | * Copyright (C) 2016 John Muir <john@jmuir.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/err.h> | ||
| 19 | #include <linux/hwmon.h> | ||
| 20 | #include <linux/hwmon-sysfs.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/mutex.h> | ||
| 23 | #include <linux/of.h> | ||
| 24 | #include <linux/i2c.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/jiffies.h> | ||
| 27 | #include <linux/regmap.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | |||
| 30 | #define DRIVER_NAME "tmp108" | ||
| 31 | |||
| 32 | #define TMP108_REG_TEMP 0x00 | ||
| 33 | #define TMP108_REG_CONF 0x01 | ||
| 34 | #define TMP108_REG_TLOW 0x02 | ||
| 35 | #define TMP108_REG_THIGH 0x03 | ||
| 36 | |||
| 37 | #define TMP108_TEMP_MIN_MC -50000 /* Minimum millicelcius. */ | ||
| 38 | #define TMP108_TEMP_MAX_MC 127937 /* Maximum millicelcius. */ | ||
| 39 | |||
| 40 | /* Configuration register bits. | ||
| 41 | * Note: these bit definitions are byte swapped. | ||
| 42 | */ | ||
| 43 | #define TMP108_CONF_M0 0x0100 /* Sensor mode. */ | ||
| 44 | #define TMP108_CONF_M1 0x0200 | ||
| 45 | #define TMP108_CONF_TM 0x0400 /* Thermostat mode. */ | ||
| 46 | #define TMP108_CONF_FL 0x0800 /* Watchdog flag - TLOW */ | ||
| 47 | #define TMP108_CONF_FH 0x1000 /* Watchdog flag - THIGH */ | ||
| 48 | #define TMP108_CONF_CR0 0x2000 /* Conversion rate. */ | ||
| 49 | #define TMP108_CONF_CR1 0x4000 | ||
| 50 | #define TMP108_CONF_ID 0x8000 | ||
| 51 | #define TMP108_CONF_HYS0 0x0010 /* Hysteresis. */ | ||
| 52 | #define TMP108_CONF_HYS1 0x0020 | ||
| 53 | #define TMP108_CONF_POL 0x0080 /* Polarity of alert. */ | ||
| 54 | |||
| 55 | /* Defaults set by the hardware upon reset. */ | ||
| 56 | #define TMP108_CONF_DEFAULTS (TMP108_CONF_CR0 | TMP108_CONF_TM |\ | ||
| 57 | TMP108_CONF_HYS0 | TMP108_CONF_M1) | ||
| 58 | /* These bits are read-only. */ | ||
| 59 | #define TMP108_CONF_READ_ONLY (TMP108_CONF_FL | TMP108_CONF_FH |\ | ||
| 60 | TMP108_CONF_ID) | ||
| 61 | |||
| 62 | #define TMP108_CONF_MODE_MASK (TMP108_CONF_M0|TMP108_CONF_M1) | ||
| 63 | #define TMP108_MODE_SHUTDOWN 0x0000 | ||
| 64 | #define TMP108_MODE_ONE_SHOT TMP108_CONF_M0 | ||
| 65 | #define TMP108_MODE_CONTINUOUS TMP108_CONF_M1 /* Default */ | ||
| 66 | /* When M1 is set, M0 is ignored. */ | ||
| 67 | |||
| 68 | #define TMP108_CONF_CONVRATE_MASK (TMP108_CONF_CR0|TMP108_CONF_CR1) | ||
| 69 | #define TMP108_CONVRATE_0P25HZ 0x0000 | ||
| 70 | #define TMP108_CONVRATE_1HZ TMP108_CONF_CR0 /* Default */ | ||
| 71 | #define TMP108_CONVRATE_4HZ TMP108_CONF_CR1 | ||
| 72 | #define TMP108_CONVRATE_16HZ (TMP108_CONF_CR0|TMP108_CONF_CR1) | ||
| 73 | |||
| 74 | #define TMP108_CONF_HYSTERESIS_MASK (TMP108_CONF_HYS0|TMP108_CONF_HYS1) | ||
| 75 | #define TMP108_HYSTERESIS_0C 0x0000 | ||
| 76 | #define TMP108_HYSTERESIS_1C TMP108_CONF_HYS0 /* Default */ | ||
| 77 | #define TMP108_HYSTERESIS_2C TMP108_CONF_HYS1 | ||
| 78 | #define TMP108_HYSTERESIS_4C (TMP108_CONF_HYS0|TMP108_CONF_HYS1) | ||
| 79 | |||
| 80 | #define TMP108_CONVERSION_TIME_MS 30 /* in milli-seconds */ | ||
| 81 | |||
| 82 | struct tmp108 { | ||
| 83 | struct regmap *regmap; | ||
| 84 | u16 orig_config; | ||
| 85 | unsigned long ready_time; | ||
| 86 | }; | ||
| 87 | |||
| 88 | /* convert 12-bit TMP108 register value to milliCelsius */ | ||
| 89 | static inline int tmp108_temp_reg_to_mC(s16 val) | ||
| 90 | { | ||
| 91 | return (val & ~0x0f) * 1000 / 256; | ||
| 92 | } | ||
| 93 | |||
| 94 | /* convert milliCelsius to left adjusted 12-bit TMP108 register value */ | ||
| 95 | static inline u16 tmp108_mC_to_temp_reg(int val) | ||
| 96 | { | ||
| 97 | return (val * 256) / 1000; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int tmp108_read(struct device *dev, enum hwmon_sensor_types type, | ||
| 101 | u32 attr, int channel, long *temp) | ||
| 102 | { | ||
| 103 | struct tmp108 *tmp108 = dev_get_drvdata(dev); | ||
| 104 | unsigned int regval; | ||
| 105 | int err, hyst; | ||
| 106 | |||
| 107 | if (type == hwmon_chip) { | ||
| 108 | if (attr == hwmon_chip_update_interval) { | ||
| 109 | err = regmap_read(tmp108->regmap, TMP108_REG_CONF, | ||
| 110 | ®val); | ||
| 111 | if (err < 0) | ||
| 112 | return err; | ||
| 113 | switch (regval & TMP108_CONF_CONVRATE_MASK) { | ||
| 114 | case TMP108_CONVRATE_0P25HZ: | ||
| 115 | default: | ||
| 116 | *temp = 4000; | ||
| 117 | break; | ||
| 118 | case TMP108_CONVRATE_1HZ: | ||
| 119 | *temp = 1000; | ||
| 120 | break; | ||
| 121 | case TMP108_CONVRATE_4HZ: | ||
| 122 | *temp = 250; | ||
| 123 | break; | ||
| 124 | case TMP108_CONVRATE_16HZ: | ||
| 125 | *temp = 63; | ||
| 126 | break; | ||
| 127 | } | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | return -EOPNOTSUPP; | ||
| 131 | } | ||
| 132 | |||
| 133 | switch (attr) { | ||
| 134 | case hwmon_temp_input: | ||
| 135 | /* Is it too early to return a conversion ? */ | ||
| 136 | if (time_before(jiffies, tmp108->ready_time)) { | ||
| 137 | dev_dbg(dev, "%s: Conversion not ready yet..\n", | ||
| 138 | __func__); | ||
| 139 | return -EAGAIN; | ||
| 140 | } | ||
| 141 | err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, ®val); | ||
| 142 | if (err < 0) | ||
| 143 | return err; | ||
| 144 | *temp = tmp108_temp_reg_to_mC(regval); | ||
| 145 | break; | ||
| 146 | case hwmon_temp_min: | ||
| 147 | case hwmon_temp_max: | ||
| 148 | err = regmap_read(tmp108->regmap, attr == hwmon_temp_min ? | ||
| 149 | TMP108_REG_TLOW : TMP108_REG_THIGH, ®val); | ||
| 150 | if (err < 0) | ||
| 151 | return err; | ||
| 152 | *temp = tmp108_temp_reg_to_mC(regval); | ||
| 153 | break; | ||
| 154 | case hwmon_temp_min_alarm: | ||
| 155 | case hwmon_temp_max_alarm: | ||
| 156 | err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val); | ||
| 157 | if (err < 0) | ||
| 158 | return err; | ||
| 159 | *temp = !!(regval & (attr == hwmon_temp_min_alarm ? | ||
| 160 | TMP108_CONF_FL : TMP108_CONF_FH)); | ||
| 161 | break; | ||
| 162 | case hwmon_temp_min_hyst: | ||
| 163 | case hwmon_temp_max_hyst: | ||
| 164 | err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val); | ||
| 165 | if (err < 0) | ||
| 166 | return err; | ||
| 167 | switch (regval & TMP108_CONF_HYSTERESIS_MASK) { | ||
| 168 | case TMP108_HYSTERESIS_0C: | ||
| 169 | default: | ||
| 170 | hyst = 0; | ||
| 171 | break; | ||
| 172 | case TMP108_HYSTERESIS_1C: | ||
| 173 | hyst = 1000; | ||
| 174 | break; | ||
| 175 | case TMP108_HYSTERESIS_2C: | ||
| 176 | hyst = 2000; | ||
| 177 | break; | ||
| 178 | case TMP108_HYSTERESIS_4C: | ||
| 179 | hyst = 4000; | ||
| 180 | break; | ||
| 181 | } | ||
| 182 | err = regmap_read(tmp108->regmap, attr == hwmon_temp_min_hyst ? | ||
| 183 | TMP108_REG_TLOW : TMP108_REG_THIGH, ®val); | ||
| 184 | if (err < 0) | ||
| 185 | return err; | ||
| 186 | *temp = tmp108_temp_reg_to_mC(regval); | ||
| 187 | if (attr == hwmon_temp_min_hyst) | ||
| 188 | *temp += hyst; | ||
| 189 | else | ||
| 190 | *temp -= hyst; | ||
| 191 | break; | ||
| 192 | default: | ||
| 193 | return -EOPNOTSUPP; | ||
| 194 | } | ||
| 195 | |||
| 196 | return 0; | ||
| 197 | } | ||
| 198 | |||
| 199 | static int tmp108_write(struct device *dev, enum hwmon_sensor_types type, | ||
| 200 | u32 attr, int channel, long temp) | ||
| 201 | { | ||
| 202 | struct tmp108 *tmp108 = dev_get_drvdata(dev); | ||
| 203 | u32 regval, mask; | ||
| 204 | int err; | ||
| 205 | |||
| 206 | if (type == hwmon_chip) { | ||
| 207 | if (attr == hwmon_chip_update_interval) { | ||
| 208 | if (temp < 156) | ||
| 209 | mask = TMP108_CONVRATE_16HZ; | ||
| 210 | else if (temp < 625) | ||
| 211 | mask = TMP108_CONVRATE_4HZ; | ||
| 212 | else if (temp < 2500) | ||
| 213 | mask = TMP108_CONVRATE_1HZ; | ||
| 214 | else | ||
| 215 | mask = TMP108_CONVRATE_0P25HZ; | ||
| 216 | return regmap_update_bits(tmp108->regmap, | ||
| 217 | TMP108_REG_CONF, | ||
| 218 | TMP108_CONF_CONVRATE_MASK, | ||
| 219 | mask); | ||
| 220 | } | ||
| 221 | return -EOPNOTSUPP; | ||
| 222 | } | ||
| 223 | |||
| 224 | switch (attr) { | ||
| 225 | case hwmon_temp_min: | ||
| 226 | case hwmon_temp_max: | ||
| 227 | temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC); | ||
| 228 | return regmap_write(tmp108->regmap, | ||
| 229 | attr == hwmon_temp_min ? | ||
| 230 | TMP108_REG_TLOW : TMP108_REG_THIGH, | ||
| 231 | tmp108_mC_to_temp_reg(temp)); | ||
| 232 | case hwmon_temp_min_hyst: | ||
| 233 | case hwmon_temp_max_hyst: | ||
| 234 | temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC); | ||
| 235 | err = regmap_read(tmp108->regmap, | ||
| 236 | attr == hwmon_temp_min_hyst ? | ||
| 237 | TMP108_REG_TLOW : TMP108_REG_THIGH, | ||
| 238 | ®val); | ||
| 239 | if (err < 0) | ||
| 240 | return err; | ||
| 241 | if (attr == hwmon_temp_min_hyst) | ||
| 242 | temp -= tmp108_temp_reg_to_mC(regval); | ||
| 243 | else | ||
| 244 | temp = tmp108_temp_reg_to_mC(regval) - temp; | ||
| 245 | if (temp < 500) | ||
| 246 | mask = TMP108_HYSTERESIS_0C; | ||
| 247 | else if (temp < 1500) | ||
| 248 | mask = TMP108_HYSTERESIS_1C; | ||
| 249 | else if (temp < 3000) | ||
| 250 | mask = TMP108_HYSTERESIS_2C; | ||
| 251 | else | ||
| 252 | mask = TMP108_HYSTERESIS_4C; | ||
| 253 | return regmap_update_bits(tmp108->regmap, TMP108_REG_CONF, | ||
| 254 | TMP108_CONF_HYSTERESIS_MASK, mask); | ||
| 255 | default: | ||
| 256 | return -EOPNOTSUPP; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type, | ||
| 261 | u32 attr, int channel) | ||
| 262 | { | ||
| 263 | if (type == hwmon_chip && attr == hwmon_chip_update_interval) | ||
| 264 | return 0644; | ||
| 265 | |||
| 266 | if (type != hwmon_temp) | ||
| 267 | return 0; | ||
| 268 | |||
| 269 | switch (attr) { | ||
| 270 | case hwmon_temp_input: | ||
| 271 | case hwmon_temp_min_alarm: | ||
| 272 | case hwmon_temp_max_alarm: | ||
| 273 | return 0444; | ||
| 274 | case hwmon_temp_min: | ||
| 275 | case hwmon_temp_max: | ||
| 276 | case hwmon_temp_min_hyst: | ||
| 277 | case hwmon_temp_max_hyst: | ||
| 278 | return 0644; | ||
| 279 | default: | ||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | static u32 tmp108_chip_config[] = { | ||
| 285 | HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL, | ||
| 286 | 0 | ||
| 287 | }; | ||
| 288 | |||
| 289 | static const struct hwmon_channel_info tmp108_chip = { | ||
| 290 | .type = hwmon_chip, | ||
| 291 | .config = tmp108_chip_config, | ||
| 292 | }; | ||
| 293 | |||
| 294 | static u32 tmp108_temp_config[] = { | ||
| 295 | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | HWMON_T_MIN_HYST | ||
| 296 | | HWMON_T_MAX_HYST | HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM, | ||
| 297 | 0 | ||
| 298 | }; | ||
| 299 | |||
| 300 | static const struct hwmon_channel_info tmp108_temp = { | ||
| 301 | .type = hwmon_temp, | ||
| 302 | .config = tmp108_temp_config, | ||
| 303 | }; | ||
| 304 | |||
| 305 | static const struct hwmon_channel_info *tmp108_info[] = { | ||
| 306 | &tmp108_chip, | ||
| 307 | &tmp108_temp, | ||
| 308 | NULL | ||
| 309 | }; | ||
| 310 | |||
| 311 | static const struct hwmon_ops tmp108_hwmon_ops = { | ||
| 312 | .is_visible = tmp108_is_visible, | ||
| 313 | .read = tmp108_read, | ||
| 314 | .write = tmp108_write, | ||
| 315 | }; | ||
| 316 | |||
| 317 | static const struct hwmon_chip_info tmp108_chip_info = { | ||
| 318 | .ops = &tmp108_hwmon_ops, | ||
| 319 | .info = tmp108_info, | ||
| 320 | }; | ||
| 321 | |||
| 322 | static void tmp108_restore_config(void *data) | ||
| 323 | { | ||
| 324 | struct tmp108 *tmp108 = data; | ||
| 325 | |||
| 326 | regmap_write(tmp108->regmap, TMP108_REG_CONF, tmp108->orig_config); | ||
| 327 | } | ||
| 328 | |||
| 329 | static bool tmp108_is_writeable_reg(struct device *dev, unsigned int reg) | ||
| 330 | { | ||
| 331 | return reg != TMP108_REG_TEMP; | ||
| 332 | } | ||
| 333 | |||
| 334 | static bool tmp108_is_volatile_reg(struct device *dev, unsigned int reg) | ||
| 335 | { | ||
| 336 | /* Configuration register must be volatile to enable FL and FH. */ | ||
| 337 | return reg == TMP108_REG_TEMP || reg == TMP108_REG_CONF; | ||
| 338 | } | ||
| 339 | |||
| 340 | static const struct regmap_config tmp108_regmap_config = { | ||
| 341 | .reg_bits = 8, | ||
| 342 | .val_bits = 16, | ||
| 343 | .max_register = TMP108_REG_THIGH, | ||
| 344 | .writeable_reg = tmp108_is_writeable_reg, | ||
| 345 | .volatile_reg = tmp108_is_volatile_reg, | ||
| 346 | .val_format_endian = REGMAP_ENDIAN_BIG, | ||
| 347 | .cache_type = REGCACHE_RBTREE, | ||
| 348 | .use_single_rw = true, | ||
| 349 | }; | ||
| 350 | |||
| 351 | static int tmp108_probe(struct i2c_client *client, | ||
| 352 | const struct i2c_device_id *id) | ||
| 353 | { | ||
| 354 | struct device *dev = &client->dev; | ||
| 355 | struct device *hwmon_dev; | ||
| 356 | struct tmp108 *tmp108; | ||
| 357 | int err; | ||
| 358 | u32 config; | ||
| 359 | |||
| 360 | if (!i2c_check_functionality(client->adapter, | ||
| 361 | I2C_FUNC_SMBUS_WORD_DATA)) { | ||
| 362 | dev_err(dev, | ||
| 363 | "adapter doesn't support SMBus word transactions\n"); | ||
| 364 | return -ENODEV; | ||
| 365 | } | ||
| 366 | |||
| 367 | tmp108 = devm_kzalloc(dev, sizeof(*tmp108), GFP_KERNEL); | ||
| 368 | if (!tmp108) | ||
| 369 | return -ENOMEM; | ||
| 370 | |||
| 371 | dev_set_drvdata(dev, tmp108); | ||
| 372 | |||
| 373 | tmp108->regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config); | ||
| 374 | if (IS_ERR(tmp108->regmap)) { | ||
| 375 | err = PTR_ERR(tmp108->regmap); | ||
| 376 | dev_err(dev, "regmap init failed: %d", err); | ||
| 377 | return err; | ||
| 378 | } | ||
| 379 | |||
| 380 | err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config); | ||
| 381 | if (err < 0) { | ||
| 382 | dev_err(dev, "error reading config register: %d", err); | ||
| 383 | return err; | ||
| 384 | } | ||
| 385 | tmp108->orig_config = config; | ||
| 386 | |||
| 387 | /* Only continuous mode is supported. */ | ||
| 388 | config &= ~TMP108_CONF_MODE_MASK; | ||
| 389 | config |= TMP108_MODE_CONTINUOUS; | ||
| 390 | |||
| 391 | /* Only comparator mode is supported. */ | ||
| 392 | config &= ~TMP108_CONF_TM; | ||
| 393 | |||
| 394 | err = regmap_write(tmp108->regmap, TMP108_REG_CONF, config); | ||
| 395 | if (err < 0) { | ||
| 396 | dev_err(dev, "error writing config register: %d", err); | ||
| 397 | return err; | ||
| 398 | } | ||
| 399 | |||
| 400 | tmp108->ready_time = jiffies; | ||
| 401 | if ((tmp108->orig_config & TMP108_CONF_MODE_MASK) == | ||
| 402 | TMP108_MODE_SHUTDOWN) | ||
| 403 | tmp108->ready_time += | ||
| 404 | msecs_to_jiffies(TMP108_CONVERSION_TIME_MS); | ||
| 405 | |||
| 406 | err = devm_add_action_or_reset(dev, tmp108_restore_config, tmp108); | ||
| 407 | if (err) { | ||
| 408 | dev_err(dev, "add action or reset failed: %d", err); | ||
| 409 | return err; | ||
| 410 | } | ||
| 411 | |||
| 412 | hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, | ||
| 413 | tmp108, | ||
| 414 | &tmp108_chip_info, | ||
| 415 | NULL); | ||
| 416 | return PTR_ERR_OR_ZERO(hwmon_dev); | ||
| 417 | } | ||
| 418 | |||
| 419 | static int __maybe_unused tmp108_suspend(struct device *dev) | ||
| 420 | { | ||
| 421 | struct tmp108 *tmp108 = dev_get_drvdata(dev); | ||
| 422 | |||
| 423 | return regmap_update_bits(tmp108->regmap, TMP108_REG_CONF, | ||
| 424 | TMP108_CONF_MODE_MASK, TMP108_MODE_SHUTDOWN); | ||
| 425 | } | ||
| 426 | |||
| 427 | static int __maybe_unused tmp108_resume(struct device *dev) | ||
| 428 | { | ||
| 429 | struct tmp108 *tmp108 = dev_get_drvdata(dev); | ||
| 430 | int err; | ||
| 431 | |||
| 432 | err = regmap_update_bits(tmp108->regmap, TMP108_REG_CONF, | ||
| 433 | TMP108_CONF_MODE_MASK, TMP108_MODE_CONTINUOUS); | ||
| 434 | tmp108->ready_time = jiffies + | ||
| 435 | msecs_to_jiffies(TMP108_CONVERSION_TIME_MS); | ||
| 436 | return err; | ||
| 437 | } | ||
| 438 | |||
| 439 | static SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume); | ||
| 440 | |||
| 441 | static const struct i2c_device_id tmp108_i2c_ids[] = { | ||
| 442 | { "tmp108", 0 }, | ||
| 443 | { } | ||
| 444 | }; | ||
| 445 | MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids); | ||
| 446 | |||
| 447 | #ifdef CONFIG_OF | ||
| 448 | static const struct of_device_id tmp108_of_ids[] = { | ||
| 449 | { .compatible = "ti,tmp108", }, | ||
| 450 | {} | ||
| 451 | }; | ||
| 452 | MODULE_DEVICE_TABLE(of, tmp108_of_ids); | ||
| 453 | #endif | ||
| 454 | |||
| 455 | static struct i2c_driver tmp108_driver = { | ||
| 456 | .driver = { | ||
| 457 | .name = DRIVER_NAME, | ||
| 458 | .pm = &tmp108_dev_pm_ops, | ||
| 459 | .of_match_table = of_match_ptr(tmp108_of_ids), | ||
| 460 | }, | ||
| 461 | .probe = tmp108_probe, | ||
| 462 | .id_table = tmp108_i2c_ids, | ||
| 463 | }; | ||
| 464 | |||
| 465 | module_i2c_driver(tmp108_driver); | ||
| 466 | |||
| 467 | MODULE_AUTHOR("John Muir <john@jmuir.com>"); | ||
| 468 | MODULE_DESCRIPTION("Texas Instruments TMP108 temperature sensor driver"); | ||
| 469 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index ac91c07e3f90..d1f209a5feac 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c | |||
| @@ -220,7 +220,7 @@ struct pdev_entry { | |||
| 220 | static LIST_HEAD(pdev_list); | 220 | static LIST_HEAD(pdev_list); |
| 221 | static DEFINE_MUTEX(pdev_list_mutex); | 221 | static DEFINE_MUTEX(pdev_list_mutex); |
| 222 | 222 | ||
| 223 | static int via_cputemp_device_add(unsigned int cpu) | 223 | static int via_cputemp_online(unsigned int cpu) |
| 224 | { | 224 | { |
| 225 | int err; | 225 | int err; |
| 226 | struct platform_device *pdev; | 226 | struct platform_device *pdev; |
| @@ -261,7 +261,7 @@ exit: | |||
| 261 | return err; | 261 | return err; |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | static void via_cputemp_device_remove(unsigned int cpu) | 264 | static int via_cputemp_down_prep(unsigned int cpu) |
| 265 | { | 265 | { |
| 266 | struct pdev_entry *p; | 266 | struct pdev_entry *p; |
| 267 | 267 | ||
| @@ -272,33 +272,13 @@ static void via_cputemp_device_remove(unsigned int cpu) | |||
| 272 | list_del(&p->list); | 272 | list_del(&p->list); |
| 273 | mutex_unlock(&pdev_list_mutex); | 273 | mutex_unlock(&pdev_list_mutex); |
| 274 | kfree(p); | 274 | kfree(p); |
| 275 | return; | 275 | return 0; |
| 276 | } | 276 | } |
| 277 | } | 277 | } |
| 278 | mutex_unlock(&pdev_list_mutex); | 278 | mutex_unlock(&pdev_list_mutex); |
| 279 | return 0; | ||
| 279 | } | 280 | } |
| 280 | 281 | ||
| 281 | static int via_cputemp_cpu_callback(struct notifier_block *nfb, | ||
| 282 | unsigned long action, void *hcpu) | ||
| 283 | { | ||
| 284 | unsigned int cpu = (unsigned long) hcpu; | ||
| 285 | |||
| 286 | switch (action) { | ||
| 287 | case CPU_ONLINE: | ||
| 288 | case CPU_DOWN_FAILED: | ||
| 289 | via_cputemp_device_add(cpu); | ||
| 290 | break; | ||
| 291 | case CPU_DOWN_PREPARE: | ||
| 292 | via_cputemp_device_remove(cpu); | ||
| 293 | break; | ||
| 294 | } | ||
| 295 | return NOTIFY_OK; | ||
| 296 | } | ||
| 297 | |||
| 298 | static struct notifier_block via_cputemp_cpu_notifier __refdata = { | ||
| 299 | .notifier_call = via_cputemp_cpu_callback, | ||
| 300 | }; | ||
| 301 | |||
| 302 | static const struct x86_cpu_id __initconst cputemp_ids[] = { | 282 | static const struct x86_cpu_id __initconst cputemp_ids[] = { |
| 303 | { X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */ | 283 | { X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */ |
| 304 | { X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */ | 284 | { X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */ |
| @@ -307,9 +287,11 @@ static const struct x86_cpu_id __initconst cputemp_ids[] = { | |||
| 307 | }; | 287 | }; |
| 308 | MODULE_DEVICE_TABLE(x86cpu, cputemp_ids); | 288 | MODULE_DEVICE_TABLE(x86cpu, cputemp_ids); |
| 309 | 289 | ||
| 290 | static enum cpuhp_state via_temp_online; | ||
| 291 | |||
| 310 | static int __init via_cputemp_init(void) | 292 | static int __init via_cputemp_init(void) |
| 311 | { | 293 | { |
| 312 | int i, err; | 294 | int err; |
| 313 | 295 | ||
| 314 | if (!x86_match_cpu(cputemp_ids)) | 296 | if (!x86_match_cpu(cputemp_ids)) |
| 315 | return -ENODEV; | 297 | return -ENODEV; |
| @@ -318,58 +300,33 @@ static int __init via_cputemp_init(void) | |||
| 318 | if (err) | 300 | if (err) |
| 319 | goto exit; | 301 | goto exit; |
| 320 | 302 | ||
| 321 | cpu_notifier_register_begin(); | 303 | err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/via:online", |
| 322 | for_each_online_cpu(i) { | 304 | via_cputemp_online, via_cputemp_down_prep); |
| 323 | struct cpuinfo_x86 *c = &cpu_data(i); | 305 | if (err < 0) |
| 324 | 306 | goto exit_driver_unreg; | |
| 325 | if (c->x86 != 6) | 307 | via_temp_online = err; |
| 326 | continue; | ||
| 327 | |||
| 328 | if (c->x86_model < 0x0a) | ||
| 329 | continue; | ||
| 330 | |||
| 331 | if (c->x86_model > 0x0f) { | ||
| 332 | pr_warn("Unknown CPU model 0x%x\n", c->x86_model); | ||
| 333 | continue; | ||
| 334 | } | ||
| 335 | |||
| 336 | via_cputemp_device_add(i); | ||
| 337 | } | ||
| 338 | 308 | ||
| 339 | #ifndef CONFIG_HOTPLUG_CPU | 309 | #ifndef CONFIG_HOTPLUG_CPU |
| 340 | if (list_empty(&pdev_list)) { | 310 | if (list_empty(&pdev_list)) { |
| 341 | cpu_notifier_register_done(); | ||
| 342 | err = -ENODEV; | 311 | err = -ENODEV; |
| 343 | goto exit_driver_unreg; | 312 | goto exit_hp_unreg; |
| 344 | } | 313 | } |
| 345 | #endif | 314 | #endif |
| 346 | |||
| 347 | __register_hotcpu_notifier(&via_cputemp_cpu_notifier); | ||
| 348 | cpu_notifier_register_done(); | ||
| 349 | return 0; | 315 | return 0; |
| 350 | 316 | ||
| 351 | #ifndef CONFIG_HOTPLUG_CPU | 317 | #ifndef CONFIG_HOTPLUG_CPU |
| 318 | exit_hp_unreg: | ||
| 319 | cpuhp_remove_state_nocalls(via_temp_online); | ||
| 320 | #endif | ||
| 352 | exit_driver_unreg: | 321 | exit_driver_unreg: |
| 353 | platform_driver_unregister(&via_cputemp_driver); | 322 | platform_driver_unregister(&via_cputemp_driver); |
| 354 | #endif | ||
| 355 | exit: | 323 | exit: |
| 356 | return err; | 324 | return err; |
| 357 | } | 325 | } |
| 358 | 326 | ||
| 359 | static void __exit via_cputemp_exit(void) | 327 | static void __exit via_cputemp_exit(void) |
| 360 | { | 328 | { |
| 361 | struct pdev_entry *p, *n; | 329 | cpuhp_remove_state(via_temp_online); |
| 362 | |||
| 363 | cpu_notifier_register_begin(); | ||
| 364 | __unregister_hotcpu_notifier(&via_cputemp_cpu_notifier); | ||
| 365 | mutex_lock(&pdev_list_mutex); | ||
| 366 | list_for_each_entry_safe(p, n, &pdev_list, list) { | ||
| 367 | platform_device_unregister(p->pdev); | ||
| 368 | list_del(&p->list); | ||
| 369 | kfree(p); | ||
| 370 | } | ||
| 371 | mutex_unlock(&pdev_list_mutex); | ||
| 372 | cpu_notifier_register_done(); | ||
| 373 | platform_driver_unregister(&via_cputemp_driver); | 330 | platform_driver_unregister(&via_cputemp_driver); |
| 374 | } | 331 | } |
| 375 | 332 | ||
diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 9d2f8bde7d12..78d59dba563e 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h | |||
| @@ -298,8 +298,8 @@ enum hwmon_pwm_attributes { | |||
| 298 | * Channel number | 298 | * Channel number |
| 299 | * The function returns the file permissions. | 299 | * The function returns the file permissions. |
| 300 | * If the return value is 0, no attribute will be created. | 300 | * If the return value is 0, no attribute will be created. |
| 301 | * @read: Read callback. Optional. If not provided, attributes | 301 | * @read: Read callback for data attributes. Mandatory if readable |
| 302 | * will not be readable. | 302 | * data attributes are present. |
| 303 | * Parameters are: | 303 | * Parameters are: |
| 304 | * @dev: Pointer to hardware monitoring device | 304 | * @dev: Pointer to hardware monitoring device |
| 305 | * @type: Sensor type | 305 | * @type: Sensor type |
| @@ -308,8 +308,19 @@ enum hwmon_pwm_attributes { | |||
| 308 | * Channel number | 308 | * Channel number |
| 309 | * @val: Pointer to returned value | 309 | * @val: Pointer to returned value |
| 310 | * The function returns 0 on success or a negative error number. | 310 | * The function returns 0 on success or a negative error number. |
| 311 | * @write: Write callback. Optional. If not provided, attributes | 311 | * @read_string: |
| 312 | * will not be writable. | 312 | * Read callback for string attributes. Mandatory if string |
| 313 | * attributes are present. | ||
| 314 | * Parameters are: | ||
| 315 | * @dev: Pointer to hardware monitoring device | ||
| 316 | * @type: Sensor type | ||
| 317 | * @attr: Sensor attribute | ||
| 318 | * @channel: | ||
| 319 | * Channel number | ||
| 320 | * @str: Pointer to returned string | ||
| 321 | * The function returns 0 on success or a negative error number. | ||
| 322 | * @write: Write callback for data attributes. Mandatory if writeable | ||
| 323 | * data attributes are present. | ||
| 313 | * Parameters are: | 324 | * Parameters are: |
| 314 | * @dev: Pointer to hardware monitoring device | 325 | * @dev: Pointer to hardware monitoring device |
| 315 | * @type: Sensor type | 326 | * @type: Sensor type |
| @@ -324,6 +335,8 @@ struct hwmon_ops { | |||
| 324 | u32 attr, int channel); | 335 | u32 attr, int channel); |
| 325 | int (*read)(struct device *dev, enum hwmon_sensor_types type, | 336 | int (*read)(struct device *dev, enum hwmon_sensor_types type, |
| 326 | u32 attr, int channel, long *val); | 337 | u32 attr, int channel, long *val); |
| 338 | int (*read_string)(struct device *dev, enum hwmon_sensor_types type, | ||
| 339 | u32 attr, int channel, char **str); | ||
| 327 | int (*write)(struct device *dev, enum hwmon_sensor_types type, | 340 | int (*write)(struct device *dev, enum hwmon_sensor_types type, |
| 328 | u32 attr, int channel, long val); | 341 | u32 attr, int channel, long val); |
| 329 | }; | 342 | }; |
| @@ -349,7 +362,9 @@ struct hwmon_chip_info { | |||
| 349 | const struct hwmon_channel_info **info; | 362 | const struct hwmon_channel_info **info; |
| 350 | }; | 363 | }; |
| 351 | 364 | ||
| 365 | /* hwmon_device_register() is deprecated */ | ||
| 352 | struct device *hwmon_device_register(struct device *dev); | 366 | struct device *hwmon_device_register(struct device *dev); |
| 367 | |||
| 353 | struct device * | 368 | struct device * |
| 354 | hwmon_device_register_with_groups(struct device *dev, const char *name, | 369 | hwmon_device_register_with_groups(struct device *dev, const char *name, |
| 355 | void *drvdata, | 370 | void *drvdata, |
| @@ -362,12 +377,12 @@ struct device * | |||
| 362 | hwmon_device_register_with_info(struct device *dev, | 377 | hwmon_device_register_with_info(struct device *dev, |
| 363 | const char *name, void *drvdata, | 378 | const char *name, void *drvdata, |
| 364 | const struct hwmon_chip_info *info, | 379 | const struct hwmon_chip_info *info, |
| 365 | const struct attribute_group **groups); | 380 | const struct attribute_group **extra_groups); |
| 366 | struct device * | 381 | struct device * |
| 367 | devm_hwmon_device_register_with_info(struct device *dev, | 382 | devm_hwmon_device_register_with_info(struct device *dev, |
| 368 | const char *name, void *drvdata, | 383 | const char *name, void *drvdata, |
| 369 | const struct hwmon_chip_info *info, | 384 | const struct hwmon_chip_info *info, |
| 370 | const struct attribute_group **groups); | 385 | const struct attribute_group **extra_groups); |
| 371 | 386 | ||
| 372 | void hwmon_device_unregister(struct device *dev); | 387 | void hwmon_device_unregister(struct device *dev); |
| 373 | void devm_hwmon_device_unregister(struct device *dev); | 388 | void devm_hwmon_device_unregister(struct device *dev); |
