diff options
125 files changed, 5698 insertions, 4335 deletions
diff --git a/Documentation/devicetree/bindings/hwmon/adi,max31760.yaml b/Documentation/devicetree/bindings/hwmon/adi,max31760.yaml new file mode 100644 index 000000000000..9f2d08d7b978 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/adi,max31760.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/adi,max31760.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices MAX31760 Fan-Speed Controller + +maintainers: + - Ibrahim Tilki <Ibrahim.Tilki@analog.com> + +description: | + Analog Devices MAX31760 Fan-Speed Controller + https://datasheets.maximintegrated.com/en/ds/MAX31760.pdf + +properties: + compatible: + enum: + - adi,max31760 + + reg: + description: I2C address of slave device. + minimum: 0x50 + maximum: 0x57 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + fan-controller@50 { + reg = <0x50>; + compatible = "adi,max31760"; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/microchip,sparx5-temp.yaml b/Documentation/devicetree/bindings/hwmon/microchip,sparx5-temp.yaml index 76be625d5646..51e8619dbf3c 100644 --- a/Documentation/devicetree/bindings/hwmon/microchip,sparx5-temp.yaml +++ b/Documentation/devicetree/bindings/hwmon/microchip,sparx5-temp.yaml @@ -22,7 +22,7 @@ properties: clocks: items: - - description: AHB reference clock + - description: System reference clock '#thermal-sensor-cells': const: 0 @@ -40,5 +40,5 @@ examples: compatible = "microchip,sparx5-temp"; reg = <0x10508110 0xc>; #thermal-sensor-cells = <0>; - clocks = <&ahb_clk>; + clocks = <&sys_clk>; }; diff --git a/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml b/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml index 8ea97e774364..d0d549749208 100644 --- a/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml +++ b/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml @@ -9,6 +9,32 @@ title: Moortec Semiconductor MR75203 PVT Controller bindings maintainers: - Rahul Tanwar <rtanwar@maxlinear.com> +description: | + A Moortec PVT (Process, Voltage, Temperature) monitoring logic design can + include many different units. + Such a design will usually consists of several Moortec's embedded analog IPs, + and a single Moortec controller (mr75203) to configure and control the IPs. + + Some of the Moortec's analog hard IPs that can be used in a design: + *) Temperature Sensor (TS) - used to monitor core temperature (e.g. mr74137). + *) Voltage Monitor (VM) - used to monitor voltage levels (e.g. mr74138). + *) Process Detector (PD) - used to assess silicon speed (e.g. mr74139). + *) Delay Chain - ring oscillator connected to the PD, used to measure IO + based transistors (e.g. mr76008 ring oscillator at 1.1V, mr76007 ring + oscillator at 1.8V). + *) Pre Scaler - provides divide-by-X scaling of input voltage, which can then + be presented for VM for measurement within its range (e.g. mr76006 - + divide by 2 pre-scaler). + + TS, VM & PD also include a digital interface, which consists of configuration + inputs and measurement outputs. + + Some of the units have number of series, each series can have slightly + different characteristics. + + The mr75203 binding describes configuration for the controller unit, but also + for some of the analog IPs. + properties: compatible: const: moortec,mr75203 @@ -44,12 +70,76 @@ properties: "#thermal-sensor-cells": const: 1 + moortec,vm-active-channels: + description: + Defines the number of channels per VM that are actually used and are + connected to some input source. + Maximum number of items - number of VMs. + Maximum value of each item - number of channels. + Minimum value of each item - 0 (which means entire VM sensor is not used). + $ref: /schemas/types.yaml#/definitions/uint8-array + + moortec,vm-pre-scaler-x2: + description: + Defines the channels that use a mr76006 pre-scaler to divide the input + source by 2. + The pre-scaler is used for input sources that exceed the VM input range. + The driver uses this information to present to the user with the actual + value of the voltage source. + For channels that are not listed, no pre-scaler is assumed. + Maximum number of items - total number of channels in all VMs. + Each channel should not appear more than once. + $ref: /schemas/types.yaml#/definitions/uint8-array + + moortec,ts-series: + description: + Definition of the temperature equation and coefficients that shall be + used to convert the digital output to value in milli-Celsius. + minimum: 5 + maximum: 6 + default: 5 + $ref: /schemas/types.yaml#/definitions/uint32 + + moortec,ts-coeff-g: + description: + G coefficient for temperature equation. + Default for series 5 = 60000 + Default for series 6 = 57400 + multipleOf: 1000 + minimum: 1000 + $ref: /schemas/types.yaml#/definitions/uint32 + + moortec,ts-coeff-h: + description: + H coefficient for temperature equation. + Default for series 5 = 200000 + Default for series 6 = 249400 + multipleOf: 1000 + minimum: 1000 + $ref: /schemas/types.yaml#/definitions/uint32 + + moortec,ts-coeff-cal5: + description: + cal5 coefficient for temperature equation. + Default for series 5 = 4094 + Default for series 6 = 4096 + minimum: 1 + $ref: /schemas/types.yaml#/definitions/uint32 + + moortec,ts-coeff-j: + description: + J coefficient for temperature equation. + Default for series 5 = -100 + Default for series 6 = 0 + multipleOf: 1000 + maximum: 0 + $ref: /schemas/types.yaml#/definitions/int32 + required: - compatible - reg - reg-names - clocks - - resets - "#thermal-sensor-cells" additionalProperties: false @@ -66,5 +156,9 @@ examples: intel,vm-map = [03 01 04 ff ff]; clocks = <&osc0>; resets = <&rcu0 0x40 7>; + moortec,vm-active-channels = /bits/ 8 <0x10 0x05>; + moortec,vm-pre-scaler-x2 = /bits/ 8 <5 6 20>; + moortec,ts-coeff-g = <61400>; + moortec,ts-coeff-h = <253700>; #thermal-sensor-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml b/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml index 7d49478d9668..159238efa9ed 100644 --- a/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml +++ b/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml @@ -10,7 +10,7 @@ maintainers: - Christopher Ruehl chris.ruehl@gtsys.com.hk description: | - The SHTC1, SHTW1 and SHTC3 are digital humidity and temperature sensor + The SHTC1, SHTW1 and SHTC3 are digital humidity and temperature sensors designed especially for battery-driven high-volume consumer electronics applications. For further information refere to Documentation/hwmon/shtc1.rst @@ -31,13 +31,13 @@ properties: sensirion,blocking-io: $ref: /schemas/types.yaml#/definitions/flag description: - If set, the driver hold the i2c bus until measurement is finished. + If set, the driver holds the i2c bus until the measurement is finished. sensirion,low-precision: $ref: /schemas/types.yaml#/definitions/flag description: - If set, the sensor aquire data with low precision (not recommended). - The driver aquire data with high precision by default. + If set, the sensor acquires data with low precision (not recommended). + The driver acquires data with high precision by default. required: - compatible diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 2f0151e9f6be..9bf7c2cd7e89 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -819,6 +819,8 @@ patternProperties: description: MNT Research GmbH "^modtronix,.*": description: Modtronix Engineering + "^moortec,.*": + description: Moortec Semiconductor Ltd. "^mosaixtech,.*": description: Mosaix Technologies, Inc. "^motorola,.*": diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index dc1b2353cea3..80bb31c37909 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -404,7 +404,6 @@ POWER PWM devm_pwm_get() - devm_of_pwm_get() devm_fwnode_pwm_get() REGULATOR diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst index fd26c3d895b6..8c71a2055d27 100644 --- a/Documentation/driver-api/pwm.rst +++ b/Documentation/driver-api/pwm.rst @@ -40,8 +40,7 @@ after usage with pwm_free(). New users should use the pwm_get() function and pass to it the consumer device or a consumer name. pwm_put() is used to free the PWM device. Managed -variants of the getter, devm_pwm_get(), devm_of_pwm_get(), -devm_fwnode_pwm_get(), also exist. +variants of the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. After being requested, a PWM has to be configured using:: diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index 33649a1e3a05..e238533b5fe0 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -10,6 +10,7 @@ Supported devices: * Aquacomputer Farbwerk 360 RGB controller * Aquacomputer Octo fan controller * Aquacomputer Quadro fan controller +* Aquacomputer High Flow Next sensor Author: Aleksa Savic @@ -20,10 +21,11 @@ This driver exposes hardware sensors of listed Aquacomputer devices, which communicate through proprietary USB HID protocols. For the D5 Next pump, available sensors are pump and fan speed, power, voltage -and current, as well as coolant temperature. Also available through debugfs are -the serial number, firmware version and power-on count. Attaching a fan to it is -optional and allows it to be controlled using temperature curves directly from the -pump. If it's not connected, the fan-related sensors will report zeroes. +and current, as well as coolant temperature and eight virtual temp sensors. Also +available through debugfs are the serial number, firmware version and power-on +count. Attaching a fan to it is optional and allows it to be controlled using +temperature curves directly from the pump. If it's not connected, the fan-related +sensors will report zeroes. The pump can be configured either through software or via its physical interface. Configuring the pump through this driver is not implemented, as it @@ -31,14 +33,23 @@ seems to require sending it a complete configuration. That includes addressable RGB LEDs, for which there is no standard sysfs interface. Thus, that task is better suited for userspace tools. -The Octo exposes four temperature sensors and eight PWM controllable fans, along -with their speed (in RPM), power, voltage and current. +The Octo exposes four physical and sixteen virtual temperature sensors, as well as +eight PWM controllable fans, along with their speed (in RPM), power, voltage and +current. -The Quadro exposes four temperature sensors, a flow sensor and four PWM controllable -fans, along with their speed (in RPM), power, voltage and current. +The Quadro exposes four physical and sixteen virtual temperature sensors, a flow +sensor and four PWM controllable fans, along with their speed (in RPM), power, +voltage and current. -The Farbwerk and Farbwerk 360 expose four temperature sensors. Depending on the device, -not all sysfs and debugfs entries will be available. +The Farbwerk and Farbwerk 360 expose four temperature sensors. Additionally, +sixteen virtual temperature sensors of the Farbwerk 360 are exposed. + +The High Flow Next exposes +5V voltages, water quality, conductivity and flow readings. +A temperature sensor can be connected to it, in which case it provides its reading +and an estimation of the dissipated/absorbed power in the liquid cooling loop. + +Depending on the device, not all sysfs and debugfs entries will be available. +Writing to virtual temperature sensors is not currently supported. Usage notes ----------- @@ -49,14 +60,14 @@ the kernel and supports hotswapping. Sysfs entries ------------- -================ ============================================== -temp[1-4]_input Temperature sensors (in millidegrees Celsius) +================ ============================================================== +temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius) fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h) power[1-8]_input Pump/fan power (in micro Watts) in[0-7]_input Pump/fan voltage (in milli Volts) curr[1-8]_input Pump/fan current (in milli Amperes) pwm[1-8] Fan PWM (0 - 255) -================ ============================================== +================ ============================================================== Debugfs entries --------------- diff --git a/Documentation/hwmon/asus_wmi_ec_sensors.rst b/Documentation/hwmon/asus_wmi_ec_sensors.rst deleted file mode 100644 index 1b287f229e86..000000000000 --- a/Documentation/hwmon/asus_wmi_ec_sensors.rst +++ /dev/null @@ -1,38 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0-or-later - -Kernel driver asus_wmi_ec_sensors -================================= - -Supported boards: - * PRIME X570-PRO, - * Pro WS X570-ACE, - * ROG CROSSHAIR VIII DARK HERO, - * ROG CROSSHAIR VIII FORMULA, - * ROG CROSSHAIR VIII HERO, - * ROG STRIX B550-E GAMING, - * ROG STRIX B550-I GAMING, - * ROG STRIX X570-E GAMING. - -Authors: - - Eugene Shalygin <eugene.shalygin@gmail.com> - -Description: ------------- -ASUS mainboards publish hardware monitoring information via Super I/O -chip and the ACPI embedded controller (EC) registers. Some of the sensors -are only available via the EC. - -ASUS WMI interface provides a method (BREC) to read data from EC registers, -which is utilized by this driver to publish those sensor readings to the -HWMON system. The driver is aware of and reads the following sensors: - -1. Chipset (PCH) temperature -2. CPU package temperature -3. Motherboard temperature -4. Readings from the T_Sensor header -5. VRM temperature -6. CPU_Opt fan RPM -7. Chipset fan RPM -8. Readings from the "Water flow meter" header (RPM) -9. Readings from the "Water In" and "Water Out" temperature headers -10. CPU current diff --git a/Documentation/hwmon/corsair-psu.rst b/Documentation/hwmon/corsair-psu.rst index e8378e7a1d8c..3c1b164eb3c0 100644 --- a/Documentation/hwmon/corsair-psu.rst +++ b/Documentation/hwmon/corsair-psu.rst @@ -15,7 +15,7 @@ Supported devices: Corsair HX850i - Corsair HX1000i + Corsair HX1000i (revision 1 and 2) Corsair HX1200i @@ -86,8 +86,9 @@ Debugfs entries --------------- ======================= ======================================================== -uptime Current uptime of the psu +ocpmode Single or multi rail mode of the PCIe power connectors +product Product name of the psu +uptime Session uptime of the psu uptime_total Total uptime of the psu vendor Vendor name of the psu -product Product name of the psu ======================= ======================================================== diff --git a/Documentation/hwmon/emc2305.rst b/Documentation/hwmon/emc2305.rst new file mode 100644 index 000000000000..2403dbaf2728 --- /dev/null +++ b/Documentation/hwmon/emc2305.rst @@ -0,0 +1,37 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver emc2305 +===================== + +Supported chips: + Microchip EMC2305, EMC2303, EMC2302, EMC2301 + + Addresses scanned: I2C 0x27, 0x2c, 0x2d, 0x2e, 0x2f, 0x4c, 0x4d + Prefixes: 'emc2305' + + Datasheet: Publicly available at the Microchip website : + https://www.microchip.com/en-us/product/EMC2305 + +Description: +------------ +This driver implements support for Microchip EMC2301/2/3/5 RPM-based PWM Fan Controller. +The EMC2305 Fan Controller supports up to 5 independently controlled PWM fan drives. +Fan rotation speeds are reported in RPM. +The driver supports the RPM-based PWM control to keep a fan at the desired speed. +The driver provides the possibility to have one common PWM interface for all FANs +or up to the maximum available or configured independent PWMs. + +The driver provides the following sysfs interfaces in hwmon subsystem: + +================= == =================================================== +fan[1-5]_fault RO files for tachometers TACH1-TACH5 fault indication +fan[1-5]_input RO files for tachometers TACH1-TACH5 input (in RPM) +pwm[1-5] RW file for fan[1-5] target duty cycle (0..255) +================= == =================================================== + +sysfs interfaces in thermal subsystem: + +================= == ======================================================================== +cur_state RW file for the current cooling state of the cooling device (0..max_state) +max_state RO file for the maximum cooling state of the cooling device +================= == ======================================================================== diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index f7113b0f8b2a..c1d11cf13eef 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -44,7 +44,6 @@ Hardware Monitoring Kernel Drivers asc7621 aspeed-pwm-tacho asus_ec_sensors - asus_wmi_ec_sensors asus_wmi_sensors bcm54140 bel-pfe @@ -63,6 +62,7 @@ Hardware Monitoring Kernel Drivers ds620 emc1403 emc2103 + emc2305 emc6w201 f71805f f71882fg @@ -133,6 +133,7 @@ Hardware Monitoring Kernel Drivers max20751 max31722 max31730 + max31760 max31785 max31790 max34440 @@ -205,6 +206,7 @@ Hardware Monitoring Kernel Drivers tps23861 tps40422 tps53679 + tps546d24 twl4030-madc-hwmon ucd9000 ucd9200 diff --git a/Documentation/hwmon/max31760.rst b/Documentation/hwmon/max31760.rst new file mode 100644 index 000000000000..b1b55fb843c1 --- /dev/null +++ b/Documentation/hwmon/max31760.rst @@ -0,0 +1,77 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver max31760 +====================== + +Supported chips: + * Analog Devices MAX31760 + + Prefix: 'max31760' + + Addresses scanned: none + + Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX31760.pdf + + +Author: Ibrahim Tilki <Ibrahim.Tilki@analog.com> + +Description +----------- + +The MAX31760 integrates temperature sensing along with precision PWM fan +control. It accurately measures its local die temperature and the remote +temperature of a discrete diode-connected transistor, such as a 2N3906, +or a thermal diode commonly found on CPUs, graphics processor units (GPUs), +and other ASICs. Multiple temperature thresholds, such as local +high/overtemperature (OT) and remote high/overtemperature, can be set by an +I2C-compatible interface. Fan speed is controlled based on the temperature +reading as an index to a 48-byte lookup table (LUT) containing +user-programmed PWM values. The flexible LUT-based architecture enables +the user to program a smooth nonlinear fan speed vs. temperature transfer +function to minimize acoustic fan noise. Two tachometer inputs allow +measuring the speeds of two fans independently. When the local or remote +OT threshold is exceeded, the SHDN pin is asserted low and can be used to +shut down the system. A dedicated ALERT pin reports that either a local or +remote high-temperature threshold has been exceeded. + +Temperature measurement range: from -55°C to 125°C + +Temperature Resolution: 11 Bits, ±0.125°C + +Please refer how to instantiate this driver: Documentation/i2c/instantiating-devices.rst + +Lookup table for auto fan control +--------------------------------- + +========= ================================= +LUT Index Name +========= ================================= +1 PWM value for T < +18°C +2 PWM value for +18°C ≤ T < +20°C +3 PWM value for +20°C ≤ T < +22°C +... ... +47 PWM value for +108°C ≤ T < +110°C +48 PWM value for T ≥ +110°C +========= ================================= + +Sysfs entries +------------- + +=============================== ================================================================================= +fan[1-2]_input Fan speed (in RPM) +fan[1-2]_enable Enable fan readings and fan fault alarms +fan[1-2]_fault Fan fault status +temp[1-2]_label "Remote" and "Local" temperature channel labels +temp[1-2]_input Temperature sensor readings (in millidegrees Celsius) +temp1_fault Remote temperature sensor fault status +temp[1-2]_max Temperature max value. Asserts "ALERT" pin when exceeded +temp[1-2]_max_alarm Temperature max alarm status +temp[1-2]_crit Temperature critical value. Asserts "SHDN" pin when exceeded +temp[1-2]_crit_alarm Temperature critical alarm status +pwm1 PWM value for direct fan control +pwm1_enable 1: direct fan control, 2: temperature based auto fan control +pwm1_freq PWM frequency in hertz +pwm1_auto_channels_temp Temperature source for auto fan control. 1: temp1, 2: temp2, 3: max(temp1, temp2) +pwm1_auto_point[1-48]_pwm PWM value for LUT point +pwm1_auto_point_temp_hyst Temperature hysteresis for auto fan control. Can be either 2000mC or 4000mC +=============================== ================================================================================= diff --git a/Documentation/hwmon/max31790.rst b/Documentation/hwmon/max31790.rst index 7b097c3b9b90..33c5c7330efc 100644 --- a/Documentation/hwmon/max31790.rst +++ b/Documentation/hwmon/max31790.rst @@ -38,6 +38,7 @@ Sysfs entries fan[1-12]_input RO fan tachometer speed in RPM fan[1-12]_fault RO fan experienced fault fan[1-6]_target RW desired fan speed in RPM +fan[1-6]_enable RW enable or disable the tachometer input pwm[1-6]_enable RW regulator mode, 0=disabled (duty cycle=0%), 1=manual mode, 2=rpm mode pwm[1-6] RW read: current pwm duty cycle, write: target pwm duty cycle (0-255) diff --git a/Documentation/hwmon/pwm-fan.rst b/Documentation/hwmon/pwm-fan.rst index 82fe96742fee..f77998b204ef 100644 --- a/Documentation/hwmon/pwm-fan.rst +++ b/Documentation/hwmon/pwm-fan.rst @@ -18,3 +18,15 @@ the hwmon's sysfs interface. The fan rotation speed returned via the optional 'fan1_input' is extrapolated from the sampled interrupts from the tachometer signal within 1 second. + +The driver provides the following sensor accesses in sysfs: + +=============== ======= ======================================================= +fan1_input ro fan tachometer speed in RPM +pwm1_enable rw keep enable mode, defines behaviour when pwm1=0 + 0 -> disable pwm and regulator + 1 -> enable pwm; if pwm==0, disable pwm, keep regulator enabled + 2 -> enable pwm; if pwm==0, keep pwm and regulator enabled + 3 -> enable pwm; if pwm==0, disable pwm and regulator +pwm1 rw relative speed (0-255), 255=max. speed. +=============== ======= ======================================================= diff --git a/Documentation/hwmon/tps546d24.rst b/Documentation/hwmon/tps546d24.rst new file mode 100644 index 000000000000..97adb8a30fc0 --- /dev/null +++ b/Documentation/hwmon/tps546d24.rst @@ -0,0 +1,35 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +Kernel driver tps546d24 +======================= + +Supported chips: + + * TI TPS546D24 + + Prefix: 'tps546d24' + + Addresses scanned: - + + Datasheet: https://www.ti.com/lit/gpn/tps546d24 + +Author: Duke Du <dukedu83@gmail.com> + + +Description +----------- + +The TPS546D24A is a highly integrated, non-isolated DC/DC converter capable +of high frequency operation and 40-A current output from a 7-mm x 5-mm +package. + +Two, three, and four TPS546D24A devices can be interconnected +to provide up to 160 A on a single output. The device has an option to +overdrive the internal 5-V LDO with an external 5-V supply via the VDD5 +pin to improve efficiency and reduce power dissipation of the converter. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. diff --git a/MAINTAINERS b/MAINTAINERS index a8e68844b34b..b3a2880db324 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1339,6 +1339,15 @@ F: drivers/iio/amplifiers/hmc425a.c F: drivers/staging/iio/*/ad* X: drivers/iio/*/adjd* +ANALOG DEVICES INC MAX31760 DRIVER +M: Ibrahim Tilki <Ibrahim.Tilki@analog.com> +S: Maintained +W: http://wiki.analog.com/ +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/hwmon/adi,max31760.yaml +F: Documentation/hwmon/max31760.rst +F: drivers/hwmon/max31760.c + ANALOGBITS PLL LIBRARIES M: Paul Walmsley <paul.walmsley@sifive.com> S: Supported @@ -3238,13 +3247,6 @@ L: linux-hwmon@vger.kernel.org S: Maintained F: drivers/hwmon/asus_wmi_sensors.c -ASUS WMI EC HARDWARE MONITOR DRIVER -M: Eugene Shalygin <eugene.shalygin@gmail.com> -M: Denis Pauk <pauk.denis@gmail.com> -L: linux-hwmon@vger.kernel.org -S: Maintained -F: drivers/hwmon/asus_wmi_ec_sensors.c - ASUS EC HARDWARE MONITOR DRIVER M: Eugene Shalygin <eugene.shalygin@gmail.com> L: linux-hwmon@vger.kernel.org @@ -6181,7 +6183,7 @@ F: Documentation/devicetree/bindings/memory-controllers/samsung,exynos5422-dmc.y F: drivers/memory/samsung/exynos5422-dmc.c DME1737 HARDWARE MONITOR DRIVER -M: Juerg Haefliger <juergh@gmail.com> +M: Juerg Haefliger <juergh@proton.me> L: linux-hwmon@vger.kernel.org S: Maintained F: Documentation/hwmon/dme1737.rst @@ -20649,6 +20651,13 @@ Q: https://patchwork.kernel.org/project/linux-integrity/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git F: drivers/char/tpm/ +TPS546D24 DRIVER +M: Duke Du <dukedu83@gmail.com> +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/tps546d24.rst +F: drivers/hwmon/pmbus/tps546d24.c + TRACING M: Steven Rostedt <rostedt@goodmis.org> M: Ingo Molnar <mingo@redhat.com> @@ -21852,7 +21861,7 @@ F: lib/test_scanf.c F: lib/vsprintf.c VT1211 HARDWARE MONITOR DRIVER -M: Juerg Haefliger <juergh@gmail.com> +M: Juerg Haefliger <juergh@proton.me> L: linux-hwmon@vger.kernel.org S: Maintained F: Documentation/hwmon/vt1211.rst diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e70d9614bec2..5695b266abcf 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -257,14 +257,14 @@ config SENSORS_AHT10 will be called aht10. config SENSORS_AQUACOMPUTER_D5NEXT - tristate "Aquacomputer D5 Next, Octo, Quadro, Farbwerk, and Farbwerk 360" + tristate "Aquacomputer D5 Next, Octo, Quadro, Farbwerk, Farbwerk 360, High Flow Next" depends on USB_HID select CRC16 help If you say yes here you get support for sensors and fans of the Aquacomputer D5 Next watercooling pump, Octo and Quadro fan - controllers, Farbwerk and Farbwerk 360 RGB controllers, where - available. + controllers, Farbwerk and Farbwerk 360 RGB controllers, High Flow + Next sensor, where available. This driver can also be built as a module. If so, the module will be called aquacomputer_d5next. @@ -393,6 +393,7 @@ config SENSORS_ASB100 config SENSORS_ASPEED tristate "ASPEED AST2400/AST2500 PWM and Fan tach driver" + depends on ARCH_ASPEED || COMPILE_TEST depends on THERMAL || THERMAL=n select REGMAP help @@ -1066,6 +1067,18 @@ config SENSORS_MAX31730 This driver can also be built as a module. If so, the module will be called max31730. +config SENSORS_MAX31760 + tristate "MAX31760 fan speed controller" + depends on I2C + select REGMAP_I2C + help + Support for the Analog Devices MAX31760 Precision Fan-Speed + Controller. MAX31760 integrates temperature sensing along with + precision PWM fan control. + + This driver can also be built as a module. If so, the module + will be called max31760. + config SENSORS_MAX6620 tristate "Maxim MAX6620 fan controller" depends on I2C @@ -1785,6 +1798,19 @@ config SENSORS_EMC2103 This driver can also be built as a module. If so, the module will be called emc2103. +config SENSORS_EMC2305 + tristate "Microchip EMC2305 and compatible EMC2301/2/3" + depends on I2C + imply THERMAL + help + If you say yes here you get support for the Microchip EMC2305 + fan controller chips. + The Microchip EMC2305 is a fan controller for up to 5 fans. + Fan rotation speeds are reported in RPM. + + This driver can also be built as a module. If so, the module + will be called emc2305. + config SENSORS_EMC6W201 tristate "SMSC EMC6W201" depends on I2C @@ -2341,21 +2367,6 @@ config SENSORS_ASUS_WMI This driver can also be built as a module. If so, the module will be called asus_wmi_sensors. -config SENSORS_ASUS_WMI_EC - tristate "ASUS WMI B550/X570" - depends on ACPI_WMI && SENSORS_ASUS_EC=n - help - If you say yes here you get support for the ACPI embedded controller - hardware monitoring interface found in B550/X570 ASUS motherboards. - This driver will provide readings of fans, voltages and temperatures - through the system firmware. - - This driver is deprecated in favor of the ASUS EC Sensors driver - which provides fully compatible output. - - This driver can also be built as a module. If so, the module - will be called asus_wmi_sensors_ec. - config SENSORS_ASUS_EC tristate "ASUS EC Sensors" depends on X86 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 007e829d1d0d..11d076cad8a2 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o obj-$(CONFIG_SENSORS_ASUS_EC) += asus-ec-sensors.o obj-$(CONFIG_SENSORS_ASUS_WMI) += asus_wmi_sensors.o -obj-$(CONFIG_SENSORS_ASUS_WMI_EC) += asus_wmi_ec_sensors.o # Native drivers # asb100, then w83781d go first, as they can override other drivers' addresses. @@ -70,6 +69,7 @@ obj-$(CONFIG_SENSORS_DS620) += ds620.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o +obj-$(CONFIG_SENSORS_EMC2305) += emc2305.o obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o obj-$(CONFIG_SENSORS_F71805F) += f71805f.o obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o @@ -140,6 +140,7 @@ obj-$(CONFIG_SENSORS_MAX1668) += max1668.o obj-$(CONFIG_SENSORS_MAX197) += max197.o obj-$(CONFIG_SENSORS_MAX31722) += max31722.o obj-$(CONFIG_SENSORS_MAX31730) += max31730.o +obj-$(CONFIG_SENSORS_MAX31760) += max31760.o obj-$(CONFIG_SENSORS_MAX6620) += max6620.o obj-$(CONFIG_SENSORS_MAX6621) += max6621.o obj-$(CONFIG_SENSORS_MAX6639) += max6639.o diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 681f0623868f..a7cae6568155 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1504,7 +1504,6 @@ LEAVE_UPDATE: return NULL; } -#ifdef CONFIG_PM_SLEEP static int abituguru_suspend(struct device *dev) { struct abituguru_data *data = dev_get_drvdata(dev); @@ -1526,16 +1525,12 @@ static int abituguru_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(abituguru_pm, abituguru_suspend, abituguru_resume); -#define ABIT_UGURU_PM (&abituguru_pm) -#else -#define ABIT_UGURU_PM NULL -#endif /* CONFIG_PM */ +static DEFINE_SIMPLE_DEV_PM_OPS(abituguru_pm, abituguru_suspend, abituguru_resume); static struct platform_driver abituguru_driver = { .driver = { .name = ABIT_UGURU_NAME, - .pm = ABIT_UGURU_PM, + .pm = pm_sleep_ptr(&abituguru_pm), }, .probe = abituguru_probe, .remove = abituguru_remove, diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 8229ad30c909..afb21f73032d 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -1127,7 +1127,6 @@ LEAVE_UPDATE: return NULL; } -#ifdef CONFIG_PM_SLEEP static int abituguru3_suspend(struct device *dev) { struct abituguru3_data *data = dev_get_drvdata(dev); @@ -1146,16 +1145,12 @@ static int abituguru3_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume); -#define ABIT_UGURU3_PM (&abituguru3_pm) -#else -#define ABIT_UGURU3_PM NULL -#endif /* CONFIG_PM */ +static DEFINE_SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume); static struct platform_driver abituguru3_driver = { .driver = { .name = ABIT_UGURU3_NAME, - .pm = ABIT_UGURU3_PM + .pm = pm_sleep_ptr(&abituguru3_pm), }, .probe = abituguru3_probe, .remove = abituguru3_remove, diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 44e04c75d0d3..0962c12eba5a 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -927,8 +927,6 @@ static int acpi_power_meter_remove(struct acpi_device *device) return 0; } -#ifdef CONFIG_PM_SLEEP - static int acpi_power_meter_resume(struct device *dev) { struct acpi_power_meter_resource *resource; @@ -946,9 +944,8 @@ static int acpi_power_meter_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(acpi_power_meter_pm, NULL, acpi_power_meter_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(acpi_power_meter_pm, NULL, + acpi_power_meter_resume); static struct acpi_driver acpi_power_meter_driver = { .name = "power_meter", @@ -959,7 +956,7 @@ static struct acpi_driver acpi_power_meter_driver = { .remove = acpi_power_meter_remove, .notify = acpi_power_meter_notify, }, - .drv.pm = &acpi_power_meter_pm, + .drv.pm = pm_sleep_ptr(&acpi_power_meter_pm), }; /* Module init/exit routines */ diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index 299160543b35..97b330b6c165 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -384,7 +384,7 @@ static int adc128_detect(struct i2c_client *client, struct i2c_board_info *info) if (i2c_smbus_read_byte_data(client, ADC128_REG_BUSY_STATUS) & 0xfc) return -ENODEV; - strlcpy(info->type, "adc128d818", I2C_NAME_SIZE); + strscpy(info->type, "adc128d818", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 91ecfee243bf..2dc45e958730 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -426,7 +426,7 @@ static int adm1021_detect(struct i2c_client *client, pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n", type_name, i2c_adapter_id(adapter), client->addr); - strlcpy(info->type, type_name, I2C_NAME_SIZE); + strscpy(info->type, type_name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 4352f6a884e8..2984c4f98496 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -470,7 +470,7 @@ static int adm1025_detect(struct i2c_client *client, else return -ENODEV; - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 69b3ec752944..1f084f708743 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -1610,7 +1610,7 @@ static int adm1026_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, "adm1026", I2C_NAME_SIZE); + strscpy(info->type, "adm1026", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index 3e1999413f32..eaf6e5e04aac 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -329,7 +329,7 @@ static int adm1029_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, "adm1029", I2C_NAME_SIZE); + strscpy(info->type, "adm1029", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index ac841fa3a369..b42797bcb5b4 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -985,7 +985,7 @@ static int adm1031_detect(struct i2c_client *client, return -ENODEV; name = (id == 0x30) ? "adm1030" : "adm1031"; - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 483cd757abd3..40e3558d3709 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -501,17 +501,23 @@ static int adm9240_fan_read(struct device *dev, u32 attr, int channel, long *val switch (attr) { case hwmon_fan_input: + mutex_lock(&data->update_lock); err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), ®val); - if (err < 0) + if (err < 0) { + mutex_unlock(&data->update_lock); return err; + } if (regval == 255 && data->fan_div[channel] < 3) { /* adjust fan clock divider on overflow */ err = adm9240_write_fan_div(data, channel, ++data->fan_div[channel]); - if (err) + if (err) { + mutex_unlock(&data->update_lock); return err; + } } *val = FAN_FROM_REG(regval, BIT(data->fan_div[channel])); + mutex_unlock(&data->update_lock); break; case hwmon_fan_div: *val = BIT(data->fan_div[channel]); diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c index 1efc0bdcceab..067865f4887a 100644 --- a/drivers/hwmon/adt7310.c +++ b/drivers/hwmon/adt7310.c @@ -152,7 +152,7 @@ MODULE_DEVICE_TABLE(spi, adt7310_id); static struct spi_driver adt7310_driver = { .driver = { .name = "adt7310", - .pm = ADT7X10_DEV_PM_OPS, + .pm = pm_sleep_ptr(&adt7x10_dev_pm_ops), }, .probe = adt7310_spi_probe, .id_table = adt7310_id, diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index aede5baca7b9..0cebf6777239 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -98,7 +98,7 @@ static struct i2c_driver adt7410_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "adt7410", - .pm = ADT7X10_DEV_PM_OPS, + .pm = pm_sleep_ptr(&adt7x10_dev_pm_ops), }, .probe_new = adt7410_i2c_probe, .id_table = adt7410_ids, diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index fad74aa62b64..bf5c5618f8d0 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -590,7 +590,7 @@ static int adt7411_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, "adt7411", I2C_NAME_SIZE); + strscpy(info->type, "adt7411", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index e75bbd87ad09..9c0235849d4b 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -1782,7 +1782,7 @@ static int adt7462_detect(struct i2c_client *client, if (revision != ADT7462_REVISION) return -ENODEV; - strlcpy(info->type, "adt7462", I2C_NAME_SIZE); + strscpy(info->type, "adt7462", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index ac480e6e4818..51b3d16c3223 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -1342,7 +1342,7 @@ static int adt7475_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index ce54bffab2ec..da67734edafd 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -397,8 +397,6 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, } EXPORT_SYMBOL_GPL(adt7x10_probe); -#ifdef CONFIG_PM_SLEEP - static int adt7x10_suspend(struct device *dev) { struct adt7x10_data *data = dev_get_drvdata(dev); @@ -414,10 +412,7 @@ static int adt7x10_resume(struct device *dev) return regmap_write(data->regmap, ADT7X10_CONFIG, data->config); } -SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume); -EXPORT_SYMBOL_GPL(adt7x10_dev_pm_ops); - -#endif /* CONFIG_PM_SLEEP */ +EXPORT_SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume); MODULE_AUTHOR("Hartmut Knaack"); MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code"); diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h index ba22c32c8355..46caf3e21978 100644 --- a/drivers/hwmon/adt7x10.h +++ b/drivers/hwmon/adt7x10.h @@ -20,11 +20,6 @@ struct device; int adt7x10_probe(struct device *dev, const char *name, int irq, struct regmap *regmap); -#ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops adt7x10_dev_pm_ops; -#define ADT7X10_DEV_PM_OPS (&adt7x10_dev_pm_ops) -#else -#define ADT7X10_DEV_PM_OPS NULL -#endif #endif diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 0c16face3fd3..3bfd12ff4b3c 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -809,7 +809,7 @@ static int amc6821_detect( } dev_info(&adapter->dev, "amc6821: chip found at 0x%02x.\n", address); - strlcpy(info->type, "amc6821", I2C_NAME_SIZE); + strscpy(info->type, "amc6821", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 66430553cc45..c51a2678f0eb 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo, - * Quadro) + * Quadro, High Flow Next) * * Aquacomputer devices send HID reports (with ID 0x01) every second to report * sensor values. @@ -26,15 +26,17 @@ #define USB_PRODUCT_ID_D5NEXT 0xf00e #define USB_PRODUCT_ID_FARBWERK360 0xf010 #define USB_PRODUCT_ID_OCTO 0xf011 +#define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012 -enum kinds { d5next, farbwerk, farbwerk360, octo, quadro }; +enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext }; static const char *const aqc_device_names[] = { [d5next] = "d5next", [farbwerk] = "farbwerk", [farbwerk360] = "farbwerk360", [octo] = "octo", - [quadro] = "quadro" + [quadro] = "quadro", + [highflownext] = "highflownext" }; #define DRIVER_NAME "aquacomputer_d5next" @@ -71,6 +73,8 @@ static u8 secondary_ctrl_report[] = { #define D5NEXT_COOLANT_TEMP 0x57 #define D5NEXT_NUM_FANS 2 #define D5NEXT_NUM_SENSORS 1 +#define D5NEXT_NUM_VIRTUAL_SENSORS 8 +#define D5NEXT_VIRTUAL_SENSORS_START 0x3f #define D5NEXT_PUMP_OFFSET 0x6c #define D5NEXT_FAN_OFFSET 0x5f #define D5NEXT_5V_VOLTAGE 0x39 @@ -86,14 +90,18 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; #define FARBWERK_SENSOR_START 0x2f /* Register offsets for the Farbwerk 360 RGB controller */ -#define FARBWERK360_NUM_SENSORS 4 -#define FARBWERK360_SENSOR_START 0x32 +#define FARBWERK360_NUM_SENSORS 4 +#define FARBWERK360_SENSOR_START 0x32 +#define FARBWERK360_NUM_VIRTUAL_SENSORS 16 +#define FARBWERK360_VIRTUAL_SENSORS_START 0x3a /* Register offsets for the Octo fan controller */ #define OCTO_POWER_CYCLES 0x18 #define OCTO_NUM_FANS 8 #define OCTO_NUM_SENSORS 4 #define OCTO_SENSOR_START 0x3D +#define OCTO_NUM_VIRTUAL_SENSORS 16 +#define OCTO_VIRTUAL_SENSORS_START 0x45 #define OCTO_CTRL_REPORT_SIZE 0x65F static u8 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 }; @@ -105,12 +113,24 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0 #define QUADRO_NUM_FANS 4 #define QUADRO_NUM_SENSORS 4 #define QUADRO_SENSOR_START 0x34 +#define QUADRO_NUM_VIRTUAL_SENSORS 16 +#define QUADRO_VIRTUAL_SENSORS_START 0x3c #define QUADRO_CTRL_REPORT_SIZE 0x3c1 #define QUADRO_FLOW_SENSOR_OFFSET 0x6e static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 }; /* Fan speed registers in Quadro control report (from 0-100%) */ -static u16 quadro_ctrl_fan_offsets[] = { 0x36, 0x8b, 0xe0, 0x135 }; +static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; + +/* Register offsets for the High Flow Next */ +#define HIGHFLOWNEXT_NUM_SENSORS 2 +#define HIGHFLOWNEXT_SENSOR_START 85 +#define HIGHFLOWNEXT_FLOW 81 +#define HIGHFLOWNEXT_WATER_QUALITY 89 +#define HIGHFLOWNEXT_POWER 91 +#define HIGHFLOWNEXT_CONDUCTIVITY 95 +#define HIGHFLOWNEXT_5V_VOLTAGE 97 +#define HIGHFLOWNEXT_5V_VOLTAGE_USB 99 /* Labels for D5 Next */ static const char *const label_d5next_temp[] = { @@ -147,6 +167,25 @@ static const char *const label_temp_sensors[] = { "Sensor 4" }; +static const char *const label_virtual_temp_sensors[] = { + "Virtual sensor 1", + "Virtual sensor 2", + "Virtual sensor 3", + "Virtual sensor 4", + "Virtual sensor 5", + "Virtual sensor 6", + "Virtual sensor 7", + "Virtual sensor 8", + "Virtual sensor 9", + "Virtual sensor 10", + "Virtual sensor 11", + "Virtual sensor 12", + "Virtual sensor 13", + "Virtual sensor 14", + "Virtual sensor 15", + "Virtual sensor 16", +}; + /* Labels for Octo and Quadro (except speed) */ static const char *const label_fan_speed[] = { "Fan 1 speed", @@ -201,6 +240,27 @@ static const char *const label_quadro_speeds[] = { "Flow speed [dL/h]" }; +/* Labels for High Flow Next */ +static const char *const label_highflownext_temp_sensors[] = { + "Coolant temp", + "External sensor" +}; + +static const char *const label_highflownext_fan_speed[] = { + "Flow [dL/h]", + "Water quality [%]", + "Conductivity [nS/cm]", +}; + +static const char *const label_highflownext_power[] = { + "Dissipated power", +}; + +static const char *const label_highflownext_voltage[] = { + "+5V voltage", + "+5V USB voltage" +}; + struct aqc_data { struct hid_device *hdev; struct device *hwmon_dev; @@ -220,6 +280,8 @@ struct aqc_data { u16 *fan_ctrl_offsets; int num_temp_sensors; int temp_sensor_start_offset; + int num_virtual_temp_sensors; + int virtual_temp_sensor_start_offset; u16 power_cycle_count_offset; u8 flow_sensor_offset; @@ -231,7 +293,7 @@ struct aqc_data { u32 power_cycles; /* Sensor values */ - s32 temp_input[4]; + s32 temp_input[20]; /* Max 4 physical and 16 virtual */ u16 speed_input[8]; u32 power_input[8]; u16 voltage_input[8]; @@ -239,6 +301,7 @@ struct aqc_data { /* Label values */ const char *const *temp_label; + const char *const *virtual_temp_label; const char *const *speed_label; const char *const *power_label; const char *const *voltage_label; @@ -345,7 +408,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 switch (type) { case hwmon_temp: - if (channel < priv->num_temp_sensors) + if (channel < priv->num_temp_sensors + priv->num_virtual_temp_sensors) return 0444; break; case hwmon_pwm: @@ -360,6 +423,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 break; case hwmon_fan: switch (priv->kind) { + case highflownext: + /* Special case to support flow sensor, water quality and conductivity */ + if (channel < 3) + return 0444; + break; case quadro: /* Special case to support flow sensor */ if (channel < priv->num_fans + 1) @@ -372,6 +440,18 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 } break; case hwmon_power: + switch (priv->kind) { + case highflownext: + /* Special case to support one power sensor */ + if (channel == 0) + return 0444; + break; + default: + if (channel < priv->num_fans) + return 0444; + break; + } + break; case hwmon_curr: if (channel < priv->num_fans) return 0444; @@ -383,6 +463,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 if (channel < priv->num_fans + 2) return 0444; break; + case highflownext: + /* Special case to support two voltage sensors */ + if (channel < 2) + return 0444; + break; default: if (channel < priv->num_fans) return 0444; @@ -447,7 +532,10 @@ static int aqc_read_string(struct device *dev, enum hwmon_sensor_types type, u32 switch (type) { case hwmon_temp: - *str = priv->temp_label[channel]; + if (channel < priv->num_temp_sensors) + *str = priv->temp_label[channel]; + else + *str = priv->virtual_temp_label[channel - priv->num_temp_sensors]; break; case hwmon_fan: *str = priv->speed_label[channel]; @@ -512,6 +600,22 @@ static const struct hwmon_channel_info *aqc_info[] = { HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL), HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL, @@ -568,7 +672,7 @@ static const struct hwmon_chip_info aqc_chip_info = { static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { - int i, sensor_value; + int i, j, sensor_value; struct aqc_data *priv; if (report->id != STATUS_REPORT_ID) @@ -581,7 +685,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 priv->serial_number[1] = get_unaligned_be16(data + SERIAL_SECOND_PART); priv->firmware_version = get_unaligned_be16(data + FIRMWARE_VERSION); - /* Temperature sensor readings */ + /* Physical temperature sensor readings */ for (i = 0; i < priv->num_temp_sensors; i++) { sensor_value = get_unaligned_be16(data + priv->temp_sensor_start_offset + @@ -592,6 +696,18 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 priv->temp_input[i] = sensor_value * 10; } + /* Virtual temperature sensor readings */ + for (j = 0; j < priv->num_virtual_temp_sensors; j++) { + sensor_value = get_unaligned_be16(data + + priv->virtual_temp_sensor_start_offset + + j * AQC_TEMP_SENSOR_SIZE); + if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED) + priv->temp_input[i] = -ENODATA; + else + priv->temp_input[i] = sensor_value * 10; + i++; + } + /* Fan speed and related readings */ for (i = 0; i < priv->num_fans; i++) { priv->speed_input[i] = @@ -618,6 +734,22 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 case quadro: priv->speed_input[4] = get_unaligned_be16(data + priv->flow_sensor_offset); break; + case highflownext: + /* If external temp sensor is not connected, its power reading is also N/A */ + if (priv->temp_input[1] == -ENODATA) + priv->power_input[0] = -ENODATA; + else + priv->power_input[0] = + get_unaligned_be16(data + HIGHFLOWNEXT_POWER) * 1000000; + + priv->voltage_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE) * 10; + priv->voltage_input[1] = + get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE_USB) * 10; + + priv->speed_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_FLOW); + priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY); + priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY); + break; default: break; } @@ -717,10 +849,13 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->fan_ctrl_offsets = d5next_ctrl_fan_offsets; priv->num_temp_sensors = D5NEXT_NUM_SENSORS; priv->temp_sensor_start_offset = D5NEXT_COOLANT_TEMP; + priv->num_virtual_temp_sensors = D5NEXT_NUM_VIRTUAL_SENSORS; + priv->virtual_temp_sensor_start_offset = D5NEXT_VIRTUAL_SENSORS_START; priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES; priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE; priv->temp_label = label_d5next_temp; + priv->virtual_temp_label = label_virtual_temp_sensors; priv->speed_label = label_d5next_speeds; priv->power_label = label_d5next_power; priv->voltage_label = label_d5next_voltages; @@ -740,7 +875,11 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->num_fans = 0; priv->num_temp_sensors = FARBWERK360_NUM_SENSORS; priv->temp_sensor_start_offset = FARBWERK360_SENSOR_START; + priv->num_virtual_temp_sensors = FARBWERK360_NUM_VIRTUAL_SENSORS; + priv->virtual_temp_sensor_start_offset = FARBWERK360_VIRTUAL_SENSORS_START; + priv->temp_label = label_temp_sensors; + priv->virtual_temp_label = label_virtual_temp_sensors; break; case USB_PRODUCT_ID_OCTO: priv->kind = octo; @@ -750,10 +889,13 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->fan_ctrl_offsets = octo_ctrl_fan_offsets; priv->num_temp_sensors = OCTO_NUM_SENSORS; priv->temp_sensor_start_offset = OCTO_SENSOR_START; + priv->num_virtual_temp_sensors = OCTO_NUM_VIRTUAL_SENSORS; + priv->virtual_temp_sensor_start_offset = OCTO_VIRTUAL_SENSORS_START; priv->power_cycle_count_offset = OCTO_POWER_CYCLES; priv->buffer_size = OCTO_CTRL_REPORT_SIZE; priv->temp_label = label_temp_sensors; + priv->virtual_temp_label = label_virtual_temp_sensors; priv->speed_label = label_fan_speed; priv->power_label = label_fan_power; priv->voltage_label = label_fan_voltage; @@ -767,16 +909,32 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->fan_ctrl_offsets = quadro_ctrl_fan_offsets; priv->num_temp_sensors = QUADRO_NUM_SENSORS; priv->temp_sensor_start_offset = QUADRO_SENSOR_START; + priv->num_virtual_temp_sensors = QUADRO_NUM_VIRTUAL_SENSORS; + priv->virtual_temp_sensor_start_offset = QUADRO_VIRTUAL_SENSORS_START; priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; priv->buffer_size = QUADRO_CTRL_REPORT_SIZE; priv->flow_sensor_offset = QUADRO_FLOW_SENSOR_OFFSET; priv->temp_label = label_temp_sensors; + priv->virtual_temp_label = label_virtual_temp_sensors; priv->speed_label = label_quadro_speeds; priv->power_label = label_fan_power; priv->voltage_label = label_fan_voltage; priv->current_label = label_fan_current; break; + case USB_PRODUCT_ID_HIGHFLOWNEXT: + priv->kind = highflownext; + + priv->num_fans = 0; + priv->num_temp_sensors = HIGHFLOWNEXT_NUM_SENSORS; + priv->temp_sensor_start_offset = HIGHFLOWNEXT_SENSOR_START; + priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; + + priv->temp_label = label_highflownext_temp_sensors; + priv->speed_label = label_highflownext_fan_speed; + priv->power_label = label_highflownext_power; + priv->voltage_label = label_highflownext_voltage; + break; default: break; } @@ -833,6 +991,7 @@ static const struct hid_device_id aqc_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK360) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOWNEXT) }, { } }; diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index a9166c8555c5..ce4da836765c 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -769,7 +769,7 @@ static int asb100_detect(struct i2c_client *client, if (val1 != 0x31 || val2 != 0x06) return -ENODEV; - strlcpy(info->type, "asb100", I2C_NAME_SIZE); + strscpy(info->type, "asb100", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 4f90fdee9cc7..54595454537b 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -1153,7 +1153,7 @@ static int asc7621_detect(struct i2c_client *client, if (company == asc7621_chips[chip_index].company_id && verstep == asc7621_chips[chip_index].verstep_id) { - strlcpy(info->type, asc7621_chips[chip_index].name, + strscpy(info->type, asc7621_chips[chip_index].name, I2C_NAME_SIZE); dev_info(&adapter->dev, "Matched %s at 0x%02x\n", diff --git a/drivers/hwmon/asus_wmi_ec_sensors.c b/drivers/hwmon/asus_wmi_ec_sensors.c deleted file mode 100644 index a3a2f014dec0..000000000000 --- a/drivers/hwmon/asus_wmi_ec_sensors.c +++ /dev/null @@ -1,622 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * HWMON driver for ASUS B550/X570 motherboards that publish sensor - * values via the embedded controller registers. - * - * Copyright (C) 2021 Eugene Shalygin <eugene.shalygin@gmail.com> - * Copyright (C) 2018-2019 Ed Brindley <kernel@maidavale.org> - * - * EC provides: - * - Chipset temperature - * - CPU temperature - * - Motherboard temperature - * - T_Sensor temperature - * - VRM temperature - * - Water In temperature - * - Water Out temperature - * - CPU Optional Fan RPM - * - Chipset Fan RPM - * - Water Flow Fan RPM - * - CPU current - */ - -#include <linux/acpi.h> -#include <linux/dmi.h> -#include <linux/hwmon.h> -#include <linux/init.h> -#include <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/nls.h> -#include <linux/units.h> -#include <linux/wmi.h> - -#include <asm/unaligned.h> - -#define ASUSWMI_MONITORING_GUID "466747A0-70EC-11DE-8A39-0800200C9A66" -#define ASUSWMI_METHODID_BLOCK_READ_EC 0x42524543 /* BREC */ -/* From the ASUS DSDT source */ -#define ASUSWMI_BREC_REGISTERS_MAX 16 -#define ASUSWMI_MAX_BUF_LEN 128 -#define SENSOR_LABEL_LEN 16 - -static u32 hwmon_attributes[hwmon_max] = { - [hwmon_chip] = HWMON_C_REGISTER_TZ, - [hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL, - [hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL, - [hwmon_curr] = HWMON_C_INPUT | HWMON_C_LABEL, - [hwmon_fan] = HWMON_F_INPUT | HWMON_F_LABEL, -}; - -struct asus_wmi_ec_sensor_address { - u8 index; - u8 bank; - u8 size; -}; - -#define MAKE_SENSOR_ADDRESS(size_i, bank_i, index_i) { \ - .size = size_i, \ - .bank = bank_i, \ - .index = index_i, \ -} - -struct ec_sensor_info { - struct asus_wmi_ec_sensor_address addr; - char label[SENSOR_LABEL_LEN]; - enum hwmon_sensor_types type; -}; - -#define EC_SENSOR(sensor_label, sensor_type, size, bank, index) { \ - .addr = MAKE_SENSOR_ADDRESS(size, bank, index), \ - .label = sensor_label, \ - .type = sensor_type, \ -} - -enum known_ec_sensor { - SENSOR_TEMP_CHIPSET, - SENSOR_TEMP_CPU, - SENSOR_TEMP_MB, - SENSOR_TEMP_T_SENSOR, - SENSOR_TEMP_VRM, - SENSOR_FAN_CPU_OPT, - SENSOR_FAN_CHIPSET, - SENSOR_FAN_VRM_HS, - SENSOR_FAN_WATER_FLOW, - SENSOR_CURR_CPU, - SENSOR_TEMP_WATER_IN, - SENSOR_TEMP_WATER_OUT, - SENSOR_MAX -}; - -/* All known sensors for ASUS EC controllers */ -static const struct ec_sensor_info known_ec_sensors[] = { - [SENSOR_TEMP_CHIPSET] = EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a), - [SENSOR_TEMP_CPU] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b), - [SENSOR_TEMP_MB] = EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c), - [SENSOR_TEMP_T_SENSOR] = EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d), - [SENSOR_TEMP_VRM] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e), - [SENSOR_FAN_CPU_OPT] = EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), - [SENSOR_FAN_VRM_HS] = EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2), - [SENSOR_FAN_CHIPSET] = EC_SENSOR("Chipset", hwmon_fan, 2, 0x00, 0xb4), - [SENSOR_FAN_WATER_FLOW] = EC_SENSOR("Water_Flow", hwmon_fan, 2, 0x00, 0xbc), - [SENSOR_CURR_CPU] = EC_SENSOR("CPU", hwmon_curr, 1, 0x00, 0xf4), - [SENSOR_TEMP_WATER_IN] = EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00), - [SENSOR_TEMP_WATER_OUT] = EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01), -}; - -struct asus_wmi_data { - const enum known_ec_sensor known_board_sensors[SENSOR_MAX + 1]; -}; - -/* boards with EC support */ -static struct asus_wmi_data sensors_board_PW_X570_P = { - .known_board_sensors = { - SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB, - SENSOR_TEMP_T_SENSOR, SENSOR_TEMP_VRM, - SENSOR_FAN_CHIPSET, - SENSOR_MAX - }, -}; - -static struct asus_wmi_data sensors_board_PW_X570_A = { - .known_board_sensors = { - SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB, SENSOR_TEMP_VRM, - SENSOR_FAN_CHIPSET, - SENSOR_CURR_CPU, - SENSOR_MAX - }, -}; - -static struct asus_wmi_data sensors_board_R_C8H = { - .known_board_sensors = { - SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB, - SENSOR_TEMP_T_SENSOR, SENSOR_TEMP_VRM, - SENSOR_TEMP_WATER_IN, SENSOR_TEMP_WATER_OUT, - SENSOR_FAN_CPU_OPT, SENSOR_FAN_CHIPSET, SENSOR_FAN_WATER_FLOW, - SENSOR_CURR_CPU, - SENSOR_MAX - }, -}; - -/* Same as Hero but without chipset fan */ -static struct asus_wmi_data sensors_board_R_C8DH = { - .known_board_sensors = { - SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB, - SENSOR_TEMP_T_SENSOR, SENSOR_TEMP_VRM, - SENSOR_TEMP_WATER_IN, SENSOR_TEMP_WATER_OUT, - SENSOR_FAN_CPU_OPT, SENSOR_FAN_WATER_FLOW, - SENSOR_CURR_CPU, - SENSOR_MAX - }, -}; - -/* Same as Hero but without water */ -static struct asus_wmi_data sensors_board_R_C8F = { - .known_board_sensors = { - SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB, - SENSOR_TEMP_T_SENSOR, SENSOR_TEMP_VRM, - SENSOR_FAN_CPU_OPT, SENSOR_FAN_CHIPSET, - SENSOR_CURR_CPU, - SENSOR_MAX - }, -}; - -static struct asus_wmi_data sensors_board_RS_B550_E_G = { - .known_board_sensors = { - SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB, - SENSOR_TEMP_T_SENSOR, SENSOR_TEMP_VRM, - SENSOR_FAN_CPU_OPT, - SENSOR_MAX - }, -}; - -static struct asus_wmi_data sensors_board_RS_B550_I_G = { - .known_board_sensors = { - SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB, - SENSOR_TEMP_T_SENSOR, SENSOR_TEMP_VRM, - SENSOR_FAN_VRM_HS, - SENSOR_CURR_CPU, - SENSOR_MAX - }, -}; - -static struct asus_wmi_data sensors_board_RS_X570_E_G = { - .known_board_sensors = { - SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB, - SENSOR_TEMP_T_SENSOR, SENSOR_TEMP_VRM, - SENSOR_FAN_CHIPSET, - SENSOR_CURR_CPU, - SENSOR_MAX - }, -}; - -#define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name, sensors) { \ - .matches = { \ - DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), \ - DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \ - }, \ - .driver_data = sensors, \ -} - -static const struct dmi_system_id asus_wmi_ec_dmi_table[] = { - DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X570-PRO", &sensors_board_PW_X570_P), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE", &sensors_board_PW_X570_A), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII DARK HERO", &sensors_board_R_C8DH), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII FORMULA", &sensors_board_R_C8F), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO", &sensors_board_R_C8H), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-E GAMING", &sensors_board_RS_B550_E_G), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-I GAMING", &sensors_board_RS_B550_I_G), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING", &sensors_board_RS_X570_E_G), - {} -}; -MODULE_DEVICE_TABLE(dmi, asus_wmi_ec_dmi_table); - -struct ec_sensor { - enum known_ec_sensor info_index; - long cached_value; -}; - -/** - * struct asus_wmi_ec_info - sensor info. - * @sensors: list of sensors. - * @read_arg: UTF-16LE string to pass to BRxx() WMI function. - * @read_buffer: decoded output from WMI result. - * @nr_sensors: number of board EC sensors. - * @nr_registers: number of EC registers to read (sensor might span more than 1 register). - * @last_updated: in jiffies. - */ -struct asus_wmi_ec_info { - struct ec_sensor sensors[SENSOR_MAX]; - char read_arg[(ASUSWMI_BREC_REGISTERS_MAX * 4 + 1) * 2]; - u8 read_buffer[ASUSWMI_BREC_REGISTERS_MAX]; - unsigned int nr_sensors; - unsigned int nr_registers; - unsigned long last_updated; -}; - -struct asus_wmi_sensors { - struct asus_wmi_ec_info ec; - /* lock access to internal cache */ - struct mutex lock; -}; - -static int asus_wmi_ec_fill_board_sensors(struct asus_wmi_ec_info *ec, - const enum known_ec_sensor *bsi) -{ - struct ec_sensor *s = ec->sensors; - int i; - - ec->nr_sensors = 0; - ec->nr_registers = 0; - - for (i = 0; bsi[i] != SENSOR_MAX; i++) { - s[i].info_index = bsi[i]; - ec->nr_sensors++; - ec->nr_registers += known_ec_sensors[bsi[i]].addr.size; - } - - return 0; -} - -/* - * The next four functions convert to or from BRxx string argument format. - * The format of the string is as follows: - * - The string consists of two-byte UTF-16LE characters. - * - The value of the very first byte in the string is equal to the total - * length of the next string in bytes, thus excluding the first two-byte - * character. - * - The rest of the string encodes the pairs of (bank, index) pairs, where - * both values are byte-long (0x00 to 0xFF). - * - Numbers are encoded as UTF-16LE hex values. - */ -static int asus_wmi_ec_decode_reply_buffer(const u8 *in, u32 length, u8 *out) -{ - char buffer[ASUSWMI_MAX_BUF_LEN * 2]; - u32 len = min_t(u32, get_unaligned_le16(in), length - 2); - - utf16s_to_utf8s((wchar_t *)(in + 2), len / 2, UTF16_LITTLE_ENDIAN, buffer, sizeof(buffer)); - - return hex2bin(out, buffer, len / 4); -} - -static void asus_wmi_ec_encode_registers(const u8 *in, u32 len, char *out) -{ - char buffer[ASUSWMI_MAX_BUF_LEN * 2]; - - bin2hex(buffer, in, len); - - utf8s_to_utf16s(buffer, len * 2, UTF16_LITTLE_ENDIAN, (wchar_t *)(out + 2), len * 2); - - put_unaligned_le16(len * 4, out); -} - -static void asus_wmi_ec_make_block_read_query(struct asus_wmi_ec_info *ec) -{ - u8 registers[ASUSWMI_BREC_REGISTERS_MAX * 2]; - const struct ec_sensor_info *si; - int i, j, offset; - - offset = 0; - for (i = 0; i < ec->nr_sensors; i++) { - si = &known_ec_sensors[ec->sensors[i].info_index]; - for (j = 0; j < si->addr.size; j++) { - registers[offset++] = si->addr.bank; - registers[offset++] = si->addr.index + j; - } - } - - asus_wmi_ec_encode_registers(registers, offset, ec->read_arg); -} - -static int asus_wmi_ec_block_read(u32 method_id, char *query, u8 *out) -{ - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer input; - union acpi_object *obj; - acpi_status status; - int ret; - - /* The first byte of the BRxx() argument string has to be the string size. */ - input.length = query[0] + 2; - input.pointer = query; - status = wmi_evaluate_method(ASUSWMI_MONITORING_GUID, 0, method_id, &input, &output); - if (ACPI_FAILURE(status)) - return -EIO; - - obj = output.pointer; - if (!obj) - return -EIO; - - if (obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 2) { - ret = -EIO; - goto out_free_obj; - } - - ret = asus_wmi_ec_decode_reply_buffer(obj->buffer.pointer, obj->buffer.length, out); - -out_free_obj: - ACPI_FREE(obj); - return ret; -} - -static inline long get_sensor_value(const struct ec_sensor_info *si, u8 *data) -{ - switch (si->addr.size) { - case 1: - return *data; - case 2: - return get_unaligned_be16(data); - case 4: - return get_unaligned_be32(data); - default: - return 0; - } -} - -static void asus_wmi_ec_update_ec_sensors(struct asus_wmi_ec_info *ec) -{ - const struct ec_sensor_info *si; - struct ec_sensor *s; - u8 i_sensor; - u8 *data; - - data = ec->read_buffer; - for (i_sensor = 0; i_sensor < ec->nr_sensors; i_sensor++) { - s = &ec->sensors[i_sensor]; - si = &known_ec_sensors[s->info_index]; - s->cached_value = get_sensor_value(si, data); - data += si->addr.size; - } -} - -static long asus_wmi_ec_scale_sensor_value(long value, int data_type) -{ - switch (data_type) { - case hwmon_curr: - case hwmon_temp: - case hwmon_in: - return value * MILLI; - default: - return value; - } -} - -static int asus_wmi_ec_find_sensor_index(const struct asus_wmi_ec_info *ec, - enum hwmon_sensor_types type, int channel) -{ - int i; - - for (i = 0; i < ec->nr_sensors; i++) { - if (known_ec_sensors[ec->sensors[i].info_index].type == type) { - if (channel == 0) - return i; - - channel--; - } - } - return -EINVAL; -} - -static int asus_wmi_ec_get_cached_value_or_update(struct asus_wmi_sensors *sensor_data, - int sensor_index, - long *value) -{ - struct asus_wmi_ec_info *ec = &sensor_data->ec; - int ret = 0; - - mutex_lock(&sensor_data->lock); - - if (time_after(jiffies, ec->last_updated + HZ)) { - ret = asus_wmi_ec_block_read(ASUSWMI_METHODID_BLOCK_READ_EC, - ec->read_arg, ec->read_buffer); - if (ret) - goto unlock; - - asus_wmi_ec_update_ec_sensors(ec); - ec->last_updated = jiffies; - } - - *value = ec->sensors[sensor_index].cached_value; - -unlock: - mutex_unlock(&sensor_data->lock); - - return ret; -} - -/* Now follow the functions that implement the hwmon interface */ - -static int asus_wmi_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long *val) -{ - struct asus_wmi_sensors *sensor_data = dev_get_drvdata(dev); - struct asus_wmi_ec_info *ec = &sensor_data->ec; - int ret, sidx, info_index; - long value = 0; - - sidx = asus_wmi_ec_find_sensor_index(ec, type, channel); - if (sidx < 0) - return sidx; - - ret = asus_wmi_ec_get_cached_value_or_update(sensor_data, sidx, &value); - if (ret) - return ret; - - info_index = ec->sensors[sidx].info_index; - *val = asus_wmi_ec_scale_sensor_value(value, known_ec_sensors[info_index].type); - - return ret; -} - -static int asus_wmi_ec_hwmon_read_string(struct device *dev, - enum hwmon_sensor_types type, u32 attr, - int channel, const char **str) -{ - struct asus_wmi_sensors *sensor_data = dev_get_drvdata(dev); - struct asus_wmi_ec_info *ec = &sensor_data->ec; - int sensor_index; - - sensor_index = asus_wmi_ec_find_sensor_index(ec, type, channel); - *str = known_ec_sensors[ec->sensors[sensor_index].info_index].label; - - return 0; -} - -static umode_t asus_wmi_ec_hwmon_is_visible(const void *drvdata, - enum hwmon_sensor_types type, u32 attr, - int channel) -{ - const struct asus_wmi_sensors *sensor_data = drvdata; - const struct asus_wmi_ec_info *ec = &sensor_data->ec; - int index; - - index = asus_wmi_ec_find_sensor_index(ec, type, channel); - - return index < 0 ? 0 : 0444; -} - -static int asus_wmi_hwmon_add_chan_info(struct hwmon_channel_info *asus_wmi_hwmon_chan, - struct device *dev, int num, - enum hwmon_sensor_types type, u32 config) -{ - u32 *cfg; - - cfg = devm_kcalloc(dev, num + 1, sizeof(*cfg), GFP_KERNEL); - if (!cfg) - return -ENOMEM; - - asus_wmi_hwmon_chan->type = type; - asus_wmi_hwmon_chan->config = cfg; - memset32(cfg, config, num); - - return 0; -} - -static const struct hwmon_ops asus_wmi_ec_hwmon_ops = { - .is_visible = asus_wmi_ec_hwmon_is_visible, - .read = asus_wmi_ec_hwmon_read, - .read_string = asus_wmi_ec_hwmon_read_string, -}; - -static struct hwmon_chip_info asus_wmi_ec_chip_info = { - .ops = &asus_wmi_ec_hwmon_ops, -}; - -static int asus_wmi_ec_configure_sensor_setup(struct device *dev, - const enum known_ec_sensor *bsi) -{ - struct asus_wmi_sensors *sensor_data = dev_get_drvdata(dev); - struct asus_wmi_ec_info *ec = &sensor_data->ec; - struct hwmon_channel_info *asus_wmi_hwmon_chan; - const struct hwmon_channel_info **asus_wmi_ci; - int nr_count[hwmon_max] = {}, nr_types = 0; - const struct hwmon_chip_info *chip_info; - const struct ec_sensor_info *si; - enum hwmon_sensor_types type; - struct device *hwdev; - int i, ret; - - ret = asus_wmi_ec_fill_board_sensors(ec, bsi); - if (ret) - return ret; - - if (!sensor_data->ec.nr_sensors) - return -ENODEV; - - for (i = 0; i < ec->nr_sensors; i++) { - si = &known_ec_sensors[ec->sensors[i].info_index]; - if (!nr_count[si->type]) - nr_types++; - nr_count[si->type]++; - } - - if (nr_count[hwmon_temp]) { - nr_count[hwmon_chip]++; - nr_types++; - } - - /* - * If we can get values for all the registers in a single query, - * the query will not change from call to call. - */ - asus_wmi_ec_make_block_read_query(ec); - - asus_wmi_hwmon_chan = devm_kcalloc(dev, nr_types, sizeof(*asus_wmi_hwmon_chan), - GFP_KERNEL); - if (!asus_wmi_hwmon_chan) - return -ENOMEM; - - asus_wmi_ci = devm_kcalloc(dev, nr_types + 1, sizeof(*asus_wmi_ci), GFP_KERNEL); - if (!asus_wmi_ci) - return -ENOMEM; - - asus_wmi_ec_chip_info.info = asus_wmi_ci; - chip_info = &asus_wmi_ec_chip_info; - - for (type = 0; type < hwmon_max; type++) { - if (!nr_count[type]) - continue; - - ret = asus_wmi_hwmon_add_chan_info(asus_wmi_hwmon_chan, dev, - nr_count[type], type, - hwmon_attributes[type]); - if (ret) - return ret; - - *asus_wmi_ci++ = asus_wmi_hwmon_chan++; - } - - dev_dbg(dev, "board has %d EC sensors that span %d registers", - ec->nr_sensors, ec->nr_registers); - - hwdev = devm_hwmon_device_register_with_info(dev, "asus_wmi_ec_sensors", - sensor_data, chip_info, NULL); - - return PTR_ERR_OR_ZERO(hwdev); -} - -static int asus_wmi_probe(struct wmi_device *wdev, const void *context) -{ - struct asus_wmi_sensors *sensor_data; - struct asus_wmi_data *board_sensors; - const struct dmi_system_id *dmi_id; - const enum known_ec_sensor *bsi; - struct device *dev = &wdev->dev; - - dmi_id = dmi_first_match(asus_wmi_ec_dmi_table); - if (!dmi_id) - return -ENODEV; - - board_sensors = dmi_id->driver_data; - bsi = board_sensors->known_board_sensors; - - sensor_data = devm_kzalloc(dev, sizeof(*sensor_data), GFP_KERNEL); - if (!sensor_data) - return -ENOMEM; - - mutex_init(&sensor_data->lock); - - dev_set_drvdata(dev, sensor_data); - - return asus_wmi_ec_configure_sensor_setup(dev, bsi); -} - -static const struct wmi_device_id asus_ec_wmi_id_table[] = { - { ASUSWMI_MONITORING_GUID, NULL }, - { } -}; - -static struct wmi_driver asus_sensors_wmi_driver = { - .driver = { - .name = "asus_wmi_ec_sensors", - }, - .id_table = asus_ec_wmi_id_table, - .probe = asus_wmi_probe, -}; -module_wmi_driver(asus_sensors_wmi_driver); - -MODULE_AUTHOR("Ed Brindley <kernel@maidavale.org>"); -MODULE_AUTHOR("Eugene Shalygin <eugene.shalygin@gmail.com>"); -MODULE_DESCRIPTION("Asus WMI Sensors Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c index 96c4a5c45291..6724e0dd3088 100644 --- a/drivers/hwmon/axi-fan-control.c +++ b/drivers/hwmon/axi-fan-control.c @@ -394,11 +394,6 @@ static int axi_fan_control_init(struct axi_fan_control_data *ctl, return ret; } -static void axi_fan_control_clk_disable(void *clk) -{ - clk_disable_unprepare(clk); -} - static const struct hwmon_channel_info *axi_fan_control_info[] = { HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT), HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_LABEL), @@ -478,20 +473,12 @@ static int axi_fan_control_probe(struct platform_device *pdev) if (IS_ERR(ctl->base)) return PTR_ERR(ctl->base); - clk = devm_clk_get(&pdev->dev, NULL); + clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "clk_get failed with %ld\n", PTR_ERR(clk)); return PTR_ERR(clk); } - ret = clk_prepare_enable(clk); - if (ret) - return ret; - - ret = devm_add_action_or_reset(&pdev->dev, axi_fan_control_clk_disable, clk); - if (ret) - return ret; - ctl->clk_rate = clk_get_rate(clk); if (!ctl->clk_rate) return -EINVAL; diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c index 14389fd7afb8..345d883ab044 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -55,6 +55,7 @@ #define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24) #define RAIL_COUNT 3 /* 3v3 + 5v + 12v */ #define TEMP_COUNT 2 +#define OCP_MULTI_RAIL 0x02 #define PSU_CMD_SELECT_RAIL 0x00 /* expects length 2 */ #define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 /* the rest of the commands expect length 3 */ @@ -71,9 +72,10 @@ #define PSU_CMD_RAIL_WATTS 0x96 #define PSU_CMD_VEND_STR 0x99 #define PSU_CMD_PROD_STR 0x9A -#define PSU_CMD_TOTAL_WATTS 0xEE #define PSU_CMD_TOTAL_UPTIME 0xD1 #define PSU_CMD_UPTIME 0xD2 +#define PSU_CMD_OCPMODE 0xD8 +#define PSU_CMD_TOTAL_WATTS 0xEE #define PSU_CMD_INIT 0xFE #define L_IN_VOLTS "v_in" @@ -268,6 +270,7 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l break; case PSU_CMD_TOTAL_UPTIME: case PSU_CMD_UPTIME: + case PSU_CMD_OCPMODE: *val = tmp; break; default: @@ -660,6 +663,29 @@ static int product_show(struct seq_file *seqf, void *unused) } DEFINE_SHOW_ATTRIBUTE(product); +static int ocpmode_show(struct seq_file *seqf, void *unused) +{ + struct corsairpsu_data *priv = seqf->private; + long val; + int ret; + + /* + * The rail mode is switchable on the fly. The RAW interface can be used for this. But it + * will not be included here, because I consider it somewhat dangerous for the health of the + * PSU. The returned value can be a bogus one, if the PSU is in the process of switching and + * getting of the value itself can also fail during this. Because of this every other value + * than OCP_MULTI_RAIL can be considered as "single rail". + */ + ret = corsairpsu_get_value(priv, PSU_CMD_OCPMODE, 0, &val); + if (ret < 0) + seq_puts(seqf, "N/A\n"); + else + seq_printf(seqf, "%s\n", (val == OCP_MULTI_RAIL) ? "multi rail" : "single rail"); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(ocpmode); + static void corsairpsu_debugfs_init(struct corsairpsu_data *priv) { char name[32]; @@ -671,6 +697,7 @@ static void corsairpsu_debugfs_init(struct corsairpsu_data *priv) debugfs_create_file("uptime_total", 0444, priv->debugfs, priv, &uptime_total_fops); debugfs_create_file("vendor", 0444, priv->debugfs, priv, &vendor_fops); debugfs_create_file("product", 0444, priv->debugfs, priv, &product_fops); + debugfs_create_file("ocpmode", 0444, priv->debugfs, priv, &ocpmode_fops); } #else @@ -786,13 +813,14 @@ static const struct hid_device_id corsairpsu_idtable[] = { { HID_USB_DEVICE(0x1b1c, 0x1c04) }, /* Corsair HX650i */ { HID_USB_DEVICE(0x1b1c, 0x1c05) }, /* Corsair HX750i */ { HID_USB_DEVICE(0x1b1c, 0x1c06) }, /* Corsair HX850i */ - { HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i */ + { HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i revision 1 */ { HID_USB_DEVICE(0x1b1c, 0x1c08) }, /* Corsair HX1200i */ { HID_USB_DEVICE(0x1b1c, 0x1c09) }, /* Corsair RM550i */ { HID_USB_DEVICE(0x1b1c, 0x1c0a) }, /* Corsair RM650i */ { HID_USB_DEVICE(0x1b1c, 0x1c0b) }, /* Corsair RM750i */ { HID_USB_DEVICE(0x1b1c, 0x1c0c) }, /* Corsair RM850i */ { HID_USB_DEVICE(0x1b1c, 0x1c0d) }, /* Corsair RM1000i */ + { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsaur HX1000i revision 2 */ { }, }; MODULE_DEVICE_TABLE(hid, corsairpsu_idtable); diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 7f8d95dd2717..1572b5416015 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -1355,15 +1355,21 @@ static int __init dell_smm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); if (dmi_check_system(i8k_blacklist_fan_support_dmi_table)) { - dev_warn(&pdev->dev, "broken Dell BIOS detected, disallow fan support\n"); - if (!force) + if (!force) { + dev_notice(&pdev->dev, "Disabling fan support due to BIOS bugs\n"); data->disallow_fan_support = true; + } else { + dev_warn(&pdev->dev, "Enabling fan support despite BIOS bugs\n"); + } } if (dmi_check_system(i8k_blacklist_fan_type_dmi_table)) { - dev_warn(&pdev->dev, "broken Dell BIOS detected, disallow fan type call\n"); - if (!force) + if (!force) { + dev_notice(&pdev->dev, "Disabling fan type call due to BIOS bugs\n"); data->disallow_fan_type_call = true; + } else { + dev_warn(&pdev->dev, "Enabling fan type call despite BIOS bugs\n"); + } } strscpy(data->bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index b1cd028c8277..66c48f70fae7 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -2456,7 +2456,7 @@ static int dme1737_i2c_detect(struct i2c_client *client, dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n", verstep == SCH5027_VERSTEP ? "SCH5027" : "DME1737", client->addr, verstep); - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 314838272049..61d59189a6d1 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -329,22 +329,22 @@ static int emc1403_detect(struct i2c_client *client, id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG); switch (id) { case 0x20: - strlcpy(info->type, "emc1402", I2C_NAME_SIZE); + strscpy(info->type, "emc1402", I2C_NAME_SIZE); break; case 0x21: - strlcpy(info->type, "emc1403", I2C_NAME_SIZE); + strscpy(info->type, "emc1403", I2C_NAME_SIZE); break; case 0x22: - strlcpy(info->type, "emc1422", I2C_NAME_SIZE); + strscpy(info->type, "emc1422", I2C_NAME_SIZE); break; case 0x23: - strlcpy(info->type, "emc1423", I2C_NAME_SIZE); + strscpy(info->type, "emc1423", I2C_NAME_SIZE); break; case 0x25: - strlcpy(info->type, "emc1404", I2C_NAME_SIZE); + strscpy(info->type, "emc1404", I2C_NAME_SIZE); break; case 0x27: - strlcpy(info->type, "emc1424", I2C_NAME_SIZE); + strscpy(info->type, "emc1424", I2C_NAME_SIZE); break; default: return -ENODEV; diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index e4c95ca9e19f..361cf9292456 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -643,7 +643,7 @@ emc2103_detect(struct i2c_client *new_client, struct i2c_board_info *info) if ((product != 0x24) && (product != 0x26)) return -ENODEV; - strlcpy(info->type, "emc2103", I2C_NAME_SIZE); + strscpy(info->type, "emc2103", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c new file mode 100644 index 000000000000..aa1f25add0b6 --- /dev/null +++ b/drivers/hwmon/emc2305.c @@ -0,0 +1,620 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for EMC2305 fan controller + * + * Copyright (C) 2022 Nvidia Technologies Ltd. + */ + +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/platform_data/emc2305.h> +#include <linux/thermal.h> + +static const unsigned short +emc2305_normal_i2c[] = { 0x27, 0x2c, 0x2d, 0x2e, 0x2f, 0x4c, 0x4d, I2C_CLIENT_END }; + +#define EMC2305_REG_DRIVE_FAIL_STATUS 0x27 +#define EMC2305_REG_DEVICE 0xfd +#define EMC2305_REG_VENDOR 0xfe +#define EMC2305_FAN_MAX 0xff +#define EMC2305_FAN_MIN 0x00 +#define EMC2305_FAN_MAX_STATE 10 +#define EMC2305_DEVICE 0x34 +#define EMC2305_VENDOR 0x5d +#define EMC2305_REG_PRODUCT_ID 0xfd +#define EMC2305_TACH_REGS_UNUSE_BITS 3 +#define EMC2305_TACH_CNT_MULTIPLIER 0x02 +#define EMC2305_TACH_RANGE_MIN 480 + +#define EMC2305_PWM_DUTY2STATE(duty, max_state, pwm_max) \ + DIV_ROUND_CLOSEST((duty) * (max_state), (pwm_max)) +#define EMC2305_PWM_STATE2DUTY(state, max_state, pwm_max) \ + DIV_ROUND_CLOSEST((state) * (pwm_max), (max_state)) + +/* + * Factor by equations [2] and [3] from data sheet; valid for fans where the number of edges + * equal (poles * 2 + 1). + */ +#define EMC2305_RPM_FACTOR 3932160 + +#define EMC2305_REG_FAN_DRIVE(n) (0x30 + 0x10 * (n)) +#define EMC2305_REG_FAN_MIN_DRIVE(n) (0x38 + 0x10 * (n)) +#define EMC2305_REG_FAN_TACH(n) (0x3e + 0x10 * (n)) + +enum emc230x_product_id { + EMC2305 = 0x34, + EMC2303 = 0x35, + EMC2302 = 0x36, + EMC2301 = 0x37, +}; + +static const struct i2c_device_id emc2305_ids[] = { + { "emc2305", 0 }, + { "emc2303", 0 }, + { "emc2302", 0 }, + { "emc2301", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, emc2305_ids); + +/** + * @cdev: cooling device; + * @curr_state: cooling current state; + * @last_hwmon_state: last cooling state updated by hwmon subsystem; + * @last_thermal_state: last cooling state updated by thermal subsystem; + * + * The 'last_hwmon_state' and 'last_thermal_state' fields are provided to support fan low limit + * speed feature. The purpose of this feature is to provides ability to limit fan speed + * according to some system wise considerations, like absence of some replaceable units (PSU or + * line cards), high system ambient temperature, unreliable transceivers temperature sensing or + * some other factors which indirectly impacts system's airflow + * Fan low limit feature is supported through 'hwmon' interface: 'hwmon' 'pwm' attribute is + * used for setting low limit for fan speed in case 'thermal' subsystem is configured in + * kernel. In this case setting fan speed through 'hwmon' will never let the 'thermal' + * subsystem to select a lower duty cycle than the duty cycle selected with the 'pwm' + * attribute. + * From other side, fan speed is to be updated in hardware through 'pwm' only in case the + * requested fan speed is above last speed set by 'thermal' subsystem, otherwise requested fan + * speed will be just stored with no PWM update. + */ +struct emc2305_cdev_data { + struct thermal_cooling_device *cdev; + unsigned int cur_state; + unsigned long last_hwmon_state; + unsigned long last_thermal_state; +}; + +/** + * @client: i2c client; + * @hwmon_dev: hwmon device; + * @max_state: maximum cooling state of the cooling device; + * @pwm_num: number of PWM channels; + * @pwm_separate: separate PWM settings for every channel; + * @pwm_min: array of minimum PWM per channel; + * @cdev_data: array of cooling devices data; + */ +struct emc2305_data { + struct i2c_client *client; + struct device *hwmon_dev; + u8 max_state; + u8 pwm_num; + bool pwm_separate; + u8 pwm_min[EMC2305_PWM_MAX]; + struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX]; +}; + +static char *emc2305_fan_name[] = { + "emc2305_fan", + "emc2305_fan1", + "emc2305_fan2", + "emc2305_fan3", + "emc2305_fan4", + "emc2305_fan5", +}; + +static void emc2305_unset_tz(struct device *dev); + +static int emc2305_get_max_channel(const struct emc2305_data *data) +{ + return data->pwm_num; +} + +static int emc2305_get_cdev_idx(struct thermal_cooling_device *cdev) +{ + struct emc2305_data *data = cdev->devdata; + size_t len = strlen(cdev->type); + int ret; + + if (len <= 0) + return -EINVAL; + + /* + * Returns index of cooling device 0..4 in case of separate PWM setting. + * Zero index is used in case of one common PWM setting. + * If the mode is not set as pwm_separate, all PWMs are to be bound + * to the common thermal zone and should work at the same speed + * to perform cooling for the same thermal junction. + * Otherwise, return specific channel that will be used in bound + * related PWM to the thermal zone. + */ + if (!data->pwm_separate) + return 0; + + ret = cdev->type[len - 1]; + switch (ret) { + case '1' ... '5': + return ret - '1'; + default: + break; + } + return -EINVAL; +} + +static int emc2305_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) +{ + int cdev_idx; + struct emc2305_data *data = cdev->devdata; + + cdev_idx = emc2305_get_cdev_idx(cdev); + if (cdev_idx < 0) + return cdev_idx; + + *state = data->cdev_data[cdev_idx].cur_state; + return 0; +} + +static int emc2305_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) +{ + struct emc2305_data *data = cdev->devdata; + *state = data->max_state; + return 0; +} + +static int emc2305_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) +{ + int cdev_idx, ret; + struct emc2305_data *data = cdev->devdata; + struct i2c_client *client = data->client; + u8 val, i; + + if (state > data->max_state) + return -EINVAL; + + cdev_idx = emc2305_get_cdev_idx(cdev); + if (cdev_idx < 0) + return cdev_idx; + + /* Save thermal state. */ + data->cdev_data[cdev_idx].last_thermal_state = state; + state = max_t(unsigned long, state, data->cdev_data[cdev_idx].last_hwmon_state); + + val = EMC2305_PWM_STATE2DUTY(state, data->max_state, EMC2305_FAN_MAX); + + data->cdev_data[cdev_idx].cur_state = state; + if (data->pwm_separate) { + ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(cdev_idx), val); + if (ret < 0) + return ret; + } else { + /* + * Set the same PWM value in all channels + * if common PWM channel is used. + */ + for (i = 0; i < data->pwm_num; i++) { + ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(i), val); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static const struct thermal_cooling_device_ops emc2305_cooling_ops = { + .get_max_state = emc2305_get_max_state, + .get_cur_state = emc2305_get_cur_state, + .set_cur_state = emc2305_set_cur_state, +}; + +static int emc2305_show_fault(struct device *dev, int channel) +{ + struct emc2305_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int status_reg; + + status_reg = i2c_smbus_read_byte_data(client, EMC2305_REG_DRIVE_FAIL_STATUS); + if (status_reg < 0) + return status_reg; + + return status_reg & (1 << channel) ? 1 : 0; +} + +static int emc2305_show_fan(struct device *dev, int channel) +{ + struct emc2305_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int ret; + + ret = i2c_smbus_read_word_swapped(client, EMC2305_REG_FAN_TACH(channel)); + if (ret <= 0) + return ret; + + ret = ret >> EMC2305_TACH_REGS_UNUSE_BITS; + ret = EMC2305_RPM_FACTOR / ret; + if (ret <= EMC2305_TACH_RANGE_MIN) + return 0; + + return ret * EMC2305_TACH_CNT_MULTIPLIER; +} + +static int emc2305_show_pwm(struct device *dev, int channel) +{ + struct emc2305_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + return i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_DRIVE(channel)); +} + +static int emc2305_set_pwm(struct device *dev, long val, int channel) +{ + struct emc2305_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int ret; + + if (val < data->pwm_min[channel] || val > EMC2305_FAN_MAX) + return -EINVAL; + + ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(channel), val); + if (ret < 0) + return ret; + data->cdev_data[channel].cur_state = EMC2305_PWM_DUTY2STATE(val, data->max_state, + EMC2305_FAN_MAX); + return 0; +} + +static int emc2305_set_single_tz(struct device *dev, int idx) +{ + struct emc2305_data *data = dev_get_drvdata(dev); + long pwm; + int i, cdev_idx, ret; + + cdev_idx = (idx) ? idx - 1 : 0; + pwm = data->pwm_min[cdev_idx]; + + data->cdev_data[cdev_idx].cdev = + thermal_cooling_device_register(emc2305_fan_name[idx], data, + &emc2305_cooling_ops); + + if (IS_ERR(data->cdev_data[cdev_idx].cdev)) { + dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_name[idx]); + return PTR_ERR(data->cdev_data[cdev_idx].cdev); + } + /* Set minimal PWM speed. */ + if (data->pwm_separate) { + ret = emc2305_set_pwm(dev, pwm, cdev_idx); + if (ret < 0) + return ret; + } else { + for (i = 0; i < data->pwm_num; i++) { + ret = emc2305_set_pwm(dev, pwm, i); + if (ret < 0) + return ret; + } + } + data->cdev_data[cdev_idx].cur_state = + EMC2305_PWM_DUTY2STATE(data->pwm_min[cdev_idx], data->max_state, + EMC2305_FAN_MAX); + data->cdev_data[cdev_idx].last_hwmon_state = + EMC2305_PWM_DUTY2STATE(data->pwm_min[cdev_idx], data->max_state, + EMC2305_FAN_MAX); + return 0; +} + +static int emc2305_set_tz(struct device *dev) +{ + struct emc2305_data *data = dev_get_drvdata(dev); + int i, ret; + + if (!data->pwm_separate) + return emc2305_set_single_tz(dev, 0); + + for (i = 0; i < data->pwm_num; i++) { + ret = emc2305_set_single_tz(dev, i + 1); + if (ret) + goto thermal_cooling_device_register_fail; + } + return 0; + +thermal_cooling_device_register_fail: + emc2305_unset_tz(dev); + return ret; +} + +static void emc2305_unset_tz(struct device *dev) +{ + struct emc2305_data *data = dev_get_drvdata(dev); + int i; + + /* Unregister cooling device. */ + for (i = 0; i < EMC2305_PWM_MAX; i++) + if (data->cdev_data[i].cdev) + thermal_cooling_device_unregister(data->cdev_data[i].cdev); +} + +static umode_t +emc2305_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) +{ + int max_channel = emc2305_get_max_channel(data); + + /* Don't show channels which are not physically connected. */ + if (channel >= max_channel) + return 0; + switch (type) { + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + return 0444; + case hwmon_fan_fault: + return 0444; + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + return 0644; + default: + break; + } + break; + default: + break; + } + + return 0; +}; + +static int +emc2305_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) +{ + struct emc2305_data *data = dev_get_drvdata(dev); + int cdev_idx; + + switch (type) { + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + /* If thermal is configured - handle PWM limit setting. */ + if (IS_REACHABLE(CONFIG_THERMAL)) { + if (data->pwm_separate) + cdev_idx = channel; + else + cdev_idx = 0; + data->cdev_data[cdev_idx].last_hwmon_state = + EMC2305_PWM_DUTY2STATE(val, data->max_state, + EMC2305_FAN_MAX); + /* + * Update PWM only in case requested state is not less than the + * last thermal state. + */ + if (data->cdev_data[cdev_idx].last_hwmon_state >= + data->cdev_data[cdev_idx].last_thermal_state) + return emc2305_set_cur_state(data->cdev_data[cdev_idx].cdev, + data->cdev_data[cdev_idx].last_hwmon_state); + return 0; + } + return emc2305_set_pwm(dev, val, channel); + default: + break; + } + break; + default: + break; + } + + return -EOPNOTSUPP; +}; + +static int +emc2305_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) +{ + int ret; + + switch (type) { + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + ret = emc2305_show_fan(dev, channel); + if (ret < 0) + return ret; + *val = ret; + return 0; + case hwmon_fan_fault: + ret = emc2305_show_fault(dev, channel); + if (ret < 0) + return ret; + *val = ret; + return 0; + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + ret = emc2305_show_pwm(dev, channel); + if (ret < 0) + return ret; + *val = ret; + return 0; + default: + break; + } + break; + default: + break; + } + + return -EOPNOTSUPP; +}; + +static const struct hwmon_ops emc2305_ops = { + .is_visible = emc2305_is_visible, + .read = emc2305_read, + .write = emc2305_write, +}; + +static const struct hwmon_channel_info *emc2305_info[] = { + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_FAULT), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT), + NULL +}; + +static const struct hwmon_chip_info emc2305_chip_info = { + .ops = &emc2305_ops, + .info = emc2305_info, +}; + +static int emc2305_identify(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct emc2305_data *data = i2c_get_clientdata(client); + int ret; + + ret = i2c_smbus_read_byte_data(client, EMC2305_REG_PRODUCT_ID); + if (ret < 0) + return ret; + + switch (ret) { + case EMC2305: + data->pwm_num = 5; + break; + case EMC2303: + data->pwm_num = 3; + break; + case EMC2302: + data->pwm_num = 2; + break; + case EMC2301: + data->pwm_num = 1; + break; + default: + return -ENODEV; + } + + return 0; +} + +static int emc2305_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct device *dev = &client->dev; + struct emc2305_data *data; + struct emc2305_platform_data *pdata; + int vendor, device; + int ret; + int i; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + vendor = i2c_smbus_read_byte_data(client, EMC2305_REG_VENDOR); + if (vendor != EMC2305_VENDOR) + return -ENODEV; + + device = i2c_smbus_read_byte_data(client, EMC2305_REG_DEVICE); + if (device != EMC2305_DEVICE) + return -ENODEV; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + data->client = client; + + ret = emc2305_identify(dev); + if (ret) + return ret; + + pdata = dev_get_platdata(&client->dev); + if (pdata) { + if (!pdata->max_state || pdata->max_state > EMC2305_FAN_MAX_STATE) + return -EINVAL; + data->max_state = pdata->max_state; + /* + * Validate a number of active PWM channels. Note that + * configured number can be less than the actual maximum + * supported by the device. + */ + if (!pdata->pwm_num || pdata->pwm_num > EMC2305_PWM_MAX) + return -EINVAL; + data->pwm_num = pdata->pwm_num; + data->pwm_separate = pdata->pwm_separate; + for (i = 0; i < EMC2305_PWM_MAX; i++) + data->pwm_min[i] = pdata->pwm_min[i]; + } else { + data->max_state = EMC2305_FAN_MAX_STATE; + data->pwm_separate = false; + for (i = 0; i < EMC2305_PWM_MAX; i++) + data->pwm_min[i] = EMC2305_FAN_MIN; + } + + data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "emc2305", data, + &emc2305_chip_info, NULL); + if (IS_ERR(data->hwmon_dev)) + return PTR_ERR(data->hwmon_dev); + + if (IS_REACHABLE(CONFIG_THERMAL)) { + ret = emc2305_set_tz(dev); + if (ret != 0) + return ret; + } + + for (i = 0; i < data->pwm_num; i++) { + ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_MIN_DRIVE(i), + data->pwm_min[i]); + if (ret < 0) + return ret; + } + + return 0; +} + +static void emc2305_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + + if (IS_REACHABLE(CONFIG_THERMAL)) + emc2305_unset_tz(dev); +} + +static struct i2c_driver emc2305_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "emc2305", + }, + .probe = emc2305_probe, + .remove = emc2305_remove, + .id_table = emc2305_ids, + .address_list = emc2305_normal_i2c, +}; + +module_i2c_driver(emc2305_driver); + +MODULE_AUTHOR("Nvidia"); +MODULE_DESCRIPTION("Microchip EMC2305 fan controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c index 29082c8463f4..bcd93f0fe982 100644 --- a/drivers/hwmon/emc6w201.c +++ b/drivers/hwmon/emc6w201.c @@ -439,7 +439,7 @@ static int emc6w201_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, "emc6w201", I2C_NAME_SIZE); + strscpy(info->type, "emc6w201", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 19b6c643059a..70121482a617 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -237,13 +237,6 @@ static const char f71882fg_nr_temps[] = { static struct platform_device *f71882fg_pdev; -/* Super-I/O Function prototypes */ -static inline int superio_inb(int base, int reg); -static inline int superio_inw(int base, int reg); -static inline int superio_enter(int base); -static inline void superio_select(int base, int ld); -static inline void superio_exit(int base); - struct f71882fg_sio_data { enum chips type; }; @@ -292,108 +285,422 @@ struct f71882fg_data { s8 pwm_auto_point_temp[4][4]; }; -/* Sysfs in */ -static ssize_t show_in(struct device *dev, struct device_attribute *devattr, - char *buf); -static ssize_t show_in_max(struct device *dev, struct device_attribute - *devattr, char *buf); -static ssize_t store_in_max(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count); -static ssize_t show_in_beep(struct device *dev, struct device_attribute - *devattr, char *buf); -static ssize_t store_in_beep(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count); -static ssize_t show_in_alarm(struct device *dev, struct device_attribute - *devattr, char *buf); -/* Sysfs Fan */ -static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, - char *buf); -static ssize_t show_fan_full_speed(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t store_fan_full_speed(struct device *dev, - struct device_attribute *devattr, const char *buf, size_t count); -static ssize_t show_fan_beep(struct device *dev, struct device_attribute - *devattr, char *buf); -static ssize_t store_fan_beep(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count); -static ssize_t show_fan_alarm(struct device *dev, struct device_attribute - *devattr, char *buf); -/* Sysfs Temp */ -static ssize_t show_temp(struct device *dev, struct device_attribute - *devattr, char *buf); +static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg) +{ + u8 val; + + outb(reg, data->addr + ADDR_REG_OFFSET); + val = inb(data->addr + DATA_REG_OFFSET); + + return val; +} + +static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg) +{ + u16 val; + + val = f71882fg_read8(data, reg) << 8; + val |= f71882fg_read8(data, reg + 1); + + return val; +} + +static inline int fan_from_reg(u16 reg) +{ + return reg ? (1500000 / reg) : 0; +} + +static inline u16 fan_to_reg(int fan) +{ + return fan ? (1500000 / fan) : 0; +} + +static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val) +{ + outb(reg, data->addr + ADDR_REG_OFFSET); + outb(val, data->addr + DATA_REG_OFFSET); +} + +static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val) +{ + f71882fg_write8(data, reg, val >> 8); + f71882fg_write8(data, reg + 1, val & 0xff); +} + +static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) +{ + if (data->type == f71858fg) + return f71882fg_read16(data, F71882FG_REG_TEMP(nr)); + else + return f71882fg_read8(data, F71882FG_REG_TEMP(nr)); +} + +static struct f71882fg_data *f71882fg_update_device(struct device *dev) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr_fans = f71882fg_nr_fans[data->type]; + int nr_temps = f71882fg_nr_temps[data->type]; + int nr, reg, point; + + mutex_lock(&data->update_lock); + + /* Update once every 60 seconds */ + if (time_after(jiffies, data->last_limits + 60 * HZ) || + !data->valid) { + if (f71882fg_has_in1_alarm[data->type]) { + if (data->type == f81866a) { + data->in1_max = + f71882fg_read8(data, + F81866_REG_IN1_HIGH); + data->in_beep = + f71882fg_read8(data, + F81866_REG_IN_BEEP); + } else { + data->in1_max = + f71882fg_read8(data, + F71882FG_REG_IN1_HIGH); + data->in_beep = + f71882fg_read8(data, + F71882FG_REG_IN_BEEP); + } + } + + /* Get High & boundary temps*/ + for (nr = data->temp_start; nr < nr_temps + data->temp_start; + nr++) { + data->temp_ovt[nr] = f71882fg_read8(data, + F71882FG_REG_TEMP_OVT(nr)); + data->temp_high[nr] = f71882fg_read8(data, + F71882FG_REG_TEMP_HIGH(nr)); + } + + if (data->type != f8000) { + data->temp_hyst[0] = f71882fg_read8(data, + F71882FG_REG_TEMP_HYST(0)); + data->temp_hyst[1] = f71882fg_read8(data, + F71882FG_REG_TEMP_HYST(1)); + } + /* All but the f71858fg / f8000 have this register */ + if ((data->type != f71858fg) && (data->type != f8000)) { + reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); + data->temp_type[1] = (reg & 0x02) ? 2 : 4; + data->temp_type[2] = (reg & 0x04) ? 2 : 4; + data->temp_type[3] = (reg & 0x08) ? 2 : 4; + } + + if (f71882fg_fan_has_beep[data->type]) + data->fan_beep = f71882fg_read8(data, + F71882FG_REG_FAN_BEEP); + + if (f71882fg_temp_has_beep[data->type]) + data->temp_beep = f71882fg_read8(data, + F71882FG_REG_TEMP_BEEP); + + data->pwm_enable = f71882fg_read8(data, + F71882FG_REG_PWM_ENABLE); + data->pwm_auto_point_hyst[0] = + f71882fg_read8(data, F71882FG_REG_FAN_HYST(0)); + data->pwm_auto_point_hyst[1] = + f71882fg_read8(data, F71882FG_REG_FAN_HYST(1)); + + for (nr = 0; nr < nr_fans; nr++) { + data->pwm_auto_point_mapping[nr] = + f71882fg_read8(data, + F71882FG_REG_POINT_MAPPING(nr)); + + switch (data->type) { + default: + for (point = 0; point < 5; point++) { + data->pwm_auto_point_pwm[nr][point] = + f71882fg_read8(data, + F71882FG_REG_POINT_PWM + (nr, point)); + } + for (point = 0; point < 4; point++) { + data->pwm_auto_point_temp[nr][point] = + f71882fg_read8(data, + F71882FG_REG_POINT_TEMP + (nr, point)); + } + break; + case f71808e: + case f71869: + data->pwm_auto_point_pwm[nr][0] = + f71882fg_read8(data, + F71882FG_REG_POINT_PWM(nr, 0)); + fallthrough; + case f71862fg: + data->pwm_auto_point_pwm[nr][1] = + f71882fg_read8(data, + F71882FG_REG_POINT_PWM + (nr, 1)); + data->pwm_auto_point_pwm[nr][4] = + f71882fg_read8(data, + F71882FG_REG_POINT_PWM + (nr, 4)); + data->pwm_auto_point_temp[nr][0] = + f71882fg_read8(data, + F71882FG_REG_POINT_TEMP + (nr, 0)); + data->pwm_auto_point_temp[nr][3] = + f71882fg_read8(data, + F71882FG_REG_POINT_TEMP + (nr, 3)); + break; + } + } + data->last_limits = jiffies; + } + + /* Update every second */ + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + data->temp_status = f71882fg_read8(data, + F71882FG_REG_TEMP_STATUS); + data->temp_diode_open = f71882fg_read8(data, + F71882FG_REG_TEMP_DIODE_OPEN); + for (nr = data->temp_start; nr < nr_temps + data->temp_start; + nr++) + data->temp[nr] = f71882fg_read_temp(data, nr); + + data->fan_status = f71882fg_read8(data, + F71882FG_REG_FAN_STATUS); + for (nr = 0; nr < nr_fans; nr++) { + data->fan[nr] = f71882fg_read16(data, + F71882FG_REG_FAN(nr)); + data->fan_target[nr] = + f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr)); + data->fan_full_speed[nr] = + f71882fg_read16(data, + F71882FG_REG_FAN_FULL_SPEED(nr)); + data->pwm[nr] = + f71882fg_read8(data, F71882FG_REG_PWM(nr)); + } + /* Some models have 1 more fan with limited capabilities */ + if (data->type == f71808a) { + data->fan[2] = f71882fg_read16(data, + F71882FG_REG_FAN(2)); + data->pwm[2] = f71882fg_read8(data, + F71882FG_REG_PWM(2)); + } + if (data->type == f8000) + data->fan[3] = f71882fg_read16(data, + F71882FG_REG_FAN(3)); + + if (f71882fg_has_in1_alarm[data->type]) { + if (data->type == f81866a) + data->in_status = f71882fg_read8(data, + F81866_REG_IN_STATUS); + + else + data->in_status = f71882fg_read8(data, + F71882FG_REG_IN_STATUS); + } + + for (nr = 0; nr < F71882FG_MAX_INS; nr++) + if (f71882fg_has_in[data->type][nr]) + data->in[nr] = f71882fg_read8(data, + F71882FG_REG_IN(nr)); + + data->last_updated = jiffies; + data->valid = true; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", f71882fg_names[data->type]); +} + +static DEVICE_ATTR_RO(name); + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + int sign, temp; + + if (data->type == f71858fg) { + /* TEMP_TABLE_SEL 1 or 3 ? */ + if (data->temp_config & 1) { + sign = data->temp[nr] & 0x0001; + temp = (data->temp[nr] >> 5) & 0x7ff; + } else { + sign = data->temp[nr] & 0x8000; + temp = (data->temp[nr] >> 5) & 0x3ff; + } + temp *= 125; + if (sign) + temp -= 128000; + } else { + temp = ((s8)data->temp[nr]) * 1000; + } + + return sprintf(buf, "%d\n", temp); +} + static ssize_t show_temp_max(struct device *dev, struct device_attribute - *devattr, char *buf); + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + return sprintf(buf, "%d\n", data->temp_high[nr] * 1000); +} + static ssize_t store_temp_max(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count); + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val /= 1000; + val = clamp_val(val, 0, 255); + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val); + data->temp_high[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute - *devattr, char *buf); + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + int temp_max_hyst; + + mutex_lock(&data->update_lock); + if (nr & 1) + temp_max_hyst = data->temp_hyst[nr / 2] >> 4; + else + temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f; + temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000; + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", temp_max_hyst); +} + static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count); + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + ssize_t ret = count; + u8 reg; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val /= 1000; + + mutex_lock(&data->update_lock); + + /* convert abs to relative and check */ + data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr)); + val = clamp_val(val, data->temp_high[nr] - 15, data->temp_high[nr]); + val = data->temp_high[nr] - val; + + /* convert value to register contents */ + reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2)); + if (nr & 1) + reg = (reg & 0x0f) | (val << 4); + else + reg = (reg & 0xf0) | val; + f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg); + data->temp_hyst[nr / 2] = reg; + + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t show_temp_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + if (data->temp_status & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + static ssize_t show_temp_crit(struct device *dev, struct device_attribute - *devattr, char *buf); + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000); +} + static ssize_t store_temp_crit(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count); + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val /= 1000; + val = clamp_val(val, 0, 255); + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val); + data->temp_ovt[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute - *devattr, char *buf); -static ssize_t show_temp_type(struct device *dev, struct device_attribute - *devattr, char *buf); -static ssize_t show_temp_beep(struct device *dev, struct device_attribute - *devattr, char *buf); -static ssize_t store_temp_beep(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count); -static ssize_t show_temp_alarm(struct device *dev, struct device_attribute - *devattr, char *buf); -static ssize_t show_temp_fault(struct device *dev, struct device_attribute - *devattr, char *buf); -/* PWM and Auto point control */ -static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, - char *buf); -static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count); -static ssize_t show_simple_pwm(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t store_simple_pwm(struct device *dev, - struct device_attribute *devattr, const char *buf, size_t count); -static ssize_t show_pwm_enable(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t store_pwm_enable(struct device *dev, - struct device_attribute *devattr, const char *buf, size_t count); -static ssize_t show_pwm_interpolate(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t store_pwm_interpolate(struct device *dev, - struct device_attribute *devattr, const char *buf, size_t count); -static ssize_t show_pwm_auto_point_channel(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t store_pwm_auto_point_channel(struct device *dev, - struct device_attribute *devattr, const char *buf, size_t count); -static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev, - struct device_attribute *devattr, const char *buf, size_t count); -static ssize_t show_pwm_auto_point_pwm(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t store_pwm_auto_point_pwm(struct device *dev, - struct device_attribute *devattr, const char *buf, size_t count); -static ssize_t show_pwm_auto_point_temp(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t store_pwm_auto_point_temp(struct device *dev, - struct device_attribute *devattr, const char *buf, size_t count); -/* Sysfs misc */ -static ssize_t name_show(struct device *dev, struct device_attribute *devattr, - char *buf); + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + int temp_crit_hyst; -static int f71882fg_probe(struct platform_device *pdev); -static int f71882fg_remove(struct platform_device *pdev); + mutex_lock(&data->update_lock); + if (nr & 1) + temp_crit_hyst = data->temp_hyst[nr / 2] >> 4; + else + temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f; + temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000; + mutex_unlock(&data->update_lock); -static struct platform_driver f71882fg_driver = { - .driver = { - .name = DRVNAME, - }, - .probe = f71882fg_probe, - .remove = f71882fg_remove, -}; + return sprintf(buf, "%d\n", temp_crit_hyst); +} -static DEVICE_ATTR_RO(name); +static ssize_t show_temp_fault(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + if (data->temp_diode_open & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} /* * Temp attr for the f71858fg, the f71858fg is special as it has its @@ -438,6 +745,15 @@ static struct sensor_device_attribute_2 f71858fg_temp_attr[] = { SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), }; +static ssize_t show_temp_type(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + return sprintf(buf, "%d\n", data->temp_type[nr]); +} + /* Temp attr for the standard models */ static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { { SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1), @@ -490,6 +806,42 @@ static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { { SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3), } }; +static ssize_t show_temp_beep(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + if (data->temp_beep & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_temp_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + unsigned long val; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP); + if (val) + data->temp_beep |= 1 << nr; + else + data->temp_beep &= ~(1 << nr); + + f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep); + mutex_unlock(&data->update_lock); + + return count; +} + /* Temp attr for models which can beep on temp alarm */ static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { { SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, @@ -555,6 +907,15 @@ static struct sensor_device_attribute_2 f8000_temp_attr[] = { SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), }; +static ssize_t show_in(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + return sprintf(buf, "%d\n", data->in[nr] * 8); +} + /* in attr for all models */ static struct sensor_device_attribute_2 fxxxx_in_attr[] = { SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), @@ -570,6 +931,94 @@ static struct sensor_device_attribute_2 fxxxx_in_attr[] = { SENSOR_ATTR_2(in10_input, S_IRUGO, show_in, NULL, 0, 10), }; +static ssize_t show_in_max(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + + return sprintf(buf, "%d\n", data->in1_max * 8); +} + +static ssize_t store_in_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val /= 8; + val = clamp_val(val, 0, 255); + + mutex_lock(&data->update_lock); + if (data->type == f81866a) + f71882fg_write8(data, F81866_REG_IN1_HIGH, val); + else + f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val); + data->in1_max = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_in_beep(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + if (data->in_beep & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_in_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + unsigned long val; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + if (data->type == f81866a) + data->in_beep = f71882fg_read8(data, F81866_REG_IN_BEEP); + else + data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP); + + if (val) + data->in_beep |= 1 << nr; + else + data->in_beep &= ~(1 << nr); + + if (data->type == f81866a) + f71882fg_write8(data, F81866_REG_IN_BEEP, data->in_beep); + else + f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_in_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + if (data->in_status & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + /* For models with in1 alarm capability */ static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = { SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, @@ -579,6 +1028,242 @@ static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = { SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1), }; +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + int speed = fan_from_reg(data->fan[nr]); + + if (speed == FAN_MIN_DETECT) + speed = 0; + + return sprintf(buf, "%d\n", speed); +} + +static ssize_t show_fan_full_speed(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + int speed = fan_from_reg(data->fan_full_speed[nr]); + return sprintf(buf, "%d\n", speed); +} + +static ssize_t store_fan_full_speed(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val = clamp_val(val, 23, 1500000); + val = fan_to_reg(val); + + mutex_lock(&data->update_lock); + f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val); + data->fan_full_speed[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_fan_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + if (data->fan_status & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_pwm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int val, nr = to_sensor_dev_attr_2(devattr)->index; + mutex_lock(&data->update_lock); + if (data->pwm_enable & (1 << (2 * nr))) + /* PWM mode */ + val = data->pwm[nr]; + else { + /* RPM mode */ + val = 255 * fan_from_reg(data->fan_target[nr]) + / fan_from_reg(data->fan_full_speed[nr]); + } + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", val); +} + +static ssize_t store_pwm(struct device *dev, + struct device_attribute *devattr, const char *buf, + size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val = clamp_val(val, 0, 255); + + mutex_lock(&data->update_lock); + data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); + if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) || + (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) { + count = -EROFS; + goto leave; + } + if (data->pwm_enable & (1 << (2 * nr))) { + /* PWM mode */ + f71882fg_write8(data, F71882FG_REG_PWM(nr), val); + data->pwm[nr] = val; + } else { + /* RPM mode */ + int target, full_speed; + full_speed = f71882fg_read16(data, + F71882FG_REG_FAN_FULL_SPEED(nr)); + target = fan_to_reg(val * fan_from_reg(full_speed) / 255); + f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target); + data->fan_target[nr] = target; + data->fan_full_speed[nr] = full_speed; + } +leave: + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_pwm_enable(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int result = 0; + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + switch ((data->pwm_enable >> 2 * nr) & 3) { + case 0: + case 1: + result = 2; /* Normal auto mode */ + break; + case 2: + result = 1; /* Manual mode */ + break; + case 3: + if (data->type == f8000) + result = 3; /* Thermostat mode */ + else + result = 1; /* Manual mode */ + break; + } + + return sprintf(buf, "%d\n", result); +} + +static ssize_t store_pwm_enable(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + /* Special case for F8000 pwm channel 3 which only does auto mode */ + if (data->type == f8000 && nr == 2 && val != 2) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); + /* Special case for F8000 auto PWM mode / Thermostat mode */ + if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) { + switch (val) { + case 2: + data->pwm_enable &= ~(2 << (2 * nr)); + break; /* Normal auto mode */ + case 3: + data->pwm_enable |= 2 << (2 * nr); + break; /* Thermostat mode */ + default: + count = -EINVAL; + goto leave; + } + } else { + switch (val) { + case 1: + /* The f71858fg does not support manual RPM mode */ + if (data->type == f71858fg && + ((data->pwm_enable >> (2 * nr)) & 1)) { + count = -EINVAL; + goto leave; + } + data->pwm_enable |= 2 << (2 * nr); + break; /* Manual */ + case 2: + data->pwm_enable &= ~(2 << (2 * nr)); + break; /* Normal auto mode */ + default: + count = -EINVAL; + goto leave; + } + } + f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable); +leave: + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_pwm_interpolate(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int result; + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + result = (data->pwm_auto_point_mapping[nr] >> 4) & 1; + + return sprintf(buf, "%d\n", result); +} + +static ssize_t store_pwm_interpolate(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + unsigned long val; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->pwm_auto_point_mapping[nr] = + f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); + if (val) + val = data->pwm_auto_point_mapping[nr] | (1 << 4); + else + val = data->pwm_auto_point_mapping[nr] & (~(1 << 4)); + f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val); + data->pwm_auto_point_mapping[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + /* Fan / PWM attr common to all models */ static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { { SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0), @@ -626,6 +1311,38 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { { show_pwm_interpolate, store_pwm_interpolate, 0, 3), } }; +static ssize_t show_simple_pwm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int val, nr = to_sensor_dev_attr_2(devattr)->index; + + val = data->pwm[nr]; + return sprintf(buf, "%d\n", val); +} + +static ssize_t store_simple_pwm(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val = clamp_val(val, 0, 255); + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_PWM(nr), val); + data->pwm[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + /* Attr for the third fan of the f71808a, which only has manual pwm */ static struct sensor_device_attribute_2 f71808a_fan3_attr[] = { SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2), @@ -634,6 +1351,42 @@ static struct sensor_device_attribute_2 f71808a_fan3_attr[] = { show_simple_pwm, store_simple_pwm, 0, 2), }; +static ssize_t show_fan_beep(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + if (data->fan_beep & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_fan_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + unsigned long val; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP); + if (val) + data->fan_beep |= 1 << nr; + else + data->fan_beep &= ~(1 << nr); + + f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep); + mutex_unlock(&data->update_lock); + + return count; +} + /* Attr for models which can beep on Fan alarm */ static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = { SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, @@ -646,6 +1399,209 @@ static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = { store_fan_beep, 0, 3), }; +static ssize_t show_pwm_auto_point_channel(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + int result; + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + + result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - + data->temp_start); + + return sprintf(buf, "%d\n", result); +} + +static ssize_t store_pwm_auto_point_channel(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + switch (val) { + case 1: + val = 0; + break; + case 2: + val = 1; + break; + case 4: + val = 2; + break; + default: + return -EINVAL; + } + val += data->temp_start; + mutex_lock(&data->update_lock); + data->pwm_auto_point_mapping[nr] = + f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); + val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val; + f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val); + data->pwm_auto_point_mapping[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_pwm_auto_point_pwm(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + int result; + struct f71882fg_data *data = f71882fg_update_device(dev); + int pwm = to_sensor_dev_attr_2(devattr)->index; + int point = to_sensor_dev_attr_2(devattr)->nr; + + mutex_lock(&data->update_lock); + if (data->pwm_enable & (1 << (2 * pwm))) { + /* PWM mode */ + result = data->pwm_auto_point_pwm[pwm][point]; + } else { + /* RPM mode */ + result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]); + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", result); +} + +static ssize_t store_pwm_auto_point_pwm(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, pwm = to_sensor_dev_attr_2(devattr)->index; + int point = to_sensor_dev_attr_2(devattr)->nr; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val = clamp_val(val, 0, 255); + + mutex_lock(&data->update_lock); + data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); + if (data->pwm_enable & (1 << (2 * pwm))) { + /* PWM mode */ + } else { + /* RPM mode */ + if (val < 29) /* Prevent negative numbers */ + val = 255; + else + val = (255 - val) * 32 / val; + } + f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val); + data->pwm_auto_point_pwm[pwm][point] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_pwm_auto_point_temp(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + int result; + struct f71882fg_data *data = f71882fg_update_device(dev); + int pwm = to_sensor_dev_attr_2(devattr)->index; + int point = to_sensor_dev_attr_2(devattr)->nr; + + result = data->pwm_auto_point_temp[pwm][point]; + return sprintf(buf, "%d\n", 1000 * result); +} + +static ssize_t store_pwm_auto_point_temp(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, pwm = to_sensor_dev_attr_2(devattr)->index; + int point = to_sensor_dev_attr_2(devattr)->nr; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val /= 1000; + + if (data->auto_point_temp_signed) + val = clamp_val(val, -128, 127); + else + val = clamp_val(val, 0, 127); + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val); + data->pwm_auto_point_temp[pwm][point] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + int result = 0; + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr_2(devattr)->index; + int point = to_sensor_dev_attr_2(devattr)->nr; + + mutex_lock(&data->update_lock); + if (nr & 1) + result = data->pwm_auto_point_hyst[nr / 2] >> 4; + else + result = data->pwm_auto_point_hyst[nr / 2] & 0x0f; + result = 1000 * (data->pwm_auto_point_temp[nr][point] - result); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", result); +} + +static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int err, nr = to_sensor_dev_attr_2(devattr)->index; + int point = to_sensor_dev_attr_2(devattr)->nr; + u8 reg; + long val; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + val /= 1000; + + mutex_lock(&data->update_lock); + data->pwm_auto_point_temp[nr][point] = + f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point)); + val = clamp_val(val, data->pwm_auto_point_temp[nr][point] - 15, + data->pwm_auto_point_temp[nr][point]); + val = data->pwm_auto_point_temp[nr][point] - val; + + reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2)); + if (nr & 1) + reg = (reg & 0x0f) | (val << 4); + else + reg = (reg & 0xf0) | val; + + f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg); + data->pwm_auto_point_hyst[nr / 2] = reg; + mutex_unlock(&data->update_lock); + + return count; +} + /* * PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the * standard models @@ -1144,1071 +2100,6 @@ static inline void superio_exit(int base) release_region(base, 2); } -static inline int fan_from_reg(u16 reg) -{ - return reg ? (1500000 / reg) : 0; -} - -static inline u16 fan_to_reg(int fan) -{ - return fan ? (1500000 / fan) : 0; -} - -static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg) -{ - u8 val; - - outb(reg, data->addr + ADDR_REG_OFFSET); - val = inb(data->addr + DATA_REG_OFFSET); - - return val; -} - -static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg) -{ - u16 val; - - val = f71882fg_read8(data, reg) << 8; - val |= f71882fg_read8(data, reg + 1); - - return val; -} - -static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val) -{ - outb(reg, data->addr + ADDR_REG_OFFSET); - outb(val, data->addr + DATA_REG_OFFSET); -} - -static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val) -{ - f71882fg_write8(data, reg, val >> 8); - f71882fg_write8(data, reg + 1, val & 0xff); -} - -static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) -{ - if (data->type == f71858fg) - return f71882fg_read16(data, F71882FG_REG_TEMP(nr)); - else - return f71882fg_read8(data, F71882FG_REG_TEMP(nr)); -} - -static struct f71882fg_data *f71882fg_update_device(struct device *dev) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int nr_fans = f71882fg_nr_fans[data->type]; - int nr_temps = f71882fg_nr_temps[data->type]; - int nr, reg, point; - - mutex_lock(&data->update_lock); - - /* Update once every 60 seconds */ - if (time_after(jiffies, data->last_limits + 60 * HZ) || - !data->valid) { - if (f71882fg_has_in1_alarm[data->type]) { - if (data->type == f81866a) { - data->in1_max = - f71882fg_read8(data, - F81866_REG_IN1_HIGH); - data->in_beep = - f71882fg_read8(data, - F81866_REG_IN_BEEP); - } else { - data->in1_max = - f71882fg_read8(data, - F71882FG_REG_IN1_HIGH); - data->in_beep = - f71882fg_read8(data, - F71882FG_REG_IN_BEEP); - } - } - - /* Get High & boundary temps*/ - for (nr = data->temp_start; nr < nr_temps + data->temp_start; - nr++) { - data->temp_ovt[nr] = f71882fg_read8(data, - F71882FG_REG_TEMP_OVT(nr)); - data->temp_high[nr] = f71882fg_read8(data, - F71882FG_REG_TEMP_HIGH(nr)); - } - - if (data->type != f8000) { - data->temp_hyst[0] = f71882fg_read8(data, - F71882FG_REG_TEMP_HYST(0)); - data->temp_hyst[1] = f71882fg_read8(data, - F71882FG_REG_TEMP_HYST(1)); - } - /* All but the f71858fg / f8000 have this register */ - if ((data->type != f71858fg) && (data->type != f8000)) { - reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); - data->temp_type[1] = (reg & 0x02) ? 2 : 4; - data->temp_type[2] = (reg & 0x04) ? 2 : 4; - data->temp_type[3] = (reg & 0x08) ? 2 : 4; - } - - if (f71882fg_fan_has_beep[data->type]) - data->fan_beep = f71882fg_read8(data, - F71882FG_REG_FAN_BEEP); - - if (f71882fg_temp_has_beep[data->type]) - data->temp_beep = f71882fg_read8(data, - F71882FG_REG_TEMP_BEEP); - - data->pwm_enable = f71882fg_read8(data, - F71882FG_REG_PWM_ENABLE); - data->pwm_auto_point_hyst[0] = - f71882fg_read8(data, F71882FG_REG_FAN_HYST(0)); - data->pwm_auto_point_hyst[1] = - f71882fg_read8(data, F71882FG_REG_FAN_HYST(1)); - - for (nr = 0; nr < nr_fans; nr++) { - data->pwm_auto_point_mapping[nr] = - f71882fg_read8(data, - F71882FG_REG_POINT_MAPPING(nr)); - - switch (data->type) { - default: - for (point = 0; point < 5; point++) { - data->pwm_auto_point_pwm[nr][point] = - f71882fg_read8(data, - F71882FG_REG_POINT_PWM - (nr, point)); - } - for (point = 0; point < 4; point++) { - data->pwm_auto_point_temp[nr][point] = - f71882fg_read8(data, - F71882FG_REG_POINT_TEMP - (nr, point)); - } - break; - case f71808e: - case f71869: - data->pwm_auto_point_pwm[nr][0] = - f71882fg_read8(data, - F71882FG_REG_POINT_PWM(nr, 0)); - fallthrough; - case f71862fg: - data->pwm_auto_point_pwm[nr][1] = - f71882fg_read8(data, - F71882FG_REG_POINT_PWM - (nr, 1)); - data->pwm_auto_point_pwm[nr][4] = - f71882fg_read8(data, - F71882FG_REG_POINT_PWM - (nr, 4)); - data->pwm_auto_point_temp[nr][0] = - f71882fg_read8(data, - F71882FG_REG_POINT_TEMP - (nr, 0)); - data->pwm_auto_point_temp[nr][3] = - f71882fg_read8(data, - F71882FG_REG_POINT_TEMP - (nr, 3)); - break; - } - } - data->last_limits = jiffies; - } - - /* Update every second */ - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - data->temp_status = f71882fg_read8(data, - F71882FG_REG_TEMP_STATUS); - data->temp_diode_open = f71882fg_read8(data, - F71882FG_REG_TEMP_DIODE_OPEN); - for (nr = data->temp_start; nr < nr_temps + data->temp_start; - nr++) - data->temp[nr] = f71882fg_read_temp(data, nr); - - data->fan_status = f71882fg_read8(data, - F71882FG_REG_FAN_STATUS); - for (nr = 0; nr < nr_fans; nr++) { - data->fan[nr] = f71882fg_read16(data, - F71882FG_REG_FAN(nr)); - data->fan_target[nr] = - f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr)); - data->fan_full_speed[nr] = - f71882fg_read16(data, - F71882FG_REG_FAN_FULL_SPEED(nr)); - data->pwm[nr] = - f71882fg_read8(data, F71882FG_REG_PWM(nr)); - } - /* Some models have 1 more fan with limited capabilities */ - if (data->type == f71808a) { - data->fan[2] = f71882fg_read16(data, - F71882FG_REG_FAN(2)); - data->pwm[2] = f71882fg_read8(data, - F71882FG_REG_PWM(2)); - } - if (data->type == f8000) - data->fan[3] = f71882fg_read16(data, - F71882FG_REG_FAN(3)); - - if (f71882fg_has_in1_alarm[data->type]) { - if (data->type == f81866a) - data->in_status = f71882fg_read8(data, - F81866_REG_IN_STATUS); - - else - data->in_status = f71882fg_read8(data, - F71882FG_REG_IN_STATUS); - } - - for (nr = 0; nr < F71882FG_MAX_INS; nr++) - if (f71882fg_has_in[data->type][nr]) - data->in[nr] = f71882fg_read8(data, - F71882FG_REG_IN(nr)); - - data->last_updated = jiffies; - data->valid = true; - } - - mutex_unlock(&data->update_lock); - - return data; -} - -/* Sysfs Interface */ -static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - int speed = fan_from_reg(data->fan[nr]); - - if (speed == FAN_MIN_DETECT) - speed = 0; - - return sprintf(buf, "%d\n", speed); -} - -static ssize_t show_fan_full_speed(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - int speed = fan_from_reg(data->fan_full_speed[nr]); - return sprintf(buf, "%d\n", speed); -} - -static ssize_t store_fan_full_speed(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val = clamp_val(val, 23, 1500000); - val = fan_to_reg(val); - - mutex_lock(&data->update_lock); - f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val); - data->fan_full_speed[nr] = val; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_fan_beep(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - if (data->fan_beep & (1 << nr)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static ssize_t store_fan_beep(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - unsigned long val; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP); - if (val) - data->fan_beep |= 1 << nr; - else - data->fan_beep &= ~(1 << nr); - - f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep); - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_fan_alarm(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - if (data->fan_status & (1 << nr)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static ssize_t show_in(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - return sprintf(buf, "%d\n", data->in[nr] * 8); -} - -static ssize_t show_in_max(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - - return sprintf(buf, "%d\n", data->in1_max * 8); -} - -static ssize_t store_in_max(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val /= 8; - val = clamp_val(val, 0, 255); - - mutex_lock(&data->update_lock); - if (data->type == f81866a) - f71882fg_write8(data, F81866_REG_IN1_HIGH, val); - else - f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val); - data->in1_max = val; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_in_beep(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - if (data->in_beep & (1 << nr)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static ssize_t store_in_beep(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - unsigned long val; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - if (data->type == f81866a) - data->in_beep = f71882fg_read8(data, F81866_REG_IN_BEEP); - else - data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP); - - if (val) - data->in_beep |= 1 << nr; - else - data->in_beep &= ~(1 << nr); - - if (data->type == f81866a) - f71882fg_write8(data, F81866_REG_IN_BEEP, data->in_beep); - else - f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep); - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_in_alarm(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - if (data->in_status & (1 << nr)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - int sign, temp; - - if (data->type == f71858fg) { - /* TEMP_TABLE_SEL 1 or 3 ? */ - if (data->temp_config & 1) { - sign = data->temp[nr] & 0x0001; - temp = (data->temp[nr] >> 5) & 0x7ff; - } else { - sign = data->temp[nr] & 0x8000; - temp = (data->temp[nr] >> 5) & 0x3ff; - } - temp *= 125; - if (sign) - temp -= 128000; - } else { - temp = ((s8)data->temp[nr]) * 1000; - } - - return sprintf(buf, "%d\n", temp); -} - -static ssize_t show_temp_max(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - return sprintf(buf, "%d\n", data->temp_high[nr] * 1000); -} - -static ssize_t store_temp_max(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val /= 1000; - val = clamp_val(val, 0, 255); - - mutex_lock(&data->update_lock); - f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val); - data->temp_high[nr] = val; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - int temp_max_hyst; - - mutex_lock(&data->update_lock); - if (nr & 1) - temp_max_hyst = data->temp_hyst[nr / 2] >> 4; - else - temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f; - temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000; - mutex_unlock(&data->update_lock); - - return sprintf(buf, "%d\n", temp_max_hyst); -} - -static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - ssize_t ret = count; - u8 reg; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val /= 1000; - - mutex_lock(&data->update_lock); - - /* convert abs to relative and check */ - data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr)); - val = clamp_val(val, data->temp_high[nr] - 15, data->temp_high[nr]); - val = data->temp_high[nr] - val; - - /* convert value to register contents */ - reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2)); - if (nr & 1) - reg = (reg & 0x0f) | (val << 4); - else - reg = (reg & 0xf0) | val; - f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg); - data->temp_hyst[nr / 2] = reg; - - mutex_unlock(&data->update_lock); - return ret; -} - -static ssize_t show_temp_crit(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000); -} - -static ssize_t store_temp_crit(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val /= 1000; - val = clamp_val(val, 0, 255); - - mutex_lock(&data->update_lock); - f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val); - data->temp_ovt[nr] = val; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - int temp_crit_hyst; - - mutex_lock(&data->update_lock); - if (nr & 1) - temp_crit_hyst = data->temp_hyst[nr / 2] >> 4; - else - temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f; - temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000; - mutex_unlock(&data->update_lock); - - return sprintf(buf, "%d\n", temp_crit_hyst); -} - -static ssize_t show_temp_type(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - return sprintf(buf, "%d\n", data->temp_type[nr]); -} - -static ssize_t show_temp_beep(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - if (data->temp_beep & (1 << nr)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static ssize_t store_temp_beep(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - unsigned long val; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP); - if (val) - data->temp_beep |= 1 << nr; - else - data->temp_beep &= ~(1 << nr); - - f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep); - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_temp_alarm(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - if (data->temp_status & (1 << nr)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static ssize_t show_temp_fault(struct device *dev, struct device_attribute - *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - if (data->temp_diode_open & (1 << nr)) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static ssize_t show_pwm(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int val, nr = to_sensor_dev_attr_2(devattr)->index; - mutex_lock(&data->update_lock); - if (data->pwm_enable & (1 << (2 * nr))) - /* PWM mode */ - val = data->pwm[nr]; - else { - /* RPM mode */ - val = 255 * fan_from_reg(data->fan_target[nr]) - / fan_from_reg(data->fan_full_speed[nr]); - } - mutex_unlock(&data->update_lock); - return sprintf(buf, "%d\n", val); -} - -static ssize_t store_pwm(struct device *dev, - struct device_attribute *devattr, const char *buf, - size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val = clamp_val(val, 0, 255); - - mutex_lock(&data->update_lock); - data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) || - (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) { - count = -EROFS; - goto leave; - } - if (data->pwm_enable & (1 << (2 * nr))) { - /* PWM mode */ - f71882fg_write8(data, F71882FG_REG_PWM(nr), val); - data->pwm[nr] = val; - } else { - /* RPM mode */ - int target, full_speed; - full_speed = f71882fg_read16(data, - F71882FG_REG_FAN_FULL_SPEED(nr)); - target = fan_to_reg(val * fan_from_reg(full_speed) / 255); - f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target); - data->fan_target[nr] = target; - data->fan_full_speed[nr] = full_speed; - } -leave: - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_simple_pwm(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct f71882fg_data *data = f71882fg_update_device(dev); - int val, nr = to_sensor_dev_attr_2(devattr)->index; - - val = data->pwm[nr]; - return sprintf(buf, "%d\n", val); -} - -static ssize_t store_simple_pwm(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val = clamp_val(val, 0, 255); - - mutex_lock(&data->update_lock); - f71882fg_write8(data, F71882FG_REG_PWM(nr), val); - data->pwm[nr] = val; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_pwm_enable(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - int result = 0; - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - switch ((data->pwm_enable >> 2 * nr) & 3) { - case 0: - case 1: - result = 2; /* Normal auto mode */ - break; - case 2: - result = 1; /* Manual mode */ - break; - case 3: - if (data->type == f8000) - result = 3; /* Thermostat mode */ - else - result = 1; /* Manual mode */ - break; - } - - return sprintf(buf, "%d\n", result); -} - -static ssize_t store_pwm_enable(struct device *dev, struct device_attribute - *devattr, const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - /* Special case for F8000 pwm channel 3 which only does auto mode */ - if (data->type == f8000 && nr == 2 && val != 2) - return -EINVAL; - - mutex_lock(&data->update_lock); - data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - /* Special case for F8000 auto PWM mode / Thermostat mode */ - if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) { - switch (val) { - case 2: - data->pwm_enable &= ~(2 << (2 * nr)); - break; /* Normal auto mode */ - case 3: - data->pwm_enable |= 2 << (2 * nr); - break; /* Thermostat mode */ - default: - count = -EINVAL; - goto leave; - } - } else { - switch (val) { - case 1: - /* The f71858fg does not support manual RPM mode */ - if (data->type == f71858fg && - ((data->pwm_enable >> (2 * nr)) & 1)) { - count = -EINVAL; - goto leave; - } - data->pwm_enable |= 2 << (2 * nr); - break; /* Manual */ - case 2: - data->pwm_enable &= ~(2 << (2 * nr)); - break; /* Normal auto mode */ - default: - count = -EINVAL; - goto leave; - } - } - f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable); -leave: - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_pwm_auto_point_pwm(struct device *dev, - struct device_attribute *devattr, - char *buf) -{ - int result; - struct f71882fg_data *data = f71882fg_update_device(dev); - int pwm = to_sensor_dev_attr_2(devattr)->index; - int point = to_sensor_dev_attr_2(devattr)->nr; - - mutex_lock(&data->update_lock); - if (data->pwm_enable & (1 << (2 * pwm))) { - /* PWM mode */ - result = data->pwm_auto_point_pwm[pwm][point]; - } else { - /* RPM mode */ - result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]); - } - mutex_unlock(&data->update_lock); - - return sprintf(buf, "%d\n", result); -} - -static ssize_t store_pwm_auto_point_pwm(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, pwm = to_sensor_dev_attr_2(devattr)->index; - int point = to_sensor_dev_attr_2(devattr)->nr; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val = clamp_val(val, 0, 255); - - mutex_lock(&data->update_lock); - data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - if (data->pwm_enable & (1 << (2 * pwm))) { - /* PWM mode */ - } else { - /* RPM mode */ - if (val < 29) /* Prevent negative numbers */ - val = 255; - else - val = (255 - val) * 32 / val; - } - f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val); - data->pwm_auto_point_pwm[pwm][point] = val; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev, - struct device_attribute *devattr, - char *buf) -{ - int result = 0; - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - int point = to_sensor_dev_attr_2(devattr)->nr; - - mutex_lock(&data->update_lock); - if (nr & 1) - result = data->pwm_auto_point_hyst[nr / 2] >> 4; - else - result = data->pwm_auto_point_hyst[nr / 2] & 0x0f; - result = 1000 * (data->pwm_auto_point_temp[nr][point] - result); - mutex_unlock(&data->update_lock); - - return sprintf(buf, "%d\n", result); -} - -static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - int point = to_sensor_dev_attr_2(devattr)->nr; - u8 reg; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val /= 1000; - - mutex_lock(&data->update_lock); - data->pwm_auto_point_temp[nr][point] = - f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point)); - val = clamp_val(val, data->pwm_auto_point_temp[nr][point] - 15, - data->pwm_auto_point_temp[nr][point]); - val = data->pwm_auto_point_temp[nr][point] - val; - - reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2)); - if (nr & 1) - reg = (reg & 0x0f) | (val << 4); - else - reg = (reg & 0xf0) | val; - - f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg); - data->pwm_auto_point_hyst[nr / 2] = reg; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_pwm_interpolate(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - int result; - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - result = (data->pwm_auto_point_mapping[nr] >> 4) & 1; - - return sprintf(buf, "%d\n", result); -} - -static ssize_t store_pwm_interpolate(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - unsigned long val; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - data->pwm_auto_point_mapping[nr] = - f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); - if (val) - val = data->pwm_auto_point_mapping[nr] | (1 << 4); - else - val = data->pwm_auto_point_mapping[nr] & (~(1 << 4)); - f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val); - data->pwm_auto_point_mapping[nr] = val; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_pwm_auto_point_channel(struct device *dev, - struct device_attribute *devattr, - char *buf) -{ - int result; - struct f71882fg_data *data = f71882fg_update_device(dev); - int nr = to_sensor_dev_attr_2(devattr)->index; - - result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - - data->temp_start); - - return sprintf(buf, "%d\n", result); -} - -static ssize_t store_pwm_auto_point_channel(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, nr = to_sensor_dev_attr_2(devattr)->index; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - switch (val) { - case 1: - val = 0; - break; - case 2: - val = 1; - break; - case 4: - val = 2; - break; - default: - return -EINVAL; - } - val += data->temp_start; - mutex_lock(&data->update_lock); - data->pwm_auto_point_mapping[nr] = - f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); - val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val; - f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val); - data->pwm_auto_point_mapping[nr] = val; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_pwm_auto_point_temp(struct device *dev, - struct device_attribute *devattr, - char *buf) -{ - int result; - struct f71882fg_data *data = f71882fg_update_device(dev); - int pwm = to_sensor_dev_attr_2(devattr)->index; - int point = to_sensor_dev_attr_2(devattr)->nr; - - result = data->pwm_auto_point_temp[pwm][point]; - return sprintf(buf, "%d\n", 1000 * result); -} - -static ssize_t store_pwm_auto_point_temp(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - int err, pwm = to_sensor_dev_attr_2(devattr)->index; - int point = to_sensor_dev_attr_2(devattr)->nr; - long val; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - val /= 1000; - - if (data->auto_point_temp_signed) - val = clamp_val(val, -128, 127); - else - val = clamp_val(val, 0, 127); - - mutex_lock(&data->update_lock); - f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val); - data->pwm_auto_point_temp[pwm][point] = val; - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t name_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct f71882fg_data *data = dev_get_drvdata(dev); - return sprintf(buf, "%s\n", f71882fg_names[data->type]); -} - static int f71882fg_create_sysfs_files(struct platform_device *pdev, struct sensor_device_attribute_2 *attr, int count) { @@ -2329,6 +2220,119 @@ static int f71882fg_create_fan_sysfs_files( return err; } +static int f71882fg_remove(struct platform_device *pdev) +{ + struct f71882fg_data *data = platform_get_drvdata(pdev); + int nr_fans = f71882fg_nr_fans[data->type]; + int nr_temps = f71882fg_nr_temps[data->type]; + int i; + u8 start_reg = f71882fg_read8(data, F71882FG_REG_START); + + if (data->hwmon_dev) + hwmon_device_unregister(data->hwmon_dev); + + device_remove_file(&pdev->dev, &dev_attr_name); + + if (start_reg & 0x01) { + switch (data->type) { + case f71858fg: + if (data->temp_config & 0x10) + f71882fg_remove_sysfs_files(pdev, + f8000_temp_attr, + ARRAY_SIZE(f8000_temp_attr)); + else + f71882fg_remove_sysfs_files(pdev, + f71858fg_temp_attr, + ARRAY_SIZE(f71858fg_temp_attr)); + break; + case f8000: + f71882fg_remove_sysfs_files(pdev, + f8000_temp_attr, + ARRAY_SIZE(f8000_temp_attr)); + break; + case f81866a: + f71882fg_remove_sysfs_files(pdev, + f71858fg_temp_attr, + ARRAY_SIZE(f71858fg_temp_attr)); + break; + default: + f71882fg_remove_sysfs_files(pdev, + &fxxxx_temp_attr[0][0], + ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps); + } + if (f71882fg_temp_has_beep[data->type]) { + if (data->type == f81866a) + f71882fg_remove_sysfs_files(pdev, + &f81866_temp_beep_attr[0][0], + ARRAY_SIZE(f81866_temp_beep_attr[0]) + * nr_temps); + else + f71882fg_remove_sysfs_files(pdev, + &fxxxx_temp_beep_attr[0][0], + ARRAY_SIZE(fxxxx_temp_beep_attr[0]) + * nr_temps); + } + + for (i = 0; i < F71882FG_MAX_INS; i++) { + if (f71882fg_has_in[data->type][i]) { + device_remove_file(&pdev->dev, + &fxxxx_in_attr[i].dev_attr); + } + } + if (f71882fg_has_in1_alarm[data->type]) { + f71882fg_remove_sysfs_files(pdev, + fxxxx_in1_alarm_attr, + ARRAY_SIZE(fxxxx_in1_alarm_attr)); + } + } + + if (start_reg & 0x02) { + f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0], + ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans); + + if (f71882fg_fan_has_beep[data->type]) { + f71882fg_remove_sysfs_files(pdev, + fxxxx_fan_beep_attr, nr_fans); + } + + switch (data->type) { + case f71808a: + f71882fg_remove_sysfs_files(pdev, + &fxxxx_auto_pwm_attr[0][0], + ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans); + f71882fg_remove_sysfs_files(pdev, + f71808a_fan3_attr, + ARRAY_SIZE(f71808a_fan3_attr)); + break; + case f71862fg: + f71882fg_remove_sysfs_files(pdev, + &f71862fg_auto_pwm_attr[0][0], + ARRAY_SIZE(f71862fg_auto_pwm_attr[0]) * + nr_fans); + break; + case f71808e: + case f71869: + f71882fg_remove_sysfs_files(pdev, + &f71869_auto_pwm_attr[0][0], + ARRAY_SIZE(f71869_auto_pwm_attr[0]) * nr_fans); + break; + case f8000: + f71882fg_remove_sysfs_files(pdev, + f8000_fan_attr, + ARRAY_SIZE(f8000_fan_attr)); + f71882fg_remove_sysfs_files(pdev, + &f8000_auto_pwm_attr[0][0], + ARRAY_SIZE(f8000_auto_pwm_attr[0]) * nr_fans); + break; + default: + f71882fg_remove_sysfs_files(pdev, + &fxxxx_auto_pwm_attr[0][0], + ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans); + } + } + return 0; +} + static int f71882fg_probe(struct platform_device *pdev) { struct f71882fg_data *data; @@ -2502,119 +2506,6 @@ exit_unregister_sysfs: return err; /* f71882fg_remove() also frees our data */ } -static int f71882fg_remove(struct platform_device *pdev) -{ - struct f71882fg_data *data = platform_get_drvdata(pdev); - int nr_fans = f71882fg_nr_fans[data->type]; - int nr_temps = f71882fg_nr_temps[data->type]; - int i; - u8 start_reg = f71882fg_read8(data, F71882FG_REG_START); - - if (data->hwmon_dev) - hwmon_device_unregister(data->hwmon_dev); - - device_remove_file(&pdev->dev, &dev_attr_name); - - if (start_reg & 0x01) { - switch (data->type) { - case f71858fg: - if (data->temp_config & 0x10) - f71882fg_remove_sysfs_files(pdev, - f8000_temp_attr, - ARRAY_SIZE(f8000_temp_attr)); - else - f71882fg_remove_sysfs_files(pdev, - f71858fg_temp_attr, - ARRAY_SIZE(f71858fg_temp_attr)); - break; - case f8000: - f71882fg_remove_sysfs_files(pdev, - f8000_temp_attr, - ARRAY_SIZE(f8000_temp_attr)); - break; - case f81866a: - f71882fg_remove_sysfs_files(pdev, - f71858fg_temp_attr, - ARRAY_SIZE(f71858fg_temp_attr)); - break; - default: - f71882fg_remove_sysfs_files(pdev, - &fxxxx_temp_attr[0][0], - ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps); - } - if (f71882fg_temp_has_beep[data->type]) { - if (data->type == f81866a) - f71882fg_remove_sysfs_files(pdev, - &f81866_temp_beep_attr[0][0], - ARRAY_SIZE(f81866_temp_beep_attr[0]) - * nr_temps); - else - f71882fg_remove_sysfs_files(pdev, - &fxxxx_temp_beep_attr[0][0], - ARRAY_SIZE(fxxxx_temp_beep_attr[0]) - * nr_temps); - } - - for (i = 0; i < F71882FG_MAX_INS; i++) { - if (f71882fg_has_in[data->type][i]) { - device_remove_file(&pdev->dev, - &fxxxx_in_attr[i].dev_attr); - } - } - if (f71882fg_has_in1_alarm[data->type]) { - f71882fg_remove_sysfs_files(pdev, - fxxxx_in1_alarm_attr, - ARRAY_SIZE(fxxxx_in1_alarm_attr)); - } - } - - if (start_reg & 0x02) { - f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0], - ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans); - - if (f71882fg_fan_has_beep[data->type]) { - f71882fg_remove_sysfs_files(pdev, - fxxxx_fan_beep_attr, nr_fans); - } - - switch (data->type) { - case f71808a: - f71882fg_remove_sysfs_files(pdev, - &fxxxx_auto_pwm_attr[0][0], - ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans); - f71882fg_remove_sysfs_files(pdev, - f71808a_fan3_attr, - ARRAY_SIZE(f71808a_fan3_attr)); - break; - case f71862fg: - f71882fg_remove_sysfs_files(pdev, - &f71862fg_auto_pwm_attr[0][0], - ARRAY_SIZE(f71862fg_auto_pwm_attr[0]) * - nr_fans); - break; - case f71808e: - case f71869: - f71882fg_remove_sysfs_files(pdev, - &f71869_auto_pwm_attr[0][0], - ARRAY_SIZE(f71869_auto_pwm_attr[0]) * nr_fans); - break; - case f8000: - f71882fg_remove_sysfs_files(pdev, - f8000_fan_attr, - ARRAY_SIZE(f8000_fan_attr)); - f71882fg_remove_sysfs_files(pdev, - &f8000_auto_pwm_attr[0][0], - ARRAY_SIZE(f8000_auto_pwm_attr[0]) * nr_fans); - break; - default: - f71882fg_remove_sysfs_files(pdev, - &fxxxx_auto_pwm_attr[0][0], - ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans); - } - } - return 0; -} - static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data) { u16 devid; @@ -2760,6 +2651,14 @@ exit_device_put: return err; } +static struct platform_driver f71882fg_driver = { + .driver = { + .name = DRVNAME, + }, + .probe = f71882fg_probe, + .remove = f71882fg_remove, +}; + static int __init f71882fg_init(void) { int err; diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index ffeed6c1e20b..64fbb8cf687c 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -896,7 +896,7 @@ static int f75375_detect(struct i2c_client *client, version = f75375_read8(client, F75375_REG_VERSION); dev_info(&adapter->dev, "found %s version: %02X\n", name, version); - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 343e227ca38a..0a77d6161928 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -1075,7 +1075,7 @@ static int fschmd_detect(struct i2c_client *client, else return -ENODEV; - strlcpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE); + strscpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index 918763832432..f5b8e724a8ca 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -739,7 +739,7 @@ static int fts_detect(struct i2c_client *client, if (val != 0x11) return -ENODEV; - strlcpy(info->type, fts_id[0].name, I2C_NAME_SIZE); + strscpy(info->type, fts_id[0].name, I2C_NAME_SIZE); info->flags = 0; return 0; } diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index dd683b0a648f..95286c40f55a 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -586,7 +586,7 @@ static int gl518_detect(struct i2c_client *client, struct i2c_board_info *info) if (rev != 0x00 && rev != 0x80) return -ENODEV; - strlcpy(info->type, "gl518sm", I2C_NAME_SIZE); + strscpy(info->type, "gl518sm", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 096ba9797211..394da4ac977c 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -811,7 +811,7 @@ static int gl520_detect(struct i2c_client *client, struct i2c_board_info *info) return -ENODEV; } - strlcpy(info->type, "gl520sm", I2C_NAME_SIZE); + strscpy(info->type, "gl520sm", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index fbf3f5a4ecb6..ba408942dbe7 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -37,9 +37,7 @@ struct gpio_fan_data { int num_speed; struct gpio_fan_speed *speed; int speed_index; -#ifdef CONFIG_PM_SLEEP int resume_speed; -#endif bool pwm_enable; struct gpio_desc *alarm_gpio; struct work_struct alarm_work; @@ -557,7 +555,6 @@ static void gpio_fan_shutdown(struct platform_device *pdev) set_fan_speed(fan_data, 0); } -#ifdef CONFIG_PM_SLEEP static int gpio_fan_suspend(struct device *dev) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); @@ -580,18 +577,14 @@ static int gpio_fan_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume); -#define GPIO_FAN_PM (&gpio_fan_pm) -#else -#define GPIO_FAN_PM NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume); static struct platform_driver gpio_fan_driver = { .probe = gpio_fan_probe, .shutdown = gpio_fan_shutdown, .driver = { .name = "gpio-fan", - .pm = GPIO_FAN_PM, + .pm = pm_sleep_ptr(&gpio_fan_pm), .of_match_table = of_match_ptr(of_gpio_fan_match), }, }; diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index d64be48f1ef6..b60ec95b5edb 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -267,6 +267,7 @@ gsc_hwmon_get_devtree_pdata(struct device *dev) pdata->nchannels = nchannels; /* fan controller base address */ + of_node_get(dev->parent->of_node); fan = of_find_compatible_node(dev->parent->of_node, NULL, "gw,gsc-fan"); if (fan && of_property_read_u32(fan, "reg", &pdata->fan_base)) { of_node_put(fan); diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 580a7d125b88..3aa40893fc09 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -6,11 +6,13 @@ #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/err.h> #include <linux/platform_device.h> +#include <linux/property.h> + #include <linux/hwmon.h> -#include <linux/of.h> #include <linux/hwmon-sysfs.h> #include <linux/iio/consumer.h> #include <linux/iio/types.h> @@ -149,8 +151,8 @@ static int iio_hwmon_probe(struct platform_device *pdev) st->attr_group.attrs = st->attrs; st->groups[0] = &st->attr_group; - if (dev->of_node) { - sname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node); + if (dev_fwnode(dev)) { + sname = devm_kasprintf(dev, GFP_KERNEL, "%pfwP", dev_fwnode(dev)); if (!sname) return -ENOMEM; strreplace(sname, '-', '_'); diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index f89bac19bd73..2a57f4b60c29 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -928,7 +928,7 @@ static void ina3221_remove(struct i2c_client *client) mutex_destroy(&ina->lock); } -static int __maybe_unused ina3221_suspend(struct device *dev) +static int ina3221_suspend(struct device *dev) { struct ina3221_data *ina = dev_get_drvdata(dev); int ret; @@ -951,7 +951,7 @@ static int __maybe_unused ina3221_suspend(struct device *dev) return 0; } -static int __maybe_unused ina3221_resume(struct device *dev) +static int ina3221_resume(struct device *dev) { struct ina3221_data *ina = dev_get_drvdata(dev); int ret; @@ -994,11 +994,8 @@ static int __maybe_unused ina3221_resume(struct device *dev) return 0; } -static const struct dev_pm_ops ina3221_pm = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(ina3221_suspend, ina3221_resume, NULL) -}; +static DEFINE_RUNTIME_DEV_PM_OPS(ina3221_pm, ina3221_suspend, ina3221_resume, + NULL); static const struct of_device_id ina3221_of_match_table[] = { { .compatible = "ti,ina3221", }, @@ -1018,7 +1015,7 @@ static struct i2c_driver ina3221_i2c_driver = { .driver = { .name = INA3221_DRIVER_NAME, .of_match_table = ina3221_of_match_table, - .pm = &ina3221_pm, + .pm = pm_ptr(&ina3221_pm), }, .id_table = ina3221_ids, }; diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 0e543dbe0a6b..7bd154ba351b 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -3179,7 +3179,7 @@ static int it87_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(hwmon_dev); } -static void __maybe_unused it87_resume_sio(struct platform_device *pdev) +static void it87_resume_sio(struct platform_device *pdev) { struct it87_data *data = dev_get_drvdata(&pdev->dev); int err; @@ -3211,7 +3211,7 @@ static void __maybe_unused it87_resume_sio(struct platform_device *pdev) superio_exit(data->sioaddr); } -static int __maybe_unused it87_resume(struct device *dev) +static int it87_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct it87_data *data = dev_get_drvdata(dev); @@ -3238,12 +3238,12 @@ static int __maybe_unused it87_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(it87_dev_pm_ops, NULL, it87_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(it87_dev_pm_ops, NULL, it87_resume); static struct platform_driver it87_driver = { .driver = { .name = DRVNAME, - .pm = &it87_dev_pm_ops, + .pm = pm_sleep_ptr(&it87_dev_pm_ops), }, .probe = it87_probe, }; diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 7b3c190959d3..30888feaf589 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -441,7 +441,7 @@ static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info) struct jc42_chips *chip = &jc42_chips[i]; if (manid == chip->manid && (devid & chip->devid_mask) == chip->devid) { - strlcpy(info->type, "jc42", I2C_NAME_SIZE); + strscpy(info->type, "jc42", I2C_NAME_SIZE); return 0; } } diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 339a145afc09..9ab2cab4c710 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -996,11 +996,11 @@ static int lm63_detect(struct i2c_client *client, } if (chip_id == 0x41 && address == 0x4c) - strlcpy(info->type, "lm63", I2C_NAME_SIZE); + strscpy(info->type, "lm63", I2C_NAME_SIZE); else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e)) - strlcpy(info->type, "lm64", I2C_NAME_SIZE); + strscpy(info->type, "lm64", I2C_NAME_SIZE); else if (chip_id == 0x49 && address == 0x4c) - strlcpy(info->type, "lm96163", I2C_NAME_SIZE); + strscpy(info->type, "lm96163", I2C_NAME_SIZE); else return -ENODEV; diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index beb0d61bcd82..1346b3b3f463 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -257,7 +257,7 @@ static int lm73_detect(struct i2c_client *new_client, if (id < 0 || id != LM73_ID) return -ENODEV; - strlcpy(info->type, "lm73", I2C_NAME_SIZE); + strscpy(info->type, "lm73", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 66dc826f7962..bcc3adcb3af1 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -893,7 +893,7 @@ static int lm75_detect(struct i2c_client *new_client, return -ENODEV; } - strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE); + strscpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index df6af85e170a..645cb2191abe 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -302,7 +302,7 @@ static int lm77_detect(struct i2c_client *client, struct i2c_board_info *info) || i2c_smbus_read_word_data(client, 7) != min) return -ENODEV; - strlcpy(info->type, "lm77", I2C_NAME_SIZE); + strscpy(info->type, "lm77", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 5e129cbec1cb..694e171cab7f 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -617,7 +617,7 @@ static int lm78_i2c_detect(struct i2c_client *client, if (isa) mutex_unlock(&isa->update_lock); - strlcpy(info->type, client_name, I2C_NAME_SIZE); + strscpy(info->type, client_name, I2C_NAME_SIZE); return 0; diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index e85e062bbf32..35db0b97f912 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -586,7 +586,7 @@ static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info) name = "lm80"; } - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 905f5689f907..616449f2cc50 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -412,7 +412,7 @@ static int lm83_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 88cf2012d34b..8d33c2484755 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1539,7 +1539,7 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) if (!type_name) return -ENODEV; - strlcpy(info->type, type_name, I2C_NAME_SIZE); + strscpy(info->type, type_name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 1750bc588856..818fb6195245 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -833,7 +833,7 @@ static int lm87_detect(struct i2c_client *client, struct i2c_board_info *info) return -ENODEV; } - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 221de01a327a..db595f7d01f8 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -2547,7 +2547,7 @@ static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info) return -ENODEV; } - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } @@ -2956,7 +2956,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, } } -static int __maybe_unused lm90_suspend(struct device *dev) +static int lm90_suspend(struct device *dev) { struct lm90_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -2967,7 +2967,7 @@ static int __maybe_unused lm90_suspend(struct device *dev) return 0; } -static int __maybe_unused lm90_resume(struct device *dev) +static int lm90_resume(struct device *dev) { struct lm90_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -2978,14 +2978,14 @@ static int __maybe_unused lm90_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(lm90_pm_ops, lm90_suspend, lm90_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(lm90_pm_ops, lm90_suspend, lm90_resume); static struct i2c_driver lm90_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "lm90", .of_match_table = of_match_ptr(lm90_of_match), - .pm = &lm90_pm_ops, + .pm = pm_sleep_ptr(&lm90_pm_ops), }, .probe_new = lm90_probe, .alert = lm90_alert, diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 5bae6eedcaf1..2ff3044a677d 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -287,7 +287,7 @@ static int lm92_detect(struct i2c_client *new_client, else return -ENODEV; - strlcpy(info->type, "lm92", I2C_NAME_SIZE); + strscpy(info->type, "lm92", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index dc67bf954b21..4cf50d5f4f59 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -2575,7 +2575,7 @@ static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info) return -ENODEV; } - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); dev_dbg(&adapter->dev, "loading %s at %d, 0x%02x\n", client->name, i2c_adapter_id(client->adapter), client->addr); diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c index ac169a994ae0..b4a9d0c223c4 100644 --- a/drivers/hwmon/lm95234.c +++ b/drivers/hwmon/lm95234.c @@ -644,7 +644,7 @@ static int lm95234_detect(struct i2c_client *client, if (val & model_mask) return -ENODEV; - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 8ea46ff20be5..f1ed777a8735 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -389,7 +389,7 @@ static int lm95241_detect(struct i2c_client *new_client, } /* Fill the i2c board info */ - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 29388fcf5f74..c433f0af2d31 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -461,7 +461,7 @@ static int lm95245_detect(struct i2c_client *new_client, return -ENODEV; } - strlcpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/ltc2947-core.c b/drivers/hwmon/ltc2947-core.c index 5423466de697..7404e974762f 100644 --- a/drivers/hwmon/ltc2947-core.c +++ b/drivers/hwmon/ltc2947-core.c @@ -956,13 +956,6 @@ static struct attribute *ltc2947_attrs[] = { }; ATTRIBUTE_GROUPS(ltc2947); -static void ltc2947_clk_disable(void *data) -{ - struct clk *extclk = data; - - clk_disable_unprepare(extclk); -} - static int ltc2947_setup(struct ltc2947_data *st) { int ret; @@ -989,7 +982,7 @@ static int ltc2947_setup(struct ltc2947_data *st) return ret; /* check external clock presence */ - extclk = devm_clk_get_optional(st->dev, NULL); + extclk = devm_clk_get_optional_enabled(st->dev, NULL); if (IS_ERR(extclk)) return dev_err_probe(st->dev, PTR_ERR(extclk), "Failed to get external clock\n"); @@ -1007,14 +1000,6 @@ static int ltc2947_setup(struct ltc2947_data *st) return -EINVAL; } - ret = clk_prepare_enable(extclk); - if (ret) - return ret; - - ret = devm_add_action_or_reset(st->dev, ltc2947_clk_disable, - extclk); - if (ret) - return ret; /* as in table 1 of the datasheet */ if (rate_hz >= LTC2947_CLK_MIN && rate_hz <= 1000000) pre = 0; @@ -1135,7 +1120,7 @@ int ltc2947_core_probe(struct regmap *map, const char *name) } EXPORT_SYMBOL_GPL(ltc2947_core_probe); -static int __maybe_unused ltc2947_resume(struct device *dev) +static int ltc2947_resume(struct device *dev) { struct ltc2947_data *st = dev_get_drvdata(dev); u32 ctrl = 0; @@ -1164,7 +1149,7 @@ static int __maybe_unused ltc2947_resume(struct device *dev) LTC2947_CONT_MODE_MASK, LTC2947_CONT_MODE(1)); } -static int __maybe_unused ltc2947_suspend(struct device *dev) +static int ltc2947_suspend(struct device *dev) { struct ltc2947_data *st = dev_get_drvdata(dev); @@ -1172,8 +1157,7 @@ static int __maybe_unused ltc2947_suspend(struct device *dev) LTC2947_SHUTDOWN_MASK, 1); } -SIMPLE_DEV_PM_OPS(ltc2947_pm_ops, ltc2947_suspend, ltc2947_resume); -EXPORT_SYMBOL_GPL(ltc2947_pm_ops); +EXPORT_SIMPLE_DEV_PM_OPS(ltc2947_pm_ops, ltc2947_suspend, ltc2947_resume); const struct of_device_id ltc2947_of_match[] = { { .compatible = "adi,ltc2947" }, diff --git a/drivers/hwmon/ltc2947-i2c.c b/drivers/hwmon/ltc2947-i2c.c index ad0dfd3efbf8..96852bc8a964 100644 --- a/drivers/hwmon/ltc2947-i2c.c +++ b/drivers/hwmon/ltc2947-i2c.c @@ -36,7 +36,7 @@ static struct i2c_driver ltc2947_driver = { .driver = { .name = "ltc2947", .of_match_table = ltc2947_of_match, - .pm = <c2947_pm_ops, + .pm = pm_sleep_ptr(<c2947_pm_ops), }, .probe_new = ltc2947_probe, .id_table = ltc2947_id, diff --git a/drivers/hwmon/ltc2947-spi.c b/drivers/hwmon/ltc2947-spi.c index c24ca569db1b..a33be110098c 100644 --- a/drivers/hwmon/ltc2947-spi.c +++ b/drivers/hwmon/ltc2947-spi.c @@ -38,7 +38,7 @@ static struct spi_driver ltc2947_driver = { .driver = { .name = "ltc2947", .of_match_table = ltc2947_of_match, - .pm = <c2947_pm_ops, + .pm = pm_sleep_ptr(<c2947_pm_ops), }, .probe = ltc2947_probe, .id_table = ltc2947_id, diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index eae9e68027bc..445c77197f69 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -241,7 +241,7 @@ static int max1619_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, "max1619", I2C_NAME_SIZE); + strscpy(info->type, "max1619", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index 78688e6cb87d..9f748973d6a3 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -386,7 +386,7 @@ static int max1668_detect(struct i2c_client *client, if (!type_name) return -ENODEV; - strlcpy(info->type, type_name, I2C_NAME_SIZE); + strscpy(info->type, type_name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/max31722.c b/drivers/hwmon/max31722.c index 93e048ee4955..9a31ef388396 100644 --- a/drivers/hwmon/max31722.c +++ b/drivers/hwmon/max31722.c @@ -113,7 +113,7 @@ static void max31722_remove(struct spi_device *spi) dev_warn(&spi->dev, "Failed to put device in stand-by mode\n"); } -static int __maybe_unused max31722_suspend(struct device *dev) +static int max31722_suspend(struct device *dev) { struct spi_device *spi_device = to_spi_device(dev); struct max31722_data *data = spi_get_drvdata(spi_device); @@ -121,7 +121,7 @@ static int __maybe_unused max31722_suspend(struct device *dev) return max31722_set_mode(data, MAX31722_MODE_STANDBY); } -static int __maybe_unused max31722_resume(struct device *dev) +static int max31722_resume(struct device *dev) { struct spi_device *spi_device = to_spi_device(dev); struct max31722_data *data = spi_get_drvdata(spi_device); @@ -129,7 +129,7 @@ static int __maybe_unused max31722_resume(struct device *dev) return max31722_set_mode(data, MAX31722_MODE_CONTINUOUS); } -static SIMPLE_DEV_PM_OPS(max31722_pm_ops, max31722_suspend, max31722_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(max31722_pm_ops, max31722_suspend, max31722_resume); static const struct spi_device_id max31722_spi_id[] = { {"max31722", 0}, @@ -141,7 +141,7 @@ MODULE_DEVICE_TABLE(spi, max31722_spi_id); static struct spi_driver max31722_driver = { .driver = { .name = "max31722", - .pm = &max31722_pm_ops, + .pm = pm_sleep_ptr(&max31722_pm_ops), }, .probe = max31722_probe, .remove = max31722_remove, diff --git a/drivers/hwmon/max31730.c b/drivers/hwmon/max31730.c index 23598b8b8793..746a767c9fc6 100644 --- a/drivers/hwmon/max31730.c +++ b/drivers/hwmon/max31730.c @@ -399,33 +399,33 @@ static int max31730_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, "max31730", I2C_NAME_SIZE); + strscpy(info->type, "max31730", I2C_NAME_SIZE); return 0; } -static int __maybe_unused max31730_suspend(struct device *dev) +static int max31730_suspend(struct device *dev) { struct max31730_data *data = dev_get_drvdata(dev); return max31730_write_config(data, MAX31730_STOP, 0); } -static int __maybe_unused max31730_resume(struct device *dev) +static int max31730_resume(struct device *dev) { struct max31730_data *data = dev_get_drvdata(dev); return max31730_write_config(data, 0, MAX31730_STOP); } -static SIMPLE_DEV_PM_OPS(max31730_pm_ops, max31730_suspend, max31730_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(max31730_pm_ops, max31730_suspend, max31730_resume); static struct i2c_driver max31730_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "max31730", .of_match_table = of_match_ptr(max31730_of_match), - .pm = &max31730_pm_ops, + .pm = pm_sleep_ptr(&max31730_pm_ops), }, .probe_new = max31730_probe, .id_table = max31730_ids, diff --git a/drivers/hwmon/max31760.c b/drivers/hwmon/max31760.c new file mode 100644 index 000000000000..06d5f39dc33d --- /dev/null +++ b/drivers/hwmon/max31760.c @@ -0,0 +1,596 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/util_macros.h> + +#define REG_CR1 0x00 +#define CR1_HYST BIT(5) +#define CR1_DRV GENMASK(4, 3) +#define CR1_TEMP_SRC GENMASK(1, 0) +#define REG_CR2 0x01 +#define CR2_STBY BIT(7) +#define CR2_ALERTS BIT(6) +#define CR2_DFC BIT(0) +#define REG_CR3 0x02 +#define REG_PWMR 0x50 +#define REG_PWMV 0x51 +#define REG_STATUS 0x5A +#define STATUS_ALARM_CRIT(ch) BIT(2 + 2 * (ch)) +#define STATUS_ALARM_MAX(ch) BIT(3 + 2 * (ch)) +#define STATUS_RDFA BIT(6) + +#define REG_TACH(ch) (0x52 + (ch) * 2) +#define REG_TEMP_INPUT(ch) (0x56 + (ch) * 2) +#define REG_TEMP_MAX(ch) (0x06 + (ch) * 2) +#define REG_TEMP_CRIT(ch) (0x0A + (ch) * 2) + +#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) +#define TEMP11_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val((val), -128000, \ + 127875), 125) * 32) + +#define LUT_SIZE 48 + +#define REG_LUT(index) (0x20 + (index)) + +struct max31760_state { + struct regmap *regmap; + + struct lut_attribute { + char name[24]; + struct sensor_device_attribute sda; + } lut[LUT_SIZE]; + + struct attribute *attrs[LUT_SIZE + 2]; + struct attribute_group group; + const struct attribute_group *groups[2]; +}; + +static bool max31760_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg > 0x50; +} + +static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x5B, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = max31760_volatile_reg, +}; + +static const int max31760_pwm_freq[] = {33, 150, 1500, 25000}; + +static int tach_to_rpm(u16 tach) +{ + if (tach == 0) + tach = 1; + + return 60 * 100000 / tach / 2; +} + +static int max31760_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct max31760_state *state = dev_get_drvdata(dev); + unsigned int regval; + unsigned int reg_temp; + s16 temp; + u8 reg[2]; + int ret; + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_fault: + ret = regmap_read(state->regmap, REG_STATUS, ®val); + if (ret) + return ret; + + *val = FIELD_GET(STATUS_RDFA, regval); + + return 0; + case hwmon_temp_max_alarm: + ret = regmap_read(state->regmap, REG_STATUS, ®val); + if (ret) + return ret; + + if (channel) + *val = FIELD_GET(STATUS_ALARM_MAX(1), regval); + else + *val = FIELD_GET(STATUS_ALARM_MAX(0), regval); + + return 0; + case hwmon_temp_crit_alarm: + ret = regmap_read(state->regmap, REG_STATUS, ®val); + if (ret) + return ret; + + if (channel) + *val = FIELD_GET(STATUS_ALARM_CRIT(1), regval); + else + *val = FIELD_GET(STATUS_ALARM_CRIT(0), regval); + + return 0; + case hwmon_temp_input: + reg_temp = REG_TEMP_INPUT(channel); + break; + case hwmon_temp_max: + reg_temp = REG_TEMP_MAX(channel); + break; + case hwmon_temp_crit: + reg_temp = REG_TEMP_CRIT(channel); + break; + default: + return -EOPNOTSUPP; + } + + ret = regmap_bulk_read(state->regmap, reg_temp, reg, 2); + if (ret) + return ret; + + temp = (reg[0] << 8) | reg[1]; + + *val = TEMP11_FROM_REG(temp); + + return 0; + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + ret = regmap_bulk_read(state->regmap, REG_TACH(channel), reg, 2); + if (ret) + return ret; + + *val = tach_to_rpm(reg[0] * 256 + reg[1]); + + return 0; + case hwmon_fan_fault: + ret = regmap_read(state->regmap, REG_STATUS, ®val); + if (ret) + return ret; + + if (channel) + *val = FIELD_GET(BIT(1), regval); + else + *val = FIELD_GET(BIT(0), regval); + + return 0; + case hwmon_fan_enable: + ret = regmap_read(state->regmap, REG_CR3, ®val); + if (ret) + return ret; + + if (channel) + *val = FIELD_GET(BIT(1), regval); + else + *val = FIELD_GET(BIT(0), regval); + + return 0; + default: + return -EOPNOTSUPP; + } + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + ret = regmap_read(state->regmap, REG_PWMV, ®val); + if (ret) + return ret; + + *val = regval; + + return 0; + case hwmon_pwm_freq: + ret = regmap_read(state->regmap, REG_CR1, ®val); + if (ret) + return ret; + + regval = FIELD_GET(CR1_DRV, regval); + if (regval >= ARRAY_SIZE(max31760_pwm_freq)) + return -EINVAL; + + *val = max31760_pwm_freq[regval]; + + return 0; + case hwmon_pwm_enable: + ret = regmap_read(state->regmap, REG_CR2, ®val); + if (ret) + return ret; + + *val = 2 - FIELD_GET(CR2_DFC, regval); + + return 0; + case hwmon_pwm_auto_channels_temp: + ret = regmap_read(state->regmap, REG_CR1, ®val); + if (ret) + return ret; + + switch (FIELD_GET(CR1_TEMP_SRC, regval)) { + case 0: + *val = 2; + break; + case 1: + *val = 1; + break; + case 2: + case 3: + *val = 3; + break; + default: + return -EINVAL; + } + + return 0; + default: + return -EOPNOTSUPP; + } + default: + return -EOPNOTSUPP; + } +} + +static int max31760_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct max31760_state *state = dev_get_drvdata(dev); + unsigned int pwm_index; + unsigned int reg_temp; + int temp; + u8 reg_val[2]; + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_max: + reg_temp = REG_TEMP_MAX(channel); + break; + case hwmon_temp_crit: + reg_temp = REG_TEMP_CRIT(channel); + break; + default: + return -EOPNOTSUPP; + } + + temp = TEMP11_TO_REG(val); + reg_val[0] = temp >> 8; + reg_val[1] = temp & 0xFF; + + return regmap_bulk_write(state->regmap, reg_temp, reg_val, 2); + case hwmon_fan: + switch (attr) { + case hwmon_fan_enable: + if (val == 0) + return regmap_clear_bits(state->regmap, REG_CR3, BIT(channel)); + + if (val == 1) + return regmap_set_bits(state->regmap, REG_CR3, BIT(channel)); + + return -EINVAL; + default: + return -EOPNOTSUPP; + } + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + if (val < 0 || val > 255) + return -EINVAL; + + return regmap_write(state->regmap, REG_PWMR, val); + case hwmon_pwm_enable: + if (val == 1) + return regmap_set_bits(state->regmap, REG_CR2, CR2_DFC); + + if (val == 2) + return regmap_clear_bits(state->regmap, REG_CR2, CR2_DFC); + + return -EINVAL; + case hwmon_pwm_freq: + pwm_index = find_closest(val, max31760_pwm_freq, + ARRAY_SIZE(max31760_pwm_freq)); + + return regmap_update_bits(state->regmap, + REG_CR1, CR1_DRV, + FIELD_PREP(CR1_DRV, pwm_index)); + case hwmon_pwm_auto_channels_temp: + switch (val) { + case 1: + break; + case 2: + val = 0; + break; + case 3: + val = 2; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(state->regmap, REG_CR1, CR1_TEMP_SRC, val); + default: + return -EOPNOTSUPP; + } + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_channel_info *max31760_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_ENABLE), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT | + HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_ENABLE | HWMON_PWM_FREQ | HWMON_PWM_INPUT | + HWMON_PWM_AUTO_CHANNELS_TEMP), + NULL +}; + +static umode_t max31760_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_max_alarm: + case hwmon_temp_crit_alarm: + case hwmon_temp_fault: + case hwmon_temp_label: + return 0444; + case hwmon_temp_max: + case hwmon_temp_crit: + return 0644; + default: + return 0; + } + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + case hwmon_fan_fault: + return 0444; + case hwmon_fan_enable: + return 0644; + default: + return 0; + } + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_enable: + case hwmon_pwm_input: + case hwmon_pwm_freq: + case hwmon_pwm_auto_channels_temp: + return 0644; + default: + return 0; + } + default: + return 0; + } +} + +static int max31760_read_string(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + switch (type) { + case hwmon_temp: + if (attr != hwmon_temp_label) + return -EOPNOTSUPP; + + *str = channel ? "local" : "remote"; + + return 0; + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_ops max31760_hwmon_ops = { + .is_visible = max31760_is_visible, + .read = max31760_read, + .write = max31760_write, + .read_string = max31760_read_string +}; + +static const struct hwmon_chip_info max31760_chip_info = { + .ops = &max31760_hwmon_ops, + .info = max31760_info, +}; + +static ssize_t lut_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + struct max31760_state *state = dev_get_drvdata(dev); + int ret; + unsigned int regval; + + ret = regmap_read(state->regmap, REG_LUT(sda->index), ®val); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", regval); +} + +static ssize_t lut_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + struct max31760_state *state = dev_get_drvdata(dev); + int ret; + u8 pwm; + + ret = kstrtou8(buf, 10, &pwm); + if (ret) + return ret; + + ret = regmap_write(state->regmap, REG_LUT(sda->index), pwm); + if (ret) + return ret; + + return count; +} + +static ssize_t pwm1_auto_point_temp_hyst_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct max31760_state *state = dev_get_drvdata(dev); + unsigned int regval; + int ret; + + ret = regmap_read(state->regmap, REG_CR1, ®val); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", (1 + (int)FIELD_GET(CR1_HYST, regval)) * 2000); +} + +static ssize_t pwm1_auto_point_temp_hyst_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct max31760_state *state = dev_get_drvdata(dev); + unsigned int hyst; + int ret; + + ret = kstrtou32(buf, 10, &hyst); + if (ret) + return ret; + + if (hyst < 3000) + ret = regmap_clear_bits(state->regmap, REG_CR1, CR1_HYST); + else + ret = regmap_set_bits(state->regmap, REG_CR1, CR1_HYST); + + if (ret) + return ret; + + return count; +} + +static DEVICE_ATTR_RW(pwm1_auto_point_temp_hyst); + +static void max31760_create_lut_nodes(struct max31760_state *state) +{ + int i; + struct sensor_device_attribute *sda; + struct lut_attribute *lut; + + for (i = 0; i < LUT_SIZE; ++i) { + lut = &state->lut[i]; + sda = &lut->sda; + + snprintf(lut->name, sizeof(lut->name), + "pwm1_auto_point%d_pwm", i + 1); + + sda->dev_attr.attr.mode = 0644; + sda->index = i; + sda->dev_attr.show = lut_show; + sda->dev_attr.store = lut_store; + sda->dev_attr.attr.name = lut->name; + + sysfs_attr_init(&sda->dev_attr.attr); + + state->attrs[i] = &sda->dev_attr.attr; + } + + state->attrs[i] = &dev_attr_pwm1_auto_point_temp_hyst.attr; + + state->group.attrs = state->attrs; + state->groups[0] = &state->group; +} + +static int max31760_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct max31760_state *state; + struct device *hwmon_dev; + int ret; + + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(state->regmap)) + return dev_err_probe(dev, + PTR_ERR(state->regmap), + "regmap initialization failed\n"); + + dev_set_drvdata(dev, state); + + /* Set alert output to comparator mode */ + ret = regmap_set_bits(state->regmap, REG_CR2, CR2_ALERTS); + if (ret) + return dev_err_probe(dev, ret, "cannot write register\n"); + + max31760_create_lut_nodes(state); + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + state, + &max31760_chip_info, + state->groups); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id max31760_of_match[] = { + {.compatible = "adi,max31760"}, + { } +}; +MODULE_DEVICE_TABLE(of, max31760_of_match); + +static const struct i2c_device_id max31760_id[] = { + {"max31760"}, + { } +}; +MODULE_DEVICE_TABLE(i2c, max31760_id); + +static int max31760_suspend(struct device *dev) +{ + struct max31760_state *state = dev_get_drvdata(dev); + + return regmap_set_bits(state->regmap, REG_CR2, CR2_STBY); +} + +static int max31760_resume(struct device *dev) +{ + struct max31760_state *state = dev_get_drvdata(dev); + + return regmap_clear_bits(state->regmap, REG_CR2, CR2_STBY); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(max31760_pm_ops, max31760_suspend, + max31760_resume); + +static struct i2c_driver max31760_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "max31760", + .of_match_table = max31760_of_match, + .pm = pm_ptr(&max31760_pm_ops) + }, + .probe_new = max31760_probe, + .id_table = max31760_id +}; +module_i2c_driver(max31760_driver); + +MODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>"); +MODULE_DESCRIPTION("Analog Devices MAX31760 Fan Speed Controller"); +MODULE_SOFTDEP("pre: regmap_i2c"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 7e9362f6dc29..20bf5ffadefe 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -202,6 +202,9 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel, } mutex_unlock(&data->update_lock); return 0; + case hwmon_fan_enable: + *val = !!(data->fan_config[channel] & MAX31790_FAN_CFG_TACH_INPUT_EN); + return 0; default: return -EOPNOTSUPP; } @@ -214,7 +217,7 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel, struct i2c_client *client = data->client; int target_count; int err = 0; - u8 bits; + u8 bits, fan_config; int sr; mutex_lock(&data->update_lock); @@ -243,6 +246,23 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel, MAX31790_REG_TARGET_COUNT(channel), data->target_count[channel]); break; + case hwmon_fan_enable: + fan_config = data->fan_config[channel]; + if (val == 0) { + fan_config &= ~MAX31790_FAN_CFG_TACH_INPUT_EN; + } else if (val == 1) { + fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN; + } else { + err = -EINVAL; + break; + } + if (fan_config != data->fan_config[channel]) { + err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel), + fan_config); + if (!err) + data->fan_config[channel] = fan_config; + } + break; default: err = -EOPNOTSUPP; break; @@ -270,6 +290,10 @@ static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel) !(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) return 0644; return 0; + case hwmon_fan_enable: + if (channel < NR_CHANNEL) + return 0644; + return 0; default: return 0; } @@ -423,12 +447,12 @@ static umode_t max31790_is_visible(const void *data, static const struct hwmon_channel_info *max31790_info[] = { HWMON_CHANNEL_INFO(fan, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE, HWMON_F_INPUT | HWMON_F_FAULT, HWMON_F_INPUT | HWMON_F_FAULT, HWMON_F_INPUT | HWMON_F_FAULT, diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 14bb7726f8d7..9b895402c80d 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -514,7 +514,7 @@ static int max6639_detect(struct i2c_client *client, if (dev_id != 0x58 || manu_id != 0x4D) return -ENODEV; - strlcpy(info->type, "max6639", I2C_NAME_SIZE); + strscpy(info->type, "max6639", I2C_NAME_SIZE); return 0; } @@ -571,7 +571,6 @@ static int max6639_probe(struct i2c_client *client) return PTR_ERR_OR_ZERO(hwmon_dev); } -#ifdef CONFIG_PM_SLEEP static int max6639_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -609,7 +608,6 @@ static int max6639_resume(struct device *dev) return i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG, ret & ~MAX6639_GCONFIG_STANDBY); } -#endif /* CONFIG_PM_SLEEP */ static const struct i2c_device_id max6639_id[] = { {"max6639", 0}, @@ -618,13 +616,13 @@ static const struct i2c_device_id max6639_id[] = { MODULE_DEVICE_TABLE(i2c, max6639_id); -static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume); static struct i2c_driver max6639_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "max6639", - .pm = &max6639_pm_ops, + .pm = pm_sleep_ptr(&max6639_pm_ops), }, .probe_new = max6639_probe, .id_table = max6639_id, diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c index 699d265aae2e..47ea34ff78f3 100644 --- a/drivers/hwmon/max6642.c +++ b/drivers/hwmon/max6642.c @@ -148,7 +148,7 @@ static int max6642_detect(struct i2c_client *client, if ((reg_status & 0x2b) != 0x00) return -ENODEV; - strlcpy(info->type, "max6642", I2C_NAME_SIZE); + strscpy(info->type, "max6642", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c index 9259779cc2df..394a4c7e46ab 100644 --- a/drivers/hwmon/mr75203.c +++ b/drivers/hwmon/mr75203.c @@ -9,6 +9,7 @@ */ #include <linux/bits.h> #include <linux/clk.h> +#include <linux/debugfs.h> #include <linux/hwmon.h> #include <linux/module.h> #include <linux/mod_devicetable.h> @@ -17,6 +18,7 @@ #include <linux/property.h> #include <linux/regmap.h> #include <linux/reset.h> +#include <linux/slab.h> #include <linux/units.h> /* PVT Common register */ @@ -30,6 +32,8 @@ #define CH_NUM_MSK GENMASK(31, 24) #define CH_NUM_SFT 24 +#define VM_NUM_MAX (VM_NUM_MSK >> VM_NUM_SFT) + /* Macro Common Register */ #define CLK_SYNTH 0x00 #define CLK_SYNTH_LO_SFT 0 @@ -99,13 +103,67 @@ #define PVT_POLL_DELAY_US 20 #define PVT_POLL_TIMEOUT_US 20000 -#define PVT_H_CONST 100000 -#define PVT_CAL5_CONST 2047 -#define PVT_G_CONST 40000 #define PVT_CONV_BITS 10 #define PVT_N_CONST 90 #define PVT_R_CONST 245805 +#define PVT_TEMP_MIN_mC -40000 +#define PVT_TEMP_MAX_mC 125000 + +/* Temperature coefficients for series 5 */ +#define PVT_SERIES5_H_CONST 200000 +#define PVT_SERIES5_G_CONST 60000 +#define PVT_SERIES5_J_CONST -100 +#define PVT_SERIES5_CAL5_CONST 4094 + +/* Temperature coefficients for series 6 */ +#define PVT_SERIES6_H_CONST 249400 +#define PVT_SERIES6_G_CONST 57400 +#define PVT_SERIES6_J_CONST 0 +#define PVT_SERIES6_CAL5_CONST 4096 + +#define TEMPERATURE_SENSOR_SERIES_5 5 +#define TEMPERATURE_SENSOR_SERIES_6 6 + +#define PRE_SCALER_X1 1 +#define PRE_SCALER_X2 2 + +/** + * struct voltage_device - VM single input parameters. + * @vm_map: Map channel number to VM index. + * @ch_map: Map channel number to channel index. + * @pre_scaler: Pre scaler value (1 or 2) used to normalize the voltage output + * result. + * + * The structure provides mapping between channel-number (0..N-1) to VM-index + * (0..num_vm-1) and channel-index (0..ch_num-1) where N = num_vm * ch_num. + * It also provides normalization factor for the VM equation. + */ +struct voltage_device { + u32 vm_map; + u32 ch_map; + u32 pre_scaler; +}; + +/** + * struct voltage_channels - VM channel count. + * @total: Total number of channels in all VMs. + * @max: Maximum number of channels among all VMs. + * + * The structure provides channel count information across all VMs. + */ +struct voltage_channels { + u32 total; + u8 max; +}; + +struct temp_coeff { + u32 h; + u32 g; + u32 cal5; + s32 j; +}; + struct pvt_device { struct regmap *c_map; struct regmap *t_map; @@ -113,14 +171,74 @@ struct pvt_device { struct regmap *v_map; struct clk *clk; struct reset_control *rst; + struct dentry *dbgfs_dir; + struct voltage_device *vd; + struct voltage_channels vm_channels; + struct temp_coeff ts_coeff; u32 t_num; u32 p_num; u32 v_num; - u32 c_num; u32 ip_freq; - u8 *vm_idx; }; +static ssize_t pvt_ts_coeff_j_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct pvt_device *pvt = file->private_data; + unsigned int len; + char buf[13]; + + len = scnprintf(buf, sizeof(buf), "%d\n", pvt->ts_coeff.j); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t pvt_ts_coeff_j_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct pvt_device *pvt = file->private_data; + int ret; + + ret = kstrtos32_from_user(user_buf, count, 0, &pvt->ts_coeff.j); + if (ret) + return ret; + + return count; +} + +static const struct file_operations pvt_ts_coeff_j_fops = { + .read = pvt_ts_coeff_j_read, + .write = pvt_ts_coeff_j_write, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static void devm_pvt_ts_dbgfs_remove(void *data) +{ + struct pvt_device *pvt = (struct pvt_device *)data; + + debugfs_remove_recursive(pvt->dbgfs_dir); + pvt->dbgfs_dir = NULL; +} + +static int pvt_ts_dbgfs_create(struct pvt_device *pvt, struct device *dev) +{ + pvt->dbgfs_dir = debugfs_create_dir(dev_name(dev), NULL); + + debugfs_create_u32("ts_coeff_h", 0644, pvt->dbgfs_dir, + &pvt->ts_coeff.h); + debugfs_create_u32("ts_coeff_g", 0644, pvt->dbgfs_dir, + &pvt->ts_coeff.g); + debugfs_create_u32("ts_coeff_cal5", 0644, pvt->dbgfs_dir, + &pvt->ts_coeff.cal5); + debugfs_create_file("ts_coeff_j", 0644, pvt->dbgfs_dir, pvt, + &pvt_ts_coeff_j_fops); + + return devm_add_action_or_reset(dev, devm_pvt_ts_dbgfs_remove, pvt); +} + static umode_t pvt_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) { @@ -139,13 +257,28 @@ static umode_t pvt_is_visible(const void *data, enum hwmon_sensor_types type, return 0; } +static long pvt_calc_temp(struct pvt_device *pvt, u32 nbs) +{ + /* + * Convert the register value to degrees centigrade temperature: + * T = G + H * (n / cal5 - 0.5) + J * F + */ + struct temp_coeff *ts_coeff = &pvt->ts_coeff; + + s64 tmp = ts_coeff->g + + div_s64(ts_coeff->h * (s64)nbs, ts_coeff->cal5) - + ts_coeff->h / 2 + + div_s64(ts_coeff->j * (s64)pvt->ip_freq, HZ_PER_MHZ); + + return clamp_val(tmp, PVT_TEMP_MIN_mC, PVT_TEMP_MAX_mC); +} + static int pvt_read_temp(struct device *dev, u32 attr, int channel, long *val) { struct pvt_device *pvt = dev_get_drvdata(dev); struct regmap *t_map = pvt->t_map; u32 stat, nbs; int ret; - u64 tmp; switch (attr) { case hwmon_temp_input: @@ -157,7 +290,7 @@ static int pvt_read_temp(struct device *dev, u32 attr, int channel, long *val) return ret; ret = regmap_read(t_map, SDIF_DATA(channel), &nbs); - if(ret < 0) + if (ret < 0) return ret; nbs &= SAMPLE_DATA_MSK; @@ -166,9 +299,7 @@ static int pvt_read_temp(struct device *dev, u32 attr, int channel, long *val) * Convert the register value to * degrees centigrade temperature */ - tmp = nbs * PVT_H_CONST; - do_div(tmp, PVT_CAL5_CONST); - *val = tmp - PVT_G_CONST - pvt->ip_freq; + *val = pvt_calc_temp(pvt, nbs); return 0; default: @@ -180,15 +311,15 @@ static int pvt_read_in(struct device *dev, u32 attr, int channel, long *val) { struct pvt_device *pvt = dev_get_drvdata(dev); struct regmap *v_map = pvt->v_map; + u32 n, stat, pre_scaler; u8 vm_idx, ch_idx; - u32 n, stat; int ret; - if (channel >= pvt->v_num * pvt->c_num) + if (channel >= pvt->vm_channels.total) return -EINVAL; - vm_idx = pvt->vm_idx[channel / pvt->c_num]; - ch_idx = channel % pvt->c_num; + vm_idx = pvt->vd[channel].vm_map; + ch_idx = pvt->vd[channel].ch_map; switch (attr) { case hwmon_in_input: @@ -200,10 +331,11 @@ static int pvt_read_in(struct device *dev, u32 attr, int channel, long *val) return ret; ret = regmap_read(v_map, VM_SDIF_DATA(vm_idx, ch_idx), &n); - if(ret < 0) + if (ret < 0) return ret; n &= SAMPLE_DATA_MSK; + pre_scaler = pvt->vd[channel].pre_scaler; /* * Convert the N bitstream count into voltage. * To support negative voltage calculation for 64bit machines @@ -215,7 +347,8 @@ static int pvt_read_in(struct device *dev, u32 attr, int channel, long *val) * BIT(x) may not be used instead of (1 << x) because it's * unsigned. */ - *val = (PVT_N_CONST * (long)n - PVT_R_CONST) / (1 << PVT_CONV_BITS); + *val = pre_scaler * (PVT_N_CONST * (long)n - PVT_R_CONST) / + (1 << PVT_CONV_BITS); return 0; default: @@ -290,23 +423,23 @@ static int pvt_init(struct pvt_device *pvt) (key >> 1) << CLK_SYNTH_HI_SFT | (key >> 1) << CLK_SYNTH_HOLD_SFT | CLK_SYNTH_EN; - pvt->ip_freq = sys_freq * 100 / (key + 2); + pvt->ip_freq = clk_get_rate(pvt->clk) / (key + 2); if (t_num) { ret = regmap_write(t_map, SDIF_SMPL_CTRL, 0x0); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_write(t_map, SDIF_HALT, 0x0); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_write(t_map, CLK_SYNTH, clk_synth); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_write(t_map, SDIF_DISABLE, 0x0); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_read_poll_timeout(t_map, SDIF_STAT, @@ -319,7 +452,7 @@ static int pvt_init(struct pvt_device *pvt) val = CFG0_MODE_2 | CFG0_PARALLEL_OUT | CFG0_12_BIT | IP_CFG << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; ret = regmap_write(t_map, SDIF_W, val); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_read_poll_timeout(t_map, SDIF_STAT, @@ -332,7 +465,7 @@ static int pvt_init(struct pvt_device *pvt) val = POWER_DELAY_CYCLE_256 | IP_TMR << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; ret = regmap_write(t_map, SDIF_W, val); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_read_poll_timeout(t_map, SDIF_STAT, @@ -346,39 +479,39 @@ static int pvt_init(struct pvt_device *pvt) IP_CTRL << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; ret = regmap_write(t_map, SDIF_W, val); - if(ret < 0) + if (ret < 0) return ret; } if (p_num) { ret = regmap_write(p_map, SDIF_HALT, 0x0); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_write(p_map, SDIF_DISABLE, BIT(p_num) - 1); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_write(p_map, CLK_SYNTH, clk_synth); - if(ret < 0) + if (ret < 0) return ret; } if (v_num) { ret = regmap_write(v_map, SDIF_SMPL_CTRL, 0x0); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_write(v_map, SDIF_HALT, 0x0); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_write(v_map, CLK_SYNTH, clk_synth); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_write(v_map, SDIF_DISABLE, 0x0); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_read_poll_timeout(v_map, SDIF_STAT, @@ -388,7 +521,7 @@ static int pvt_init(struct pvt_device *pvt) if (ret) return ret; - val = (BIT(pvt->c_num) - 1) | VM_CH_INIT | + val = (BIT(pvt->vm_channels.max) - 1) | VM_CH_INIT | IP_POLL << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; ret = regmap_write(v_map, SDIF_W, val); if (ret < 0) @@ -405,7 +538,7 @@ static int pvt_init(struct pvt_device *pvt) CFG1_14_BIT | IP_CFG << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; ret = regmap_write(v_map, SDIF_W, val); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_read_poll_timeout(v_map, SDIF_STAT, @@ -418,7 +551,7 @@ static int pvt_init(struct pvt_device *pvt) val = POWER_DELAY_CYCLE_64 | IP_TMR << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; ret = regmap_write(v_map, SDIF_W, val); - if(ret < 0) + if (ret < 0) return ret; ret = regmap_read_poll_timeout(v_map, SDIF_STAT, @@ -432,7 +565,7 @@ static int pvt_init(struct pvt_device *pvt) IP_CTRL << SDIF_ADDR_SFT | SDIF_WRN_W | SDIF_PROG; ret = regmap_write(v_map, SDIF_W, val); - if(ret < 0) + if (ret < 0) return ret; } @@ -477,40 +610,157 @@ static int pvt_get_regmap(struct platform_device *pdev, char *reg_name, return 0; } -static void pvt_clk_disable(void *data) +static void pvt_reset_control_assert(void *data) { struct pvt_device *pvt = data; - clk_disable_unprepare(pvt->clk); + reset_control_assert(pvt->rst); } -static int pvt_clk_enable(struct device *dev, struct pvt_device *pvt) +static int pvt_reset_control_deassert(struct device *dev, struct pvt_device *pvt) { int ret; - ret = clk_prepare_enable(pvt->clk); + ret = reset_control_deassert(pvt->rst); if (ret) return ret; - return devm_add_action_or_reset(dev, pvt_clk_disable, pvt); + return devm_add_action_or_reset(dev, pvt_reset_control_assert, pvt); } -static void pvt_reset_control_assert(void *data) +static int pvt_get_active_channel(struct device *dev, struct pvt_device *pvt, + u32 vm_num, u32 ch_num, u8 *vm_idx) { - struct pvt_device *pvt = data; + u8 vm_active_ch[VM_NUM_MAX]; + int ret, i, j, k; - reset_control_assert(pvt->rst); + ret = device_property_read_u8_array(dev, "moortec,vm-active-channels", + vm_active_ch, vm_num); + if (ret) { + /* + * Incase "moortec,vm-active-channels" property is not defined, + * we assume each VM sensor has all of its channels active. + */ + memset(vm_active_ch, ch_num, vm_num); + pvt->vm_channels.max = ch_num; + pvt->vm_channels.total = ch_num * vm_num; + } else { + for (i = 0; i < vm_num; i++) { + if (vm_active_ch[i] > ch_num) { + dev_err(dev, "invalid active channels: %u\n", + vm_active_ch[i]); + return -EINVAL; + } + + pvt->vm_channels.total += vm_active_ch[i]; + + if (vm_active_ch[i] > pvt->vm_channels.max) + pvt->vm_channels.max = vm_active_ch[i]; + } + } + + /* + * Map between the channel-number to VM-index and channel-index. + * Example - 3 VMs, "moortec,vm_active_ch" = <5 2 4>: + * vm_map = [0 0 0 0 0 1 1 2 2 2 2] + * ch_map = [0 1 2 3 4 0 1 0 1 2 3] + */ + pvt->vd = devm_kcalloc(dev, pvt->vm_channels.total, sizeof(*pvt->vd), + GFP_KERNEL); + if (!pvt->vd) + return -ENOMEM; + + k = 0; + for (i = 0; i < vm_num; i++) { + for (j = 0; j < vm_active_ch[i]; j++) { + pvt->vd[k].vm_map = vm_idx[i]; + pvt->vd[k].ch_map = j; + k++; + } + } + + return 0; } -static int pvt_reset_control_deassert(struct device *dev, struct pvt_device *pvt) +static int pvt_get_pre_scaler(struct device *dev, struct pvt_device *pvt) +{ + u8 *pre_scaler_ch_list; + int i, ret, num_ch; + u32 channel; + + /* Set default pre-scaler value to be 1. */ + for (i = 0; i < pvt->vm_channels.total; i++) + pvt->vd[i].pre_scaler = PRE_SCALER_X1; + + /* Get number of channels configured in "moortec,vm-pre-scaler-x2". */ + num_ch = device_property_count_u8(dev, "moortec,vm-pre-scaler-x2"); + if (num_ch <= 0) + return 0; + + pre_scaler_ch_list = kcalloc(num_ch, sizeof(*pre_scaler_ch_list), + GFP_KERNEL); + if (!pre_scaler_ch_list) + return -ENOMEM; + + /* Get list of all channels that have pre-scaler of 2. */ + ret = device_property_read_u8_array(dev, "moortec,vm-pre-scaler-x2", + pre_scaler_ch_list, num_ch); + if (ret) + goto out; + + for (i = 0; i < num_ch; i++) { + channel = pre_scaler_ch_list[i]; + pvt->vd[channel].pre_scaler = PRE_SCALER_X2; + } + +out: + kfree(pre_scaler_ch_list); + + return ret; +} + +static int pvt_set_temp_coeff(struct device *dev, struct pvt_device *pvt) { + struct temp_coeff *ts_coeff = &pvt->ts_coeff; + u32 series; int ret; - ret = reset_control_deassert(pvt->rst); + /* Incase ts-series property is not defined, use default 5. */ + ret = device_property_read_u32(dev, "moortec,ts-series", &series); if (ret) - return ret; + series = TEMPERATURE_SENSOR_SERIES_5; + + switch (series) { + case TEMPERATURE_SENSOR_SERIES_5: + ts_coeff->h = PVT_SERIES5_H_CONST; + ts_coeff->g = PVT_SERIES5_G_CONST; + ts_coeff->j = PVT_SERIES5_J_CONST; + ts_coeff->cal5 = PVT_SERIES5_CAL5_CONST; + break; + case TEMPERATURE_SENSOR_SERIES_6: + ts_coeff->h = PVT_SERIES6_H_CONST; + ts_coeff->g = PVT_SERIES6_G_CONST; + ts_coeff->j = PVT_SERIES6_J_CONST; + ts_coeff->cal5 = PVT_SERIES6_CAL5_CONST; + break; + default: + dev_err(dev, "invalid temperature sensor series (%u)\n", + series); + return -EINVAL; + } - return devm_add_action_or_reset(dev, pvt_reset_control_assert, pvt); + dev_dbg(dev, "temperature sensor series = %u\n", series); + + /* Override ts-coeff-h/g/j/cal5 if they are defined. */ + device_property_read_u32(dev, "moortec,ts-coeff-h", &ts_coeff->h); + device_property_read_u32(dev, "moortec,ts-coeff-g", &ts_coeff->g); + device_property_read_u32(dev, "moortec,ts-coeff-j", &ts_coeff->j); + device_property_read_u32(dev, "moortec,ts-coeff-cal5", &ts_coeff->cal5); + + dev_dbg(dev, "ts-coeff: h = %u, g = %u, j = %d, cal5 = %u\n", + ts_coeff->h, ts_coeff->g, ts_coeff->j, ts_coeff->cal5); + + return 0; } static int mr75203_probe(struct platform_device *pdev) @@ -531,27 +781,24 @@ static int mr75203_probe(struct platform_device *pdev) if (ret) return ret; - pvt->clk = devm_clk_get(dev, NULL); + pvt->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(pvt->clk)) return dev_err_probe(dev, PTR_ERR(pvt->clk), "failed to get clock\n"); - ret = pvt_clk_enable(dev, pvt); - if (ret) { - dev_err(dev, "failed to enable clock\n"); - return ret; - } - - pvt->rst = devm_reset_control_get_exclusive(dev, NULL); + pvt->rst = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(pvt->rst)) return dev_err_probe(dev, PTR_ERR(pvt->rst), "failed to get reset control\n"); - ret = pvt_reset_control_deassert(dev, pvt); - if (ret) - return dev_err_probe(dev, ret, "cannot deassert reset control\n"); + if (pvt->rst) { + ret = pvt_reset_control_deassert(dev, pvt); + if (ret) + return dev_err_probe(dev, ret, + "cannot deassert reset control\n"); + } ret = regmap_read(pvt->c_map, PVT_IP_CONFIG, &val); - if(ret < 0) + if (ret < 0) return ret; ts_num = (val & TS_NUM_MSK) >> TS_NUM_SFT; @@ -561,7 +808,6 @@ static int mr75203_probe(struct platform_device *pdev) pvt->t_num = ts_num; pvt->p_num = pd_num; pvt->v_num = vm_num; - pvt->c_num = ch_num; val = 0; if (ts_num) val++; @@ -581,6 +827,10 @@ static int mr75203_probe(struct platform_device *pdev) if (ret) return ret; + ret = pvt_set_temp_coeff(dev, pvt); + if (ret) + return ret; + temp_config = devm_kcalloc(dev, ts_num + 1, sizeof(*temp_config), GFP_KERNEL); if (!temp_config) @@ -589,6 +839,8 @@ static int mr75203_probe(struct platform_device *pdev) memset32(temp_config, HWMON_T_INPUT, ts_num); pvt_temp.config = temp_config; pvt_info[index++] = &pvt_temp; + + pvt_ts_dbgfs_create(pvt, dev); } if (pd_num) { @@ -598,44 +850,45 @@ static int mr75203_probe(struct platform_device *pdev) } if (vm_num) { - u32 total_ch; + u8 vm_idx[VM_NUM_MAX]; ret = pvt_get_regmap(pdev, "vm", pvt); if (ret) return ret; - pvt->vm_idx = devm_kcalloc(dev, vm_num, sizeof(*pvt->vm_idx), - GFP_KERNEL); - if (!pvt->vm_idx) - return -ENOMEM; - - ret = device_property_read_u8_array(dev, "intel,vm-map", - pvt->vm_idx, vm_num); + ret = device_property_read_u8_array(dev, "intel,vm-map", vm_idx, + vm_num); if (ret) { /* * Incase intel,vm-map property is not defined, we * assume incremental channel numbers. */ for (i = 0; i < vm_num; i++) - pvt->vm_idx[i] = i; + vm_idx[i] = i; } else { for (i = 0; i < vm_num; i++) - if (pvt->vm_idx[i] >= vm_num || - pvt->vm_idx[i] == 0xff) { + if (vm_idx[i] >= vm_num || vm_idx[i] == 0xff) { pvt->v_num = i; vm_num = i; break; } } - total_ch = ch_num * vm_num; - in_config = devm_kcalloc(dev, total_ch + 1, + ret = pvt_get_active_channel(dev, pvt, vm_num, ch_num, vm_idx); + if (ret) + return ret; + + ret = pvt_get_pre_scaler(dev, pvt); + if (ret) + return ret; + + in_config = devm_kcalloc(dev, pvt->vm_channels.total + 1, sizeof(*in_config), GFP_KERNEL); if (!in_config) return -ENOMEM; - memset32(in_config, HWMON_I_INPUT, total_ch); - in_config[total_ch] = 0; + memset32(in_config, HWMON_I_INPUT, pvt->vm_channels.total); + in_config[pvt->vm_channels.total] = 0; pvt_in.config = in_config; pvt_info[index++] = &pvt_in; diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index 6a9f420e7d32..a872f783e9cc 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -412,7 +412,7 @@ nct6683_create_attr_group(struct device *dev, struct sensor_device_attr_u *su; struct attribute_group *group; struct attribute **attrs; - int i, j, count; + int i, count; if (repeat <= 0) return ERR_PTR(-EINVAL); @@ -443,7 +443,7 @@ nct6683_create_attr_group(struct device *dev, for (i = 0; i < repeat; i++) { t = tg->templates; - for (j = 0; *t != NULL; j++) { + while (*t) { snprintf(su->name, sizeof(su->name), (*t)->dev_attr.attr.name, tg->base + i); if ((*t)->s2) { diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index 41c97cfacfb8..b34783784213 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -355,7 +355,7 @@ static void nct6791_enable_io_mapping(struct nct6775_sio_data *sio_data) } } -static int __maybe_unused nct6775_suspend(struct device *dev) +static int nct6775_suspend(struct device *dev) { int err; u16 tmp; @@ -386,7 +386,7 @@ out: return err; } -static int __maybe_unused nct6775_resume(struct device *dev) +static int nct6775_resume(struct device *dev) { struct nct6775_data *data = dev_get_drvdata(dev); struct nct6775_sio_data *sio_data = dev_get_platdata(dev); @@ -467,7 +467,7 @@ abort: return err; } -static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume); static void nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio_data) @@ -934,7 +934,7 @@ static int nct6775_platform_probe(struct platform_device *pdev) static struct platform_driver nct6775_driver = { .driver = { .name = DRVNAME, - .pm = &nct6775_dev_pm_ops, + .pm = pm_sleep_ptr(&nct6775_dev_pm_ops), }, .probe = nct6775_platform_probe, }; diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index d1eeef02b6dc..a175f8283695 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -1038,7 +1038,7 @@ static int nct7802_detect(struct i2c_client *client, if (reg < 0 || (reg & 0x3f)) return -ENODEV; - strlcpy(info->type, "nct7802", I2C_NAME_SIZE); + strscpy(info->type, "nct7802", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index b1c837fc407a..ecc5db0011a3 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c @@ -798,7 +798,7 @@ static int nct7904_detect(struct i2c_client *client, (i2c_smbus_read_byte_data(client, BANK_SEL_REG) & 0xf8) != 0x00) return -ENODEV; - strlcpy(info->type, "nct7904", I2C_NAME_SIZE); + strscpy(info->type, "nct7904", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c index dd892ff5a3e8..533f38b0b4e9 100644 --- a/drivers/hwmon/nzxt-smart2.c +++ b/drivers/hwmon/nzxt-smart2.c @@ -787,6 +787,7 @@ static void nzxt_smart2_hid_remove(struct hid_device *hdev) static const struct hid_device_id nzxt_smart2_hid_id_table[] = { { HID_USB_DEVICE(0x1e71, 0x2006) }, /* NZXT Smart Device V2 */ { HID_USB_DEVICE(0x1e71, 0x200d) }, /* NZXT Smart Device V2 */ + { HID_USB_DEVICE(0x1e71, 0x200f) }, /* NZXT Smart Device V2 */ { HID_USB_DEVICE(0x1e71, 0x2009) }, /* NZXT RGB & Fan Controller */ { HID_USB_DEVICE(0x1e71, 0x200e) }, /* NZXT RGB & Fan Controller */ { HID_USB_DEVICE(0x1e71, 0x2010) }, /* NZXT RGB & Fan Controller */ diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 0828436a1f6c..a4adc8bd531f 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -35,6 +35,18 @@ #include <linux/acpi.h> #include <linux/io.h> +#define DRIVER_NAME "pc87360" + +/* (temp & vin) channel conversion status register flags (pdf sec.11.5.12) */ +#define CHAN_CNVRTD 0x80 /* new data ready */ +#define CHAN_ENA 0x01 /* enabled channel (temp or vin) */ +#define CHAN_ALM_ENA 0x10 /* propagate to alarms-reg ?? (chk val!) */ +#define CHAN_READY (CHAN_ENA|CHAN_CNVRTD) /* sample ready mask */ + +#define TEMP_OTS_OE 0x20 /* OTS Output Enable */ +#define VIN_RW1C_MASK (CHAN_READY|CHAN_ALM_MAX|CHAN_ALM_MIN) /* 0x87 */ +#define TEMP_RW1C_MASK (VIN_RW1C_MASK|TEMP_ALM_CRIT|TEMP_FAULT) /* 0xCF */ + static u8 devid; static struct platform_device *pdev; static unsigned short extra_isa[3]; @@ -211,183 +223,181 @@ struct pc87360_data { }; /* - * Functions declaration + * ldi is the logical device index + * bank is for voltages and temperatures only */ - -static int pc87360_probe(struct platform_device *pdev); -static int pc87360_remove(struct platform_device *pdev); - static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg); -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value); -static void pc87360_init_device(struct platform_device *pdev, - int use_thermistors); -static struct pc87360_data *pc87360_update_device(struct device *dev); - -/* - * Driver data - */ - -static struct platform_driver pc87360_driver = { - .driver = { - .name = "pc87360", - }, - .probe = pc87360_probe, - .remove = pc87360_remove, -}; + u8 reg) +{ + int res; -/* - * Sysfs stuff - */ + mutex_lock(&(data->lock)); + if (bank != NO_BANK) + outb_p(bank, data->address[ldi] + PC87365_REG_BANK); + res = inb_p(data->address[ldi] + reg); + mutex_unlock(&(data->lock)); -static ssize_t fan_input_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index], - FAN_DIV_FROM_REG(data->fan_status[attr->index]))); -} -static ssize_t fan_min_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index], - FAN_DIV_FROM_REG(data->fan_status[attr->index]))); -} -static ssize_t fan_div_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", - FAN_DIV_FROM_REG(data->fan_status[attr->index])); + return res; } -static ssize_t fan_status_show(struct device *dev, - struct device_attribute *devattr, char *buf) + +static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg, u8 value) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", - FAN_STATUS_FROM_REG(data->fan_status[attr->index])); + mutex_lock(&(data->lock)); + if (bank != NO_BANK) + outb_p(bank, data->address[ldi] + PC87365_REG_BANK); + outb_p(value, data->address[ldi] + reg); + mutex_unlock(&(data->lock)); } -static ssize_t fan_min_store(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) + +static void pc87360_autodiv(struct device *dev, int nr) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long fan_min; - int err; - - err = kstrtol(buf, 10, &fan_min); - if (err) - return err; - - mutex_lock(&data->update_lock); - fan_min = FAN_TO_REG(fan_min, - FAN_DIV_FROM_REG(data->fan_status[attr->index])); + u8 old_min = data->fan_min[nr]; - /* If it wouldn't fit, change clock divisor */ - while (fan_min > 255 - && (data->fan_status[attr->index] & 0x60) != 0x60) { - fan_min >>= 1; - data->fan[attr->index] >>= 1; - data->fan_status[attr->index] += 0x20; + /* Increase clock divider if needed and possible */ + if ((data->fan_status[nr] & 0x04) /* overflow flag */ + || (data->fan[nr] >= 224)) { /* next to overflow */ + if ((data->fan_status[nr] & 0x60) != 0x60) { + data->fan_status[nr] += 0x20; + data->fan_min[nr] >>= 1; + data->fan[nr] >>= 1; + dev_dbg(dev, + "Increasing clock divider to %d for fan %d\n", + FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1); + } + } else { + /* Decrease clock divider if possible */ + while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */ + && data->fan[nr] < 85 /* bad accuracy */ + && (data->fan_status[nr] & 0x60) != 0x00) { + data->fan_status[nr] -= 0x20; + data->fan_min[nr] <<= 1; + data->fan[nr] <<= 1; + dev_dbg(dev, + "Decreasing clock divider to %d for fan %d\n", + FAN_DIV_FROM_REG(data->fan_status[nr]), + nr + 1); + } } - data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min; - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(attr->index), - data->fan_min[attr->index]); - - /* Write new divider, preserve alarm bits */ - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(attr->index), - data->fan_status[attr->index] & 0xF9); - mutex_unlock(&data->update_lock); - - return count; -} -static struct sensor_device_attribute fan_input[] = { - SENSOR_ATTR_RO(fan1_input, fan_input, 0), - SENSOR_ATTR_RO(fan2_input, fan_input, 1), - SENSOR_ATTR_RO(fan3_input, fan_input, 2), -}; -static struct sensor_device_attribute fan_status[] = { - SENSOR_ATTR_RO(fan1_status, fan_status, 0), - SENSOR_ATTR_RO(fan2_status, fan_status, 1), - SENSOR_ATTR_RO(fan3_status, fan_status, 2), -}; -static struct sensor_device_attribute fan_div[] = { - SENSOR_ATTR_RO(fan1_div, fan_div, 0), - SENSOR_ATTR_RO(fan2_div, fan_div, 1), - SENSOR_ATTR_RO(fan3_div, fan_div, 2), -}; -static struct sensor_device_attribute fan_min[] = { - SENSOR_ATTR_RW(fan1_min, fan_min, 0), - SENSOR_ATTR_RW(fan2_min, fan_min, 1), - SENSOR_ATTR_RW(fan3_min, fan_min, 2), -}; - -#define FAN_UNIT_ATTRS(X) \ -{ &fan_input[X].dev_attr.attr, \ - &fan_status[X].dev_attr.attr, \ - &fan_div[X].dev_attr.attr, \ - &fan_min[X].dev_attr.attr, \ - NULL \ + /* Write new fan min if it changed */ + if (old_min != data->fan_min[nr]) { + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_MIN(nr), + data->fan_min[nr]); + } } -static ssize_t pwm_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", - PWM_FROM_REG(data->pwm[attr->index], - FAN_CONFIG_INVERT(data->fan_conf, - attr->index))); -} -static ssize_t pwm_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +static struct pc87360_data *pc87360_update_device(struct device *dev) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val; - int err; - - err = kstrtol(buf, 10, &val); - if (err) - return err; + u8 i; mutex_lock(&data->update_lock); - data->pwm[attr->index] = PWM_TO_REG(val, - FAN_CONFIG_INVERT(data->fan_conf, attr->index)); - pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index), - data->pwm[attr->index]); - mutex_unlock(&data->update_lock); - return count; -} -static struct sensor_device_attribute pwm[] = { - SENSOR_ATTR_RW(pwm1, pwm, 0), - SENSOR_ATTR_RW(pwm2, pwm, 1), - SENSOR_ATTR_RW(pwm3, pwm, 2), -}; + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + dev_dbg(dev, "Data update\n"); -static struct attribute *pc8736x_fan_attr[][5] = { - FAN_UNIT_ATTRS(0), - FAN_UNIT_ATTRS(1), - FAN_UNIT_ATTRS(2) -}; + /* Fans */ + for (i = 0; i < data->fannr; i++) { + if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { + data->fan_status[i] = + pc87360_read_value(data, LD_FAN, + NO_BANK, PC87360_REG_FAN_STATUS(i)); + data->fan[i] = pc87360_read_value(data, LD_FAN, + NO_BANK, PC87360_REG_FAN(i)); + data->fan_min[i] = pc87360_read_value(data, + LD_FAN, NO_BANK, + PC87360_REG_FAN_MIN(i)); + /* Change clock divider if needed */ + pc87360_autodiv(dev, i); + /* Clear bits and write new divider */ + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_STATUS(i), + data->fan_status[i]); + } + if (FAN_CONFIG_CONTROL(data->fan_conf, i)) + data->pwm[i] = pc87360_read_value(data, LD_FAN, + NO_BANK, PC87360_REG_PWM(i)); + } -static const struct attribute_group pc8736x_fan_attr_group[] = { - { .attrs = pc8736x_fan_attr[0], }, - { .attrs = pc8736x_fan_attr[1], }, - { .attrs = pc8736x_fan_attr[2], }, -}; + /* Voltages */ + for (i = 0; i < data->innr; i++) { + data->in_status[i] = pc87360_read_value(data, LD_IN, i, + PC87365_REG_IN_STATUS); + /* Clear bits */ + pc87360_write_value(data, LD_IN, i, + PC87365_REG_IN_STATUS, + data->in_status[i]); + if ((data->in_status[i] & CHAN_READY) == CHAN_READY) { + data->in[i] = pc87360_read_value(data, LD_IN, + i, PC87365_REG_IN); + } + if (data->in_status[i] & CHAN_ENA) { + data->in_min[i] = pc87360_read_value(data, + LD_IN, i, + PC87365_REG_IN_MIN); + data->in_max[i] = pc87360_read_value(data, + LD_IN, i, + PC87365_REG_IN_MAX); + if (i >= 11) + data->in_crit[i-11] = + pc87360_read_value(data, LD_IN, + i, PC87365_REG_TEMP_CRIT); + } + } + if (data->innr) { + data->in_alarms = pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_IN_ALARMS1) + | ((pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_IN_ALARMS2) + & 0x07) << 8); + data->vid = (data->vid_conf & 0xE0) ? + pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_VID) : 0x1F; + } + + /* Temperatures */ + for (i = 0; i < data->tempnr; i++) { + data->temp_status[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_STATUS); + /* Clear bits */ + pc87360_write_value(data, LD_TEMP, i, + PC87365_REG_TEMP_STATUS, + data->temp_status[i]); + if ((data->temp_status[i] & CHAN_READY) == CHAN_READY) { + data->temp[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP); + } + if (data->temp_status[i] & CHAN_ENA) { + data->temp_min[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_MIN); + data->temp_max[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_MAX); + data->temp_crit[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_CRIT); + } + } + if (data->tempnr) { + data->temp_alarms = pc87360_read_value(data, LD_TEMP, + NO_BANK, PC87365_REG_TEMP_ALARMS) + & 0x3F; + } + + data->last_updated = jiffies; + data->valid = true; + } + + mutex_unlock(&data->update_lock); + + return data; +} static ssize_t in_input_show(struct device *dev, struct device_attribute *devattr, char *buf) @@ -397,29 +407,52 @@ static ssize_t in_input_show(struct device *dev, return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index], data->in_vref)); } -static ssize_t in_min_show(struct device *dev, - struct device_attribute *devattr, char *buf) + +static struct sensor_device_attribute in_input[] = { + SENSOR_ATTR_RO(in0_input, in_input, 0), + SENSOR_ATTR_RO(in1_input, in_input, 1), + SENSOR_ATTR_RO(in2_input, in_input, 2), + SENSOR_ATTR_RO(in3_input, in_input, 3), + SENSOR_ATTR_RO(in4_input, in_input, 4), + SENSOR_ATTR_RO(in5_input, in_input, 5), + SENSOR_ATTR_RO(in6_input, in_input, 6), + SENSOR_ATTR_RO(in7_input, in_input, 7), + SENSOR_ATTR_RO(in8_input, in_input, 8), + SENSOR_ATTR_RO(in9_input, in_input, 9), + SENSOR_ATTR_RO(in10_input, in_input, 10), +}; + +static ssize_t in_status_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index], - data->in_vref)); + return sprintf(buf, "%u\n", data->in_status[attr->index]); } -static ssize_t in_max_show(struct device *dev, + +static struct sensor_device_attribute in_status[] = { + SENSOR_ATTR_RO(in0_status, in_status, 0), + SENSOR_ATTR_RO(in1_status, in_status, 1), + SENSOR_ATTR_RO(in2_status, in_status, 2), + SENSOR_ATTR_RO(in3_status, in_status, 3), + SENSOR_ATTR_RO(in4_status, in_status, 4), + SENSOR_ATTR_RO(in5_status, in_status, 5), + SENSOR_ATTR_RO(in6_status, in_status, 6), + SENSOR_ATTR_RO(in7_status, in_status, 7), + SENSOR_ATTR_RO(in8_status, in_status, 8), + SENSOR_ATTR_RO(in9_status, in_status, 9), + SENSOR_ATTR_RO(in10_status, in_status, 10), +}; + +static ssize_t in_min_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index], + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index], data->in_vref)); } -static ssize_t in_status_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->in_status[attr->index]); -} + static ssize_t in_min_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) @@ -440,6 +473,30 @@ static ssize_t in_min_store(struct device *dev, mutex_unlock(&data->update_lock); return count; } + +static struct sensor_device_attribute in_min[] = { + SENSOR_ATTR_RW(in0_min, in_min, 0), + SENSOR_ATTR_RW(in1_min, in_min, 1), + SENSOR_ATTR_RW(in2_min, in_min, 2), + SENSOR_ATTR_RW(in3_min, in_min, 3), + SENSOR_ATTR_RW(in4_min, in_min, 4), + SENSOR_ATTR_RW(in5_min, in_min, 5), + SENSOR_ATTR_RW(in6_min, in_min, 6), + SENSOR_ATTR_RW(in7_min, in_min, 7), + SENSOR_ATTR_RW(in8_min, in_min, 8), + SENSOR_ATTR_RW(in9_min, in_min, 9), + SENSOR_ATTR_RW(in10_min, in_min, 10), +}; + +static ssize_t in_max_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index], + data->in_vref)); +} + static ssize_t in_max_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) @@ -462,45 +519,6 @@ static ssize_t in_max_store(struct device *dev, return count; } -static struct sensor_device_attribute in_input[] = { - SENSOR_ATTR_RO(in0_input, in_input, 0), - SENSOR_ATTR_RO(in1_input, in_input, 1), - SENSOR_ATTR_RO(in2_input, in_input, 2), - SENSOR_ATTR_RO(in3_input, in_input, 3), - SENSOR_ATTR_RO(in4_input, in_input, 4), - SENSOR_ATTR_RO(in5_input, in_input, 5), - SENSOR_ATTR_RO(in6_input, in_input, 6), - SENSOR_ATTR_RO(in7_input, in_input, 7), - SENSOR_ATTR_RO(in8_input, in_input, 8), - SENSOR_ATTR_RO(in9_input, in_input, 9), - SENSOR_ATTR_RO(in10_input, in_input, 10), -}; -static struct sensor_device_attribute in_status[] = { - SENSOR_ATTR_RO(in0_status, in_status, 0), - SENSOR_ATTR_RO(in1_status, in_status, 1), - SENSOR_ATTR_RO(in2_status, in_status, 2), - SENSOR_ATTR_RO(in3_status, in_status, 3), - SENSOR_ATTR_RO(in4_status, in_status, 4), - SENSOR_ATTR_RO(in5_status, in_status, 5), - SENSOR_ATTR_RO(in6_status, in_status, 6), - SENSOR_ATTR_RO(in7_status, in_status, 7), - SENSOR_ATTR_RO(in8_status, in_status, 8), - SENSOR_ATTR_RO(in9_status, in_status, 9), - SENSOR_ATTR_RO(in10_status, in_status, 10), -}; -static struct sensor_device_attribute in_min[] = { - SENSOR_ATTR_RW(in0_min, in_min, 0), - SENSOR_ATTR_RW(in1_min, in_min, 1), - SENSOR_ATTR_RW(in2_min, in_min, 2), - SENSOR_ATTR_RW(in3_min, in_min, 3), - SENSOR_ATTR_RW(in4_min, in_min, 4), - SENSOR_ATTR_RW(in5_min, in_min, 5), - SENSOR_ATTR_RW(in6_min, in_min, 6), - SENSOR_ATTR_RW(in7_min, in_min, 7), - SENSOR_ATTR_RW(in8_min, in_min, 8), - SENSOR_ATTR_RW(in9_min, in_min, 9), - SENSOR_ATTR_RW(in10_min, in_min, 10), -}; static struct sensor_device_attribute in_max[] = { SENSOR_ATTR_RW(in0_max, in_max, 0), SENSOR_ATTR_RW(in1_max, in_max, 1), @@ -534,14 +552,6 @@ static ssize_t in_min_alarm_show(struct device *dev, return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN)); } -static ssize_t in_max_alarm_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - unsigned nr = to_sensor_dev_attr(devattr)->index; - - return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX)); -} static struct sensor_device_attribute in_min_alarm[] = { SENSOR_ATTR_RO(in0_min_alarm, in_min_alarm, 0), @@ -556,6 +566,16 @@ static struct sensor_device_attribute in_min_alarm[] = { SENSOR_ATTR_RO(in9_min_alarm, in_min_alarm, 9), SENSOR_ATTR_RO(in10_min_alarm, in_min_alarm, 10), }; + +static ssize_t in_max_alarm_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + unsigned nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX)); +} + static struct sensor_device_attribute in_max_alarm[] = { SENSOR_ATTR_RO(in0_max_alarm, in_max_alarm, 0), SENSOR_ATTR_RO(in1_max_alarm, in_max_alarm, 1), @@ -592,6 +612,7 @@ static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, struct pc87360_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } + static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -648,37 +669,39 @@ static ssize_t therm_input_show(struct device *dev, return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index], data->in_vref)); } -static ssize_t therm_min_show(struct device *dev, - struct device_attribute *devattr, char *buf) + +/* + * the +11 term below reflects the fact that VLM units 11,12,13 are + * used in the chip to measure voltage across the thermistors + */ +static struct sensor_device_attribute therm_input[] = { + SENSOR_ATTR_RO(temp4_input, therm_input, 0 + 11), + SENSOR_ATTR_RO(temp5_input, therm_input, 1 + 11), + SENSOR_ATTR_RO(temp6_input, therm_input, 2 + 11), +}; + +static ssize_t therm_status_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index], - data->in_vref)); + return sprintf(buf, "%u\n", data->in_status[attr->index]); } -static ssize_t therm_max_show(struct device *dev, + +static struct sensor_device_attribute therm_status[] = { + SENSOR_ATTR_RO(temp4_status, therm_status, 0 + 11), + SENSOR_ATTR_RO(temp5_status, therm_status, 1 + 11), + SENSOR_ATTR_RO(temp6_status, therm_status, 2 + 11), +}; + +static ssize_t therm_min_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index], - data->in_vref)); -} -static ssize_t therm_crit_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11], + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index], data->in_vref)); } -static ssize_t therm_status_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->in_status[attr->index]); -} static ssize_t therm_min_store(struct device *dev, struct device_attribute *devattr, @@ -701,6 +724,21 @@ static ssize_t therm_min_store(struct device *dev, return count; } +static struct sensor_device_attribute therm_min[] = { + SENSOR_ATTR_RW(temp4_min, therm_min, 0 + 11), + SENSOR_ATTR_RW(temp5_min, therm_min, 1 + 11), + SENSOR_ATTR_RW(temp6_min, therm_min, 2 + 11), +}; + +static ssize_t therm_max_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index], + data->in_vref)); +} + static ssize_t therm_max_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) @@ -721,6 +759,22 @@ static ssize_t therm_max_store(struct device *dev, mutex_unlock(&data->update_lock); return count; } + +static struct sensor_device_attribute therm_max[] = { + SENSOR_ATTR_RW(temp4_max, therm_max, 0 + 11), + SENSOR_ATTR_RW(temp5_max, therm_max, 1 + 11), + SENSOR_ATTR_RW(temp6_max, therm_max, 2 + 11), +}; + +static ssize_t therm_crit_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11], + data->in_vref)); +} + static ssize_t therm_crit_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) @@ -742,30 +796,6 @@ static ssize_t therm_crit_store(struct device *dev, return count; } -/* - * the +11 term below reflects the fact that VLM units 11,12,13 are - * used in the chip to measure voltage across the thermistors - */ -static struct sensor_device_attribute therm_input[] = { - SENSOR_ATTR_RO(temp4_input, therm_input, 0 + 11), - SENSOR_ATTR_RO(temp5_input, therm_input, 1 + 11), - SENSOR_ATTR_RO(temp6_input, therm_input, 2 + 11), -}; -static struct sensor_device_attribute therm_status[] = { - SENSOR_ATTR_RO(temp4_status, therm_status, 0 + 11), - SENSOR_ATTR_RO(temp5_status, therm_status, 1 + 11), - SENSOR_ATTR_RO(temp6_status, therm_status, 2 + 11), -}; -static struct sensor_device_attribute therm_min[] = { - SENSOR_ATTR_RW(temp4_min, therm_min, 0 + 11), - SENSOR_ATTR_RW(temp5_min, therm_min, 1 + 11), - SENSOR_ATTR_RW(temp6_min, therm_min, 2 + 11), -}; -static struct sensor_device_attribute therm_max[] = { - SENSOR_ATTR_RW(temp4_max, therm_max, 0 + 11), - SENSOR_ATTR_RW(temp5_max, therm_max, 1 + 11), - SENSOR_ATTR_RW(temp6_max, therm_max, 2 + 11), -}; static struct sensor_device_attribute therm_crit[] = { SENSOR_ATTR_RW(temp4_crit, therm_crit, 0 + 11), SENSOR_ATTR_RW(temp5_crit, therm_crit, 1 + 11), @@ -776,7 +806,6 @@ static struct sensor_device_attribute therm_crit[] = { * show_therm_min/max_alarm() reads data from the per-channel voltage * status register (sec 11.5.12) */ - static ssize_t therm_min_alarm_show(struct device *dev, struct device_attribute *devattr, char *buf) @@ -786,6 +815,13 @@ static ssize_t therm_min_alarm_show(struct device *dev, return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN)); } + +static struct sensor_device_attribute therm_min_alarm[] = { + SENSOR_ATTR_RO(temp4_min_alarm, therm_min_alarm, 0 + 11), + SENSOR_ATTR_RO(temp5_min_alarm, therm_min_alarm, 1 + 11), + SENSOR_ATTR_RO(temp6_min_alarm, therm_min_alarm, 2 + 11), +}; + static ssize_t therm_max_alarm_show(struct device *dev, struct device_attribute *devattr, char *buf) @@ -795,6 +831,13 @@ static ssize_t therm_max_alarm_show(struct device *dev, return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX)); } + +static struct sensor_device_attribute therm_max_alarm[] = { + SENSOR_ATTR_RO(temp4_max_alarm, therm_max_alarm, 0 + 11), + SENSOR_ATTR_RO(temp5_max_alarm, therm_max_alarm, 1 + 11), + SENSOR_ATTR_RO(temp6_max_alarm, therm_max_alarm, 2 + 11), +}; + static ssize_t therm_crit_alarm_show(struct device *dev, struct device_attribute *devattr, char *buf) @@ -805,16 +848,6 @@ static ssize_t therm_crit_alarm_show(struct device *dev, return sprintf(buf, "%u\n", !!(data->in_status[nr] & TEMP_ALM_CRIT)); } -static struct sensor_device_attribute therm_min_alarm[] = { - SENSOR_ATTR_RO(temp4_min_alarm, therm_min_alarm, 0 + 11), - SENSOR_ATTR_RO(temp5_min_alarm, therm_min_alarm, 1 + 11), - SENSOR_ATTR_RO(temp6_min_alarm, therm_min_alarm, 2 + 11), -}; -static struct sensor_device_attribute therm_max_alarm[] = { - SENSOR_ATTR_RO(temp4_max_alarm, therm_max_alarm, 0 + 11), - SENSOR_ATTR_RO(temp5_max_alarm, therm_max_alarm, 1 + 11), - SENSOR_ATTR_RO(temp6_max_alarm, therm_max_alarm, 2 + 11), -}; static struct sensor_device_attribute therm_crit_alarm[] = { SENSOR_ATTR_RO(temp4_crit_alarm, therm_crit_alarm, 0 + 11), SENSOR_ATTR_RO(temp5_crit_alarm, therm_crit_alarm, 1 + 11), @@ -849,37 +882,32 @@ static ssize_t temp_input_show(struct device *dev, return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -static ssize_t temp_min_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index])); -} +static struct sensor_device_attribute temp_input[] = { + SENSOR_ATTR_RO(temp1_input, temp_input, 0), + SENSOR_ATTR_RO(temp2_input, temp_input, 1), + SENSOR_ATTR_RO(temp3_input, temp_input, 2), +}; -static ssize_t temp_max_show(struct device *dev, - struct device_attribute *devattr, char *buf) +static ssize_t temp_status_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index])); + return sprintf(buf, "%d\n", data->temp_status[attr->index]); } -static ssize_t temp_crit_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%d\n", - TEMP_FROM_REG(data->temp_crit[attr->index])); -} +static struct sensor_device_attribute temp_status[] = { + SENSOR_ATTR_RO(temp1_status, temp_status, 0), + SENSOR_ATTR_RO(temp2_status, temp_status, 1), + SENSOR_ATTR_RO(temp3_status, temp_status, 2), +}; -static ssize_t temp_status_show(struct device *dev, - struct device_attribute *devattr, char *buf) +static ssize_t temp_min_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%d\n", data->temp_status[attr->index]); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index])); } static ssize_t temp_min_store(struct device *dev, @@ -903,6 +931,20 @@ static ssize_t temp_min_store(struct device *dev, return count; } +static struct sensor_device_attribute temp_min[] = { + SENSOR_ATTR_RW(temp1_min, temp_min, 0), + SENSOR_ATTR_RW(temp2_min, temp_min, 1), + SENSOR_ATTR_RW(temp3_min, temp_min, 2), +}; + +static ssize_t temp_max_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index])); +} + static ssize_t temp_max_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) @@ -924,6 +966,21 @@ static ssize_t temp_max_store(struct device *dev, return count; } +static struct sensor_device_attribute temp_max[] = { + SENSOR_ATTR_RW(temp1_max, temp_max, 0), + SENSOR_ATTR_RW(temp2_max, temp_max, 1), + SENSOR_ATTR_RW(temp3_max, temp_max, 2), +}; + +static ssize_t temp_crit_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%d\n", + TEMP_FROM_REG(data->temp_crit[attr->index])); +} + static ssize_t temp_crit_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) @@ -945,47 +1002,17 @@ static ssize_t temp_crit_store(struct device *dev, return count; } -static struct sensor_device_attribute temp_input[] = { - SENSOR_ATTR_RO(temp1_input, temp_input, 0), - SENSOR_ATTR_RO(temp2_input, temp_input, 1), - SENSOR_ATTR_RO(temp3_input, temp_input, 2), -}; -static struct sensor_device_attribute temp_status[] = { - SENSOR_ATTR_RO(temp1_status, temp_status, 0), - SENSOR_ATTR_RO(temp2_status, temp_status, 1), - SENSOR_ATTR_RO(temp3_status, temp_status, 2), -}; -static struct sensor_device_attribute temp_min[] = { - SENSOR_ATTR_RW(temp1_min, temp_min, 0), - SENSOR_ATTR_RW(temp2_min, temp_min, 1), - SENSOR_ATTR_RW(temp3_min, temp_min, 2), -}; -static struct sensor_device_attribute temp_max[] = { - SENSOR_ATTR_RW(temp1_max, temp_max, 0), - SENSOR_ATTR_RW(temp2_max, temp_max, 1), - SENSOR_ATTR_RW(temp3_max, temp_max, 2), -}; static struct sensor_device_attribute temp_crit[] = { SENSOR_ATTR_RW(temp1_crit, temp_crit, 0), SENSOR_ATTR_RW(temp2_crit, temp_crit, 1), SENSOR_ATTR_RW(temp3_crit, temp_crit, 2), }; -static ssize_t alarms_temp_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->temp_alarms); -} - -static DEVICE_ATTR_RO(alarms_temp); - /* - * show_temp_min/max_alarm() reads data from the per-channel status + * temp_min/max_alarm_show() reads data from the per-channel status * register (sec 12.3.7), not the temp event status registers (sec * 12.3.2) that show_temp_alarm() reads (via data->temp_alarms) */ - static ssize_t temp_min_alarm_show(struct device *dev, struct device_attribute *devattr, char *buf) @@ -996,6 +1023,12 @@ static ssize_t temp_min_alarm_show(struct device *dev, return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MIN)); } +static struct sensor_device_attribute temp_min_alarm[] = { + SENSOR_ATTR_RO(temp1_min_alarm, temp_min_alarm, 0), + SENSOR_ATTR_RO(temp2_min_alarm, temp_min_alarm, 1), + SENSOR_ATTR_RO(temp3_min_alarm, temp_min_alarm, 2), +}; + static ssize_t temp_max_alarm_show(struct device *dev, struct device_attribute *devattr, char *buf) @@ -1006,6 +1039,12 @@ static ssize_t temp_max_alarm_show(struct device *dev, return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MAX)); } +static struct sensor_device_attribute temp_max_alarm[] = { + SENSOR_ATTR_RO(temp1_max_alarm, temp_max_alarm, 0), + SENSOR_ATTR_RO(temp2_max_alarm, temp_max_alarm, 1), + SENSOR_ATTR_RO(temp3_max_alarm, temp_max_alarm, 2), +}; + static ssize_t temp_crit_alarm_show(struct device *dev, struct device_attribute *devattr, char *buf) @@ -1016,18 +1055,6 @@ static ssize_t temp_crit_alarm_show(struct device *dev, return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_ALM_CRIT)); } -static struct sensor_device_attribute temp_min_alarm[] = { - SENSOR_ATTR_RO(temp1_min_alarm, temp_min_alarm, 0), - SENSOR_ATTR_RO(temp2_min_alarm, temp_min_alarm, 1), - SENSOR_ATTR_RO(temp3_min_alarm, temp_min_alarm, 2), -}; - -static struct sensor_device_attribute temp_max_alarm[] = { - SENSOR_ATTR_RO(temp1_max_alarm, temp_max_alarm, 0), - SENSOR_ATTR_RO(temp2_max_alarm, temp_max_alarm, 1), - SENSOR_ATTR_RO(temp3_max_alarm, temp_max_alarm, 2), -}; - static struct sensor_device_attribute temp_crit_alarm[] = { SENSOR_ATTR_RO(temp1_crit_alarm, temp_crit_alarm, 0), SENSOR_ATTR_RO(temp2_crit_alarm, temp_crit_alarm, 1), @@ -1043,6 +1070,7 @@ static ssize_t temp_fault_show(struct device *dev, return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_FAULT)); } + static struct sensor_device_attribute temp_fault[] = { SENSOR_ATTR_RO(temp1_fault, temp_fault, 0), SENSOR_ATTR_RO(temp2_fault, temp_fault, 1), @@ -1074,106 +1102,180 @@ static const struct attribute_group pc8736x_temp_attr_group[] = { { .attrs = pc8736x_temp_attr[2] } }; -static ssize_t name_show(struct device *dev, - struct device_attribute *devattr, char *buf) +static ssize_t alarms_temp_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct pc87360_data *data = dev_get_drvdata(dev); - return sprintf(buf, "%s\n", data->name); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->temp_alarms); } -static DEVICE_ATTR_RO(name); +static DEVICE_ATTR_RO(alarms_temp); -/* - * Device detection, registration and update - */ +static ssize_t fan_input_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index], + FAN_DIV_FROM_REG(data->fan_status[attr->index]))); +} -static int __init pc87360_find(int sioaddr, u8 *devid, - unsigned short *addresses) +static struct sensor_device_attribute fan_input[] = { + SENSOR_ATTR_RO(fan1_input, fan_input, 0), + SENSOR_ATTR_RO(fan2_input, fan_input, 1), + SENSOR_ATTR_RO(fan3_input, fan_input, 2), +}; + +static ssize_t fan_status_show(struct device *dev, + struct device_attribute *devattr, char *buf) { - u16 val; - int i; - int nrdev; /* logical device count */ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", + FAN_STATUS_FROM_REG(data->fan_status[attr->index])); +} - /* No superio_enter */ +static struct sensor_device_attribute fan_status[] = { + SENSOR_ATTR_RO(fan1_status, fan_status, 0), + SENSOR_ATTR_RO(fan2_status, fan_status, 1), + SENSOR_ATTR_RO(fan3_status, fan_status, 2), +}; - /* Identify device */ - val = force_id ? force_id : superio_inb(sioaddr, DEVID); - switch (val) { - case 0xE1: /* PC87360 */ - case 0xE8: /* PC87363 */ - case 0xE4: /* PC87364 */ - nrdev = 1; - break; - case 0xE5: /* PC87365 */ - case 0xE9: /* PC87366 */ - nrdev = 3; - break; - default: - superio_exit(sioaddr); - return -ENODEV; +static ssize_t fan_div_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", + FAN_DIV_FROM_REG(data->fan_status[attr->index])); +} + +static struct sensor_device_attribute fan_div[] = { + SENSOR_ATTR_RO(fan1_div, fan_div, 0), + SENSOR_ATTR_RO(fan2_div, fan_div, 1), + SENSOR_ATTR_RO(fan3_div, fan_div, 2), +}; + +static ssize_t fan_min_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index], + FAN_DIV_FROM_REG(data->fan_status[attr->index]))); +} + +static ssize_t fan_min_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = dev_get_drvdata(dev); + long fan_min; + int err; + + err = kstrtol(buf, 10, &fan_min); + if (err) + return err; + + mutex_lock(&data->update_lock); + fan_min = FAN_TO_REG(fan_min, + FAN_DIV_FROM_REG(data->fan_status[attr->index])); + + /* If it wouldn't fit, change clock divisor */ + while (fan_min > 255 + && (data->fan_status[attr->index] & 0x60) != 0x60) { + fan_min >>= 1; + data->fan[attr->index] >>= 1; + data->fan_status[attr->index] += 0x20; } - /* Remember the device id */ - *devid = val; + data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min; + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_MIN(attr->index), + data->fan_min[attr->index]); - for (i = 0; i < nrdev; i++) { - /* select logical device */ - superio_outb(sioaddr, DEV, logdev[i]); + /* Write new divider, preserve alarm bits */ + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_STATUS(attr->index), + data->fan_status[attr->index] & 0xF9); + mutex_unlock(&data->update_lock); - val = superio_inb(sioaddr, ACT); - if (!(val & 0x01)) { - pr_info("Device 0x%02x not activated\n", logdev[i]); - continue; - } + return count; +} - val = (superio_inb(sioaddr, BASE) << 8) - | superio_inb(sioaddr, BASE + 1); - if (!val) { - pr_info("Base address not set for device 0x%02x\n", - logdev[i]); - continue; - } +static struct sensor_device_attribute fan_min[] = { + SENSOR_ATTR_RW(fan1_min, fan_min, 0), + SENSOR_ATTR_RW(fan2_min, fan_min, 1), + SENSOR_ATTR_RW(fan3_min, fan_min, 2), +}; - addresses[i] = val; +#define FAN_UNIT_ATTRS(X) \ +{ &fan_input[X].dev_attr.attr, \ + &fan_status[X].dev_attr.attr, \ + &fan_div[X].dev_attr.attr, \ + &fan_min[X].dev_attr.attr, \ + NULL \ +} - if (i == 0) { /* Fans */ - confreg[0] = superio_inb(sioaddr, 0xF0); - confreg[1] = superio_inb(sioaddr, 0xF1); +static struct attribute *pc8736x_fan_attr[][5] = { + FAN_UNIT_ATTRS(0), + FAN_UNIT_ATTRS(1), + FAN_UNIT_ATTRS(2) +}; - pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 1, - (confreg[0] >> 2) & 1, (confreg[0] >> 3) & 1, - (confreg[0] >> 4) & 1); - pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 2, - (confreg[0] >> 5) & 1, (confreg[0] >> 6) & 1, - (confreg[0] >> 7) & 1); - pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 3, - confreg[1] & 1, (confreg[1] >> 1) & 1, - (confreg[1] >> 2) & 1); - } else if (i == 1) { /* Voltages */ - /* Are we using thermistors? */ - if (*devid == 0xE9) { /* PC87366 */ - /* - * These registers are not logical-device - * specific, just that we won't need them if - * we don't use the VLM device - */ - confreg[2] = superio_inb(sioaddr, 0x2B); - confreg[3] = superio_inb(sioaddr, 0x25); +static const struct attribute_group pc8736x_fan_attr_group[] = { + { .attrs = pc8736x_fan_attr[0], }, + { .attrs = pc8736x_fan_attr[1], }, + { .attrs = pc8736x_fan_attr[2], }, +}; - if (confreg[2] & 0x40) { - pr_info("Using thermistors for temperature monitoring\n"); - } - if (confreg[3] & 0xE0) { - pr_info("VID inputs routed (mode %u)\n", - confreg[3] >> 5); - } - } - } - } +static ssize_t pwm_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", + PWM_FROM_REG(data->pwm[attr->index], + FAN_CONFIG_INVERT(data->fan_conf, + attr->index))); +} - superio_exit(sioaddr); - return 0; +static ssize_t pwm_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pc87360_data *data = dev_get_drvdata(dev); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->pwm[attr->index] = PWM_TO_REG(val, + FAN_CONFIG_INVERT(data->fan_conf, attr->index)); + pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index), + data->pwm[attr->index]); + mutex_unlock(&data->update_lock); + return count; } +static struct sensor_device_attribute pwm[] = { + SENSOR_ATTR_RW(pwm1, pwm, 0), + SENSOR_ATTR_RW(pwm2, pwm, 1), + SENSOR_ATTR_RW(pwm3, pwm, 2), +}; + +static ssize_t name_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pc87360_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->name); +} + +static DEVICE_ATTR_RO(name); + static void pc87360_remove_files(struct device *dev) { int i; @@ -1190,6 +1292,146 @@ static void pc87360_remove_files(struct device *dev) sysfs_remove_group(&dev->kobj, &pc8736x_vin_group); } +static void pc87360_init_device(struct platform_device *pdev, + int use_thermistors) +{ + struct pc87360_data *data = platform_get_drvdata(pdev); + int i, nr; + const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; + const u8 init_temp[3] = { 2, 2, 1 }; + u8 reg; + + if (init >= 2 && data->innr) { + reg = pc87360_read_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONVRATE); + dev_info(&pdev->dev, + "VLM conversion set to 1s period, 160us delay\n"); + pc87360_write_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONVRATE, + (reg & 0xC0) | 0x11); + } + + nr = data->innr < 11 ? data->innr : 11; + for (i = 0; i < nr; i++) { + reg = pc87360_read_value(data, LD_IN, i, + PC87365_REG_IN_STATUS); + dev_dbg(&pdev->dev, "bios in%d status:0x%02x\n", i, reg); + if (init >= init_in[i]) { + /* Forcibly enable voltage channel */ + if (!(reg & CHAN_ENA)) { + dev_dbg(&pdev->dev, "Forcibly enabling in%d\n", + i); + pc87360_write_value(data, LD_IN, i, + PC87365_REG_IN_STATUS, + (reg & 0x68) | 0x87); + } + } + } + + /* + * We can't blindly trust the Super-I/O space configuration bit, + * most BIOS won't set it properly + */ + dev_dbg(&pdev->dev, "bios thermistors:%d\n", use_thermistors); + for (i = 11; i < data->innr; i++) { + reg = pc87360_read_value(data, LD_IN, i, + PC87365_REG_TEMP_STATUS); + use_thermistors = use_thermistors || (reg & CHAN_ENA); + /* thermistors are temp[4-6], measured on vin[11-14] */ + dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i-7, reg); + } + dev_dbg(&pdev->dev, "using thermistors:%d\n", use_thermistors); + + i = use_thermistors ? 2 : 0; + for (; i < data->tempnr; i++) { + reg = pc87360_read_value(data, LD_TEMP, i, + PC87365_REG_TEMP_STATUS); + dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i + 1, reg); + if (init >= init_temp[i]) { + /* Forcibly enable temperature channel */ + if (!(reg & CHAN_ENA)) { + dev_dbg(&pdev->dev, + "Forcibly enabling temp%d\n", i + 1); + pc87360_write_value(data, LD_TEMP, i, + PC87365_REG_TEMP_STATUS, + 0xCF); + } + } + } + + if (use_thermistors) { + for (i = 11; i < data->innr; i++) { + if (init >= init_in[i]) { + /* + * The pin may already be used by thermal + * diodes + */ + reg = pc87360_read_value(data, LD_TEMP, + (i - 11) / 2, PC87365_REG_TEMP_STATUS); + if (reg & CHAN_ENA) { + dev_dbg(&pdev->dev, + "Skipping temp%d, pin already in use by temp%d\n", + i - 7, (i - 11) / 2); + continue; + } + + /* Forcibly enable thermistor channel */ + reg = pc87360_read_value(data, LD_IN, i, + PC87365_REG_IN_STATUS); + if (!(reg & CHAN_ENA)) { + dev_dbg(&pdev->dev, + "Forcibly enabling temp%d\n", + i - 7); + pc87360_write_value(data, LD_IN, i, + PC87365_REG_TEMP_STATUS, + (reg & 0x60) | 0x8F); + } + } + } + } + + if (data->innr) { + reg = pc87360_read_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONFIG); + dev_dbg(&pdev->dev, "bios vin-cfg:0x%02x\n", reg); + if (reg & CHAN_ENA) { + dev_dbg(&pdev->dev, + "Forcibly enabling monitoring (VLM)\n"); + pc87360_write_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONFIG, + reg & 0xFE); + } + } + + if (data->tempnr) { + reg = pc87360_read_value(data, LD_TEMP, NO_BANK, + PC87365_REG_TEMP_CONFIG); + dev_dbg(&pdev->dev, "bios temp-cfg:0x%02x\n", reg); + if (reg & CHAN_ENA) { + dev_dbg(&pdev->dev, + "Forcibly enabling monitoring (TMS)\n"); + pc87360_write_value(data, LD_TEMP, NO_BANK, + PC87365_REG_TEMP_CONFIG, + reg & 0xFE); + } + + if (init >= 2) { + /* Chip config as documented by National Semi. */ + pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); + /* + * We voluntarily omit the bank here, in case the + * sequence itself matters. It shouldn't be a problem, + * since nobody else is supposed to access the + * device at that point. + */ + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); + } + } +} + static int pc87360_probe(struct platform_device *pdev) { int i; @@ -1239,7 +1481,7 @@ static int pc87360_probe(struct platform_device *pdev) data->address[i] = extra_isa[i]; if (data->address[i] && !devm_request_region(dev, extra_isa[i], PC87360_EXTENT, - pc87360_driver.driver.name)) { + DRIVER_NAME)) { dev_err(dev, "Region 0x%x-0x%x already in use!\n", extra_isa[i], extra_isa[i]+PC87360_EXTENT-1); @@ -1355,330 +1597,105 @@ static int pc87360_remove(struct platform_device *pdev) } /* - * ldi is the logical device index - * bank is for voltages and temperatures only + * Driver data */ -static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg) -{ - int res; - - mutex_lock(&(data->lock)); - if (bank != NO_BANK) - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - res = inb_p(data->address[ldi] + reg); - mutex_unlock(&(data->lock)); +static struct platform_driver pc87360_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = pc87360_probe, + .remove = pc87360_remove, +}; - return res; -} +/* + * Device detection, registration and update + */ -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value) +static int __init pc87360_find(int sioaddr, u8 *devid, + unsigned short *addresses) { - mutex_lock(&(data->lock)); - if (bank != NO_BANK) - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - outb_p(value, data->address[ldi] + reg); - mutex_unlock(&(data->lock)); -} + u16 val; + int i; + int nrdev; /* logical device count */ -/* (temp & vin) channel conversion status register flags (pdf sec.11.5.12) */ -#define CHAN_CNVRTD 0x80 /* new data ready */ -#define CHAN_ENA 0x01 /* enabled channel (temp or vin) */ -#define CHAN_ALM_ENA 0x10 /* propagate to alarms-reg ?? (chk val!) */ -#define CHAN_READY (CHAN_ENA|CHAN_CNVRTD) /* sample ready mask */ + /* No superio_enter */ -#define TEMP_OTS_OE 0x20 /* OTS Output Enable */ -#define VIN_RW1C_MASK (CHAN_READY|CHAN_ALM_MAX|CHAN_ALM_MIN) /* 0x87 */ -#define TEMP_RW1C_MASK (VIN_RW1C_MASK|TEMP_ALM_CRIT|TEMP_FAULT) /* 0xCF */ + /* Identify device */ + val = force_id ? force_id : superio_inb(sioaddr, DEVID); + switch (val) { + case 0xE1: /* PC87360 */ + case 0xE8: /* PC87363 */ + case 0xE4: /* PC87364 */ + nrdev = 1; + break; + case 0xE5: /* PC87365 */ + case 0xE9: /* PC87366 */ + nrdev = 3; + break; + default: + superio_exit(sioaddr); + return -ENODEV; + } + /* Remember the device id */ + *devid = val; -static void pc87360_init_device(struct platform_device *pdev, - int use_thermistors) -{ - struct pc87360_data *data = platform_get_drvdata(pdev); - int i, nr; - const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; - const u8 init_temp[3] = { 2, 2, 1 }; - u8 reg; + for (i = 0; i < nrdev; i++) { + /* select logical device */ + superio_outb(sioaddr, DEV, logdev[i]); - if (init >= 2 && data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE); - dev_info(&pdev->dev, - "VLM conversion set to 1s period, 160us delay\n"); - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE, - (reg & 0xC0) | 0x11); - } + val = superio_inb(sioaddr, ACT); + if (!(val & 0x01)) { + pr_info("Device 0x%02x not activated\n", logdev[i]); + continue; + } - nr = data->innr < 11 ? data->innr : 11; - for (i = 0; i < nr; i++) { - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - dev_dbg(&pdev->dev, "bios in%d status:0x%02x\n", i, reg); - if (init >= init_in[i]) { - /* Forcibly enable voltage channel */ - if (!(reg & CHAN_ENA)) { - dev_dbg(&pdev->dev, "Forcibly enabling in%d\n", - i); - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - (reg & 0x68) | 0x87); - } + val = (superio_inb(sioaddr, BASE) << 8) + | superio_inb(sioaddr, BASE + 1); + if (!val) { + pr_info("Base address not set for device 0x%02x\n", + logdev[i]); + continue; } - } - /* - * We can't blindly trust the Super-I/O space configuration bit, - * most BIOS won't set it properly - */ - dev_dbg(&pdev->dev, "bios thermistors:%d\n", use_thermistors); - for (i = 11; i < data->innr; i++) { - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS); - use_thermistors = use_thermistors || (reg & CHAN_ENA); - /* thermistors are temp[4-6], measured on vin[11-14] */ - dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i-7, reg); - } - dev_dbg(&pdev->dev, "using thermistors:%d\n", use_thermistors); + addresses[i] = val; - i = use_thermistors ? 2 : 0; - for (; i < data->tempnr; i++) { - reg = pc87360_read_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i + 1, reg); - if (init >= init_temp[i]) { - /* Forcibly enable temperature channel */ - if (!(reg & CHAN_ENA)) { - dev_dbg(&pdev->dev, - "Forcibly enabling temp%d\n", i + 1); - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - 0xCF); - } - } - } + if (i == 0) { /* Fans */ + confreg[0] = superio_inb(sioaddr, 0xF0); + confreg[1] = superio_inb(sioaddr, 0xF1); - if (use_thermistors) { - for (i = 11; i < data->innr; i++) { - if (init >= init_in[i]) { + pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 1, + (confreg[0] >> 2) & 1, (confreg[0] >> 3) & 1, + (confreg[0] >> 4) & 1); + pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 2, + (confreg[0] >> 5) & 1, (confreg[0] >> 6) & 1, + (confreg[0] >> 7) & 1); + pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 3, + confreg[1] & 1, (confreg[1] >> 1) & 1, + (confreg[1] >> 2) & 1); + } else if (i == 1) { /* Voltages */ + /* Are we using thermistors? */ + if (*devid == 0xE9) { /* PC87366 */ /* - * The pin may already be used by thermal - * diodes + * These registers are not logical-device + * specific, just that we won't need them if + * we don't use the VLM device */ - reg = pc87360_read_value(data, LD_TEMP, - (i - 11) / 2, PC87365_REG_TEMP_STATUS); - if (reg & CHAN_ENA) { - dev_dbg(&pdev->dev, - "Skipping temp%d, pin already in use by temp%d\n", - i - 7, (i - 11) / 2); - continue; - } + confreg[2] = superio_inb(sioaddr, 0x2B); + confreg[3] = superio_inb(sioaddr, 0x25); - /* Forcibly enable thermistor channel */ - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - if (!(reg & CHAN_ENA)) { - dev_dbg(&pdev->dev, - "Forcibly enabling temp%d\n", - i - 7); - pc87360_write_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS, - (reg & 0x60) | 0x8F); + if (confreg[2] & 0x40) { + pr_info("Using thermistors for temperature monitoring\n"); + } + if (confreg[3] & 0xE0) { + pr_info("VID inputs routed (mode %u)\n", + confreg[3] >> 5); } } } } - if (data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG); - dev_dbg(&pdev->dev, "bios vin-cfg:0x%02x\n", reg); - if (reg & CHAN_ENA) { - dev_dbg(&pdev->dev, - "Forcibly enabling monitoring (VLM)\n"); - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG, - reg & 0xFE); - } - } - - if (data->tempnr) { - reg = pc87360_read_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG); - dev_dbg(&pdev->dev, "bios temp-cfg:0x%02x\n", reg); - if (reg & CHAN_ENA) { - dev_dbg(&pdev->dev, - "Forcibly enabling monitoring (TMS)\n"); - pc87360_write_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG, - reg & 0xFE); - } - - if (init >= 2) { - /* Chip config as documented by National Semi. */ - pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); - /* - * We voluntarily omit the bank here, in case the - * sequence itself matters. It shouldn't be a problem, - * since nobody else is supposed to access the - * device at that point. - */ - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); - } - } -} - -static void pc87360_autodiv(struct device *dev, int nr) -{ - struct pc87360_data *data = dev_get_drvdata(dev); - u8 old_min = data->fan_min[nr]; - - /* Increase clock divider if needed and possible */ - if ((data->fan_status[nr] & 0x04) /* overflow flag */ - || (data->fan[nr] >= 224)) { /* next to overflow */ - if ((data->fan_status[nr] & 0x60) != 0x60) { - data->fan_status[nr] += 0x20; - data->fan_min[nr] >>= 1; - data->fan[nr] >>= 1; - dev_dbg(dev, - "Increasing clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1); - } - } else { - /* Decrease clock divider if possible */ - while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */ - && data->fan[nr] < 85 /* bad accuracy */ - && (data->fan_status[nr] & 0x60) != 0x00) { - data->fan_status[nr] -= 0x20; - data->fan_min[nr] <<= 1; - data->fan[nr] <<= 1; - dev_dbg(dev, - "Decreasing clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), - nr + 1); - } - } - - /* Write new fan min if it changed */ - if (old_min != data->fan_min[nr]) { - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(nr), - data->fan_min[nr]); - } -} - -static struct pc87360_data *pc87360_update_device(struct device *dev) -{ - struct pc87360_data *data = dev_get_drvdata(dev); - u8 i; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - dev_dbg(dev, "Data update\n"); - - /* Fans */ - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { - data->fan_status[i] = - pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_FAN_STATUS(i)); - data->fan[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_FAN(i)); - data->fan_min[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(i)); - /* Change clock divider if needed */ - pc87360_autodiv(dev, i); - /* Clear bits and write new divider */ - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i), - data->fan_status[i]); - } - if (FAN_CONFIG_CONTROL(data->fan_conf, i)) - data->pwm[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_PWM(i)); - } - - /* Voltages */ - for (i = 0; i < data->innr; i++) { - data->in_status[i] = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - data->in_status[i]); - if ((data->in_status[i] & CHAN_READY) == CHAN_READY) { - data->in[i] = pc87360_read_value(data, LD_IN, - i, PC87365_REG_IN); - } - if (data->in_status[i] & CHAN_ENA) { - data->in_min[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MIN); - data->in_max[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MAX); - if (i >= 11) - data->in_crit[i-11] = - pc87360_read_value(data, LD_IN, - i, PC87365_REG_TEMP_CRIT); - } - } - if (data->innr) { - data->in_alarms = pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS1) - | ((pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS2) - & 0x07) << 8); - data->vid = (data->vid_conf & 0xE0) ? - pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_VID) : 0x1F; - } - - /* Temperatures */ - for (i = 0; i < data->tempnr; i++) { - data->temp_status[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - data->temp_status[i]); - if ((data->temp_status[i] & CHAN_READY) == CHAN_READY) { - data->temp[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP); - } - if (data->temp_status[i] & CHAN_ENA) { - data->temp_min[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MIN); - data->temp_max[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MAX); - data->temp_crit[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_CRIT); - } - } - if (data->tempnr) { - data->temp_alarms = pc87360_read_value(data, LD_TEMP, - NO_BANK, PC87365_REG_TEMP_ALARMS) - & 0x3F; - } - - data->last_updated = jiffies; - data->valid = true; - } - - mutex_unlock(&data->update_lock); - - return data; + superio_exit(sioaddr); + return 0; } static int __init pc87360_device_add(unsigned short address) @@ -1777,10 +1794,10 @@ static void __exit pc87360_exit(void) platform_driver_unregister(&pc87360_driver); } - MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); MODULE_DESCRIPTION("PC8736x hardware monitor"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); module_init(pc87360_init); module_exit(pc87360_exit); diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 951e4a9ff2d6..89668af67206 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -397,6 +397,15 @@ config SENSORS_TPS53679 This driver can also be built as a module. If so, the module will be called tps53679. +config SENSORS_TPS546D24 + tristate "TPS546D24" + help + If you say yes here you get hardware monitoring support for TEXAS + TPS546D24. + + This driver can also be built as a module. If so, the module will + be called tps546d24 + config SENSORS_UCD9000 tristate "TI UCD90120, UCD90124, UCD90160, UCD90320, UCD9090, UCD90910" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index e2fe86f98965..0002dbe22d52 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o +obj-$(CONFIG_SENSORS_TPS546D24) += tps546d24.o obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o diff --git a/drivers/hwmon/pmbus/mp2888.c b/drivers/hwmon/pmbus/mp2888.c index 8ecd4adfef40..24e5194706cf 100644 --- a/drivers/hwmon/pmbus/mp2888.c +++ b/drivers/hwmon/pmbus/mp2888.c @@ -34,7 +34,7 @@ struct mp2888_data { int curr_sense_gain; }; -#define to_mp2888_data(x) container_of(x, struct mp2888_data, info) +#define to_mp2888_data(x) container_of(x, struct mp2888_data, info) static int mp2888_read_byte_data(struct i2c_client *client, int page, int reg) { @@ -109,7 +109,7 @@ mp2888_read_phase(struct i2c_client *client, struct mp2888_data *data, int page, * - Kcs is the DrMOS current sense gain of power stage, which is obtained from the * register MP2888_MFR_VR_CONFIG1, bits 13-12 with the following selection of DrMOS * (data->curr_sense_gain): - * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. + * 00b - 8.5µA/A, 01b - 9.7µA/A, 1b - 10µA/A, 11b - 5µA/A. * - Rcs is the internal phase current sense resistor. This parameter depends on hardware * assembly. By default it is set to 1kΩ. In case of different assembly, user should * scale this parameter by dividing it by Rcs. @@ -118,10 +118,9 @@ mp2888_read_phase(struct i2c_client *client, struct mp2888_data *data, int page, * because sampling of current occurrence of bit weight has a big deviation, especially for * light load. */ - ret = DIV_ROUND_CLOSEST(ret * 100 - 9800, data->curr_sense_gain); - ret = (data->phase_curr_resolution) ? ret * 2 : ret; + ret = DIV_ROUND_CLOSEST(ret * 200 - 19600, data->curr_sense_gain); /* Scale according to total current resolution. */ - ret = (data->total_curr_resolution) ? ret * 8 : ret * 4; + ret = (data->total_curr_resolution) ? ret * 2 : ret; return ret; } @@ -212,7 +211,7 @@ static int mp2888_read_word_data(struct i2c_client *client, int page, int phase, ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret; - ret = data->total_curr_resolution ? ret * 2 : ret; + ret = data->total_curr_resolution ? ret : DIV_ROUND_CLOSEST(ret, 2); break; case PMBUS_POUT_OP_WARN_LIMIT: ret = pmbus_read_word_data(client, page, phase, reg); @@ -223,7 +222,7 @@ static int mp2888_read_word_data(struct i2c_client *client, int page, int phase, * set 1. Actual power is reported with 0.5W or 1W respectively resolution. Scaling * is needed to match both. */ - ret = data->total_curr_resolution ? ret * 4 : ret * 2; + ret = data->total_curr_resolution ? ret * 2 : ret; break; /* * The below registers are not implemented by device or implemented not according to the diff --git a/drivers/hwmon/pmbus/tps546d24.c b/drivers/hwmon/pmbus/tps546d24.c new file mode 100644 index 000000000000..435f94304ad8 --- /dev/null +++ b/drivers/hwmon/pmbus/tps546d24.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for TEXAS TPS546D24 buck converter + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pmbus.h> +#include "pmbus.h" + +static struct pmbus_driver_info tps546d24_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_OUT] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN + | PMBUS_HAVE_IOUT | PMBUS_HAVE_VOUT + | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, +}; + +static int tps546d24_probe(struct i2c_client *client) +{ + int reg; + + reg = i2c_smbus_read_byte_data(client, PMBUS_VOUT_MODE); + if (reg < 0) + return reg; + + if (reg & 0x80) { + int err; + + err = i2c_smbus_write_byte_data(client, PMBUS_VOUT_MODE, reg & 0x7f); + if (err < 0) + return err; + } + return pmbus_do_probe(client, &tps546d24_info); +} + +static const struct i2c_device_id tps546d24_id[] = { + {"tps546d24", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, tps546d24_id); + +static const struct of_device_id __maybe_unused tps546d24_of_match[] = { + {.compatible = "ti,tps546d24"}, + {} +}; +MODULE_DEVICE_TABLE(of, tps546d24_of_match); + +/* This is the driver that will be inserted */ +static struct i2c_driver tps546d24_driver = { + .driver = { + .name = "tps546d24", + .of_match_table = of_match_ptr(tps546d24_of_match), + }, + .probe_new = tps546d24_probe, + .id_table = tps546d24_id, +}; + +module_i2c_driver(tps546d24_driver); + +MODULE_AUTHOR("Duke Du <dukedu83@gmail.com>"); +MODULE_DESCRIPTION("PMBus driver for TI tps546d24"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 6c08551d8d14..dc3d9a22d917 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -28,11 +28,23 @@ struct pwm_fan_tach { u8 pulses_per_revolution; }; +enum pwm_fan_enable_mode { + pwm_off_reg_off, + pwm_disable_reg_enable, + pwm_enable_reg_enable, + pwm_disable_reg_disable, +}; + struct pwm_fan_ctx { + struct device *dev; + struct mutex lock; struct pwm_device *pwm; struct pwm_state pwm_state; struct regulator *reg_en; + enum pwm_fan_enable_mode enable_mode; + bool regulator_enabled; + bool enabled; int tach_count; struct pwm_fan_tach *tachs; @@ -82,25 +94,140 @@ static void sample_timer(struct timer_list *t) mod_timer(&ctx->rpm_timer, jiffies + HZ); } -static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) +static void pwm_fan_enable_mode_2_state(int enable_mode, + struct pwm_state *state, + bool *enable_regulator) +{ + switch (enable_mode) { + case pwm_disable_reg_enable: + /* disable pwm, keep regulator enabled */ + state->enabled = false; + *enable_regulator = true; + break; + case pwm_enable_reg_enable: + /* keep pwm and regulator enabled */ + state->enabled = true; + *enable_regulator = true; + break; + case pwm_off_reg_off: + case pwm_disable_reg_disable: + /* disable pwm and regulator */ + state->enabled = false; + *enable_regulator = false; + } +} + +static int pwm_fan_switch_power(struct pwm_fan_ctx *ctx, bool on) { - unsigned long period; int ret = 0; + + if (!ctx->reg_en) + return ret; + + if (!ctx->regulator_enabled && on) { + ret = regulator_enable(ctx->reg_en); + if (ret == 0) + ctx->regulator_enabled = true; + } else if (ctx->regulator_enabled && !on) { + ret = regulator_disable(ctx->reg_en); + if (ret == 0) + ctx->regulator_enabled = false; + } + return ret; +} + +static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) +{ struct pwm_state *state = &ctx->pwm_state; + int ret; - mutex_lock(&ctx->lock); - if (ctx->pwm_value == pwm) - goto exit_set_pwm_err; + if (ctx->enabled) + return 0; + + ret = pwm_fan_switch_power(ctx, true); + if (ret < 0) { + dev_err(ctx->dev, "failed to enable power supply\n"); + return ret; + } + + state->enabled = true; + ret = pwm_apply_state(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to enable PWM\n"); + goto disable_regulator; + } + + ctx->enabled = true; + + return 0; + +disable_regulator: + pwm_fan_switch_power(ctx, false); + return ret; +} - period = state->period; - state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); - state->enabled = pwm ? true : false; +static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) +{ + struct pwm_state *state = &ctx->pwm_state; + bool enable_regulator = false; + int ret; + if (!ctx->enabled) + return 0; + + pwm_fan_enable_mode_2_state(ctx->enable_mode, + state, + &enable_regulator); + + state->enabled = false; + state->duty_cycle = 0; ret = pwm_apply_state(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to disable PWM\n"); + return ret; + } + + pwm_fan_switch_power(ctx, enable_regulator); + + ctx->enabled = false; + + return 0; +} + +static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) +{ + struct pwm_state *state = &ctx->pwm_state; + unsigned long period; + int ret = 0; + + if (pwm > 0) { + if (ctx->enable_mode == pwm_off_reg_off) + /* pwm-fan hard disabled */ + return 0; + + period = state->period; + state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); + ret = pwm_apply_state(ctx->pwm, state); + if (ret) + return ret; + ret = pwm_fan_power_on(ctx); + } else { + ret = pwm_fan_power_off(ctx); + } if (!ret) ctx->pwm_value = pwm; -exit_set_pwm_err: + + return ret; +} + +static int set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) +{ + int ret; + + mutex_lock(&ctx->lock); + ret = __set_pwm(ctx, pwm); mutex_unlock(&ctx->lock); + return ret; } @@ -115,20 +242,76 @@ static void pwm_fan_update_state(struct pwm_fan_ctx *ctx, unsigned long pwm) ctx->pwm_fan_state = i; } +static int pwm_fan_update_enable(struct pwm_fan_ctx *ctx, long val) +{ + int ret = 0; + int old_val; + + mutex_lock(&ctx->lock); + + if (ctx->enable_mode == val) + goto out; + + old_val = ctx->enable_mode; + ctx->enable_mode = val; + + if (val == 0) { + /* Disable pwm-fan unconditionally */ + ret = __set_pwm(ctx, 0); + if (ret) + ctx->enable_mode = old_val; + pwm_fan_update_state(ctx, 0); + } else { + /* + * Change PWM and/or regulator state if currently disabled + * Nothing to do if currently enabled + */ + if (!ctx->enabled) { + struct pwm_state *state = &ctx->pwm_state; + bool enable_regulator = false; + + state->duty_cycle = 0; + pwm_fan_enable_mode_2_state(val, + state, + &enable_regulator); + + pwm_apply_state(ctx->pwm, state); + pwm_fan_switch_power(ctx, enable_regulator); + pwm_fan_update_state(ctx, 0); + } + } +out: + mutex_unlock(&ctx->lock); + + return ret; +} + static int pwm_fan_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); int ret; - if (val < 0 || val > MAX_PWM) - return -EINVAL; + switch (attr) { + case hwmon_pwm_input: + if (val < 0 || val > MAX_PWM) + return -EINVAL; + ret = set_pwm(ctx, val); + if (ret) + return ret; + pwm_fan_update_state(ctx, val); + break; + case hwmon_pwm_enable: + if (val < 0 || val > 3) + ret = -EINVAL; + else + ret = pwm_fan_update_enable(ctx, val); - ret = __set_pwm(ctx, val); - if (ret) return ret; + default: + return -EOPNOTSUPP; + } - pwm_fan_update_state(ctx, val); return 0; } @@ -139,9 +322,15 @@ static int pwm_fan_read(struct device *dev, enum hwmon_sensor_types type, switch (type) { case hwmon_pwm: - *val = ctx->pwm_value; - return 0; - + switch (attr) { + case hwmon_pwm_input: + *val = ctx->pwm_value; + return 0; + case hwmon_pwm_enable: + *val = ctx->enable_mode; + return 0; + } + return -EOPNOTSUPP; case hwmon_fan: *val = ctx->tachs[channel].rpm; return 0; @@ -212,7 +401,7 @@ pwm_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) if (state == ctx->pwm_fan_state) return 0; - ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]); + ret = set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]); if (ret) { dev_err(&cdev->device, "Cannot set pwm!\n"); return ret; @@ -270,18 +459,14 @@ static int pwm_fan_of_get_cooling_data(struct device *dev, return 0; } -static void pwm_fan_regulator_disable(void *data) -{ - regulator_disable(data); -} - -static void pwm_fan_pwm_disable(void *__ctx) +static void pwm_fan_cleanup(void *__ctx) { struct pwm_fan_ctx *ctx = __ctx; - ctx->pwm_state.enabled = false; - pwm_apply_state(ctx->pwm, &ctx->pwm_state); del_timer_sync(&ctx->rpm_timer); + /* Switch off everything */ + ctx->enable_mode = pwm_disable_reg_disable; + pwm_fan_power_off(ctx); } static int pwm_fan_probe(struct platform_device *pdev) @@ -302,7 +487,8 @@ static int pwm_fan_probe(struct platform_device *pdev) mutex_init(&ctx->lock); - ctx->pwm = devm_of_pwm_get(dev, dev->of_node, NULL); + ctx->dev = &pdev->dev; + ctx->pwm = devm_pwm_get(dev, NULL); if (IS_ERR(ctx->pwm)) return dev_err_probe(dev, PTR_ERR(ctx->pwm), "Could not get PWM\n"); @@ -314,22 +500,12 @@ static int pwm_fan_probe(struct platform_device *pdev) return PTR_ERR(ctx->reg_en); ctx->reg_en = NULL; - } else { - ret = regulator_enable(ctx->reg_en); - if (ret) { - dev_err(dev, "Failed to enable fan supply: %d\n", ret); - return ret; - } - ret = devm_add_action_or_reset(dev, pwm_fan_regulator_disable, - ctx->reg_en); - if (ret) - return ret; } pwm_init_state(ctx->pwm, &ctx->pwm_state); /* - * __set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned + * set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned * long. Check this here to prevent the fan running at a too low * frequency. */ @@ -338,14 +514,19 @@ static int pwm_fan_probe(struct platform_device *pdev) return -EINVAL; } - /* Set duty cycle to maximum allowed and enable PWM output */ - ret = __set_pwm(ctx, MAX_PWM); + ctx->enable_mode = pwm_disable_reg_enable; + + /* + * Set duty cycle to maximum allowed and enable PWM output as well as + * the regulator. In case of error nothing is changed + */ + ret = set_pwm(ctx, MAX_PWM); if (ret) { dev_err(dev, "Failed to configure PWM: %d\n", ret); return ret; } timer_setup(&ctx->rpm_timer, sample_timer, 0); - ret = devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx); + ret = devm_add_action_or_reset(dev, pwm_fan_cleanup, ctx); if (ret) return ret; @@ -377,7 +558,7 @@ static int pwm_fan_probe(struct platform_device *pdev) if (!channels) return -ENOMEM; - channels[0] = HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT); + channels[0] = HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE); for (i = 0; i < ctx->tach_count; i++) { struct pwm_fan_tach *tach = &ctx->tachs[i]; @@ -451,65 +632,28 @@ static int pwm_fan_probe(struct platform_device *pdev) return 0; } -static int pwm_fan_disable(struct device *dev) -{ - struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); - int ret; - - if (ctx->pwm_value) { - /* keep ctx->pwm_state unmodified for pwm_fan_resume() */ - struct pwm_state state = ctx->pwm_state; - - state.duty_cycle = 0; - state.enabled = false; - ret = pwm_apply_state(ctx->pwm, &state); - if (ret < 0) - return ret; - } - - if (ctx->reg_en) { - ret = regulator_disable(ctx->reg_en); - if (ret) { - dev_err(dev, "Failed to disable fan supply: %d\n", ret); - return ret; - } - } - - return 0; -} - static void pwm_fan_shutdown(struct platform_device *pdev) { - pwm_fan_disable(&pdev->dev); + struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); + + pwm_fan_cleanup(ctx); } -#ifdef CONFIG_PM_SLEEP static int pwm_fan_suspend(struct device *dev) { - return pwm_fan_disable(dev); + struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + + return pwm_fan_power_off(ctx); } static int pwm_fan_resume(struct device *dev) { struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); - int ret; - - if (ctx->reg_en) { - ret = regulator_enable(ctx->reg_en); - if (ret) { - dev_err(dev, "Failed to enable fan supply: %d\n", ret); - return ret; - } - } - - if (ctx->pwm_value == 0) - return 0; - return pwm_apply_state(ctx->pwm, &ctx->pwm_state); + return set_pwm(ctx, ctx->pwm_value); } -#endif -static SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume); static const struct of_device_id of_pwm_fan_match[] = { { .compatible = "pwm-fan", }, @@ -522,7 +666,7 @@ static struct platform_driver pwm_fan_driver = { .shutdown = pwm_fan_shutdown, .driver = { .name = "pwm-fan", - .pm = &pwm_fan_pm, + .pm = pm_sleep_ptr(&pwm_fan_pm), .of_match_table = of_pwm_fan_match, }, }; diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index c19df3ade48e..13ac2d8f22c7 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -129,7 +129,7 @@ unlock: static ssize_t sht4x_interval_write(struct sht4x_data *data, long val) { - data->update_interval = clamp_val(val, SHT4X_MIN_POLL_INTERVAL, UINT_MAX); + data->update_interval = clamp_val(val, SHT4X_MIN_POLL_INTERVAL, INT_MAX); return 0; } diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 018cb5a7651f..b0b05fd12221 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -37,6 +37,7 @@ * 735 0008 0735 */ +#define DRIVER_NAME "sis5595" #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> @@ -191,21 +192,75 @@ struct sis5595_data { static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ -static int sis5595_probe(struct platform_device *pdev); -static int sis5595_remove(struct platform_device *pdev); +/* ISA access must be locked explicitly. */ +static int sis5595_read_value(struct sis5595_data *data, u8 reg) +{ + int res; -static int sis5595_read_value(struct sis5595_data *data, u8 reg); -static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value); -static struct sis5595_data *sis5595_update_device(struct device *dev); -static void sis5595_init_device(struct sis5595_data *data); + mutex_lock(&data->lock); + outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET); + res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET); + mutex_unlock(&data->lock); + return res; +} -static struct platform_driver sis5595_driver = { - .driver = { - .name = "sis5595", - }, - .probe = sis5595_probe, - .remove = sis5595_remove, -}; +static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value) +{ + mutex_lock(&data->lock); + outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET); + outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET); + mutex_unlock(&data->lock); +} + +static struct sis5595_data *sis5595_update_device(struct device *dev) +{ + struct sis5595_data *data = dev_get_drvdata(dev); + int i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + for (i = 0; i <= data->maxins; i++) { + data->in[i] = + sis5595_read_value(data, SIS5595_REG_IN(i)); + data->in_min[i] = + sis5595_read_value(data, + SIS5595_REG_IN_MIN(i)); + data->in_max[i] = + sis5595_read_value(data, + SIS5595_REG_IN_MAX(i)); + } + for (i = 0; i < 2; i++) { + data->fan[i] = + sis5595_read_value(data, SIS5595_REG_FAN(i)); + data->fan_min[i] = + sis5595_read_value(data, + SIS5595_REG_FAN_MIN(i)); + } + if (data->maxins == 3) { + data->temp = + sis5595_read_value(data, SIS5595_REG_TEMP); + data->temp_over = + sis5595_read_value(data, SIS5595_REG_TEMP_OVER); + data->temp_hyst = + sis5595_read_value(data, SIS5595_REG_TEMP_HYST); + } + i = sis5595_read_value(data, SIS5595_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = + sis5595_read_value(data, SIS5595_REG_ALARM1) | + (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = true; + } + + mutex_unlock(&data->update_lock); + + return data; +} /* 4 Voltages */ static ssize_t in_show(struct device *dev, struct device_attribute *da, @@ -568,6 +623,15 @@ static const struct attribute_group sis5595_group_temp1 = { .attrs = sis5595_attributes_temp1, }; +/* Called when we have found a new SIS5595. */ +static void sis5595_init_device(struct sis5595_data *data) +{ + u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG); + if (!(config & 0x01)) + sis5595_write_value(data, SIS5595_REG_CONFIG, + (config & 0xf7) | 0x01); +} + /* This is called when the module is loaded */ static int sis5595_probe(struct platform_device *pdev) { @@ -580,7 +644,7 @@ static int sis5595_probe(struct platform_device *pdev) /* Reserve the ISA region */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start, SIS5595_EXTENT, - sis5595_driver.driver.name)) + DRIVER_NAME)) return -EBUSY; data = devm_kzalloc(&pdev->dev, sizeof(struct sis5595_data), @@ -591,7 +655,7 @@ static int sis5595_probe(struct platform_device *pdev) mutex_init(&data->lock); mutex_init(&data->update_lock); data->addr = res->start; - data->name = "sis5595"; + data->name = DRIVER_NAME; platform_set_drvdata(pdev, data); /* @@ -657,85 +721,6 @@ static int sis5595_remove(struct platform_device *pdev) return 0; } -/* ISA access must be locked explicitly. */ -static int sis5595_read_value(struct sis5595_data *data, u8 reg) -{ - int res; - - mutex_lock(&data->lock); - outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET); - res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET); - mutex_unlock(&data->lock); - return res; -} - -static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value) -{ - mutex_lock(&data->lock); - outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET); - outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET); - mutex_unlock(&data->lock); -} - -/* Called when we have found a new SIS5595. */ -static void sis5595_init_device(struct sis5595_data *data) -{ - u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG); - if (!(config & 0x01)) - sis5595_write_value(data, SIS5595_REG_CONFIG, - (config & 0xf7) | 0x01); -} - -static struct sis5595_data *sis5595_update_device(struct device *dev) -{ - struct sis5595_data *data = dev_get_drvdata(dev); - int i; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - for (i = 0; i <= data->maxins; i++) { - data->in[i] = - sis5595_read_value(data, SIS5595_REG_IN(i)); - data->in_min[i] = - sis5595_read_value(data, - SIS5595_REG_IN_MIN(i)); - data->in_max[i] = - sis5595_read_value(data, - SIS5595_REG_IN_MAX(i)); - } - for (i = 0; i < 2; i++) { - data->fan[i] = - sis5595_read_value(data, SIS5595_REG_FAN(i)); - data->fan_min[i] = - sis5595_read_value(data, - SIS5595_REG_FAN_MIN(i)); - } - if (data->maxins == 3) { - data->temp = - sis5595_read_value(data, SIS5595_REG_TEMP); - data->temp_over = - sis5595_read_value(data, SIS5595_REG_TEMP_OVER); - data->temp_hyst = - sis5595_read_value(data, SIS5595_REG_TEMP_HYST); - } - i = sis5595_read_value(data, SIS5595_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - sis5595_read_value(data, SIS5595_REG_ALARM1) | - (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = true; - } - - mutex_unlock(&data->update_lock); - - return data; -} - static const struct pci_device_id sis5595_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { 0, } @@ -764,7 +749,7 @@ static int sis5595_device_add(unsigned short address) struct resource res = { .start = address, .end = address + SIS5595_EXTENT - 1, - .name = "sis5595", + .name = DRIVER_NAME, .flags = IORESOURCE_IO, }; int err; @@ -773,7 +758,7 @@ static int sis5595_device_add(unsigned short address) if (err) goto exit; - pdev = platform_device_alloc("sis5595", address); + pdev = platform_device_alloc(DRIVER_NAME, address); if (!pdev) { err = -ENOMEM; pr_err("Device allocation failed\n"); @@ -800,6 +785,14 @@ exit: return err; } +static struct platform_driver sis5595_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = sis5595_probe, + .remove = sis5595_remove, +}; + static int sis5595_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { @@ -886,7 +879,7 @@ exit: } static struct pci_driver sis5595_pci_driver = { - .name = "sis5595", + .name = DRIVER_NAME, .id_table = sis5595_pci_ids, .probe = sis5595_pci_probe, }; diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index a5db15c087ae..70d2152234e2 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -582,7 +582,7 @@ static int smsc47m192_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, "smsc47m192", I2C_NAME_SIZE); + strscpy(info->type, "smsc47m192", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/sparx5-temp.c b/drivers/hwmon/sparx5-temp.c index 98be48e3a22a..04fd8505e5d6 100644 --- a/drivers/hwmon/sparx5-temp.c +++ b/drivers/hwmon/sparx5-temp.c @@ -26,13 +26,6 @@ struct s5_hwmon { struct clk *clk; }; -static void s5_temp_clk_disable(void *data) -{ - struct clk *clk = data; - - clk_disable_unprepare(clk); -} - static void s5_temp_enable(struct s5_hwmon *hwmon) { u32 val = readl(hwmon->base + TEMP_CFG); @@ -113,7 +106,6 @@ static int s5_temp_probe(struct platform_device *pdev) { struct device *hwmon_dev; struct s5_hwmon *hwmon; - int ret; hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL); if (!hwmon) @@ -123,19 +115,10 @@ static int s5_temp_probe(struct platform_device *pdev) if (IS_ERR(hwmon->base)) return PTR_ERR(hwmon->base); - hwmon->clk = devm_clk_get(&pdev->dev, NULL); + hwmon->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(hwmon->clk)) return PTR_ERR(hwmon->clk); - ret = clk_prepare_enable(hwmon->clk); - if (ret) - return ret; - - ret = devm_add_action_or_reset(&pdev->dev, s5_temp_clk_disable, - hwmon->clk); - if (ret) - return ret; - s5_temp_enable(hwmon); hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, diff --git a/drivers/hwmon/stts751.c b/drivers/hwmon/stts751.c index 0ed28408aa07..2f67c6747ead 100644 --- a/drivers/hwmon/stts751.c +++ b/drivers/hwmon/stts751.c @@ -692,7 +692,7 @@ static int stts751_detect(struct i2c_client *new_client, } dev_dbg(&new_client->dev, "Chip %s detected", name); - strlcpy(info->type, stts751_id[0].name, I2C_NAME_SIZE); + strscpy(info->type, stts751_id[0].name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 6a804f5036f4..81cdb012993c 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c @@ -352,7 +352,7 @@ static int thmc50_detect(struct i2c_client *client, pr_debug("thmc50: Detected %s (version %x, revision %x)\n", type_name, (revision >> 4) - 0xc, revision & 0xf); - strlcpy(info->type, type_name, I2C_NAME_SIZE); + strscpy(info->type, type_name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index e867a0c2e539..2bf496a62206 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -260,7 +260,6 @@ static int tmp102_probe(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM_SLEEP static int tmp102_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -283,9 +282,8 @@ static int tmp102_resume(struct device *dev) return err; } -#endif /* CONFIG_PM */ -static SIMPLE_DEV_PM_OPS(tmp102_dev_pm_ops, tmp102_suspend, tmp102_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tmp102_dev_pm_ops, tmp102_suspend, tmp102_resume); static const struct i2c_device_id tmp102_id[] = { { "tmp102", 0 }, @@ -302,7 +300,7 @@ MODULE_DEVICE_TABLE(of, tmp102_of_match); static struct i2c_driver tmp102_driver = { .driver.name = DRIVER_NAME, .driver.of_match_table = of_match_ptr(tmp102_of_match), - .driver.pm = &tmp102_dev_pm_ops, + .driver.pm = pm_sleep_ptr(&tmp102_dev_pm_ops), .probe_new = tmp102_probe, .id_table = tmp102_id, }; diff --git a/drivers/hwmon/tmp103.c b/drivers/hwmon/tmp103.c index 5cab4436aa77..56d5cbf36a45 100644 --- a/drivers/hwmon/tmp103.c +++ b/drivers/hwmon/tmp103.c @@ -178,7 +178,7 @@ static int tmp103_probe(struct i2c_client *client) return PTR_ERR_OR_ZERO(hwmon_dev); } -static int __maybe_unused tmp103_suspend(struct device *dev) +static int tmp103_suspend(struct device *dev) { struct regmap *regmap = dev_get_drvdata(dev); @@ -186,7 +186,7 @@ static int __maybe_unused tmp103_suspend(struct device *dev) TMP103_CONF_SD_MASK, 0); } -static int __maybe_unused tmp103_resume(struct device *dev) +static int tmp103_resume(struct device *dev) { struct regmap *regmap = dev_get_drvdata(dev); @@ -194,7 +194,7 @@ static int __maybe_unused tmp103_resume(struct device *dev) TMP103_CONF_SD_MASK, TMP103_CONF_SD); } -static SIMPLE_DEV_PM_OPS(tmp103_dev_pm_ops, tmp103_suspend, tmp103_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tmp103_dev_pm_ops, tmp103_suspend, tmp103_resume); static const struct i2c_device_id tmp103_id[] = { { "tmp103", 0 }, @@ -212,7 +212,7 @@ static struct i2c_driver tmp103_driver = { .driver = { .name = "tmp103", .of_match_table = of_match_ptr(tmp103_of_match), - .pm = &tmp103_dev_pm_ops, + .pm = pm_sleep_ptr(&tmp103_dev_pm_ops), }, .probe_new = tmp103_probe, .id_table = tmp103_id, diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index 5435664c3f6e..acb4ba750b09 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -390,7 +390,7 @@ static int tmp108_probe(struct i2c_client *client) return PTR_ERR_OR_ZERO(hwmon_dev); } -static int __maybe_unused tmp108_suspend(struct device *dev) +static int tmp108_suspend(struct device *dev) { struct tmp108 *tmp108 = dev_get_drvdata(dev); @@ -398,7 +398,7 @@ static int __maybe_unused tmp108_suspend(struct device *dev) TMP108_CONF_MODE_MASK, TMP108_MODE_SHUTDOWN); } -static int __maybe_unused tmp108_resume(struct device *dev) +static int tmp108_resume(struct device *dev) { struct tmp108 *tmp108 = dev_get_drvdata(dev); int err; @@ -410,7 +410,7 @@ static int __maybe_unused tmp108_resume(struct device *dev) return err; } -static SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume); static const struct i2c_device_id tmp108_i2c_ids[] = { { "tmp108", 0 }, @@ -429,7 +429,7 @@ MODULE_DEVICE_TABLE(of, tmp108_of_ids); static struct i2c_driver tmp108_driver = { .driver = { .name = DRIVER_NAME, - .pm = &tmp108_dev_pm_ops, + .pm = pm_sleep_ptr(&tmp108_dev_pm_ops), .of_match_table = of_match_ptr(tmp108_of_ids), }, .probe_new = tmp108_probe, diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index cc0a1c219b1f..f358ba679626 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -671,7 +671,7 @@ static int tmp401_detect(struct i2c_client *client, if (reg > 15) return -ENODEV; - strlcpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE); + strscpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index 1fd8d41d90c8..45fd7fb5ee01 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -353,7 +353,7 @@ static int tmp421_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, tmp421_id[kind].name, I2C_NAME_SIZE); + strscpy(info->type, tmp421_id[kind].name, I2C_NAME_SIZE); dev_info(&adapter->dev, "Detected TI %s chip at 0x%02x\n", names[kind], client->addr); diff --git a/drivers/hwmon/tps23861.c b/drivers/hwmon/tps23861.c index 5e3fc2251510..68c77c493270 100644 --- a/drivers/hwmon/tps23861.c +++ b/drivers/hwmon/tps23861.c @@ -372,29 +372,12 @@ static const struct hwmon_chip_info tps23861_chip_info = { .info = tps23861_info, }; -static char *tps23861_port_operating_mode(struct tps23861_data *data, int port) +static char *port_operating_mode_string(uint8_t mode_reg, unsigned int port) { - unsigned int regval; - int mode; - - regmap_read(data->regmap, OPERATING_MODE, ®val); + unsigned int mode = ~0; - switch (port) { - case 1: - mode = FIELD_GET(OPERATING_MODE_PORT_1_MASK, regval); - break; - case 2: - mode = FIELD_GET(OPERATING_MODE_PORT_2_MASK, regval); - break; - case 3: - mode = FIELD_GET(OPERATING_MODE_PORT_3_MASK, regval); - break; - case 4: - mode = FIELD_GET(OPERATING_MODE_PORT_4_MASK, regval); - break; - default: - mode = -EINVAL; - } + if (port < TPS23861_NUM_PORTS) + mode = (mode_reg >> (2 * port)) & OPERATING_MODE_PORT_1_MASK; switch (mode) { case OPERATING_MODE_OFF: @@ -410,15 +393,9 @@ static char *tps23861_port_operating_mode(struct tps23861_data *data, int port) } } -static char *tps23861_port_detect_status(struct tps23861_data *data, int port) +static char *port_detect_status_string(uint8_t status_reg) { - unsigned int regval; - - regmap_read(data->regmap, - PORT_1_STATUS + (port - 1), - ®val); - - switch (FIELD_GET(PORT_STATUS_DETECT_MASK, regval)) { + switch (FIELD_GET(PORT_STATUS_DETECT_MASK, status_reg)) { case PORT_DETECT_UNKNOWN: return "Unknown device"; case PORT_DETECT_SHORT: @@ -448,15 +425,9 @@ static char *tps23861_port_detect_status(struct tps23861_data *data, int port) } } -static char *tps23861_port_class_status(struct tps23861_data *data, int port) +static char *port_class_status_string(uint8_t status_reg) { - unsigned int regval; - - regmap_read(data->regmap, - PORT_1_STATUS + (port - 1), - ®val); - - switch (FIELD_GET(PORT_STATUS_CLASS_MASK, regval)) { + switch (FIELD_GET(PORT_STATUS_CLASS_MASK, status_reg)) { case PORT_CLASS_UNKNOWN: return "Unknown"; case PORT_CLASS_RESERVED: @@ -479,16 +450,9 @@ static char *tps23861_port_class_status(struct tps23861_data *data, int port) } } -static char *tps23861_port_poe_plus_status(struct tps23861_data *data, int port) +static char *port_poe_plus_status_string(uint8_t poe_plus, unsigned int port) { - unsigned int regval; - - regmap_read(data->regmap, POE_PLUS, ®val); - - if (BIT(port + 3) & regval) - return "Yes"; - else - return "No"; + return (BIT(port + 4) & poe_plus) ? "Yes" : "No"; } static int tps23861_port_resistance(struct tps23861_data *data, int port) @@ -497,7 +461,7 @@ static int tps23861_port_resistance(struct tps23861_data *data, int port) __le16 regval; regmap_bulk_read(data->regmap, - PORT_1_RESISTANCE_LSB + PORT_N_RESISTANCE_LSB_OFFSET * (port - 1), + PORT_1_RESISTANCE_LSB + PORT_N_RESISTANCE_LSB_OFFSET * port, ®val, 2); @@ -517,14 +481,19 @@ static int tps23861_port_resistance(struct tps23861_data *data, int port) static int tps23861_port_status_show(struct seq_file *s, void *data) { struct tps23861_data *priv = s->private; - int i; - - for (i = 1; i < TPS23861_NUM_PORTS + 1; i++) { - seq_printf(s, "Port: \t\t%d\n", i); - seq_printf(s, "Operating mode: %s\n", tps23861_port_operating_mode(priv, i)); - seq_printf(s, "Detected: \t%s\n", tps23861_port_detect_status(priv, i)); - seq_printf(s, "Class: \t\t%s\n", tps23861_port_class_status(priv, i)); - seq_printf(s, "PoE Plus: \t%s\n", tps23861_port_poe_plus_status(priv, i)); + unsigned int i, mode, poe_plus, status; + + regmap_read(priv->regmap, OPERATING_MODE, &mode); + regmap_read(priv->regmap, POE_PLUS, &poe_plus); + + for (i = 0; i < TPS23861_NUM_PORTS; i++) { + regmap_read(priv->regmap, PORT_1_STATUS + i, &status); + + seq_printf(s, "Port: \t\t%d\n", i + 1); + seq_printf(s, "Operating mode: %s\n", port_operating_mode_string(mode, i)); + seq_printf(s, "Detected: \t%s\n", port_detect_status_string(status)); + seq_printf(s, "Class: \t\t%s\n", port_class_status_string(status)); + seq_printf(s, "PoE Plus: \t%s\n", port_poe_plus_status_string(poe_plus, i)); seq_printf(s, "Resistance: \t%d\n", tps23861_port_resistance(priv, i)); seq_putc(s, '\n'); } @@ -534,9 +503,17 @@ static int tps23861_port_status_show(struct seq_file *s, void *data) DEFINE_SHOW_ATTRIBUTE(tps23861_port_status); -static void tps23861_init_debugfs(struct tps23861_data *data) +static void tps23861_init_debugfs(struct tps23861_data *data, + struct device *hwmon_dev) { - data->debugfs_dir = debugfs_create_dir(data->client->name, NULL); + const char *debugfs_name; + + debugfs_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "%s-%s", + data->client->name, dev_name(hwmon_dev)); + if (!debugfs_name) + return; + + data->debugfs_dir = debugfs_create_dir(debugfs_name, NULL); debugfs_create_file("port_status", 0400, @@ -585,7 +562,7 @@ static int tps23861_probe(struct i2c_client *client) if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); - tps23861_init_debugfs(data); + tps23861_init_debugfs(data, hwmon_dev); return 0; } diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 55634110c2f9..37d7374896f6 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -34,6 +34,8 @@ #include <linux/acpi.h> #include <linux/io.h> +#define DRIVER_NAME "via686a" + /* * If force_addr is set to anything different from 0, we forcibly enable * the device at the given address. @@ -321,9 +323,6 @@ struct via686a_data { static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ -static int via686a_probe(struct platform_device *pdev); -static int via686a_remove(struct platform_device *pdev); - static inline int via686a_read_value(struct via686a_data *data, u8 reg) { return inb_p(data->addr + reg); @@ -335,8 +334,76 @@ static inline void via686a_write_value(struct via686a_data *data, u8 reg, outb_p(value, data->addr + reg); } -static struct via686a_data *via686a_update_device(struct device *dev); -static void via686a_init_device(struct via686a_data *data); +static void via686a_update_fan_div(struct via686a_data *data) +{ + int reg = via686a_read_value(data, VIA686A_REG_FANDIV); + data->fan_div[0] = (reg >> 4) & 0x03; + data->fan_div[1] = reg >> 6; +} + +static struct via686a_data *via686a_update_device(struct device *dev) +{ + struct via686a_data *data = dev_get_drvdata(dev); + int i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + for (i = 0; i <= 4; i++) { + data->in[i] = + via686a_read_value(data, VIA686A_REG_IN(i)); + data->in_min[i] = via686a_read_value(data, + VIA686A_REG_IN_MIN + (i)); + data->in_max[i] = + via686a_read_value(data, VIA686A_REG_IN_MAX(i)); + } + for (i = 1; i <= 2; i++) { + data->fan[i - 1] = + via686a_read_value(data, VIA686A_REG_FAN(i)); + data->fan_min[i - 1] = via686a_read_value(data, + VIA686A_REG_FAN_MIN(i)); + } + for (i = 0; i <= 2; i++) { + data->temp[i] = via686a_read_value(data, + VIA686A_REG_TEMP[i]) << 2; + data->temp_over[i] = + via686a_read_value(data, + VIA686A_REG_TEMP_OVER[i]); + data->temp_hyst[i] = + via686a_read_value(data, + VIA686A_REG_TEMP_HYST[i]); + } + /* + * add in lower 2 bits + * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 + * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 + * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 + */ + data->temp[0] |= (via686a_read_value(data, + VIA686A_REG_TEMP_LOW1) + & 0xc0) >> 6; + data->temp[1] |= + (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & + 0x30) >> 4; + data->temp[2] |= + (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & + 0xc0) >> 6; + + via686a_update_fan_div(data); + data->alarms = + via686a_read_value(data, + VIA686A_REG_ALARM1) | + (via686a_read_value(data, VIA686A_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = true; + } + + mutex_unlock(&data->update_lock); + + return data; +} /* following are the sysfs callback functions */ @@ -654,13 +721,23 @@ static const struct attribute_group via686a_group = { .attrs = via686a_attributes, }; -static struct platform_driver via686a_driver = { - .driver = { - .name = "via686a", - }, - .probe = via686a_probe, - .remove = via686a_remove, -}; +static void via686a_init_device(struct via686a_data *data) +{ + u8 reg; + + /* Start monitoring */ + reg = via686a_read_value(data, VIA686A_REG_CONFIG); + via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F); + + /* Configure temp interrupt mode for continuous-interrupt operation */ + reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE); + via686a_write_value(data, VIA686A_REG_TEMP_MODE, + (reg & ~VIA686A_TEMP_MODE_MASK) + | VIA686A_TEMP_MODE_CONTINUOUS); + + /* Pre-read fan clock divisor values */ + via686a_update_fan_div(data); +} /* This is called when the module is loaded */ static int via686a_probe(struct platform_device *pdev) @@ -672,7 +749,7 @@ static int via686a_probe(struct platform_device *pdev) /* Reserve the ISA region */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start, VIA686A_EXTENT, - via686a_driver.driver.name)) { + DRIVER_NAME)) { dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n", (unsigned long)res->start, (unsigned long)res->end); return -ENODEV; @@ -685,7 +762,7 @@ static int via686a_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); data->addr = res->start; - data->name = "via686a"; + data->name = DRIVER_NAME; mutex_init(&data->update_lock); /* Initialize the VIA686A chip */ @@ -719,94 +796,13 @@ static int via686a_remove(struct platform_device *pdev) return 0; } -static void via686a_update_fan_div(struct via686a_data *data) -{ - int reg = via686a_read_value(data, VIA686A_REG_FANDIV); - data->fan_div[0] = (reg >> 4) & 0x03; - data->fan_div[1] = reg >> 6; -} - -static void via686a_init_device(struct via686a_data *data) -{ - u8 reg; - - /* Start monitoring */ - reg = via686a_read_value(data, VIA686A_REG_CONFIG); - via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F); - - /* Configure temp interrupt mode for continuous-interrupt operation */ - reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE); - via686a_write_value(data, VIA686A_REG_TEMP_MODE, - (reg & ~VIA686A_TEMP_MODE_MASK) - | VIA686A_TEMP_MODE_CONTINUOUS); - - /* Pre-read fan clock divisor values */ - via686a_update_fan_div(data); -} - -static struct via686a_data *via686a_update_device(struct device *dev) -{ - struct via686a_data *data = dev_get_drvdata(dev); - int i; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - for (i = 0; i <= 4; i++) { - data->in[i] = - via686a_read_value(data, VIA686A_REG_IN(i)); - data->in_min[i] = via686a_read_value(data, - VIA686A_REG_IN_MIN - (i)); - data->in_max[i] = - via686a_read_value(data, VIA686A_REG_IN_MAX(i)); - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = - via686a_read_value(data, VIA686A_REG_FAN(i)); - data->fan_min[i - 1] = via686a_read_value(data, - VIA686A_REG_FAN_MIN(i)); - } - for (i = 0; i <= 2; i++) { - data->temp[i] = via686a_read_value(data, - VIA686A_REG_TEMP[i]) << 2; - data->temp_over[i] = - via686a_read_value(data, - VIA686A_REG_TEMP_OVER[i]); - data->temp_hyst[i] = - via686a_read_value(data, - VIA686A_REG_TEMP_HYST[i]); - } - /* - * add in lower 2 bits - * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 - * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 - * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 - */ - data->temp[0] |= (via686a_read_value(data, - VIA686A_REG_TEMP_LOW1) - & 0xc0) >> 6; - data->temp[1] |= - (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & - 0x30) >> 4; - data->temp[2] |= - (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & - 0xc0) >> 6; - - via686a_update_fan_div(data); - data->alarms = - via686a_read_value(data, - VIA686A_REG_ALARM1) | - (via686a_read_value(data, VIA686A_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = true; - } - - mutex_unlock(&data->update_lock); - - return data; -} +static struct platform_driver via686a_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = via686a_probe, + .remove = via686a_remove, +}; static const struct pci_device_id via686a_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, @@ -819,7 +815,7 @@ static int via686a_device_add(unsigned short address) struct resource res = { .start = address, .end = address + VIA686A_EXTENT - 1, - .name = "via686a", + .name = DRIVER_NAME, .flags = IORESOURCE_IO, }; int err; @@ -828,7 +824,7 @@ static int via686a_device_add(unsigned short address) if (err) goto exit; - pdev = platform_device_alloc("via686a", address); + pdev = platform_device_alloc(DRIVER_NAME, address); if (!pdev) { err = -ENOMEM; pr_err("Device allocation failed\n"); @@ -918,7 +914,7 @@ exit: } static struct pci_driver via686a_pci_driver = { - .name = "via686a", + .name = DRIVER_NAME, .id_table = via686a_pci_ids, .probe = via686a_pci_probe, }; diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 03275ac8ba72..3b7f8922b0d5 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -38,6 +38,8 @@ static struct platform_device *pdev; #define VT8231_BASE_REG 0x70 #define VT8231_ENABLE_REG 0x74 +#define DRIVER_NAME "vt8231" + /* * The VT8231 registers * @@ -162,10 +164,6 @@ struct vt8231_data { }; static struct pci_dev *s_bridge; -static int vt8231_probe(struct platform_device *pdev); -static int vt8231_remove(struct platform_device *pdev); -static struct vt8231_data *vt8231_update_device(struct device *dev); -static void vt8231_init_device(struct vt8231_data *data); static inline int vt8231_read_value(struct vt8231_data *data, u8 reg) { @@ -178,6 +176,74 @@ static inline void vt8231_write_value(struct vt8231_data *data, u8 reg, outb_p(value, data->addr + reg); } +static struct vt8231_data *vt8231_update_device(struct device *dev) +{ + struct vt8231_data *data = dev_get_drvdata(dev); + int i; + u16 low; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + for (i = 0; i < 6; i++) { + if (ISVOLT(i, data->uch_config)) { + data->in[i] = vt8231_read_value(data, + regvolt[i]); + data->in_min[i] = vt8231_read_value(data, + regvoltmin[i]); + data->in_max[i] = vt8231_read_value(data, + regvoltmax[i]); + } + } + for (i = 0; i < 2; i++) { + data->fan[i] = vt8231_read_value(data, + VT8231_REG_FAN(i)); + data->fan_min[i] = vt8231_read_value(data, + VT8231_REG_FAN_MIN(i)); + } + + low = vt8231_read_value(data, VT8231_REG_TEMP_LOW01); + low = (low >> 6) | ((low & 0x30) >> 2) + | (vt8231_read_value(data, VT8231_REG_TEMP_LOW25) << 4); + for (i = 0; i < 6; i++) { + if (ISTEMP(i, data->uch_config)) { + data->temp[i] = (vt8231_read_value(data, + regtemp[i]) << 2) + | ((low >> (2 * i)) & 0x03); + data->temp_max[i] = vt8231_read_value(data, + regtempmax[i]); + data->temp_min[i] = vt8231_read_value(data, + regtempmin[i]); + } + } + + i = vt8231_read_value(data, VT8231_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = vt8231_read_value(data, VT8231_REG_ALARM1) | + (vt8231_read_value(data, VT8231_REG_ALARM2) << 8); + + /* Set alarm flags correctly */ + if (!data->fan[0] && data->fan_min[0]) + data->alarms |= 0x40; + else if (data->fan[0] && !data->fan_min[0]) + data->alarms &= ~0x40; + + if (!data->fan[1] && data->fan_min[1]) + data->alarms |= 0x80; + else if (data->fan[1] && !data->fan_min[1]) + data->alarms &= ~0x80; + + data->last_updated = jiffies; + data->valid = true; + } + + mutex_unlock(&data->update_lock); + + return data; +} + /* following are the sysfs callback functions */ static ssize_t in_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -751,29 +817,11 @@ static const struct attribute_group vt8231_group = { .attrs = vt8231_attributes, }; -static struct platform_driver vt8231_driver = { - .driver = { - .name = "vt8231", - }, - .probe = vt8231_probe, - .remove = vt8231_remove, -}; - -static const struct pci_device_id vt8231_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, vt8231_pci_ids); - -static int vt8231_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id); - -static struct pci_driver vt8231_pci_driver = { - .name = "vt8231", - .id_table = vt8231_pci_ids, - .probe = vt8231_pci_probe, -}; +static void vt8231_init_device(struct vt8231_data *data) +{ + vt8231_write_value(data, VT8231_REG_TEMP1_CONFIG, 0); + vt8231_write_value(data, VT8231_REG_TEMP2_CONFIG, 0); +} static int vt8231_probe(struct platform_device *pdev) { @@ -784,7 +832,7 @@ static int vt8231_probe(struct platform_device *pdev) /* Reserve the ISA region */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start, VT8231_EXTENT, - vt8231_driver.driver.name)) { + DRIVER_NAME)) { dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n", (unsigned long)res->start, (unsigned long)res->end); return -ENODEV; @@ -796,7 +844,7 @@ static int vt8231_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); data->addr = res->start; - data->name = "vt8231"; + data->name = DRIVER_NAME; mutex_init(&data->update_lock); vt8231_init_device(data); @@ -863,86 +911,28 @@ static int vt8231_remove(struct platform_device *pdev) return 0; } -static void vt8231_init_device(struct vt8231_data *data) -{ - vt8231_write_value(data, VT8231_REG_TEMP1_CONFIG, 0); - vt8231_write_value(data, VT8231_REG_TEMP2_CONFIG, 0); -} - -static struct vt8231_data *vt8231_update_device(struct device *dev) -{ - struct vt8231_data *data = dev_get_drvdata(dev); - int i; - u16 low; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - for (i = 0; i < 6; i++) { - if (ISVOLT(i, data->uch_config)) { - data->in[i] = vt8231_read_value(data, - regvolt[i]); - data->in_min[i] = vt8231_read_value(data, - regvoltmin[i]); - data->in_max[i] = vt8231_read_value(data, - regvoltmax[i]); - } - } - for (i = 0; i < 2; i++) { - data->fan[i] = vt8231_read_value(data, - VT8231_REG_FAN(i)); - data->fan_min[i] = vt8231_read_value(data, - VT8231_REG_FAN_MIN(i)); - } - - low = vt8231_read_value(data, VT8231_REG_TEMP_LOW01); - low = (low >> 6) | ((low & 0x30) >> 2) - | (vt8231_read_value(data, VT8231_REG_TEMP_LOW25) << 4); - for (i = 0; i < 6; i++) { - if (ISTEMP(i, data->uch_config)) { - data->temp[i] = (vt8231_read_value(data, - regtemp[i]) << 2) - | ((low >> (2 * i)) & 0x03); - data->temp_max[i] = vt8231_read_value(data, - regtempmax[i]); - data->temp_min[i] = vt8231_read_value(data, - regtempmin[i]); - } - } - - i = vt8231_read_value(data, VT8231_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = vt8231_read_value(data, VT8231_REG_ALARM1) | - (vt8231_read_value(data, VT8231_REG_ALARM2) << 8); - - /* Set alarm flags correctly */ - if (!data->fan[0] && data->fan_min[0]) - data->alarms |= 0x40; - else if (data->fan[0] && !data->fan_min[0]) - data->alarms &= ~0x40; - - if (!data->fan[1] && data->fan_min[1]) - data->alarms |= 0x80; - else if (data->fan[1] && !data->fan_min[1]) - data->alarms &= ~0x80; - data->last_updated = jiffies; - data->valid = true; - } +static struct platform_driver vt8231_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = vt8231_probe, + .remove = vt8231_remove, +}; - mutex_unlock(&data->update_lock); +static const struct pci_device_id vt8231_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4) }, + { 0, } +}; - return data; -} +MODULE_DEVICE_TABLE(pci, vt8231_pci_ids); static int vt8231_device_add(unsigned short address) { struct resource res = { .start = address, .end = address + VT8231_EXTENT - 1, - .name = "vt8231", + .name = DRIVER_NAME, .flags = IORESOURCE_IO, }; int err; @@ -951,7 +941,7 @@ static int vt8231_device_add(unsigned short address) if (err) goto exit; - pdev = platform_device_alloc("vt8231", address); + pdev = platform_device_alloc(DRIVER_NAME, address); if (!pdev) { err = -ENOMEM; pr_err("Device allocation failed\n"); @@ -1040,6 +1030,12 @@ exit: return -ENODEV; } +static struct pci_driver vt8231_pci_driver = { + .name = DRIVER_NAME, + .id_table = vt8231_pci_ids, + .probe = vt8231_pci_probe, +}; + static int __init sm_vt8231_init(void) { return pci_register_driver(&vt8231_pci_driver); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index af89b32a93a5..939d4c35e713 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1944,7 +1944,7 @@ static int __init w83627ehf_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(hwmon_dev); } -static int __maybe_unused w83627ehf_suspend(struct device *dev) +static int w83627ehf_suspend(struct device *dev) { struct w83627ehf_data *data = w83627ehf_update_device(dev); @@ -1955,7 +1955,7 @@ static int __maybe_unused w83627ehf_suspend(struct device *dev) return 0; } -static int __maybe_unused w83627ehf_resume(struct device *dev) +static int w83627ehf_resume(struct device *dev) { struct w83627ehf_data *data = dev_get_drvdata(dev); int i; @@ -2010,12 +2010,12 @@ static int __maybe_unused w83627ehf_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(w83627ehf_dev_pm_ops, w83627ehf_suspend, w83627ehf_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(w83627ehf_dev_pm_ops, w83627ehf_suspend, w83627ehf_resume); static struct platform_driver w83627ehf_driver = { .driver = { .name = DRVNAME, - .pm = &w83627ehf_dev_pm_ops, + .pm = pm_sleep_ptr(&w83627ehf_dev_pm_ops), }, }; diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 9be277156ed2..b638d672ac45 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -389,14 +389,184 @@ struct w83627hf_data { #endif }; -static int w83627hf_probe(struct platform_device *pdev); -static int w83627hf_remove(struct platform_device *pdev); +/* Registers 0x50-0x5f are banked */ +static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg) +{ + if ((reg & 0x00f0) == 0x50) { + outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET); + } +} + +/* Not strictly necessary, but play it safe for now */ +static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); + } +} + +static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) +{ + int res, word_sized; + + mutex_lock(&data->lock); + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x50) + || ((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + w83627hf_set_bank(data, reg); + outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); + res = inb_p(data->addr + W83781D_DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + data->addr + W83781D_ADDR_REG_OFFSET); + res = + (res << 8) + inb_p(data->addr + + W83781D_DATA_REG_OFFSET); + } + w83627hf_reset_bank(data, reg); + mutex_unlock(&data->lock); + return res; +} + +static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) +{ + int word_sized; + + mutex_lock(&data->lock); + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + w83627hf_set_bank(data, reg); + outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, + data->addr + W83781D_DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + data->addr + W83781D_ADDR_REG_OFFSET); + } + outb_p(value & 0xff, + data->addr + W83781D_DATA_REG_OFFSET); + w83627hf_reset_bank(data, reg); + mutex_unlock(&data->lock); + return 0; +} + +static void w83627hf_update_fan_div(struct w83627hf_data *data) +{ + int reg; + + reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); + data->fan_div[0] = (reg >> 4) & 0x03; + data->fan_div[1] = (reg >> 6) & 0x03; + if (data->type != w83697hf) { + data->fan_div[2] = (w83627hf_read_value(data, + W83781D_REG_PIN) >> 6) & 0x03; + } + reg = w83627hf_read_value(data, W83781D_REG_VBAT); + data->fan_div[0] |= (reg >> 3) & 0x04; + data->fan_div[1] |= (reg >> 4) & 0x04; + if (data->type != w83697hf) + data->fan_div[2] |= (reg >> 5) & 0x04; +} -static int w83627hf_read_value(struct w83627hf_data *data, u16 reg); -static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value); -static void w83627hf_update_fan_div(struct w83627hf_data *data); -static struct w83627hf_data *w83627hf_update_device(struct device *dev); -static void w83627hf_init_device(struct platform_device *pdev); +static struct w83627hf_data *w83627hf_update_device(struct device *dev) +{ + struct w83627hf_data *data = dev_get_drvdata(dev); + int i, num_temps = (data->type == w83697hf) ? 2 : 3; + int num_pwms = (data->type == w83697hf) ? 2 : 3; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + for (i = 0; i <= 8; i++) { + /* skip missing sensors */ + if (((data->type == w83697hf) && (i == 1)) || + ((data->type != w83627hf && data->type != w83697hf) + && (i == 5 || i == 6))) + continue; + data->in[i] = + w83627hf_read_value(data, W83781D_REG_IN(i)); + data->in_min[i] = + w83627hf_read_value(data, + W83781D_REG_IN_MIN(i)); + data->in_max[i] = + w83627hf_read_value(data, + W83781D_REG_IN_MAX(i)); + } + for (i = 0; i <= 2; i++) { + data->fan[i] = + w83627hf_read_value(data, W83627HF_REG_FAN(i)); + data->fan_min[i] = + w83627hf_read_value(data, + W83627HF_REG_FAN_MIN(i)); + } + for (i = 0; i <= 2; i++) { + u8 tmp = w83627hf_read_value(data, + W836X7HF_REG_PWM(data->type, i)); + /* bits 0-3 are reserved in 627THF */ + if (data->type == w83627thf) + tmp &= 0xf0; + data->pwm[i] = tmp; + if (i == 1 && + (data->type == w83627hf || data->type == w83697hf)) + break; + } + if (data->type == w83627hf) { + u8 tmp = w83627hf_read_value(data, + W83627HF_REG_PWM_FREQ); + data->pwm_freq[0] = tmp & 0x07; + data->pwm_freq[1] = (tmp >> 4) & 0x07; + } else if (data->type != w83627thf) { + for (i = 1; i <= 3; i++) { + data->pwm_freq[i - 1] = + w83627hf_read_value(data, + W83637HF_REG_PWM_FREQ[i - 1]); + if (i == 2 && (data->type == w83697hf)) + break; + } + } + if (data->type != w83627hf) { + for (i = 0; i < num_pwms; i++) { + u8 tmp = w83627hf_read_value(data, + W83627THF_REG_PWM_ENABLE[i]); + data->pwm_enable[i] = + ((tmp >> W83627THF_PWM_ENABLE_SHIFT[i]) + & 0x03) + 1; + } + } + for (i = 0; i < num_temps; i++) { + data->temp[i] = w83627hf_read_value( + data, w83627hf_reg_temp[i]); + data->temp_max[i] = w83627hf_read_value( + data, w83627hf_reg_temp_over[i]); + data->temp_max_hyst[i] = w83627hf_read_value( + data, w83627hf_reg_temp_hyst[i]); + } + + w83627hf_update_fan_div(data); + + data->alarms = + w83627hf_read_value(data, W83781D_REG_ALARM1) | + (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) | + (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16); + i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2); + data->beep_mask = (i << 8) | + w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) | + w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16; + data->last_updated = jiffies; + data->valid = true; + } + + mutex_unlock(&data->update_lock); + + return data; +} #ifdef CONFIG_PM static int w83627hf_suspend(struct device *dev) @@ -464,99 +634,171 @@ static const struct dev_pm_ops w83627hf_dev_pm_ops = { #define W83627HF_DEV_PM_OPS NULL #endif /* CONFIG_PM */ -static struct platform_driver w83627hf_driver = { - .driver = { - .name = DRVNAME, - .pm = W83627HF_DEV_PM_OPS, - }, - .probe = w83627hf_probe, - .remove = w83627hf_remove, -}; - -static ssize_t -in_input_show(struct device *dev, struct device_attribute *devattr, char *buf) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr])); -} -static ssize_t -in_min_show(struct device *dev, struct device_attribute *devattr, char *buf) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr])); -} -static ssize_t -in_max_show(struct device *dev, struct device_attribute *devattr, char *buf) +static int w83627thf_read_gpio5(struct platform_device *pdev) { - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr])); + struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); + int res = 0xff, sel; + + if (superio_enter(sio_data)) { + /* + * Some other driver reserved the address space for itself. + * We don't want to fail driver instantiation because of that, + * so display a warning and keep going. + */ + dev_warn(&pdev->dev, + "Can not read VID data: Failed to enable SuperIO access\n"); + return res; + } + + superio_select(sio_data, W83627HF_LD_GPIO5); + + res = 0xff; + + /* Make sure these GPIO pins are enabled */ + if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) { + dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n"); + goto exit; + } + + /* + * Make sure the pins are configured for input + * There must be at least five (VRM 9), and possibly 6 (VRM 10) + */ + sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f; + if ((sel & 0x1f) != 0x1f) { + dev_dbg(&pdev->dev, "GPIO5 not configured for VID " + "function\n"); + goto exit; + } + + dev_info(&pdev->dev, "Reading VID from GPIO5\n"); + res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel; + +exit: + superio_exit(sio_data); + return res; } -static ssize_t -in_min_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) + +static int w83687thf_read_vid(struct platform_device *pdev) { - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = dev_get_drvdata(dev); - long val; - int err; + struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); + int res = 0xff; - err = kstrtol(buf, 10, &val); - if (err) - return err; + if (superio_enter(sio_data)) { + /* + * Some other driver reserved the address space for itself. + * We don't want to fail driver instantiation because of that, + * so display a warning and keep going. + */ + dev_warn(&pdev->dev, + "Can not read VID data: Failed to enable SuperIO access\n"); + return res; + } - mutex_lock(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val); - w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]); - mutex_unlock(&data->update_lock); - return count; + superio_select(sio_data, W83627HF_LD_HWM); + + /* Make sure these GPIO pins are enabled */ + if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) { + dev_dbg(&pdev->dev, "VID disabled, no VID function\n"); + goto exit; + } + + /* Make sure the pins are configured for input */ + if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) { + dev_dbg(&pdev->dev, "VID configured as output, " + "no VID function\n"); + goto exit; + } + + res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f; + +exit: + superio_exit(sio_data); + return res; } -static ssize_t -in_max_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) + +static void w83627hf_init_device(struct platform_device *pdev) { - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = dev_get_drvdata(dev); - long val; - int err; + struct w83627hf_data *data = platform_get_drvdata(pdev); + int i; + enum chips type = data->type; + u8 tmp; - err = kstrtol(buf, 10, &val); - if (err) - return err; + /* Minimize conflicts with other winbond i2c-only clients... */ + /* disable i2c subclients... how to disable main i2c client?? */ + /* force i2c address to relatively uncommon address */ + if (type == w83627hf) { + w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89); + w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c); + } - mutex_lock(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val); - w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]); - mutex_unlock(&data->update_lock); - return count; -} + /* Read VID only once */ + if (type == w83627hf || type == w83637hf) { + int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); + int hi = w83627hf_read_value(data, W83781D_REG_CHIPID); + data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); + } else if (type == w83627thf) { + data->vid = w83627thf_read_gpio5(pdev); + } else if (type == w83687thf) { + data->vid = w83687thf_read_vid(pdev); + } -static SENSOR_DEVICE_ATTR_RO(in1_input, in_input, 1); -static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1); -static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1); -static SENSOR_DEVICE_ATTR_RO(in2_input, in_input, 2); -static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2); -static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2); -static SENSOR_DEVICE_ATTR_RO(in3_input, in_input, 3); -static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3); -static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3); -static SENSOR_DEVICE_ATTR_RO(in4_input, in_input, 4); -static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4); -static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4); -static SENSOR_DEVICE_ATTR_RO(in5_input, in_input, 5); -static SENSOR_DEVICE_ATTR_RW(in5_min, in_min, 5); -static SENSOR_DEVICE_ATTR_RW(in5_max, in_max, 5); -static SENSOR_DEVICE_ATTR_RO(in6_input, in_input, 6); -static SENSOR_DEVICE_ATTR_RW(in6_min, in_min, 6); -static SENSOR_DEVICE_ATTR_RW(in6_max, in_max, 6); -static SENSOR_DEVICE_ATTR_RO(in7_input, in_input, 7); -static SENSOR_DEVICE_ATTR_RW(in7_min, in_min, 7); -static SENSOR_DEVICE_ATTR_RW(in7_max, in_max, 7); -static SENSOR_DEVICE_ATTR_RO(in8_input, in_input, 8); -static SENSOR_DEVICE_ATTR_RW(in8_min, in_min, 8); -static SENSOR_DEVICE_ATTR_RW(in8_max, in_max, 8); + /* Read VRM & OVT Config only once */ + if (type == w83627thf || type == w83637hf || type == w83687thf) { + data->vrm_ovt = + w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG); + } + + tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); + for (i = 1; i <= 3; i++) { + if (!(tmp & BIT_SCFG1[i - 1])) { + data->sens[i - 1] = 4; + } else { + if (w83627hf_read_value + (data, + W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) + data->sens[i - 1] = 1; + else + data->sens[i - 1] = 2; + } + if ((type == w83697hf) && (i == 2)) + break; + } + + if(init) { + /* Enable temp2 */ + tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG); + if (tmp & 0x01) { + dev_warn(&pdev->dev, "Enabling temp2, readings " + "might not make sense\n"); + w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG, + tmp & 0xfe); + } + + /* Enable temp3 */ + if (type != w83697hf) { + tmp = w83627hf_read_value(data, + W83627HF_REG_TEMP3_CONFIG); + if (tmp & 0x01) { + dev_warn(&pdev->dev, "Enabling temp3, " + "readings might not make sense\n"); + w83627hf_write_value(data, + W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe); + } + } + } + + /* Start monitoring */ + w83627hf_write_value(data, W83781D_REG_CONFIG, + (w83627hf_read_value(data, + W83781D_REG_CONFIG) & 0xf7) + | 0x01); + + /* Enable VBAT monitoring if needed */ + tmp = w83627hf_read_value(data, W83781D_REG_VBAT); + if (!(tmp & 0x01)) + w83627hf_write_value(data, W83781D_REG_VBAT, tmp | 0x01); +} /* use a different set of functions for in0 */ static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) @@ -582,6 +824,7 @@ static ssize_t in0_input_show(struct device *dev, struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in[0]); } +static DEVICE_ATTR_RO(in0_input); static ssize_t in0_min_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -590,13 +833,6 @@ static ssize_t in0_min_show(struct device *dev, struct device_attribute *attr, return show_in_0(data, buf, data->in_min[0]); } -static ssize_t in0_max_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return show_in_0(data, buf, data->in_max[0]); -} - static ssize_t in0_min_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -627,6 +863,15 @@ static ssize_t in0_min_store(struct device *dev, return count; } +static DEVICE_ATTR_RW(in0_min); + +static ssize_t in0_max_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in_max[0]); +} + static ssize_t in0_max_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -657,193 +902,16 @@ static ssize_t in0_max_store(struct device *dev, return count; } -static DEVICE_ATTR_RO(in0_input); -static DEVICE_ATTR_RW(in0_min); static DEVICE_ATTR_RW(in0_max); static ssize_t -fan_input_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr], - (long)DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t -fan_min_show(struct device *dev, struct device_attribute *devattr, char *buf) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr], - (long)DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t -fan_min_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = dev_get_drvdata(dev); - unsigned long val; - int err; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), - data->fan_min[nr]); - - mutex_unlock(&data->update_lock); - return count; -} - -static SENSOR_DEVICE_ATTR_RO(fan1_input, fan_input, 0); -static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0); -static SENSOR_DEVICE_ATTR_RO(fan2_input, fan_input, 1); -static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1); -static SENSOR_DEVICE_ATTR_RO(fan3_input, fan_input, 2); -static SENSOR_DEVICE_ATTR_RW(fan3_min, fan_min, 2); - -static ssize_t -temp_show(struct device *dev, struct device_attribute *devattr, char *buf) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = w83627hf_update_device(dev); - - u16 tmp = data->temp[nr]; - return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp) - : (long) TEMP_FROM_REG(tmp)); -} - -static ssize_t -temp_max_show(struct device *dev, struct device_attribute *devattr, char *buf) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = w83627hf_update_device(dev); - - u16 tmp = data->temp_max[nr]; - return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp) - : (long) TEMP_FROM_REG(tmp)); -} - -static ssize_t -temp_max_hyst_show(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = w83627hf_update_device(dev); - - u16 tmp = data->temp_max_hyst[nr]; - return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp) - : (long) TEMP_FROM_REG(tmp)); -} - -static ssize_t -temp_max_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = dev_get_drvdata(dev); - u16 tmp; - long val; - int err; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); - mutex_lock(&data->update_lock); - data->temp_max[nr] = tmp; - w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp); - mutex_unlock(&data->update_lock); - return count; -} - -static ssize_t -temp_max_hyst_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = dev_get_drvdata(dev); - u16 tmp; - long val; - int err; - - err = kstrtol(buf, 10, &val); - if (err) - return err; - - tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); - mutex_lock(&data->update_lock); - data->temp_max_hyst[nr] = tmp; - w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp); - mutex_unlock(&data->update_lock); - return count; -} - -static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); -static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0); -static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp_max_hyst, 0); -static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1); -static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1); -static SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, temp_max_hyst, 1); -static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2); -static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2); -static SENSOR_DEVICE_ATTR_RW(temp3_max_hyst, temp_max_hyst, 2); - -static ssize_t -cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR_RO(cpu0_vid); - -static ssize_t -vrm_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = dev_get_drvdata(dev); - return sprintf(buf, "%ld\n", (long) data->vrm); -} -static ssize_t -vrm_store(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct w83627hf_data *data = dev_get_drvdata(dev); - unsigned long val; - int err; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - if (val > 255) - return -EINVAL; - data->vrm = val; - - return count; -} -static DEVICE_ATTR_RW(vrm); - -static ssize_t -alarms_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->alarms); -} -static DEVICE_ATTR_RO(alarms); - -static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); int bitnr = to_sensor_dev_attr(attr)->index; return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } + static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0); static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1); static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2); @@ -861,44 +929,6 @@ static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 5); static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, 13); static ssize_t -beep_mask_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", - (long)BEEP_MASK_FROM_REG(data->beep_mask)); -} - -static ssize_t -beep_mask_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct w83627hf_data *data = dev_get_drvdata(dev); - unsigned long val; - int err; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - - /* preserve beep enable */ - data->beep_mask = (data->beep_mask & 0x8000) - | BEEP_MASK_TO_REG(val); - w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, - data->beep_mask & 0xff); - w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, - ((data->beep_mask) >> 16) & 0xff); - w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, - (data->beep_mask >> 8) & 0xff); - - mutex_unlock(&data->update_lock); - return count; -} - -static DEVICE_ATTR_RW(beep_mask); - -static ssize_t beep_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); @@ -974,6 +1004,143 @@ static SENSOR_DEVICE_ATTR_RW(temp3_beep, beep, 13); static SENSOR_DEVICE_ATTR_RW(beep_enable, beep, 15); static ssize_t +in_input_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr])); +} + +static ssize_t +in_min_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t +in_min_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +in_max_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t +in_max_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static SENSOR_DEVICE_ATTR_RO(in1_input, in_input, 1); +static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1); +static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1); +static SENSOR_DEVICE_ATTR_RO(in2_input, in_input, 2); +static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2); +static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2); +static SENSOR_DEVICE_ATTR_RO(in3_input, in_input, 3); +static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3); +static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3); +static SENSOR_DEVICE_ATTR_RO(in4_input, in_input, 4); +static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4); +static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4); +static SENSOR_DEVICE_ATTR_RO(in5_input, in_input, 5); +static SENSOR_DEVICE_ATTR_RW(in5_min, in_min, 5); +static SENSOR_DEVICE_ATTR_RW(in5_max, in_max, 5); +static SENSOR_DEVICE_ATTR_RO(in6_input, in_input, 6); +static SENSOR_DEVICE_ATTR_RW(in6_min, in_min, 6); +static SENSOR_DEVICE_ATTR_RW(in6_max, in_max, 6); +static SENSOR_DEVICE_ATTR_RO(in7_input, in_input, 7); +static SENSOR_DEVICE_ATTR_RW(in7_min, in_min, 7); +static SENSOR_DEVICE_ATTR_RW(in7_max, in_max, 7); +static SENSOR_DEVICE_ATTR_RO(in8_input, in_input, 8); +static SENSOR_DEVICE_ATTR_RW(in8_min, in_min, 8); +static SENSOR_DEVICE_ATTR_RW(in8_max, in_max, 8); + +static ssize_t +fan_input_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr], + (long)DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t +fan_min_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr], + (long)DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t +fan_min_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), + data->fan_min[nr]); + + mutex_unlock(&data->update_lock); + return count; +} + +static SENSOR_DEVICE_ATTR_RO(fan1_input, fan_input, 0); +static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0); +static SENSOR_DEVICE_ATTR_RO(fan2_input, fan_input, 1); +static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1); +static SENSOR_DEVICE_ATTR_RO(fan3_input, fan_input, 2); +static SENSOR_DEVICE_ATTR_RW(fan3_min, fan_min, 2); + +static ssize_t fan_div_show(struct device *dev, struct device_attribute *devattr, char *buf) { int nr = to_sensor_dev_attr(devattr)->index; @@ -981,6 +1148,7 @@ fan_div_show(struct device *dev, struct device_attribute *devattr, char *buf) return sprintf(buf, "%ld\n", (long) DIV_FROM_REG(data->fan_div[nr])); } + /* * Note: we save and restore the fan minimum here, because its value is * determined in part by the fan divisor. This follows the principle of @@ -1033,138 +1201,92 @@ static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1); static SENSOR_DEVICE_ATTR_RW(fan3_div, fan_div, 2); static ssize_t -pwm_show(struct device *dev, struct device_attribute *devattr, char *buf) +temp_show(struct device *dev, struct device_attribute *devattr, char *buf) { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->pwm[nr]); -} -static ssize_t -pwm_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - int nr = to_sensor_dev_attr(devattr)->index; - struct w83627hf_data *data = dev_get_drvdata(dev); - unsigned long val; - int err; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - - mutex_lock(&data->update_lock); - - if (data->type == w83627thf) { - /* bits 0-3 are reserved in 627THF */ - data->pwm[nr] = PWM_TO_REG(val) & 0xf0; - w83627hf_write_value(data, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr] | - (w83627hf_read_value(data, - W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); - } else { - data->pwm[nr] = PWM_TO_REG(val); - w83627hf_write_value(data, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr]); - } - - mutex_unlock(&data->update_lock); - return count; + u16 tmp = data->temp[nr]; + return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp) + : (long) TEMP_FROM_REG(tmp)); } -static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); -static SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1); -static SENSOR_DEVICE_ATTR_RW(pwm3, pwm, 2); - static ssize_t -pwm_enable_show(struct device *dev, struct device_attribute *devattr, - char *buf) +temp_max_show(struct device *dev, struct device_attribute *devattr, char *buf) { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%d\n", data->pwm_enable[nr]); + + u16 tmp = data->temp_max[nr]; + return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp) + : (long) TEMP_FROM_REG(tmp)); } static ssize_t -pwm_enable_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +temp_max_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - u8 reg; - unsigned long val; + u16 tmp; + long val; int err; - err = kstrtoul(buf, 10, &val); + err = kstrtol(buf, 10, &val); if (err) return err; - if (!val || val > 3) /* modes 1, 2 and 3 are supported */ - return -EINVAL; + tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); mutex_lock(&data->update_lock); - data->pwm_enable[nr] = val; - reg = w83627hf_read_value(data, W83627THF_REG_PWM_ENABLE[nr]); - reg &= ~(0x03 << W83627THF_PWM_ENABLE_SHIFT[nr]); - reg |= (val - 1) << W83627THF_PWM_ENABLE_SHIFT[nr]; - w83627hf_write_value(data, W83627THF_REG_PWM_ENABLE[nr], reg); + data->temp_max[nr] = tmp; + w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp); mutex_unlock(&data->update_lock); return count; } -static SENSOR_DEVICE_ATTR_RW(pwm1_enable, pwm_enable, 0); -static SENSOR_DEVICE_ATTR_RW(pwm2_enable, pwm_enable, 1); -static SENSOR_DEVICE_ATTR_RW(pwm3_enable, pwm_enable, 2); - static ssize_t -pwm_freq_show(struct device *dev, struct device_attribute *devattr, char *buf) +temp_max_hyst_show(struct device *dev, struct device_attribute *devattr, + char *buf) { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); - if (data->type == w83627hf) - return sprintf(buf, "%ld\n", - pwm_freq_from_reg_627hf(data->pwm_freq[nr])); - else - return sprintf(buf, "%ld\n", - pwm_freq_from_reg(data->pwm_freq[nr])); + + u16 tmp = data->temp_max_hyst[nr]; + return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp) + : (long) TEMP_FROM_REG(tmp)); } static ssize_t -pwm_freq_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +temp_max_hyst_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - static const u8 mask[]={0xF8, 0x8F}; - unsigned long val; + u16 tmp; + long val; int err; - err = kstrtoul(buf, 10, &val); + err = kstrtol(buf, 10, &val); if (err) return err; + tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); mutex_lock(&data->update_lock); - - if (data->type == w83627hf) { - data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val); - w83627hf_write_value(data, W83627HF_REG_PWM_FREQ, - (data->pwm_freq[nr] << (nr*4)) | - (w83627hf_read_value(data, - W83627HF_REG_PWM_FREQ) & mask[nr])); - } else { - data->pwm_freq[nr] = pwm_freq_to_reg(val); - w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr], - data->pwm_freq[nr]); - } - + data->temp_max_hyst[nr] = tmp; + w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp); mutex_unlock(&data->update_lock); return count; } -static SENSOR_DEVICE_ATTR_RW(pwm1_freq, pwm_freq, 0); -static SENSOR_DEVICE_ATTR_RW(pwm2_freq, pwm_freq, 1); -static SENSOR_DEVICE_ATTR_RW(pwm3_freq, pwm_freq, 2); +static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); +static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0); +static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp_max_hyst, 0); +static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1); +static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1); +static SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, temp_max_hyst, 1); +static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2); +static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2); +static SENSOR_DEVICE_ATTR_RW(temp3_max_hyst, temp_max_hyst, 2); static ssize_t temp_type_show(struct device *dev, struct device_attribute *devattr, @@ -1236,81 +1358,12 @@ static SENSOR_DEVICE_ATTR_RW(temp2_type, temp_type, 1); static SENSOR_DEVICE_ATTR_RW(temp3_type, temp_type, 2); static ssize_t -name_show(struct device *dev, struct device_attribute *devattr, char *buf) -{ - struct w83627hf_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", data->name); -} -static DEVICE_ATTR_RO(name); - -static int __init w83627hf_find(int sioaddr, unsigned short *addr, - struct w83627hf_sio_data *sio_data) +alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { - int err; - u16 val; - - static __initconst char *const names[] = { - "W83627HF", - "W83627THF", - "W83697HF", - "W83637HF", - "W83687THF", - }; - - sio_data->sioaddr = sioaddr; - err = superio_enter(sio_data); - if (err) - return err; - - err = -ENODEV; - val = force_id ? force_id : superio_inb(sio_data, DEVID); - switch (val) { - case W627_DEVID: - sio_data->type = w83627hf; - break; - case W627THF_DEVID: - sio_data->type = w83627thf; - break; - case W697_DEVID: - sio_data->type = w83697hf; - break; - case W637_DEVID: - sio_data->type = w83637hf; - break; - case W687THF_DEVID: - sio_data->type = w83687thf; - break; - case 0xff: /* No device at all */ - goto exit; - default: - pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val); - goto exit; - } - - superio_select(sio_data, W83627HF_LD_HWM); - val = (superio_inb(sio_data, WINB_BASE_REG) << 8) | - superio_inb(sio_data, WINB_BASE_REG + 1); - *addr = val & WINB_ALIGNMENT; - if (*addr == 0) { - pr_warn("Base address not set, skipping\n"); - goto exit; - } - - val = superio_inb(sio_data, WINB_ACT_REG); - if (!(val & 0x01)) { - pr_warn("Enabling HWM logical device\n"); - superio_outb(sio_data, WINB_ACT_REG, val | 0x01); - } - - err = 0; - pr_info(DRVNAME ": Found %s chip at %#x\n", - names[sio_data->type], *addr); - - exit: - superio_exit(sio_data); - return err; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->alarms); } +static DEVICE_ATTR_RO(alarms); #define VIN_UNIT_ATTRS(_X_) \ &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \ @@ -1334,6 +1387,100 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr, &sensor_dev_attr_temp##_X_##_alarm.dev_attr.attr, \ &sensor_dev_attr_temp##_X_##_beep.dev_attr.attr +static ssize_t +beep_mask_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", + (long)BEEP_MASK_FROM_REG(data->beep_mask)); +} + +static ssize_t +beep_mask_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct w83627hf_data *data = dev_get_drvdata(dev); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + + /* preserve beep enable */ + data->beep_mask = (data->beep_mask & 0x8000) + | BEEP_MASK_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, + data->beep_mask & 0xff); + w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, + ((data->beep_mask) >> 16) & 0xff); + w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, + (data->beep_mask >> 8) & 0xff); + + mutex_unlock(&data->update_lock); + return count; +} + +static DEVICE_ATTR_RW(beep_mask); + +static ssize_t +pwm_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->pwm[nr]); +} + +static ssize_t +pwm_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + + if (data->type == w83627thf) { + /* bits 0-3 are reserved in 627THF */ + data->pwm[nr] = PWM_TO_REG(val) & 0xf0; + w83627hf_write_value(data, + W836X7HF_REG_PWM(data->type, nr), + data->pwm[nr] | + (w83627hf_read_value(data, + W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); + } else { + data->pwm[nr] = PWM_TO_REG(val); + w83627hf_write_value(data, + W836X7HF_REG_PWM(data->type, nr), + data->pwm[nr]); + } + + mutex_unlock(&data->update_lock); + return count; +} + +static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); +static SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1); +static SENSOR_DEVICE_ATTR_RW(pwm3, pwm, 2); + +static ssize_t +name_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct w83627hf_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->name); +} + +static DEVICE_ATTR_RO(name); + static struct attribute *w83627hf_attributes[] = { &dev_attr_in0_input.attr, &dev_attr_in0_min.attr, @@ -1366,6 +1513,131 @@ static const struct attribute_group w83627hf_group = { .attrs = w83627hf_attributes, }; +static ssize_t +pwm_freq_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + if (data->type == w83627hf) + return sprintf(buf, "%ld\n", + pwm_freq_from_reg_627hf(data->pwm_freq[nr])); + else + return sprintf(buf, "%ld\n", + pwm_freq_from_reg(data->pwm_freq[nr])); +} + +static ssize_t +pwm_freq_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + static const u8 mask[]={0xF8, 0x8F}; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + + if (data->type == w83627hf) { + data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val); + w83627hf_write_value(data, W83627HF_REG_PWM_FREQ, + (data->pwm_freq[nr] << (nr*4)) | + (w83627hf_read_value(data, + W83627HF_REG_PWM_FREQ) & mask[nr])); + } else { + data->pwm_freq[nr] = pwm_freq_to_reg(val); + w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr], + data->pwm_freq[nr]); + } + + mutex_unlock(&data->update_lock); + return count; +} + +static SENSOR_DEVICE_ATTR_RW(pwm1_freq, pwm_freq, 0); +static SENSOR_DEVICE_ATTR_RW(pwm2_freq, pwm_freq, 1); +static SENSOR_DEVICE_ATTR_RW(pwm3_freq, pwm_freq, 2); + +static ssize_t +cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} + +static DEVICE_ATTR_RO(cpu0_vid); + +static ssize_t +vrm_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} + +static ssize_t +vrm_store(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct w83627hf_data *data = dev_get_drvdata(dev); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + if (val > 255) + return -EINVAL; + data->vrm = val; + + return count; +} + +static DEVICE_ATTR_RW(vrm); + +static ssize_t +pwm_enable_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%d\n", data->pwm_enable[nr]); +} + +static ssize_t +pwm_enable_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + u8 reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + if (!val || val > 3) /* modes 1, 2 and 3 are supported */ + return -EINVAL; + mutex_lock(&data->update_lock); + data->pwm_enable[nr] = val; + reg = w83627hf_read_value(data, W83627THF_REG_PWM_ENABLE[nr]); + reg &= ~(0x03 << W83627THF_PWM_ENABLE_SHIFT[nr]); + reg |= (val - 1) << W83627THF_PWM_ENABLE_SHIFT[nr]; + w83627hf_write_value(data, W83627THF_REG_PWM_ENABLE[nr], reg); + mutex_unlock(&data->update_lock); + return count; +} + +static SENSOR_DEVICE_ATTR_RW(pwm1_enable, pwm_enable, 0); +static SENSOR_DEVICE_ATTR_RW(pwm2_enable, pwm_enable, 1); +static SENSOR_DEVICE_ATTR_RW(pwm3_enable, pwm_enable, 2); + static struct attribute *w83627hf_attributes_opt[] = { VIN_UNIT_ATTRS(1), VIN_UNIT_ATTRS(5), @@ -1568,349 +1840,81 @@ static int w83627hf_remove(struct platform_device *pdev) return 0; } -/* Registers 0x50-0x5f are banked */ -static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg) -{ - if ((reg & 0x00f0) == 0x50) { - outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET); - } -} - -/* Not strictly necessary, but play it safe for now */ -static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg) -{ - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); - } -} - -static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) -{ - int res, word_sized; - - mutex_lock(&data->lock); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x50) - || ((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - w83627hf_set_bank(data, reg); - outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(data->addr + W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - data->addr + W83781D_ADDR_REG_OFFSET); - res = - (res << 8) + inb_p(data->addr + - W83781D_DATA_REG_OFFSET); - } - w83627hf_reset_bank(data, reg); - mutex_unlock(&data->lock); - return res; -} +static struct platform_driver w83627hf_driver = { + .driver = { + .name = DRVNAME, + .pm = W83627HF_DEV_PM_OPS, + }, + .probe = w83627hf_probe, + .remove = w83627hf_remove, +}; -static int w83627thf_read_gpio5(struct platform_device *pdev) +static int __init w83627hf_find(int sioaddr, unsigned short *addr, + struct w83627hf_sio_data *sio_data) { - struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); - int res = 0xff, sel; - - if (superio_enter(sio_data)) { - /* - * Some other driver reserved the address space for itself. - * We don't want to fail driver instantiation because of that, - * so display a warning and keep going. - */ - dev_warn(&pdev->dev, - "Can not read VID data: Failed to enable SuperIO access\n"); - return res; - } + int err; + u16 val; - superio_select(sio_data, W83627HF_LD_GPIO5); + static __initconst char *const names[] = { + "W83627HF", + "W83627THF", + "W83697HF", + "W83637HF", + "W83687THF", + }; - res = 0xff; + sio_data->sioaddr = sioaddr; + err = superio_enter(sio_data); + if (err) + return err; - /* Make sure these GPIO pins are enabled */ - if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) { - dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n"); + err = -ENODEV; + val = force_id ? force_id : superio_inb(sio_data, DEVID); + switch (val) { + case W627_DEVID: + sio_data->type = w83627hf; + break; + case W627THF_DEVID: + sio_data->type = w83627thf; + break; + case W697_DEVID: + sio_data->type = w83697hf; + break; + case W637_DEVID: + sio_data->type = w83637hf; + break; + case W687THF_DEVID: + sio_data->type = w83687thf; + break; + case 0xff: /* No device at all */ goto exit; - } - - /* - * Make sure the pins are configured for input - * There must be at least five (VRM 9), and possibly 6 (VRM 10) - */ - sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f; - if ((sel & 0x1f) != 0x1f) { - dev_dbg(&pdev->dev, "GPIO5 not configured for VID " - "function\n"); + default: + pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val); goto exit; } - dev_info(&pdev->dev, "Reading VID from GPIO5\n"); - res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel; - -exit: - superio_exit(sio_data); - return res; -} - -static int w83687thf_read_vid(struct platform_device *pdev) -{ - struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); - int res = 0xff; - - if (superio_enter(sio_data)) { - /* - * Some other driver reserved the address space for itself. - * We don't want to fail driver instantiation because of that, - * so display a warning and keep going. - */ - dev_warn(&pdev->dev, - "Can not read VID data: Failed to enable SuperIO access\n"); - return res; - } - superio_select(sio_data, W83627HF_LD_HWM); - - /* Make sure these GPIO pins are enabled */ - if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) { - dev_dbg(&pdev->dev, "VID disabled, no VID function\n"); + val = (superio_inb(sio_data, WINB_BASE_REG) << 8) | + superio_inb(sio_data, WINB_BASE_REG + 1); + *addr = val & WINB_ALIGNMENT; + if (*addr == 0) { + pr_warn("Base address not set, skipping\n"); goto exit; } - /* Make sure the pins are configured for input */ - if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) { - dev_dbg(&pdev->dev, "VID configured as output, " - "no VID function\n"); - goto exit; + val = superio_inb(sio_data, WINB_ACT_REG); + if (!(val & 0x01)) { + pr_warn("Enabling HWM logical device\n"); + superio_outb(sio_data, WINB_ACT_REG, val | 0x01); } - res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f; + err = 0; + pr_info(DRVNAME ": Found %s chip at %#x\n", + names[sio_data->type], *addr); -exit: + exit: superio_exit(sio_data); - return res; -} - -static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) -{ - int word_sized; - - mutex_lock(&data->lock); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - w83627hf_set_bank(data, reg); - outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, - data->addr + W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - data->addr + W83781D_ADDR_REG_OFFSET); - } - outb_p(value & 0xff, - data->addr + W83781D_DATA_REG_OFFSET); - w83627hf_reset_bank(data, reg); - mutex_unlock(&data->lock); - return 0; -} - -static void w83627hf_init_device(struct platform_device *pdev) -{ - struct w83627hf_data *data = platform_get_drvdata(pdev); - int i; - enum chips type = data->type; - u8 tmp; - - /* Minimize conflicts with other winbond i2c-only clients... */ - /* disable i2c subclients... how to disable main i2c client?? */ - /* force i2c address to relatively uncommon address */ - if (type == w83627hf) { - w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89); - w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c); - } - - /* Read VID only once */ - if (type == w83627hf || type == w83637hf) { - int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); - int hi = w83627hf_read_value(data, W83781D_REG_CHIPID); - data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); - } else if (type == w83627thf) { - data->vid = w83627thf_read_gpio5(pdev); - } else if (type == w83687thf) { - data->vid = w83687thf_read_vid(pdev); - } - - /* Read VRM & OVT Config only once */ - if (type == w83627thf || type == w83637hf || type == w83687thf) { - data->vrm_ovt = - w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG); - } - - tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); - for (i = 1; i <= 3; i++) { - if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = 4; - } else { - if (w83627hf_read_value - (data, - W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) - data->sens[i - 1] = 1; - else - data->sens[i - 1] = 2; - } - if ((type == w83697hf) && (i == 2)) - break; - } - - if(init) { - /* Enable temp2 */ - tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG); - if (tmp & 0x01) { - dev_warn(&pdev->dev, "Enabling temp2, readings " - "might not make sense\n"); - w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG, - tmp & 0xfe); - } - - /* Enable temp3 */ - if (type != w83697hf) { - tmp = w83627hf_read_value(data, - W83627HF_REG_TEMP3_CONFIG); - if (tmp & 0x01) { - dev_warn(&pdev->dev, "Enabling temp3, " - "readings might not make sense\n"); - w83627hf_write_value(data, - W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe); - } - } - } - - /* Start monitoring */ - w83627hf_write_value(data, W83781D_REG_CONFIG, - (w83627hf_read_value(data, - W83781D_REG_CONFIG) & 0xf7) - | 0x01); - - /* Enable VBAT monitoring if needed */ - tmp = w83627hf_read_value(data, W83781D_REG_VBAT); - if (!(tmp & 0x01)) - w83627hf_write_value(data, W83781D_REG_VBAT, tmp | 0x01); -} - -static void w83627hf_update_fan_div(struct w83627hf_data *data) -{ - int reg; - - reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); - data->fan_div[0] = (reg >> 4) & 0x03; - data->fan_div[1] = (reg >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83627hf_read_value(data, - W83781D_REG_PIN) >> 6) & 0x03; - } - reg = w83627hf_read_value(data, W83781D_REG_VBAT); - data->fan_div[0] |= (reg >> 3) & 0x04; - data->fan_div[1] |= (reg >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (reg >> 5) & 0x04; -} - -static struct w83627hf_data *w83627hf_update_device(struct device *dev) -{ - struct w83627hf_data *data = dev_get_drvdata(dev); - int i, num_temps = (data->type == w83697hf) ? 2 : 3; - int num_pwms = (data->type == w83697hf) ? 2 : 3; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - for (i = 0; i <= 8; i++) { - /* skip missing sensors */ - if (((data->type == w83697hf) && (i == 1)) || - ((data->type != w83627hf && data->type != w83697hf) - && (i == 5 || i == 6))) - continue; - data->in[i] = - w83627hf_read_value(data, W83781D_REG_IN(i)); - data->in_min[i] = - w83627hf_read_value(data, - W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83627hf_read_value(data, - W83781D_REG_IN_MAX(i)); - } - for (i = 0; i <= 2; i++) { - data->fan[i] = - w83627hf_read_value(data, W83627HF_REG_FAN(i)); - data->fan_min[i] = - w83627hf_read_value(data, - W83627HF_REG_FAN_MIN(i)); - } - for (i = 0; i <= 2; i++) { - u8 tmp = w83627hf_read_value(data, - W836X7HF_REG_PWM(data->type, i)); - /* bits 0-3 are reserved in 627THF */ - if (data->type == w83627thf) - tmp &= 0xf0; - data->pwm[i] = tmp; - if (i == 1 && - (data->type == w83627hf || data->type == w83697hf)) - break; - } - if (data->type == w83627hf) { - u8 tmp = w83627hf_read_value(data, - W83627HF_REG_PWM_FREQ); - data->pwm_freq[0] = tmp & 0x07; - data->pwm_freq[1] = (tmp >> 4) & 0x07; - } else if (data->type != w83627thf) { - for (i = 1; i <= 3; i++) { - data->pwm_freq[i - 1] = - w83627hf_read_value(data, - W83637HF_REG_PWM_FREQ[i - 1]); - if (i == 2 && (data->type == w83697hf)) - break; - } - } - if (data->type != w83627hf) { - for (i = 0; i < num_pwms; i++) { - u8 tmp = w83627hf_read_value(data, - W83627THF_REG_PWM_ENABLE[i]); - data->pwm_enable[i] = - ((tmp >> W83627THF_PWM_ENABLE_SHIFT[i]) - & 0x03) + 1; - } - } - for (i = 0; i < num_temps; i++) { - data->temp[i] = w83627hf_read_value( - data, w83627hf_reg_temp[i]); - data->temp_max[i] = w83627hf_read_value( - data, w83627hf_reg_temp_over[i]); - data->temp_max_hyst[i] = w83627hf_read_value( - data, w83627hf_reg_temp_hyst[i]); - } - - w83627hf_update_fan_div(data); - - data->alarms = - w83627hf_read_value(data, W83781D_REG_ALARM1) | - (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) | - (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16); - i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2); - data->beep_mask = (i << 8) | - w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) | - w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16; - data->last_updated = jiffies; - data->valid = true; - } - - mutex_unlock(&data->update_lock); - - return data; + return err; } static int __init w83627hf_device_add(unsigned short address, diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 55c78e12bbbe..dacabf25e83f 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1171,7 +1171,7 @@ w83781d_detect(struct i2c_client *client, struct i2c_board_info *info) if (isa) mutex_unlock(&isa->update_lock); - strlcpy(info->type, client_name, I2C_NAME_SIZE); + strscpy(info->type, client_name, I2C_NAME_SIZE); return 0; diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 5fe5c93856af..eaf691365023 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -1333,7 +1333,7 @@ static int w83791d_detect(struct i2c_client *client, if (val1 != 0x71 || val2 != 0x5c) return -ENODEV; - strlcpy(info->type, "w83791d", I2C_NAME_SIZE); + strscpy(info->type, "w83791d", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 2ee8ee4f0f1c..6d160eee1446 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -1346,7 +1346,7 @@ w83792d_detect(struct i2c_client *client, struct i2c_board_info *info) if (val1 != 0x7a || val2 != 0x5c) return -ENODEV; - strlcpy(info->type, "w83792d", I2C_NAME_SIZE); + strscpy(info->type, "w83792d", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index daeaaded6b76..a4926d907198 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -1634,7 +1634,7 @@ static int w83793_detect(struct i2c_client *client, if (chip_id != 0x7b) return -ENODEV; - strlcpy(info->type, "w83793", I2C_NAME_SIZE); + strscpy(info->type, "w83793", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index b170cdf3c2be..84ff5c57e98c 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -1967,7 +1967,7 @@ static int w83795_detect(struct i2c_client *client, else chip_name = "w83795g"; - strlcpy(info->type, chip_name, I2C_NAME_SIZE); + strscpy(info->type, chip_name, I2C_NAME_SIZE); dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name, 'A' + (device_id & 0xf), address); diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index 99f68358378b..f3622de0d96f 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -157,7 +157,7 @@ static int w83l785ts_detect(struct i2c_client *client, return -ENODEV; } - strlcpy(info->type, "w83l785ts", I2C_NAME_SIZE); + strscpy(info->type, "w83l785ts", I2C_NAME_SIZE); return 0; } diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 11ba23c1af85..2c4646fa8426 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -687,7 +687,7 @@ w83l786ng_detect(struct i2c_client *client, struct i2c_board_info *info) return -ENODEV; } - strlcpy(info->type, "w83l786ng", I2C_NAME_SIZE); + strscpy(info->type, "w83l786ng", I2C_NAME_SIZE); return 0; } diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 0e042410f6b9..cfe3a0327471 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -734,8 +734,8 @@ static struct device_link *pwm_device_link_add(struct device *dev, * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded * error code on failure. */ -struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np, - const char *con_id) +static struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np, + const char *con_id) { struct pwm_device *pwm = NULL; struct of_phandle_args args; @@ -797,7 +797,6 @@ put: return pwm; } -EXPORT_SYMBOL_GPL(of_pwm_get); /** * acpi_pwm_get() - request a PWM via parsing "pwms" property in ACPI @@ -1071,36 +1070,6 @@ struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id) EXPORT_SYMBOL_GPL(devm_pwm_get); /** - * devm_of_pwm_get() - resource managed of_pwm_get() - * @dev: device for PWM consumer - * @np: device node to get the PWM from - * @con_id: consumer name - * - * This function performs like of_pwm_get() but the acquired PWM device will - * automatically be released on driver detach. - * - * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded - * error code on failure. - */ -struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, - const char *con_id) -{ - struct pwm_device *pwm; - int ret; - - pwm = of_pwm_get(dev, np, con_id); - if (IS_ERR(pwm)) - return pwm; - - ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm); - if (ret) - return ERR_PTR(ret); - - return pwm; -} -EXPORT_SYMBOL_GPL(devm_of_pwm_get); - -/** * devm_fwnode_pwm_get() - request a resource managed PWM from firmware node * @dev: device for PWM consumer * @fwnode: firmware node to get the PWM from diff --git a/include/linux/platform_data/emc2305.h b/include/linux/platform_data/emc2305.h new file mode 100644 index 000000000000..54d672dd6f7d --- /dev/null +++ b/include/linux/platform_data/emc2305.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __LINUX_PLATFORM_DATA_EMC2305__ +#define __LINUX_PLATFORM_DATA_EMC2305__ + +#define EMC2305_PWM_MAX 5 + +/** + * struct emc2305_platform_data - EMC2305 driver platform data + * @max_state: maximum cooling state of the cooling device; + * @pwm_num: number of active channels; + * @pwm_separate: separate PWM settings for every channel; + * @pwm_min: array of minimum PWM per channel; + */ +struct emc2305_platform_data { + u8 max_state; + u8 pwm_num; + bool pwm_separate; + u8 pwm_min[EMC2305_PWM_MAX]; +}; + +#endif diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 9429930c5566..d70c6e5a839d 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -403,13 +403,9 @@ struct pwm_device *of_pwm_single_xlate(struct pwm_chip *pc, const struct of_phandle_args *args); struct pwm_device *pwm_get(struct device *dev, const char *con_id); -struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np, - const char *con_id); void pwm_put(struct pwm_device *pwm); struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id); -struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, - const char *con_id); struct pwm_device *devm_fwnode_pwm_get(struct device *dev, struct fwnode_handle *fwnode, const char *con_id); @@ -497,14 +493,6 @@ static inline struct pwm_device *pwm_get(struct device *dev, return ERR_PTR(-ENODEV); } -static inline struct pwm_device *of_pwm_get(struct device *dev, - struct device_node *np, - const char *con_id) -{ - might_sleep(); - return ERR_PTR(-ENODEV); -} - static inline void pwm_put(struct pwm_device *pwm) { might_sleep(); @@ -517,14 +505,6 @@ static inline struct pwm_device *devm_pwm_get(struct device *dev, return ERR_PTR(-ENODEV); } -static inline struct pwm_device *devm_of_pwm_get(struct device *dev, - struct device_node *np, - const char *con_id) -{ - might_sleep(); - return ERR_PTR(-ENODEV); -} - static inline struct pwm_device * devm_fwnode_pwm_get(struct device *dev, struct fwnode_handle *fwnode, const char *con_id) |