diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-13 19:15:31 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-13 19:15:31 +0200 |
commit | c4439713e82a0d746e533ae5ddd7dfa832e2a486 (patch) | |
tree | af1590a67536a4af13b4a94bb672ca98313870e0 | |
parent | Merge tag 'gpio-v5.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/lin... (diff) | |
parent | hwmon: (pmbus/max20730) adjust the vout reading given voltage divider (diff) | |
download | linux-c4439713e82a0d746e533ae5ddd7dfa832e2a486.tar.xz linux-c4439713e82a0d746e533ae5ddd7dfa832e2a486.zip |
Merge tag 'hwmon-for-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck:
"New driver and chip support:
- Moortec MR75203 PVT controller
- MPS Multi-phase mp2975 controller
- ADM1266
- Zen3 CPUs
- Intel MAX 10 BMC
Enhancements:
- Support for rated attributes in hwmon core
- MAX20730:
- Device monitoring via debugfs
- VOUT readin adjustment vie devicetree bindings
- LM75:
- Devicetree support
- Regulator support
- Improved accumulationm logic in amd_energy driver
- Added fan sensor to gsc-hwmon driver
- Support for simplified I2C probing
Various other minor fixes and improvements"
* tag 'hwmon-for-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (64 commits)
hwmon: (pmbus/max20730) adjust the vout reading given voltage divider
dt-bindings: hwmon: max20730: adding device tree doc for max20730
hwmon: Add hardware monitoring driver for Moortec MR75203 PVT controller
hwmon: Add DT bindings schema for PVT controller
dt-bindings: hwmon: Add the +vs supply to the lm75 bindings
dt-bindings: hwmon: Convert lm75 bindings to yaml
docs: hwmon: (ltc2945) update datasheet link
hwmon: (mlxreg-fan) Fix double "Mellanox"
hwmon: (pmbus/max20730) add device monitoring via debugfs
hwmon: (pmbus/max34440) Fix OC fault limits
hwmon: (bt1-pvt) Wait for the completion with timeout
hwmon: (bt1-pvt) Cache current update timeout
hwmon: (bt1-pvt) Test sensor power supply on probe
hwmon: (lm75) Add regulator support
hwmon: Add hwmon driver for Intel MAX 10 BMC
dt-bindings: Add MP2975 voltage regulator device
hwmon: (pmbus) Add support for MPS Multi-phase mp2975 controller
hwmon: (tmp513) fix spelling typo in comments
hwmon: (amd_energy) Update driver documentation
hwmon: (amd_energy) Improve the accumulation logic
...
167 files changed, 4576 insertions, 1022 deletions
diff --git a/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml b/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml new file mode 100644 index 000000000000..43b4f4f57b49 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/adi,adm1266.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADM1266 Cascadable Super Sequencer with Margin + Control and Fault Recording + +maintainers: + - Alexandru Tachici <alexandru.tachici@analog.com> + +description: | + Analog Devices ADM1266 Cascadable Super Sequencer with Margin + Control and Fault Recording. + https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1266.pdf + +properties: + compatible: + enum: + - adi,adm1266 + + reg: + description: | + I2C address of slave device. + items: + minimum: 0x40 + maximum: 0x4F + + avcc-supply: + description: | + Phandle to the Avcc power supply. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + adm1266@40 { + compatible = "adi,adm1266"; + reg = <0x40>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/hwmon/lm75.txt b/Documentation/devicetree/bindings/hwmon/lm75.txt deleted file mode 100644 index 273616702c51..000000000000 --- a/Documentation/devicetree/bindings/hwmon/lm75.txt +++ /dev/null @@ -1,39 +0,0 @@ -*LM75 hwmon sensor. - -Required properties: -- compatible: manufacturer and chip name, one of - "adi,adt75", - "dallas,ds1775", - "dallas,ds75", - "dallas,ds7505", - "gmt,g751", - "national,lm75", - "national,lm75a", - "national,lm75b", - "maxim,max6625", - "maxim,max6626", - "maxim,max31725", - "maxim,max31726", - "maxim,mcp980x", - "nxp,pct2075", - "st,stds75", - "st,stlm75", - "microchip,tcn75", - "ti,tmp100", - "ti,tmp101", - "ti,tmp105", - "ti,tmp112", - "ti,tmp175", - "ti,tmp275", - "ti,tmp75", - "ti,tmp75b", - "ti,tmp75c", - -- reg: I2C bus address of the device - -Example: - -sensor@48 { - compatible = "st,stlm75"; - reg = <0x48>; -}; diff --git a/Documentation/devicetree/bindings/hwmon/lm75.yaml b/Documentation/devicetree/bindings/hwmon/lm75.yaml new file mode 100644 index 000000000000..96eed5cc7841 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/lm75.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/lm75.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LM75 hwmon sensor + +maintainers: + - Jean Delvare <jdelvare@suse.com> + - Guenter Roeck <linux@roeck-us.net> + +properties: + compatible: + enum: + - adi,adt75 + - dallas,ds1775 + - dallas,ds75 + - dallas,ds7505 + - gmt,g751 + - national,lm75 + - national,lm75a + - national,lm75b + - maxim,max6625 + - maxim,max6626 + - maxim,max31725 + - maxim,max31726 + - maxim,mcp980x + - nxp,pct2075 + - st,stds75 + - st,stlm75 + - microchip,tcn75 + - ti,tmp100 + - ti,tmp101 + - ti,tmp105 + - ti,tmp112 + - ti,tmp175 + - ti,tmp275 + - ti,tmp75 + - ti,tmp75b + - ti,tmp75c + + reg: + maxItems: 1 + + vs-supply: + description: phandle to the regulator that provides the +VS supply + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@48 { + compatible = "st,stlm75"; + reg = <0x48>; + vs-supply = <&vs>; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml b/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml new file mode 100644 index 000000000000..93e86e3b4602 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/maxim,max20730.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim max20730 + +maintainers: + - Jean Delvare <jdelvare@suse.com> + - Guenter Roeck <linux@roeck-us.net> + +description: | + The MAX20730 is a fully integrated, highly efficient switching regulator + with PMBus for applications operating from 4.5V to 16V and requiring + up to 25A (max) load. This single-chip regulator provides extremely + compact, high efficiency power-delivery solutions with high-precision + output voltages and excellent transient response. + + Datasheets: + https://datasheets.maximintegrated.com/en/ds/MAX20730.pdf + https://datasheets.maximintegrated.com/en/ds/MAX20734.pdf + https://datasheets.maximintegrated.com/en/ds/MAX20743.pdf + +properties: + compatible: + enum: + - maxim,max20730 + - maxim,max20734 + - maxim,max20743 + + reg: + maxItems: 1 + + vout-voltage-divider: + description: | + If voltage divider present at vout, the voltage at voltage sensor pin + will be scaled. The properties will convert the raw reading to a more + meaningful number if voltage divider present. It has two numbers, + the first number is the output resistor, the second number is the total + resistance. Therefore, the adjusted vout is equal to + Vout = Vout * output_resistance / total resistance. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 2 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + max20730@10 { + compatible = "maxim,max20730"; + reg = <0x10>; + vout-voltage-divider = <1000 2000>; // vout would be scaled to 0.5 + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml b/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml new file mode 100644 index 000000000000..6f3e3c01f717 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/moortec,mr75203.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/moortec,mr75203.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Moortec Semiconductor MR75203 PVT Controller bindings + +maintainers: + - Rahul Tanwar <rtanwar@maxlinear.com> + +properties: + compatible: + const: moortec,mr75203 + + reg: + items: + - description: PVT common registers + - description: PVT temprature sensor registers + - description: PVT process detector registers + - description: PVT voltage monitor registers + + reg-names: + items: + - const: common + - const: ts + - const: pd + - const: vm + + intel,vm-map: + description: + PVT controller has 5 VM (voltage monitor) sensors. + vm-map defines CPU core to VM instance mapping. A + value of 0xff means that VM sensor is unused. + $ref: /schemas/types.yaml#definitions/uint8-array + maxItems: 5 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + "#thermal-sensor-cells": + const: 1 + +required: + - compatible + - reg + - reg-names + - intel,vm-map + - clocks + - resets + - "#thermal-sensor-cells" + +additionalProperties: false + +examples: + - | + pvt: pvt@e0680000 { + compatible = "moortec,mr75203"; + reg = <0xe0680000 0x80>, + <0xe0680080 0x180>, + <0xe0680200 0x200>, + <0xe0680400 0xc00>; + reg-names = "common", "ts", "pd", "vm"; + intel,vm-map = [03 01 04 ff ff]; + clocks = <&osc0>; + resets = <&rcu0 0x40 7>; + #thermal-sensor-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml b/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml new file mode 100644 index 000000000000..c523a1beb2b7 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/sensirion,shtc1.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/sensirion,shtc1.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sensirion SHTC1 Humidity and Temperature Sensor IC + +maintainers: + - Christopher Ruehl chris.ruehl@gtsys.com.hk + +description: | + The SHTC1, SHTW1 and SHTC3 are digital humidity and temperature sensor + designed especially for battery-driven high-volume consumer electronics + applications. + For further information refere to Documentation/hwmon/shtc1.rst + + This binding document describes the binding for the hardware monitor + portion of the driver. + +properties: + compatible: + enum: + - sensirion,shtc1 + - sensirion,shtw1 + - sensirion,shtc3 + + reg: + const: 0x70 + + sensirion,blocking-io: + $ref: /schemas/types.yaml#definitions/flag + description: + If set, the driver hold the i2c bus until 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. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + + shtc3@70 { + compatible = "sensirion,shtc3"; + reg = <0x70>; + sensirion,blocking-io; + }; + }; +... diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 78410df80022..aa62d74375a2 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -80,6 +80,8 @@ properties: - fsl,mpl3115 # MPR121: Proximity Capacitive Touch Sensor Controller - fsl,mpr121 + # Monolithic Power Systems Inc. multi-phase controller mp2975 + - mps,mp2975 # G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface - gmt,g751 # Infineon IR38064 Voltage Regulator diff --git a/Documentation/hwmon/adm1266.rst b/Documentation/hwmon/adm1266.rst new file mode 100644 index 000000000000..9257f8a48650 --- /dev/null +++ b/Documentation/hwmon/adm1266.rst @@ -0,0 +1,37 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver adm1266 +===================== + +Supported chips: + * Analog Devices ADM1266 + Prefix: 'adm1266' + Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1266.pdf + +Author: Alexandru Tachici <alexandru.tachici@analog.com> + + +Description +----------- + +This driver supports hardware monitoring for Analog Devices ADM1266 sequencer. + +ADM1266 is a sequencer that features voltage readback from 17 channels via an +integrated 12 bit SAR ADC, accessed using a PMBus interface. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write, history reset +attributes are write-only, all other attributes are read-only. + +inX_label "voutx" +inX_input Measured voltage. +inX_min Minimum Voltage. +inX_max Maximum voltage. +inX_min_alarm Voltage low alarm. +inX_max_alarm Voltage high alarm. diff --git a/Documentation/hwmon/amd_energy.rst b/Documentation/hwmon/amd_energy.rst index f8288edff664..86e4ebc5cbc2 100644 --- a/Documentation/hwmon/amd_energy.rst +++ b/Documentation/hwmon/amd_energy.rst @@ -84,6 +84,11 @@ per run to a respective 64-bit counter. The kernel thread starts running during probe, wakes up every 100secs and stops running when driver is removed. +Frequency of the accumulator thread is set during the probe +based on the chosen energy unit resolution. For example +A. fine grain (1.625 micro J) +B. course grain (0.125 milli J) + A socket and core energy read would return the current register value added to the respective energy accumulator. diff --git a/Documentation/hwmon/drivetemp.rst b/Documentation/hwmon/drivetemp.rst index 2d37d049247f..0b1cf2f912c5 100644 --- a/Documentation/hwmon/drivetemp.rst +++ b/Documentation/hwmon/drivetemp.rst @@ -30,6 +30,24 @@ Transport is not supported, the driver uses SMART attributes to read the drive temperature. +Usage Note +---------- + +Reading the drive temperature may reset the spin down timer on some drives. +This has been observed with WD120EFAX drives, but may be seen with other +drives as well. The same behavior is observed if the 'hdtemp' or 'smartd' +tools are used to access the drive. +With the WD120EFAX drive, reading the drive temperature using the drivetemp +driver is still possible _after_ it transitioned to standby mode, and +reading the drive temperature in this mode will not cause the drive to +change its mode (meaning the drive will not spin up). It is unknown if other +drives experience similar behavior. + +A known workaround for WD120EFAX drives is to read the drive temperature at +intervals larger than twice the spin-down time. Otherwise affected drives +will never spin down. + + Sysfs entries ------------- diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 77a1ae975037..4bcb1a75fd4a 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -30,6 +30,7 @@ Hardware Monitoring Kernel Drivers adm1026 adm1031 adm1177 + adm1266 adm1275 adm9240 ads7828 @@ -73,6 +74,7 @@ Hardware Monitoring Kernel Drivers ina209 ina2xx ina3221 + intel-m10-bmc-hwmon ir35221 ir38064 isl68137 diff --git a/Documentation/hwmon/intel-m10-bmc-hwmon.rst b/Documentation/hwmon/intel-m10-bmc-hwmon.rst new file mode 100644 index 000000000000..3d148c6e3256 --- /dev/null +++ b/Documentation/hwmon/intel-m10-bmc-hwmon.rst @@ -0,0 +1,78 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver intel-m10-bmc-hwmon +================================= + +Supported chips: + + * Intel MAX 10 BMC for Intel PAC N3000 + + Prefix: 'n3000bmc-hwmon' + +Author: Xu Yilun <yilun.xu@intel.com> + + +Description +----------- + +This driver adds the temperature, voltage, current and power reading +support for the Intel MAX 10 Board Management Controller (BMC) chip. +The BMC chip is integrated in some Intel Programmable Acceleration +Cards (PAC). It connects to a set of sensor chips to monitor the +sensor data of different components on the board. The BMC firmware is +responsible for sensor data sampling and recording in shared +registers. The host driver reads the sensor data from these shared +registers and exposes them to users as hwmon interfaces. + +The BMC chip is implemented using the Intel MAX 10 CPLD. It could be +reprogramed to some variants in order to support different Intel +PACs. The driver is designed to be able to distinguish between the +variants, but now it only supports the BMC for Intel PAC N3000. + + +Sysfs attributes +---------------- + +The following attributes are supported: + +- Intel MAX 10 BMC for Intel PAC N3000: + +======================= ======================================================= +tempX_input Temperature of the component (specified by tempX_label) +tempX_max Temperature maximum setpoint of the component +tempX_crit Temperature critical setpoint of the component +tempX_max_hyst Hysteresis for temperature maximum of the component +tempX_crit_hyst Hysteresis for temperature critical of the component +temp1_label "Board Temperature" +temp2_label "FPGA Die Temperature" +temp3_label "QSFP0 Temperature" +temp4_label "QSFP1 Temperature" +temp5_label "Retimer A Temperature" +temp6_label "Retimer A SerDes Temperature" +temp7_label "Retimer B Temperature" +temp8_label "Retimer B SerDes Temperature" + +inX_input Measured voltage of the component (specified by + inX_label) +in0_label "QSFP0 Supply Voltage" +in1_label "QSFP1 Supply Voltage" +in2_label "FPGA Core Voltage" +in3_label "12V Backplane Voltage" +in4_label "1.2V Voltage" +in5_label "12V AUX Voltage" +in6_label "1.8V Voltage" +in7_label "3.3V Voltage" + +currX_input Measured current of the component (specified by + currX_label) +curr1_label "FPGA Core Current" +curr2_label "12V Backplane Current" +curr3_label "12V AUX Current" + +powerX_input Measured power of the component (specified by + powerX_label) +power1_label "Board Power" + +======================= ======================================================= + +All the attributes are read-only. diff --git a/Documentation/hwmon/ltc2945.rst b/Documentation/hwmon/ltc2945.rst index 20c884985367..8d65c141ce2b 100644 --- a/Documentation/hwmon/ltc2945.rst +++ b/Documentation/hwmon/ltc2945.rst @@ -11,7 +11,7 @@ Supported chips: Datasheet: - http://cds.linear.com/docs/en/datasheet/2945fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/2945fb.pdf Author: Guenter Roeck <linux@roeck-us.net> diff --git a/Documentation/hwmon/mp2975.rst b/Documentation/hwmon/mp2975.rst new file mode 100644 index 000000000000..5b0609c62f48 --- /dev/null +++ b/Documentation/hwmon/mp2975.rst @@ -0,0 +1,116 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver mp2975 +==================== + +Supported chips: + + * MPS MP12254 + + Prefix: 'mp2975' + +Author: + + Vadim Pasternak <vadimp@nvidia.com> + +Description +----------- + +This driver implements support for Monolithic Power Systems, Inc. (MPS) +vendor dual-loop, digital, multi-phase controller MP2975. + +This device: +- Supports up to two power rail. +- Provides 8 pulse-width modulations (PWMs), and can be configured up + to 8-phase operation for rail 1 and up to 4-phase operation for rail + 2. +- Supports two pages 0 and 1 for telemetry and also pages 2 and 3 for + configuration. +- Can configured VOUT readout in direct or VID format and allows + setting of different formats on rails 1 and 2. For VID the following + protocols are available: VR13 mode with 5-mV DAC; VR13 mode with + 10-mV DAC, IMVP9 mode with 5-mV DAC. + +Device supports: +- SVID interface. +- AVSBus interface. + +Device complaint with: +- PMBus rev 1.3 interface. + +Device supports direct format for reading output current, output voltage, +input and output power and temperature. +Device supports linear format for reading input voltage and input power. +Device supports VID and direct formats for reading output voltage. +The below VID modes are supported: VR12, VR13, IMVP9. + +The driver provides the next attributes for the current: +- for current in: input, maximum alarm; +- for current out input, maximum alarm and highest values; +- for phase current: input and label. +attributes. +The driver exports the following attributes via the 'sysfs' files, where +- 'n' is number of telemetry pages (from 1 to 2); +- 'k' is number of configured phases (from 1 to 8); +- indexes 1, 1*n for "iin"; +- indexes n+1, n+2 for "iout"; +- indexes 2*n+1 ... 2*n + k for phases. + +**curr[1-{2n}]_alarm** + +**curr[{n+1}-{n+2}]_highest** + +**curr[1-{2n+k}]_input** + +**curr[1-{2n+k}]_label** + +The driver provides the next attributes for the voltage: +- for voltage in: input, high critical threshold, high critical alarm, all only + from page 0; +- for voltage out: input, low and high critical thresholds, low and high + critical alarms, from pages 0 and 1; +The driver exports the following attributes via the 'sysfs' files, where +- 'n' is number of telemetry pages (from 1 to 2); +- indexes 1 for "iin"; +- indexes n+1, n+2 for "vout"; + +**in[1-{2n+1}]_crit** + +**in[1-{2n+1}]_crit_alarm** + +**in[1-{2n+1}]_input** + +**in[1-{2n+1}]_label** + +**in[2-{n+1}]_lcrit** + +**in[2-{n+1}1_lcrit_alarm** + +The driver provides the next attributes for the power: +- for power in alarm and input. +- for power out: highest and input. +The driver exports the following attributes via the 'sysfs' files, where +- 'n' is number of telemetry pages (from 1 to 2); +- indexes 1 for "pin"; +- indexes n+1, n+2 for "pout"; + +**power1_alarm** + +**power[2-{n+1}]_highest** + +**power[1-{2n+1}]_input** + +**power[1-{2n+1}]_label** + +The driver provides the next attributes for the temperature (only from page 0): + + +**temp1_crit** + +**temp1_crit_alarm** + +**temp1_input** + +**temp1_max** + +**temp1_max_alarm** diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst index 501b37b0610d..e22c4f6808bc 100644 --- a/Documentation/hwmon/pmbus-core.rst +++ b/Documentation/hwmon/pmbus-core.rst @@ -270,8 +270,7 @@ obtain the chip status. Therefore, it must _not_ be called from that function. :: - int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, - struct pmbus_driver_info *info); + int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); Execute probe function. Similar to standard probe function for other drivers, with the pointer to struct pmbus_driver_info as additional argument. Calls diff --git a/Documentation/hwmon/pmbus.rst b/Documentation/hwmon/pmbus.rst index 66b3e894612f..fb3ad67dedc1 100644 --- a/Documentation/hwmon/pmbus.rst +++ b/Documentation/hwmon/pmbus.rst @@ -143,10 +143,9 @@ Emerson DS1200 power modules might look as follows:: | PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12, }; - static int ds1200_probe(struct i2c_client *client, - const struct i2c_device_id *id) + static int ds1200_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &ds1200_info); + return pmbus_do_probe(client, &ds1200_info); } static int ds1200_remove(struct i2c_client *client) @@ -166,7 +165,7 @@ Emerson DS1200 power modules might look as follows:: .driver = { .name = "ds1200", }, - .probe = ds1200_probe, + .probe_new = ds1200_probe, .remove = ds1200_remove, .id_table = ds1200_id, }; @@ -211,6 +210,10 @@ inX_lcrit_alarm Voltage critical low alarm. inX_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. inX_label "vin", "vcap", or "voutY" +inX_rated_min Minimum rated voltage. + From MFR_VIN_MIN or MFR_VOUT_MIN register. +inX_rated_max Maximum rated voltage. + From MFR_VIN_MAX or MFR_VOUT_MAX register. currX_input Measured current. From READ_IIN or READ_IOUT register. currX_max Maximum current. @@ -230,6 +233,8 @@ currX_crit_alarm Current critical high alarm. currX_label "iin", "iinY", "iinY.Z", "ioutY", or "ioutY.Z", where Y reflects the page number and Z reflects the phase. +currX_rated_max Maximum rated current. + From MFR_IIN_MAX or MFR_IOUT_MAX register. powerX_input Measured power. From READ_PIN or READ_POUT register. powerX_cap Output power cap. From POUT_MAX register. @@ -244,10 +249,12 @@ powerX_crit_alarm Output power critical high alarm. powerX_label "pin", "pinY", "pinY.Z", "poutY", or "poutY.Z", where Y reflects the page number and Z reflects the phase. +powerX_rated_max Maximum rated power. + From MFR_PIN_MAX or MFR_POUT_MAX register. tempX_input Measured temperature. From READ_TEMPERATURE_X register. -tempX_min Mimimum temperature. From UT_WARN_LIMIT register. +tempX_min Minimum temperature. From UT_WARN_LIMIT register. tempX_max Maximum temperature. From OT_WARN_LIMIT register. tempX_lcrit Critical low temperature. From UT_FAULT_LIMIT register. @@ -265,4 +272,9 @@ tempX_lcrit_alarm Chip temperature critical low alarm. Set by comparing tempX_crit_alarm Chip temperature critical high alarm. Set by comparing READ_TEMPERATURE_X with OT_FAULT_LIMIT if TEMP_OT_FAULT status is set. +tempX_rated_min Minimum rated temperature. + From MFR_TAMBIENT_MIN register. +tempX_rated_max Maximum rated temperature. + From MFR_TAMBIENT_MAX, MFR_MAX_TEMP_1, MFR_MAX_TEMP_2 or + MFR_MAX_TEMP_3 register. ======================= ======================================================== diff --git a/Documentation/hwmon/sysfs-interface.rst b/Documentation/hwmon/sysfs-interface.rst index fd590633bb14..678c9c60b5a3 100644 --- a/Documentation/hwmon/sysfs-interface.rst +++ b/Documentation/hwmon/sysfs-interface.rst @@ -241,6 +241,20 @@ Voltages Affects the way the driver calculates the CPU core reference voltage from the vid pins. +`in[0-*]_rated_min` + Minimum rated voltage. + + Unit: millivolt + + RO + +`in[0-*]_rated_max` + Maximum rated voltage. + + Unit: millivolt + + RO + Also see the Alarms section for status flags associated with voltages. @@ -574,6 +588,20 @@ Temperatures RW +`temp[1-*]_rated_min` + Minimum rated temperature. + + Unit: millidegree Celsius + + RO + +`temp[1-*]_rated_max` + Maximum rated temperature. + + Unit: millidegree Celsius + + RO + Some chips measure temperature using external thermistors and an ADC, and report the temperature measurement as a voltage. Converting this voltage back to a temperature (or the other way around for limits) requires @@ -664,6 +692,20 @@ Currents RW +`curr[1-*]_rated_min` + Minimum rated current. + + Unit: milliampere + + RO + +`curr[1-*]_rated_max` + Maximum rated current. + + Unit: milliampere + + RO + Also see the Alarms section for status flags associated with currents. ***** @@ -830,6 +872,20 @@ Power RW +`power[1-*]_rated_min` + Minimum rated power. + + Unit: microWatt + + RO + +`power[1-*]_rated_max` + Maximum rated power. + + Unit: microWatt + + RO + Also see the Alarms section for status flags associated with power readings. ****** @@ -877,6 +933,20 @@ Humidity RW +`humidity[1-*]_rated_min` + Minimum rated humidity. + + Unit: milli-percent (per cent mille, pcm) + + RO + +`humidity[1-*]_rated_max` + Maximum rated humidity. + + Unit: milli-percent (per cent mille, pcm) + + RO + ****** Alarms ****** diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 8dc28b26916e..676ad6ee7f8d 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1080,7 +1080,7 @@ config SENSORS_MCP3021 will be called mcp3021. config SENSORS_MLXREG_FAN - tristate "Mellanox Mellanox FAN driver" + tristate "Mellanox FAN driver" depends on MELLANOX_PLATFORM imply THERMAL select REGMAP @@ -1112,6 +1112,16 @@ config SENSORS_MENF21BMC_HWMON This driver can also be built as a module. If so the module will be called menf21bmc_hwmon. +config SENSORS_MR75203 + tristate "Moortec Semiconductor MR75203 PVT Controller" + select REGMAP_MMIO + help + If you say yes here you get support for Moortec MR75203 + PVT controller. + + This driver can also be built as a module. If so, the module + will be called mr75203. + config SENSORS_ADCXX tristate "National Semiconductor ADCxxxSxxx" depends on SPI_MASTER @@ -2064,6 +2074,17 @@ config SENSORS_XGENE If you say yes here you get support for the temperature and power sensors for APM X-Gene SoC. +config SENSORS_INTEL_M10_BMC_HWMON + tristate "Intel MAX10 BMC Hardware Monitoring" + depends on MFD_INTEL_M10_BMC + help + This driver provides support for the hardware monitoring functionality + on Intel MAX10 BMC chip. + + This BMC Chip is used on Intel FPGA PCIe Acceleration Cards (PAC). Its + sensors monitor various telemetry data of different components on the + card, e.g. board temperature, FPGA core temperature/voltage/current. + if ACPI comment "ACPI drivers" diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index a8f4b35b136b..8193340a7238 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o obj-$(CONFIG_SENSORS_INA209) += ina209.o obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o obj-$(CONFIG_SENSORS_INA3221) += ina3221.o +obj-$(CONFIG_SENSORS_INTEL_M10_BMC_HWMON) += intel-m10-bmc-hwmon.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_JC42) += jc42.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o @@ -142,6 +143,7 @@ obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o obj-$(CONFIG_SENSORS_TC654) += tc654.o obj-$(CONFIG_SENSORS_MLXREG_FAN) += mlxreg-fan.o obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o +obj-$(CONFIG_SENSORS_MR75203) += mr75203.o obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c index a529f2efc790..6a765755d061 100644 --- a/drivers/hwmon/ad7414.c +++ b/drivers/hwmon/ad7414.c @@ -169,8 +169,7 @@ static struct attribute *ad7414_attrs[] = { ATTRIBUTE_GROUPS(ad7414); -static int ad7414_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) +static int ad7414_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ad7414_data *data; @@ -222,7 +221,7 @@ static struct i2c_driver ad7414_driver = { .name = "ad7414", .of_match_table = of_match_ptr(ad7414_of_match), }, - .probe = ad7414_probe, + .probe_new = ad7414_probe, .id_table = ad7414_id, }; diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c index 74542b8ad8ef..d618f6b2f382 100644 --- a/drivers/hwmon/ad7418.c +++ b/drivers/hwmon/ad7418.c @@ -230,8 +230,9 @@ static void ad7418_init_client(struct i2c_client *client) } } -static int ad7418_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id ad7418_id[]; + +static int ad7418_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct i2c_adapter *adapter = client->adapter; @@ -254,7 +255,7 @@ static int ad7418_probe(struct i2c_client *client, if (dev->of_node) data->type = (enum chips)of_device_get_match_data(dev); else - data->type = id->driver_data; + data->type = i2c_match_id(ad7418_id, client)->driver_data; switch (data->type) { case ad7416: @@ -305,7 +306,7 @@ static struct i2c_driver ad7418_driver = { .name = "ad7418", .of_match_table = ad7418_dt_ids, }, - .probe = ad7418_probe, + .probe_new = ad7418_probe, .id_table = ad7418_id, }; diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index 571d5454c6b2..6c9a906631b8 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -427,8 +427,7 @@ static int adc128_init_client(struct adc128_data *data) return 0; } -static int adc128_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adc128_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct regulator *regulator; @@ -524,7 +523,7 @@ static struct i2c_driver adc128_driver = { .name = "adc128d818", .of_match_table = of_match_ptr(adc128_of_match), }, - .probe = adc128_probe, + .probe_new = adc128_probe, .remove = adc128_remove, .id_table = adc128_id, .detect = adc128_detect, diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index c45046241a1c..71deb2cd20f5 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -425,8 +425,9 @@ static void adm1021_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04); } -static int adm1021_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adm1021_id[]; + +static int adm1021_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adm1021_data *data; @@ -437,7 +438,7 @@ static int adm1021_probe(struct i2c_client *client, return -ENOMEM; data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(adm1021_id, client)->driver_data; mutex_init(&data->update_lock); /* Initialize the ADM1021 chip */ @@ -472,7 +473,7 @@ static struct i2c_driver adm1021_driver = { .driver = { .name = "adm1021", }, - .probe = adm1021_probe, + .probe_new = adm1021_probe, .id_table = adm1021_id, .detect = adm1021_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index ed15185fa60f..de51e01c061b 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -517,8 +517,7 @@ static void adm1025_init_client(struct i2c_client *client) (reg&0x7E)|0x01); } -static int adm1025_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1025_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -560,7 +559,7 @@ static struct i2c_driver adm1025_driver = { .driver = { .name = "adm1025", }, - .probe = adm1025_probe, + .probe_new = adm1025_probe, .id_table = adm1025_id, .detect = adm1025_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index af77096724fd..49cefbadb156 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -1816,8 +1816,7 @@ static void adm1026_init_client(struct i2c_client *client) } } -static int adm1026_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1026_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1860,7 +1859,7 @@ static struct i2c_driver adm1026_driver = { .driver = { .name = "adm1026", }, - .probe = adm1026_probe, + .probe_new = adm1026_probe, .id_table = adm1026_id, .detect = adm1026_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index f7752a5bef31..50b1df7b008c 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -352,8 +352,7 @@ static int adm1029_init_client(struct i2c_client *client) return 1; } -static int adm1029_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1029_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adm1029_data *data; @@ -390,7 +389,7 @@ static struct i2c_driver adm1029_driver = { .driver = { .name = "adm1029", }, - .probe = adm1029_probe, + .probe_new = adm1029_probe, .id_table = adm1029_id, .detect = adm1029_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 7723a338446d..b538ace2d292 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -1022,8 +1022,9 @@ static void adm1031_init_client(struct i2c_client *client) data->update_interval = update_intervals[i]; } -static int adm1031_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id adm1031_id[]; + +static int adm1031_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1035,7 +1036,7 @@ static int adm1031_probe(struct i2c_client *client, i2c_set_clientdata(client, data); data->client = client; - data->chip_type = id->driver_data; + data->chip_type = i2c_match_id(adm1031_id, client)->driver_data; mutex_init(&data->update_lock); if (data->chip_type == adm1030) @@ -1068,7 +1069,7 @@ static struct i2c_driver adm1031_driver = { .driver = { .name = "adm1031", }, - .probe = adm1031_probe, + .probe_new = adm1031_probe, .id_table = adm1031_id, .detect = adm1031_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c index d314223a404a..6e8bb661894b 100644 --- a/drivers/hwmon/adm1177.c +++ b/drivers/hwmon/adm1177.c @@ -196,8 +196,7 @@ static void adm1177_remove(void *data) regulator_disable(st->reg); } -static int adm1177_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1177_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -277,7 +276,7 @@ static struct i2c_driver adm1177_driver = { .name = "adm1177", .of_match_table = adm1177_dt_ids, }, - .probe = adm1177_probe, + .probe_new = adm1177_probe, .id_table = adm1177_id, }; module_i2c_driver(adm1177_driver); diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 496d47490e10..cc3e0184e720 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -38,6 +38,7 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/jiffies.h> +#include <linux/regmap.h> /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, @@ -123,6 +124,7 @@ static inline unsigned int AOUT_FROM_REG(u8 reg) /* per client data */ struct adm9240_data { struct i2c_client *client; + struct regmap *regmap; struct mutex update_lock; char valid; unsigned long last_updated_measure; @@ -143,68 +145,141 @@ struct adm9240_data { }; /* write new fan div, callers must hold data->update_lock */ -static void adm9240_write_fan_div(struct i2c_client *client, int nr, +static int adm9240_write_fan_div(struct adm9240_data *data, int nr, u8 fan_div) { - u8 reg, old, shift = (nr + 2) * 2; + unsigned int reg, old, shift = (nr + 2) * 2; + int err; - reg = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); + err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, ®); + if (err < 0) + return err; old = (reg >> shift) & 3; reg &= ~(3 << shift); reg |= (fan_div << shift); - i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg); - dev_dbg(&client->dev, + err = regmap_write(data->regmap, ADM9240_REG_VID_FAN_DIV, reg); + if (err < 0) + return err; + dev_dbg(&data->client->dev, "fan%d clock divider changed from %u to %u\n", nr + 1, 1 << old, 1 << fan_div); + + return 0; +} + +static int adm9240_update_measure(struct adm9240_data *data) +{ + unsigned int val; + u8 regs[2]; + int err; + int i; + + err = regmap_bulk_read(data->regmap, ADM9240_REG_IN(0), &data->in[0], 6); + if (err < 0) + return err; + err = regmap_bulk_read(data->regmap, ADM9240_REG_INT(0), ®s, 2); + if (err < 0) + return err; + + data->alarms = regs[0] | regs[1] << 8; + + /* + * read temperature: assume temperature changes less than + * 0.5'C per two measurement cycles thus ignore possible + * but unlikely aliasing error on lsb reading. --Grant + */ + err = regmap_read(data->regmap, ADM9240_REG_TEMP, &val); + if (err < 0) + return err; + data->temp = val << 8; + err = regmap_read(data->regmap, ADM9240_REG_TEMP_CONF, &val); + if (err < 0) + return err; + data->temp |= val; + + err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN(0), + &data->fan[0], 2); + if (err < 0) + return err; + + for (i = 0; i < 2; i++) { /* read fans */ + /* adjust fan clock divider on overflow */ + if (data->valid && data->fan[i] == 255 && + data->fan_div[i] < 3) { + + err = adm9240_write_fan_div(data, i, + ++data->fan_div[i]); + if (err < 0) + return err; + + /* adjust fan_min if active, but not to 0 */ + if (data->fan_min[i] < 255 && + data->fan_min[i] >= 2) + data->fan_min[i] /= 2; + } + } + + return 0; +} + +static int adm9240_update_config(struct adm9240_data *data) +{ + unsigned int val; + int i; + int err; + + for (i = 0; i < 6; i++) { + err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MIN(i), + &data->in_min[i], 1); + if (err < 0) + return err; + err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MAX(i), + &data->in_max[i], 1); + if (err < 0) + return err; + } + err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN_MIN(0), + &data->fan_min[0], 2); + if (err < 0) + return err; + err = regmap_bulk_read(data->regmap, ADM9240_REG_TEMP_MAX(0), + &data->temp_max[0], 2); + if (err < 0) + return err; + + /* read fan divs and 5-bit VID */ + err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &val); + if (err < 0) + return err; + data->fan_div[0] = (val >> 4) & 3; + data->fan_div[1] = (val >> 6) & 3; + data->vid = val & 0x0f; + err = regmap_read(data->regmap, ADM9240_REG_VID4, &val); + if (err < 0) + return err; + data->vid |= (val & 1) << 4; + /* read analog out */ + err = regmap_raw_read(data->regmap, ADM9240_REG_ANALOG_OUT, + &data->aout, 1); + + return err; } static struct adm9240_data *adm9240_update_device(struct device *dev) { struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - int i; + int err; mutex_lock(&data->update_lock); /* minimum measurement cycle: 1.75 seconds */ if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) || !data->valid) { - - for (i = 0; i < 6; i++) { /* read voltages */ - data->in[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_IN(i)); - } - data->alarms = i2c_smbus_read_byte_data(client, - ADM9240_REG_INT(0)) | - i2c_smbus_read_byte_data(client, - ADM9240_REG_INT(1)) << 8; - - /* - * read temperature: assume temperature changes less than - * 0.5'C per two measurement cycles thus ignore possible - * but unlikely aliasing error on lsb reading. --Grant - */ - data->temp = (i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP) << 8) | - i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_CONF); - - for (i = 0; i < 2; i++) { /* read fans */ - data->fan[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_FAN(i)); - - /* adjust fan clock divider on overflow */ - if (data->valid && data->fan[i] == 255 && - data->fan_div[i] < 3) { - - adm9240_write_fan_div(client, i, - ++data->fan_div[i]); - - /* adjust fan_min if active, but not to 0 */ - if (data->fan_min[i] < 255 && - data->fan_min[i] >= 2) - data->fan_min[i] /= 2; - } + err = adm9240_update_measure(data); + if (err < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + return ERR_PTR(err); } data->last_updated_measure = jiffies; } @@ -212,33 +287,12 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) /* minimum config reading cycle: 300 seconds */ if (time_after(jiffies, data->last_updated_config + (HZ * 300)) || !data->valid) { - - for (i = 0; i < 6; i++) { - data->in_min[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MIN(i)); - data->in_max[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MAX(i)); - } - for (i = 0; i < 2; i++) { - data->fan_min[i] = i2c_smbus_read_byte_data(client, - ADM9240_REG_FAN_MIN(i)); + err = adm9240_update_config(data); + if (err < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + return ERR_PTR(err); } - data->temp_max[0] = i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_MAX(0)); - data->temp_max[1] = i2c_smbus_read_byte_data(client, - ADM9240_REG_TEMP_MAX(1)); - - /* read fan divs and 5-bit VID */ - i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 3; - data->fan_div[1] = (i >> 6) & 3; - data->vid = i & 0x0f; - data->vid |= (i2c_smbus_read_byte_data(client, - ADM9240_REG_VID4) & 1) << 4; - /* read analog out */ - data->aout = i2c_smbus_read_byte_data(client, - ADM9240_REG_ANALOG_OUT); - data->last_updated_config = jiffies; data->valid = 1; } @@ -253,6 +307,10 @@ static ssize_t temp1_input_show(struct device *dev, struct device_attribute *dummy, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", data->temp / 128 * 500); /* 9-bit value */ } @@ -261,6 +319,10 @@ static ssize_t max_show(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", data->temp_max[attr->index] * 1000); } @@ -269,7 +331,6 @@ static ssize_t max_store(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; long val; int err; @@ -279,10 +340,10 @@ static ssize_t max_store(struct device *dev, struct device_attribute *devattr, mutex_lock(&data->update_lock); data->temp_max[attr->index] = TEMP_TO_REG(val); - i2c_smbus_write_byte_data(client, ADM9240_REG_TEMP_MAX(attr->index), - data->temp_max[attr->index]); + err = regmap_write(data->regmap, ADM9240_REG_TEMP_MAX(attr->index), + data->temp_max[attr->index]); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static DEVICE_ATTR_RO(temp1_input); @@ -295,6 +356,10 @@ static ssize_t in_show(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index], attr->index)); } @@ -304,6 +369,10 @@ static ssize_t in_min_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index], attr->index)); } @@ -313,6 +382,10 @@ static ssize_t in_max_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index], attr->index)); } @@ -323,7 +396,6 @@ static ssize_t in_min_store(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; unsigned long val; int err; @@ -333,10 +405,10 @@ static ssize_t in_min_store(struct device *dev, mutex_lock(&data->update_lock); data->in_min[attr->index] = IN_TO_REG(val, attr->index); - i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(attr->index), - data->in_min[attr->index]); + err = regmap_write(data->regmap, ADM9240_REG_IN_MIN(attr->index), + data->in_min[attr->index]); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static ssize_t in_max_store(struct device *dev, @@ -345,7 +417,6 @@ static ssize_t in_max_store(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; unsigned long val; int err; @@ -355,10 +426,10 @@ static ssize_t in_max_store(struct device *dev, mutex_lock(&data->update_lock); data->in_max[attr->index] = IN_TO_REG(val, attr->index); - i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(attr->index), - data->in_max[attr->index]); + err = regmap_write(data->regmap, ADM9240_REG_IN_MAX(attr->index), + data->in_max[attr->index]); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0); @@ -386,6 +457,10 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index], 1 << data->fan_div[attr->index])); } @@ -395,6 +470,10 @@ static ssize_t fan_min_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[attr->index], 1 << data->fan_div[attr->index])); } @@ -404,6 +483,10 @@ static ssize_t fan_div_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", 1 << data->fan_div[attr->index]); } @@ -469,13 +552,13 @@ static ssize_t fan_min_store(struct device *dev, if (new_div != data->fan_div[nr]) { data->fan_div[nr] = new_div; - adm9240_write_fan_div(client, nr, new_div); + adm9240_write_fan_div(data, nr, new_div); } - i2c_smbus_write_byte_data(client, ADM9240_REG_FAN_MIN(nr), - data->fan_min[nr]); + err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(nr), + data->fan_min[nr]); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0); @@ -490,6 +573,10 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR_RO(alarms); @@ -499,6 +586,10 @@ static ssize_t alarm_show(struct device *dev, struct device_attribute *attr, { int bitnr = to_sensor_dev_attr(attr)->index; struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0); @@ -516,6 +607,10 @@ static ssize_t cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR_RO(cpu0_vid); @@ -525,6 +620,10 @@ static ssize_t aout_output_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); } @@ -533,7 +632,6 @@ static ssize_t aout_output_store(struct device *dev, const char *buf, size_t count) { struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; long val; int err; @@ -543,9 +641,9 @@ static ssize_t aout_output_store(struct device *dev, mutex_lock(&data->update_lock); data->aout = AOUT_TO_REG(val); - i2c_smbus_write_byte_data(client, ADM9240_REG_ANALOG_OUT, data->aout); + err = regmap_write(data->regmap, ADM9240_REG_ANALOG_OUT, data->aout); mutex_unlock(&data->update_lock); - return count; + return err < 0 ? err : count; } static DEVICE_ATTR_RW(aout_output); @@ -553,17 +651,19 @@ static ssize_t alarm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct adm9240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; unsigned long val; + int err; if (kstrtoul(buf, 10, &val) || val != 0) return -EINVAL; mutex_lock(&data->update_lock); - i2c_smbus_write_byte_data(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + err = regmap_write(data->regmap, ADM9240_REG_CHASSIS_CLEAR, 0x80); data->valid = 0; /* Force cache refresh */ mutex_unlock(&data->update_lock); - dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); + if (err < 0) + return err; + dev_dbg(&data->client->dev, "chassis intrusion latch cleared\n"); return count; } @@ -662,11 +762,18 @@ static int adm9240_detect(struct i2c_client *new_client, return 0; } -static void adm9240_init_client(struct i2c_client *client) +static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *data) { - struct adm9240_data *data = i2c_get_clientdata(client); - u8 conf = i2c_smbus_read_byte_data(client, ADM9240_REG_CONFIG); - u8 mode = i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_CONF) & 3; + u8 conf, mode; + int err; + + err = regmap_raw_read(data->regmap, ADM9240_REG_CONFIG, &conf, 1); + if (err < 0) + return err; + err = regmap_raw_read(data->regmap, ADM9240_REG_TEMP_CONF, &mode, 1); + if (err < 0) + return err; + mode &= 3; data->vrm = vid_which_vrm(); /* need this to report vid as mV */ @@ -682,44 +789,67 @@ static void adm9240_init_client(struct i2c_client *client) int i; for (i = 0; i < 6; i++) { - i2c_smbus_write_byte_data(client, - ADM9240_REG_IN_MIN(i), 0); - i2c_smbus_write_byte_data(client, - ADM9240_REG_IN_MAX(i), 255); + err = regmap_write(data->regmap, + ADM9240_REG_IN_MIN(i), 0); + if (err < 0) + return err; + err = regmap_write(data->regmap, + ADM9240_REG_IN_MAX(i), 255); + if (err < 0) + return err; + } + for (i = 0; i < 2; i++) { + err = regmap_write(data->regmap, + ADM9240_REG_FAN_MIN(i), 255); + if (err < 0) + return err; + } + for (i = 0; i < 2; i++) { + err = regmap_write(data->regmap, + ADM9240_REG_TEMP_MAX(i), 127); + if (err < 0) + return err; } - i2c_smbus_write_byte_data(client, - ADM9240_REG_FAN_MIN(0), 255); - i2c_smbus_write_byte_data(client, - ADM9240_REG_FAN_MIN(1), 255); - i2c_smbus_write_byte_data(client, - ADM9240_REG_TEMP_MAX(0), 127); - i2c_smbus_write_byte_data(client, - ADM9240_REG_TEMP_MAX(1), 127); /* start measurement cycle */ - i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1); + err = regmap_write(data->regmap, ADM9240_REG_CONFIG, 1); + if (err < 0) + return err; dev_info(&client->dev, "cold start: config was 0x%02x mode %u\n", conf, mode); } + + return 0; } -static int adm9240_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static const struct regmap_config adm9240_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, +}; + +static int adm9240_probe(struct i2c_client *new_client) { struct device *dev = &new_client->dev; struct device *hwmon_dev; struct adm9240_data *data; + int err; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); data->client = new_client; mutex_init(&data->update_lock); + data->regmap = devm_regmap_init_i2c(new_client, &adm9240_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); - adm9240_init_client(new_client); + err = adm9240_init_client(new_client, data); + if (err < 0) + return err; hwmon_dev = devm_hwmon_device_register_with_groups(dev, new_client->name, @@ -741,7 +871,7 @@ static struct i2c_driver adm9240_driver = { .driver = { .name = "adm9240", }, - .probe = adm9240_probe, + .probe_new = adm9240_probe, .id_table = adm9240_id, .detect = adm9240_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index d895b73fde6f..7246198f0901 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -99,8 +99,9 @@ static const struct regmap_config ads2830_regmap_config = { .val_bits = 8, }; -static int ads7828_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id ads7828_device_ids[]; + +static int ads7828_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ads7828_platform_data *pdata = dev_get_platdata(dev); @@ -141,7 +142,7 @@ static int ads7828_probe(struct i2c_client *client, chip = (enum ads7828_chips) of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = i2c_match_id(ads7828_device_ids, client)->driver_data; /* Bound Vref with min/max values */ vref_mv = clamp_val(vref_mv, ADS7828_EXT_VREF_MV_MIN, @@ -207,7 +208,7 @@ static struct i2c_driver ads7828_driver = { }, .id_table = ads7828_device_ids, - .probe = ads7828_probe, + .probe_new = ads7828_probe, }; module_i2c_driver(ads7828_driver); diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 80f8a4673315..9d80895d0266 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -39,8 +39,7 @@ static const struct adt7x10_ops adt7410_i2c_ops = { .write_byte = adt7410_i2c_write_byte, }; -static int adt7410_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7410_i2c_probe(struct i2c_client *client) { if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) @@ -67,7 +66,7 @@ static struct i2c_driver adt7410_driver = { .name = "adt7410", .pm = ADT7X10_DEV_PM_OPS, }, - .probe = adt7410_i2c_probe, + .probe_new = adt7410_i2c_probe, .remove = adt7410_i2c_remove, .id_table = adt7410_ids, .address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b), diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 5a839cc2ed1c..fad74aa62b64 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -666,8 +666,7 @@ static const struct hwmon_chip_info adt7411_chip_info = { .info = adt7411_info, }; -static int adt7411_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7411_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adt7411_data *data; @@ -707,7 +706,7 @@ static struct i2c_driver adt7411_driver = { .driver = { .name = "adt7411", }, - .probe = adt7411_probe, + .probe_new = adt7411_probe, .id_table = adt7411_id, .detect = adt7411_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 208813158bb4..e75bbd87ad09 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -1787,8 +1787,7 @@ static int adt7462_detect(struct i2c_client *client, return 0; } -static int adt7462_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7462_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adt7462_data *data; @@ -1820,7 +1819,7 @@ static struct i2c_driver adt7462_driver = { .driver = { .name = "adt7462", }, - .probe = adt7462_probe, + .probe_new = adt7462_probe, .id_table = adt7462_id, .detect = adt7462_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index a30f34cf512c..740f39a54ab0 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -1217,8 +1217,7 @@ static void adt7470_init_client(struct i2c_client *client) } } -static int adt7470_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7470_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct adt7470_data *data; @@ -1276,7 +1275,7 @@ static struct i2c_driver adt7470_driver = { .driver = { .name = "adt7470", }, - .probe = adt7470_probe, + .probe_new = adt7470_probe, .remove = adt7470_remove, .id_table = adt7470_id, .detect = adt7470_detect, diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 054080443b47..9d5b019651f2 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -1539,8 +1539,7 @@ static int adt7475_set_pwm_polarity(struct i2c_client *client) return 0; } -static int adt7475_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adt7475_probe(struct i2c_client *client) { enum chips chip; static const char * const names[] = { @@ -1554,6 +1553,7 @@ static int adt7475_probe(struct i2c_client *client, struct device *hwmon_dev; int i, ret = 0, revision, group_num = 0; u8 config3; + const struct i2c_device_id *id = i2c_match_id(adt7475_id, client); data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (data == NULL) @@ -1728,7 +1728,7 @@ static struct i2c_driver adt7475_driver = { .name = "adt7475", .of_match_table = of_match_ptr(adt7475_of_match), }, - .probe = adt7475_probe, + .probe_new = adt7475_probe, .id_table = adt7475_id, .detect = adt7475_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 013fb056b1d0..6b1ce2242c61 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -900,8 +900,7 @@ static int amc6821_init_client(struct i2c_client *client) return 0; } -static int amc6821_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int amc6821_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct amc6821_data *data; @@ -940,7 +939,7 @@ static struct i2c_driver amc6821_driver = { .driver = { .name = "amc6821", }, - .probe = amc6821_probe, + .probe_new = amc6821_probe, .id_table = amc6821_id, .detect = amc6821_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c index 29603742c858..d06597303d5a 100644 --- a/drivers/hwmon/amd_energy.c +++ b/drivers/hwmon/amd_energy.c @@ -35,7 +35,6 @@ struct sensor_accumulator { u64 energy_ctr; u64 prev_value; - char label[10]; }; struct amd_energy_data { @@ -47,11 +46,13 @@ struct amd_energy_data { struct mutex lock; /* An accumulator for each core and socket */ struct sensor_accumulator *accums; + unsigned int timeout_ms; /* Energy Status Units */ - u64 energy_units; + int energy_units; int nr_cpus; int nr_socks; int core_id; + char (*label)[10]; }; static int amd_energy_read_labels(struct device *dev, @@ -61,7 +62,7 @@ static int amd_energy_read_labels(struct device *dev, { struct amd_energy_data *data = dev_get_drvdata(dev); - *str = data->accums[channel].label; + *str = data->label[channel]; return 0; } @@ -73,108 +74,67 @@ static void get_energy_units(struct amd_energy_data *data) data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8; } -static void accumulate_socket_delta(struct amd_energy_data *data, - int sock, int cpu) +static void accumulate_delta(struct amd_energy_data *data, + int channel, int cpu, u32 reg) { - struct sensor_accumulator *s_accum; + struct sensor_accumulator *accum; u64 input; mutex_lock(&data->lock); - rdmsrl_safe_on_cpu(cpu, ENERGY_PKG_MSR, &input); + rdmsrl_safe_on_cpu(cpu, reg, &input); input &= AMD_ENERGY_MASK; - s_accum = &data->accums[data->nr_cpus + sock]; - if (input >= s_accum->prev_value) - s_accum->energy_ctr += - input - s_accum->prev_value; + accum = &data->accums[channel]; + if (input >= accum->prev_value) + accum->energy_ctr += + input - accum->prev_value; else - s_accum->energy_ctr += UINT_MAX - - s_accum->prev_value + input; + accum->energy_ctr += UINT_MAX - + accum->prev_value + input; - s_accum->prev_value = input; + accum->prev_value = input; mutex_unlock(&data->lock); } -static void accumulate_core_delta(struct amd_energy_data *data) +static void read_accumulate(struct amd_energy_data *data) { - struct sensor_accumulator *c_accum; - u64 input; - int cpu; + int sock, scpu, cpu; + + for (sock = 0; sock < data->nr_socks; sock++) { + scpu = cpumask_first_and(cpu_online_mask, + cpumask_of_node(sock)); + + accumulate_delta(data, data->nr_cpus + sock, + scpu, ENERGY_PKG_MSR); + } - mutex_lock(&data->lock); if (data->core_id >= data->nr_cpus) data->core_id = 0; cpu = data->core_id; + if (cpu_online(cpu)) + accumulate_delta(data, cpu, cpu, ENERGY_CORE_MSR); - if (!cpu_online(cpu)) - goto out; - - rdmsrl_safe_on_cpu(cpu, ENERGY_CORE_MSR, &input); - input &= AMD_ENERGY_MASK; - - c_accum = &data->accums[cpu]; - - if (input >= c_accum->prev_value) - c_accum->energy_ctr += - input - c_accum->prev_value; - else - c_accum->energy_ctr += UINT_MAX - - c_accum->prev_value + input; - - c_accum->prev_value = input; - -out: data->core_id++; - mutex_unlock(&data->lock); -} - -static void read_accumulate(struct amd_energy_data *data) -{ - int sock; - - for (sock = 0; sock < data->nr_socks; sock++) { - int cpu; - - cpu = cpumask_first_and(cpu_online_mask, - cpumask_of_node(sock)); - - accumulate_socket_delta(data, sock, cpu); - } - - accumulate_core_delta(data); } static void amd_add_delta(struct amd_energy_data *data, int ch, - int cpu, long *val, bool is_core) + int cpu, long *val, u32 reg) { - struct sensor_accumulator *s_accum, *c_accum; + struct sensor_accumulator *accum; u64 input; mutex_lock(&data->lock); - if (!is_core) { - rdmsrl_safe_on_cpu(cpu, ENERGY_PKG_MSR, &input); - input &= AMD_ENERGY_MASK; - - s_accum = &data->accums[ch]; - if (input >= s_accum->prev_value) - input += s_accum->energy_ctr - - s_accum->prev_value; - else - input += UINT_MAX - s_accum->prev_value + - s_accum->energy_ctr; - } else { - rdmsrl_safe_on_cpu(cpu, ENERGY_CORE_MSR, &input); - input &= AMD_ENERGY_MASK; + rdmsrl_safe_on_cpu(cpu, reg, &input); + input &= AMD_ENERGY_MASK; - c_accum = &data->accums[ch]; - if (input >= c_accum->prev_value) - input += c_accum->energy_ctr - - c_accum->prev_value; - else - input += UINT_MAX - c_accum->prev_value + - c_accum->energy_ctr; - } + accum = &data->accums[ch]; + if (input >= accum->prev_value) + input += accum->energy_ctr - + accum->prev_value; + else + input += UINT_MAX - accum->prev_value + + accum->energy_ctr; /* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */ *val = div64_ul(input * 1000000UL, BIT(data->energy_units)); @@ -187,20 +147,22 @@ static int amd_energy_read(struct device *dev, u32 attr, int channel, long *val) { struct amd_energy_data *data = dev_get_drvdata(dev); + u32 reg; int cpu; if (channel >= data->nr_cpus) { cpu = cpumask_first_and(cpu_online_mask, cpumask_of_node (channel - data->nr_cpus)); - amd_add_delta(data, channel, cpu, val, false); + reg = ENERGY_PKG_MSR; } else { cpu = channel; if (!cpu_online(cpu)) return -ENODEV; - amd_add_delta(data, channel, cpu, val, true); + reg = ENERGY_CORE_MSR; } + amd_add_delta(data, channel, cpu, val, reg); return 0; } @@ -215,6 +177,7 @@ static umode_t amd_energy_is_visible(const void *_data, static int energy_accumulator(void *p) { struct amd_energy_data *data = (struct amd_energy_data *)p; + unsigned int timeout = data->timeout_ms; while (!kthread_should_stop()) { /* @@ -227,14 +190,7 @@ static int energy_accumulator(void *p) if (kthread_should_stop()) break; - /* - * On a 240W system, with default resolution the - * Socket Energy status register may wrap around in - * 2^32*15.3 e-6/240 = 273.8041 secs (~4.5 mins) - * - * let us accumulate for every 100secs - */ - schedule_timeout(msecs_to_jiffies(100000)); + schedule_timeout(msecs_to_jiffies(timeout)); } return 0; } @@ -247,12 +203,13 @@ static const struct hwmon_ops amd_energy_ops = { static int amd_create_sensor(struct device *dev, struct amd_energy_data *data, - u8 type, u32 config) + enum hwmon_sensor_types type, u32 config) { struct hwmon_channel_info *info = &data->energy_info; struct sensor_accumulator *accums; int i, num_siblings, cpus, sockets; u32 *s_config; + char (*label_l)[10]; /* Identify the number of siblings per core */ num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1; @@ -276,21 +233,25 @@ static int amd_create_sensor(struct device *dev, if (!accums) return -ENOMEM; + label_l = devm_kcalloc(dev, cpus + sockets, + sizeof(*label_l), GFP_KERNEL); + if (!label_l) + return -ENOMEM; + info->type = type; info->config = s_config; data->nr_cpus = cpus; data->nr_socks = sockets; data->accums = accums; + data->label = label_l; for (i = 0; i < cpus + sockets; i++) { s_config[i] = config; if (i < cpus) - scnprintf(accums[i].label, 10, - "Ecore%03u", i); + scnprintf(label_l[i], 10, "Ecore%03u", i); else - scnprintf(accums[i].label, 10, - "Esocket%u", (i - cpus)); + scnprintf(label_l[i], 10, "Esocket%u", (i - cpus)); } return 0; @@ -301,6 +262,7 @@ static int amd_energy_probe(struct platform_device *pdev) struct device *hwmon_dev; struct amd_energy_data *data; struct device *dev = &pdev->dev; + int ret; data = devm_kzalloc(dev, sizeof(struct amd_energy_data), GFP_KERNEL); @@ -313,8 +275,10 @@ static int amd_energy_probe(struct platform_device *pdev) dev_set_drvdata(dev, data); /* Populate per-core energy reporting */ data->info[0] = &data->energy_info; - amd_create_sensor(dev, data, hwmon_energy, - HWMON_E_INPUT | HWMON_E_LABEL); + ret = amd_create_sensor(dev, data, hwmon_energy, + HWMON_E_INPUT | HWMON_E_LABEL); + if (ret) + return ret; mutex_init(&data->lock); get_energy_units(data); @@ -326,11 +290,15 @@ static int amd_energy_probe(struct platform_device *pdev) if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); + /* + * On a system with peak wattage of 250W + * timeout = 2 ^ 32 / 2 ^ energy_units / 250 secs + */ + data->timeout_ms = 1000 * + BIT(min(28, 31 - data->energy_units)) / 250; + data->wrap_accumulate = kthread_run(energy_accumulator, data, "%s", dev_name(hwmon_dev)); - if (IS_ERR(data->wrap_accumulate)) - return PTR_ERR(data->wrap_accumulate); - return PTR_ERR_OR_ZERO(data->wrap_accumulate); } diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 4c609e23a4ef..ba9fcf6f9264 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -205,8 +205,7 @@ struct asb100_data { static int asb100_read_value(struct i2c_client *client, u16 reg); static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); -static int asb100_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int asb100_probe(struct i2c_client *client); static int asb100_detect(struct i2c_client *client, struct i2c_board_info *info); static int asb100_remove(struct i2c_client *client); @@ -224,7 +223,7 @@ static struct i2c_driver asb100_driver = { .driver = { .name = "asb100", }, - .probe = asb100_probe, + .probe_new = asb100_probe, .remove = asb100_remove, .id_table = asb100_id, .detect = asb100_detect, @@ -775,8 +774,7 @@ static int asb100_detect(struct i2c_client *client, return 0; } -static int asb100_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int asb100_probe(struct i2c_client *client) { int err; struct asb100_data *data; diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 9e14e2829ee9..600ffc7e1900 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -1087,7 +1087,7 @@ static void asc7621_init_client(struct i2c_client *client) } static int -asc7621_probe(struct i2c_client *client, const struct i2c_device_id *id) +asc7621_probe(struct i2c_client *client) { struct asc7621_data *data; int i, err; @@ -1193,7 +1193,7 @@ static struct i2c_driver asc7621_driver = { .driver = { .name = "asc7621", }, - .probe = asc7621_probe, + .probe_new = asc7621_probe, .remove = asc7621_remove, .id_table = asc7621_id, .detect = asc7621_detect, diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 79b8df258371..1e08a5431f12 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -244,8 +244,7 @@ static struct attribute *atxp1_attrs[] = { }; ATTRIBUTE_GROUPS(atxp1); -static int atxp1_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int atxp1_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct atxp1_data *data; @@ -288,7 +287,7 @@ static struct i2c_driver atxp1_driver = { .driver = { .name = "atxp1", }, - .probe = atxp1_probe, + .probe_new = atxp1_probe, .id_table = atxp1_id, }; diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c index 94698cae0497..3e1d56585b91 100644 --- a/drivers/hwmon/bt1-pvt.c +++ b/drivers/hwmon/bt1-pvt.c @@ -13,6 +13,7 @@ #include <linux/bitops.h> #include <linux/clk.h> #include <linux/completion.h> +#include <linux/delay.h> #include <linux/device.h> #include <linux/hwmon-sysfs.h> #include <linux/hwmon.h> @@ -476,6 +477,7 @@ static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type, long *val) { struct pvt_cache *cache = &pvt->cache[type]; + unsigned long timeout; u32 data; int ret; @@ -499,7 +501,14 @@ static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type, pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0); pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN); - wait_for_completion(&cache->conversion); + /* + * Wait with timeout since in case if the sensor is suddenly powered + * down the request won't be completed and the caller will hang up on + * this procedure until the power is back up again. Multiply the + * timeout by the factor of two to prevent a false timeout. + */ + timeout = 2 * usecs_to_jiffies(ktime_to_us(pvt->timeout)); + ret = wait_for_completion_timeout(&cache->conversion, timeout); pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, @@ -509,6 +518,9 @@ static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type, mutex_unlock(&pvt->iface_mtx); + if (!ret) + return -ETIMEDOUT; + if (type == PVT_TEMP) *val = pvt_calc_poly(&poly_N_to_temp, data); else @@ -654,44 +666,16 @@ static int pvt_write_trim(struct pvt_hwmon *pvt, long val) static int pvt_read_timeout(struct pvt_hwmon *pvt, long *val) { - unsigned long rate; - ktime_t kt; - u32 data; - - rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk); - if (!rate) - return -ENODEV; - - /* - * Don't bother with mutex here, since we just read data from MMIO. - * We also have to scale the ticks timeout up to compensate the - * ms-ns-data translations. - */ - data = readl(pvt->regs + PVT_TTIMEOUT) + 1; + int ret; - /* - * Calculate ref-clock based delay (Ttotal) between two consecutive - * data samples of the same sensor. So we first must calculate the - * delay introduced by the internal ref-clock timer (Tref * Fclk). - * Then add the constant timeout cuased by each conversion latency - * (Tmin). The basic formulae for each conversion is following: - * Ttotal = Tref * Fclk + Tmin - * Note if alarms are enabled the sensors are polled one after - * another, so in order to have the delay being applicable for each - * sensor the requested value must be equally redistirbuted. - */ -#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS) - kt = ktime_set(PVT_SENSORS_NUM * (u64)data, 0); - kt = ktime_divns(kt, rate); - kt = ktime_add_ns(kt, PVT_SENSORS_NUM * PVT_TOUT_MIN); -#else - kt = ktime_set(data, 0); - kt = ktime_divns(kt, rate); - kt = ktime_add_ns(kt, PVT_TOUT_MIN); -#endif + ret = mutex_lock_interruptible(&pvt->iface_mtx); + if (ret) + return ret; /* Return the result in msec as hwmon sysfs interface requires. */ - *val = ktime_to_ms(kt); + *val = ktime_to_ms(pvt->timeout); + + mutex_unlock(&pvt->iface_mtx); return 0; } @@ -699,7 +683,7 @@ static int pvt_read_timeout(struct pvt_hwmon *pvt, long *val) static int pvt_write_timeout(struct pvt_hwmon *pvt, long val) { unsigned long rate; - ktime_t kt; + ktime_t kt, cache; u32 data; int ret; @@ -712,7 +696,7 @@ static int pvt_write_timeout(struct pvt_hwmon *pvt, long val) * between all available sensors to have the requested delay * applicable to each individual sensor. */ - kt = ms_to_ktime(val); + cache = kt = ms_to_ktime(val); #if defined(CONFIG_SENSORS_BT1_PVT_ALARMS) kt = ktime_divns(kt, PVT_SENSORS_NUM); #endif @@ -741,6 +725,7 @@ static int pvt_write_timeout(struct pvt_hwmon *pvt, long val) return ret; pvt_set_tout(pvt, data); + pvt->timeout = cache; mutex_unlock(&pvt->iface_mtx); @@ -982,10 +967,52 @@ static int pvt_request_clks(struct pvt_hwmon *pvt) return 0; } -static void pvt_init_iface(struct pvt_hwmon *pvt) +static int pvt_check_pwr(struct pvt_hwmon *pvt) { + unsigned long tout; + int ret = 0; + u32 data; + + /* + * Test out the sensor conversion functionality. If it is not done on + * time then the domain must have been unpowered and we won't be able + * to use the device later in this driver. + * Note If the power source is lost during the normal driver work the + * data read procedure will either return -ETIMEDOUT (for the + * alarm-less driver configuration) or just stop the repeated + * conversion. In the later case alas we won't be able to detect the + * problem. + */ + pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL); + pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN); + pvt_set_tout(pvt, 0); + readl(pvt->regs + PVT_DATA); + + tout = PVT_TOUT_MIN / NSEC_PER_USEC; + usleep_range(tout, 2 * tout); + + data = readl(pvt->regs + PVT_DATA); + if (!(data & PVT_DATA_VALID)) { + ret = -ENODEV; + dev_err(pvt->dev, "Sensor is powered down\n"); + } + + pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0); + + return ret; +} + +static int pvt_init_iface(struct pvt_hwmon *pvt) +{ + unsigned long rate; u32 trim, temp; + rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk); + if (!rate) { + dev_err(pvt->dev, "Invalid reference clock rate\n"); + return -ENODEV; + } + /* * Make sure all interrupts and controller are disabled so not to * accidentally have ISR executed before the driver data is fully @@ -1000,12 +1027,37 @@ static void pvt_init_iface(struct pvt_hwmon *pvt) pvt_set_mode(pvt, pvt_info[pvt->sensor].mode); pvt_set_tout(pvt, PVT_TOUT_DEF); + /* + * Preserve the current ref-clock based delay (Ttotal) between the + * sensors data samples in the driver data so not to recalculate it + * each time on the data requests and timeout reads. It consists of the + * delay introduced by the internal ref-clock timer (N / Fclk) and the + * constant timeout caused by each conversion latency (Tmin): + * Ttotal = N / Fclk + Tmin + * If alarms are enabled the sensors are polled one after another and + * in order to get the next measurement of a particular sensor the + * caller will have to wait for at most until all the others are + * polled. In that case the formulae will look a bit different: + * Ttotal = 5 * (N / Fclk + Tmin) + */ +#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS) + pvt->timeout = ktime_set(PVT_SENSORS_NUM * PVT_TOUT_DEF, 0); + pvt->timeout = ktime_divns(pvt->timeout, rate); + pvt->timeout = ktime_add_ns(pvt->timeout, PVT_SENSORS_NUM * PVT_TOUT_MIN); +#else + pvt->timeout = ktime_set(PVT_TOUT_DEF, 0); + pvt->timeout = ktime_divns(pvt->timeout, rate); + pvt->timeout = ktime_add_ns(pvt->timeout, PVT_TOUT_MIN); +#endif + trim = PVT_TRIM_DEF; if (!of_property_read_u32(pvt->dev->of_node, "baikal,pvt-temp-offset-millicelsius", &temp)) trim = pvt_calc_trim(temp); pvt_set_trim(pvt, trim); + + return 0; } static int pvt_request_irq(struct pvt_hwmon *pvt) @@ -1109,7 +1161,13 @@ static int pvt_probe(struct platform_device *pdev) if (ret) return ret; - pvt_init_iface(pvt); + ret = pvt_check_pwr(pvt); + if (ret) + return ret; + + ret = pvt_init_iface(pvt); + if (ret) + return ret; ret = pvt_request_irq(pvt); if (ret) diff --git a/drivers/hwmon/bt1-pvt.h b/drivers/hwmon/bt1-pvt.h index 5eac73e94885..93b8dd5e7c94 100644 --- a/drivers/hwmon/bt1-pvt.h +++ b/drivers/hwmon/bt1-pvt.h @@ -10,6 +10,7 @@ #include <linux/completion.h> #include <linux/hwmon.h> #include <linux/kernel.h> +#include <linux/ktime.h> #include <linux/mutex.h> #include <linux/seqlock.h> @@ -201,6 +202,7 @@ struct pvt_cache { * if alarms are disabled). * @sensor: current PVT sensor the data conversion is being performed for. * @cache: data cache descriptor. + * @timeout: conversion timeout cache. */ struct pvt_hwmon { struct device *dev; @@ -214,6 +216,7 @@ struct pvt_hwmon { struct mutex iface_mtx; enum pvt_sensor_type sensor; struct pvt_cache cache[PVT_SENSORS_NUM]; + ktime_t timeout; }; /* diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index c3472b73fa79..c1e4cfb40c3d 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -2461,8 +2461,9 @@ static int dme1737_i2c_detect(struct i2c_client *client, return 0; } -static int dme1737_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id dme1737_id[]; + +static int dme1737_i2c_probe(struct i2c_client *client) { struct dme1737_data *data; struct device *dev = &client->dev; @@ -2473,7 +2474,7 @@ static int dme1737_i2c_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, data); - data->type = id->driver_data; + data->type = i2c_match_id(dme1737_id, client)->driver_data; data->client = client; data->name = client->name; mutex_init(&data->update_lock); @@ -2529,7 +2530,7 @@ static struct i2c_driver dme1737_i2c_driver = { .driver = { .name = "dme1737", }, - .probe = dme1737_i2c_probe, + .probe_new = dme1737_i2c_probe, .remove = dme1737_i2c_remove, .id_table = dme1737_id, .detect = dme1737_i2c_detect, diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 541bed8732b7..e1d742bfc74c 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -342,8 +342,9 @@ static const struct attribute_group ds1621_group = { }; __ATTRIBUTE_GROUPS(ds1621); -static int ds1621_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id ds1621_id[]; + +static int ds1621_probe(struct i2c_client *client) { struct ds1621_data *data; struct device *hwmon_dev; @@ -355,7 +356,7 @@ static int ds1621_probe(struct i2c_client *client, mutex_init(&data->update_lock); - data->kind = id->driver_data; + data->kind = i2c_match_id(ds1621_id, client)->driver_data; data->client = client; /* Initialize the DS1621 chip */ @@ -383,7 +384,7 @@ static struct i2c_driver ds1621_driver = { .driver = { .name = "ds1621", }, - .probe = ds1621_probe, + .probe_new = ds1621_probe, .id_table = ds1621_id, }; diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c index 8f1fc83ac37b..9ec722798c4a 100644 --- a/drivers/hwmon/ds620.c +++ b/drivers/hwmon/ds620.c @@ -211,8 +211,7 @@ static struct attribute *ds620_attrs[] = { ATTRIBUTE_GROUPS(ds620); -static int ds620_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds620_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -246,7 +245,7 @@ static struct i2c_driver ds620_driver = { .driver = { .name = "ds620", }, - .probe = ds620_probe, + .probe_new = ds620_probe, .id_table = ds620_id, }; diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index e9c0bbc2caa9..314838272049 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -386,11 +386,13 @@ static const struct regmap_config emc1403_regmap_config = { .volatile_reg = emc1403_regmap_is_volatile, }; -static int emc1403_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id emc1403_idtable[]; + +static int emc1403_probe(struct i2c_client *client) { struct thermal_data *data; struct device *hwmon_dev; + const struct i2c_device_id *id = i2c_match_id(emc1403_idtable, client); data = devm_kzalloc(&client->dev, sizeof(struct thermal_data), GFP_KERNEL); @@ -452,7 +454,7 @@ static struct i2c_driver sensor_emc1403 = { .name = "emc1403", }, .detect = emc1403_detect, - .probe = emc1403_probe, + .probe_new = emc1403_probe, .id_table = emc1403_idtable, .address_list = emc1403_address_list, }; diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 924c02c1631d..e4c95ca9e19f 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -551,7 +551,7 @@ static const struct attribute_group emc2103_temp4_group = { }; static int -emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id) +emc2103_probe(struct i2c_client *client) { struct emc2103_data *data; struct device *hwmon_dev; @@ -653,7 +653,7 @@ static struct i2c_driver emc2103_driver = { .driver = { .name = "emc2103", }, - .probe = emc2103_probe, + .probe_new = emc2103_probe, .id_table = emc2103_ids, .detect = emc2103_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c index df0f7292e214..ec5c98702bf5 100644 --- a/drivers/hwmon/emc6w201.c +++ b/drivers/hwmon/emc6w201.c @@ -444,8 +444,7 @@ static int emc6w201_detect(struct i2c_client *client, return 0; } -static int emc6w201_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int emc6w201_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct emc6w201_data *data; @@ -475,7 +474,7 @@ static struct i2c_driver emc6w201_driver = { .driver = { .name = "emc6w201", }, - .probe = emc6w201_probe, + .probe_new = emc6w201_probe, .id_table = emc6w201_id, .detect = emc6w201_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index eb847a7d6b83..3e567be60fb1 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -113,8 +113,7 @@ struct f75375_data { static int f75375_detect(struct i2c_client *client, struct i2c_board_info *info); -static int f75375_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int f75375_probe(struct i2c_client *client); static int f75375_remove(struct i2c_client *client); static const struct i2c_device_id f75375_id[] = { @@ -130,7 +129,7 @@ static struct i2c_driver f75375_driver = { .driver = { .name = "f75375", }, - .probe = f75375_probe, + .probe_new = f75375_probe, .remove = f75375_remove, .id_table = f75375_id, .detect = f75375_detect, @@ -814,8 +813,7 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data, } -static int f75375_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int f75375_probe(struct i2c_client *client) { struct f75375_data *data; struct f75375s_platform_data *f75375s_pdata = @@ -832,7 +830,7 @@ static int f75375_probe(struct i2c_client *client, i2c_set_clientdata(client, data); mutex_init(&data->update_lock); - data->kind = id->driver_data; + data->kind = i2c_match_id(f75375_id, client)->driver_data; err = sysfs_create_group(&client->dev.kobj, &f75375_group); if (err) diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 4136643d8e0c..5191cd85a8d1 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -214,8 +214,7 @@ static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 }; * Functions declarations */ -static int fschmd_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int fschmd_probe(struct i2c_client *client); static int fschmd_detect(struct i2c_client *client, struct i2c_board_info *info); static int fschmd_remove(struct i2c_client *client); @@ -242,7 +241,7 @@ static struct i2c_driver fschmd_driver = { .driver = { .name = "fschmd", }, - .probe = fschmd_probe, + .probe_new = fschmd_probe, .remove = fschmd_remove, .id_table = fschmd_id, .detect = fschmd_detect, @@ -1081,15 +1080,14 @@ static int fschmd_detect(struct i2c_client *client, return 0; } -static int fschmd_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int fschmd_probe(struct i2c_client *client) { struct fschmd_data *data; const char * const names[7] = { "Poseidon", "Hermes", "Scylla", "Heracles", "Heimdall", "Hades", "Syleus" }; const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; int i, err; - enum chips kind = id->driver_data; + enum chips kind = i2c_match_id(fschmd_id, client)->driver_data; data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL); if (!data) diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index 371ce7745f5e..ef88a156efc2 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -752,7 +752,7 @@ static int fts_remove(struct i2c_client *client) return 0; } -static int fts_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int fts_probe(struct i2c_client *client) { u8 revision; struct fts_data *data; @@ -819,7 +819,7 @@ static struct i2c_driver fts_driver = { .name = "ftsteutates", }, .id_table = fts_id, - .probe = fts_probe, + .probe_new = fts_probe, .remove = fts_remove, .detect = fts_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c index 31beedcb420f..a692f7b2f6f7 100644 --- a/drivers/hwmon/g760a.c +++ b/drivers/hwmon/g760a.c @@ -170,8 +170,7 @@ ATTRIBUTE_GROUPS(g760a); * new-style driver model code */ -static int g760a_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int g760a_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct g760a_data *data; @@ -207,7 +206,7 @@ static struct i2c_driver g760a_driver = { .driver = { .name = "g760a", }, - .probe = g760a_probe, + .probe_new = g760a_probe, .id_table = g760a_id, }; diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index 5f0f34631580..64a0599b2da5 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -1033,7 +1033,7 @@ static inline int g762_fan_init(struct device *dev) data->fan_cmd1); } -static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int g762_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1079,7 +1079,7 @@ static struct i2c_driver g762_driver = { .name = DRVNAME, .of_match_table = of_match_ptr(g762_dt_match), }, - .probe = g762_probe, + .probe_new = g762_probe, .id_table = g762_id, }; diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 4964beeea542..7aaee5a48243 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -611,8 +611,7 @@ static void gl518_init_client(struct i2c_client *client) gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue); } -static int gl518_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int gl518_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -653,7 +652,7 @@ static struct i2c_driver gl518_driver = { .driver = { .name = "gl518sm", }, - .probe = gl518_probe, + .probe_new = gl518_probe, .id_table = gl518_id, .detect = gl518_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 4689e01cb56d..4ae1295cc3ea 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -854,8 +854,7 @@ static void gl520_init_client(struct i2c_client *client) gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); } -static int gl520_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int gl520_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -896,7 +895,7 @@ static struct i2c_driver gl520_driver = { .driver = { .name = "gl520sm", }, - .probe = gl520_probe, + .probe_new = gl520_probe, .id_table = gl520_id, .detect = gl520_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index c6d4567f3952..1fe37418ff46 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -17,6 +17,7 @@ #define GSC_HWMON_MAX_TEMP_CH 16 #define GSC_HWMON_MAX_IN_CH 16 +#define GSC_HWMON_MAX_FAN_CH 16 #define GSC_HWMON_RESOLUTION 12 #define GSC_HWMON_VREF 2500 @@ -27,11 +28,14 @@ struct gsc_hwmon_data { struct regmap *regmap; const struct gsc_hwmon_channel *temp_ch[GSC_HWMON_MAX_TEMP_CH]; const struct gsc_hwmon_channel *in_ch[GSC_HWMON_MAX_IN_CH]; + const struct gsc_hwmon_channel *fan_ch[GSC_HWMON_MAX_FAN_CH]; u32 temp_config[GSC_HWMON_MAX_TEMP_CH + 1]; u32 in_config[GSC_HWMON_MAX_IN_CH + 1]; + u32 fan_config[GSC_HWMON_MAX_FAN_CH + 1]; struct hwmon_channel_info temp_info; struct hwmon_channel_info in_info; - const struct hwmon_channel_info *info[3]; + struct hwmon_channel_info fan_info; + const struct hwmon_channel_info *info[4]; struct hwmon_chip_info chip; }; @@ -155,6 +159,9 @@ gsc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, case hwmon_temp: ch = hwmon->temp_ch[channel]; break; + case hwmon_fan: + ch = hwmon->fan_ch[channel]; + break; default: return -EOPNOTSUPP; } @@ -187,6 +194,9 @@ gsc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, /* adjust by uV offset */ tmp += ch->mvoffset; break; + case mode_fan: + tmp *= 30; /* convert to revolutions per minute */ + break; case mode_voltage_24bit: case mode_voltage_16bit: /* no adjustment needed */ @@ -211,6 +221,9 @@ gsc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, case hwmon_temp: *buf = hwmon->temp_ch[channel]->name; break; + case hwmon_fan: + *buf = hwmon->fan_ch[channel]->name; + break; default: return -ENOTSUPP; } @@ -304,7 +317,7 @@ static int gsc_hwmon_probe(struct platform_device *pdev) struct gsc_hwmon_platform_data *pdata = dev_get_platdata(dev); struct gsc_hwmon_data *hwmon; const struct attribute_group **groups; - int i, i_in, i_temp; + int i, i_in, i_temp, i_fan; if (!pdata) { pdata = gsc_hwmon_get_devtree_pdata(dev); @@ -324,7 +337,7 @@ static int gsc_hwmon_probe(struct platform_device *pdev) if (IS_ERR(hwmon->regmap)) return PTR_ERR(hwmon->regmap); - for (i = 0, i_in = 0, i_temp = 0; i < hwmon->pdata->nchannels; i++) { + for (i = 0, i_in = 0, i_temp = 0, i_fan = 0; i < hwmon->pdata->nchannels; i++) { const struct gsc_hwmon_channel *ch = &pdata->channels[i]; switch (ch->mode) { @@ -338,6 +351,16 @@ static int gsc_hwmon_probe(struct platform_device *pdev) HWMON_T_LABEL; i_temp++; break; + case mode_fan: + if (i_fan == GSC_HWMON_MAX_FAN_CH) { + dev_err(gsc->dev, "too many fan channels\n"); + return -EINVAL; + } + hwmon->fan_ch[i_fan] = ch; + hwmon->fan_config[i_fan] = HWMON_F_INPUT | + HWMON_F_LABEL; + i_fan++; + break; case mode_voltage_24bit: case mode_voltage_16bit: case mode_voltage_raw: @@ -361,10 +384,13 @@ static int gsc_hwmon_probe(struct platform_device *pdev) hwmon->chip.info = hwmon->info; hwmon->info[0] = &hwmon->temp_info; hwmon->info[1] = &hwmon->in_info; + hwmon->info[2] = &hwmon->fan_info; hwmon->temp_info.type = hwmon_temp; hwmon->temp_info.config = hwmon->temp_config; hwmon->in_info.type = hwmon_in; hwmon->in_info.config = hwmon->in_config; + hwmon->fan_info.type = hwmon_fan; + hwmon->fan_info.config = hwmon->fan_config; groups = pdata->fan_base ? gsc_hwmon_groups : NULL; hwmon_dev = devm_hwmon_device_register_with_info(dev, diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c index 018df6074f7b..d9394e19fea8 100644 --- a/drivers/hwmon/hih6130.c +++ b/drivers/hwmon/hih6130.c @@ -204,8 +204,7 @@ static struct attribute *hih6130_attrs[] = { ATTRIBUTE_GROUPS(hih6130); -static int hih6130_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int hih6130_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct hih6130 *hih6130; @@ -250,7 +249,7 @@ static struct i2c_driver hih6130_driver = { .name = "hih6130", .of_match_table = of_match_ptr(hih6130_of_match), }, - .probe = hih6130_probe, + .probe_new = hih6130_probe, .id_table = hih6130_id, }; diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 3f596a5328da..6c684058bfdf 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -431,6 +431,8 @@ static const char * const hwmon_temp_attr_templates[] = { [hwmon_temp_lowest] = "temp%d_lowest", [hwmon_temp_highest] = "temp%d_highest", [hwmon_temp_reset_history] = "temp%d_reset_history", + [hwmon_temp_rated_min] = "temp%d_rated_min", + [hwmon_temp_rated_max] = "temp%d_rated_max", }; static const char * const hwmon_in_attr_templates[] = { @@ -450,6 +452,8 @@ static const char * const hwmon_in_attr_templates[] = { [hwmon_in_max_alarm] = "in%d_max_alarm", [hwmon_in_lcrit_alarm] = "in%d_lcrit_alarm", [hwmon_in_crit_alarm] = "in%d_crit_alarm", + [hwmon_in_rated_min] = "in%d_rated_min", + [hwmon_in_rated_max] = "in%d_rated_max", }; static const char * const hwmon_curr_attr_templates[] = { @@ -469,6 +473,8 @@ static const char * const hwmon_curr_attr_templates[] = { [hwmon_curr_max_alarm] = "curr%d_max_alarm", [hwmon_curr_lcrit_alarm] = "curr%d_lcrit_alarm", [hwmon_curr_crit_alarm] = "curr%d_crit_alarm", + [hwmon_curr_rated_min] = "curr%d_rated_min", + [hwmon_curr_rated_max] = "curr%d_rated_max", }; static const char * const hwmon_power_attr_templates[] = { @@ -501,6 +507,8 @@ static const char * const hwmon_power_attr_templates[] = { [hwmon_power_max_alarm] = "power%d_max_alarm", [hwmon_power_lcrit_alarm] = "power%d_lcrit_alarm", [hwmon_power_crit_alarm] = "power%d_crit_alarm", + [hwmon_power_rated_min] = "power%d_rated_min", + [hwmon_power_rated_max] = "power%d_rated_max", }; static const char * const hwmon_energy_attr_templates[] = { @@ -519,6 +527,8 @@ static const char * const hwmon_humidity_attr_templates[] = { [hwmon_humidity_max_hyst] = "humidity%d_max_hyst", [hwmon_humidity_alarm] = "humidity%d_alarm", [hwmon_humidity_fault] = "humidity%d_fault", + [hwmon_humidity_rated_min] = "humidity%d_rated_min", + [hwmon_humidity_rated_max] = "humidity%d_rated_max", }; static const char * const hwmon_fan_attr_templates[] = { diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c index 08ee3a64a026..f4c7b5f76359 100644 --- a/drivers/hwmon/ina209.c +++ b/drivers/hwmon/ina209.c @@ -531,8 +531,7 @@ static int ina209_init_client(struct i2c_client *client, return 0; } -static int ina209_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ina209_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct ina209_data *data; @@ -597,7 +596,7 @@ static struct i2c_driver ina209_driver = { .name = "ina209", .of_match_table = of_match_ptr(ina209_of_match), }, - .probe = ina209_probe, + .probe_new = ina209_probe, .remove = ina209_remove, .id_table = ina209_id, }; diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 0fc6d5857993..ca97f9e931bc 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -614,8 +614,9 @@ static const struct attribute_group ina226_group = { .attrs = ina226_attrs, }; -static int ina2xx_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id ina2xx_id[]; + +static int ina2xx_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ina2xx_data *data; @@ -627,7 +628,7 @@ static int ina2xx_probe(struct i2c_client *client, if (client->dev.of_node) chip = (enum ina2xx_ids)of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = i2c_match_id(ina2xx_id, client)->driver_data; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -717,7 +718,7 @@ static struct i2c_driver ina2xx_driver = { .name = "ina2xx", .of_match_table = of_match_ptr(ina2xx_of_match), }, - .probe = ina2xx_probe, + .probe_new = ina2xx_probe, .id_table = ina2xx_id, }; diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 81e155692aba..41fb17e0d641 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -822,8 +822,7 @@ static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) return 0; } -static int ina3221_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ina3221_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ina3221_data *ina; @@ -1016,7 +1015,7 @@ static const struct i2c_device_id ina3221_ids[] = { MODULE_DEVICE_TABLE(i2c, ina3221_ids); static struct i2c_driver ina3221_i2c_driver = { - .probe = ina3221_probe, + .probe_new = ina3221_probe, .remove = ina3221_remove, .driver = { .name = INA3221_DRIVER_NAME, diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c new file mode 100644 index 000000000000..17d5e6b91c8a --- /dev/null +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel MAX 10 BMC HWMON Driver + * + * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. + * + */ +#include <linux/device.h> +#include <linux/hwmon.h> +#include <linux/mfd/intel-m10-bmc.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> + +struct m10bmc_sdata { + unsigned int reg_input; + unsigned int reg_max; + unsigned int reg_crit; + unsigned int reg_hyst; + unsigned int reg_min; + unsigned int multiplier; + const char *label; +}; + +struct m10bmc_hwmon_board_data { + const struct m10bmc_sdata *tables[hwmon_max]; + const struct hwmon_channel_info **hinfo; +}; + +struct m10bmc_hwmon { + struct device *dev; + struct hwmon_chip_info chip; + char *hw_name; + struct intel_m10bmc *m10bmc; + const struct m10bmc_hwmon_board_data *bdata; +}; + +static const struct m10bmc_sdata n3000bmc_temp_tbl[] = { + { 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Temperature" }, + { 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Die Temperature" }, + { 0x11c, 0x124, 0x120, 0x0, 0x0, 500, "QSFP0 Temperature" }, + { 0x12c, 0x134, 0x130, 0x0, 0x0, 500, "QSFP1 Temperature" }, + { 0x168, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A Temperature" }, + { 0x16c, 0x0, 0x0, 0x0, 0x0, 500, "Retimer A SerDes Temperature" }, + { 0x170, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B Temperature" }, + { 0x174, 0x0, 0x0, 0x0, 0x0, 500, "Retimer B SerDes Temperature" }, +}; + +static const struct m10bmc_sdata n3000bmc_in_tbl[] = { + { 0x128, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" }, + { 0x138, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" }, + { 0x13c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" }, + { 0x144, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Voltage" }, + { 0x14c, 0x0, 0x0, 0x0, 0x0, 1, "1.2V Voltage" }, + { 0x150, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Voltage" }, + { 0x158, 0x0, 0x0, 0x0, 0x0, 1, "1.8V Voltage" }, + { 0x15c, 0x0, 0x0, 0x0, 0x0, 1, "3.3V Voltage" }, +}; + +static const struct m10bmc_sdata n3000bmc_curr_tbl[] = { + { 0x140, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" }, + { 0x148, 0x0, 0x0, 0x0, 0x0, 1, "12V Backplane Current" }, + { 0x154, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Current" }, +}; + +static const struct m10bmc_sdata n3000bmc_power_tbl[] = { + { 0x160, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" }, +}; + +static const struct hwmon_channel_info *n3000bmc_hinfo[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + 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(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL), + HWMON_CHANNEL_INFO(power, + HWMON_P_INPUT | HWMON_P_LABEL), + NULL +}; + +static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = { + .tables = { + [hwmon_temp] = n3000bmc_temp_tbl, + [hwmon_in] = n3000bmc_in_tbl, + [hwmon_curr] = n3000bmc_curr_tbl, + [hwmon_power] = n3000bmc_power_tbl, + }, + + .hinfo = n3000bmc_hinfo, +}; + +static umode_t +m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + return 0444; +} + +static const struct m10bmc_sdata * +find_sensor_data(struct m10bmc_hwmon *hw, enum hwmon_sensor_types type, + int channel) +{ + const struct m10bmc_sdata *tbl; + + tbl = hw->bdata->tables[type]; + if (!tbl) + return ERR_PTR(-EOPNOTSUPP); + + return &tbl[channel]; +} + +static int do_sensor_read(struct m10bmc_hwmon *hw, + const struct m10bmc_sdata *data, + unsigned int regoff, long *val) +{ + unsigned int regval; + int ret; + + ret = m10bmc_sys_read(hw->m10bmc, regoff, ®val); + if (ret) + return ret; + + /* + * BMC Firmware will return 0xdeadbeef if the sensor value is invalid + * at that time. This usually happens on sensor channels which connect + * to external pluggable modules, e.g. QSFP temperature and voltage. + * When the QSFP is unplugged from cage, driver will get 0xdeadbeef + * from their registers. + */ + if (regval == 0xdeadbeef) + return -ENODATA; + + *val = regval * data->multiplier; + + return 0; +} + +static int m10bmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct m10bmc_hwmon *hw = dev_get_drvdata(dev); + unsigned int reg = 0, reg_hyst = 0; + const struct m10bmc_sdata *data; + long hyst, value; + int ret; + + data = find_sensor_data(hw, type, channel); + if (IS_ERR(data)) + return PTR_ERR(data); + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + reg = data->reg_input; + break; + case hwmon_temp_max_hyst: + reg_hyst = data->reg_hyst; + fallthrough; + case hwmon_temp_max: + reg = data->reg_max; + break; + case hwmon_temp_crit_hyst: + reg_hyst = data->reg_hyst; + fallthrough; + case hwmon_temp_crit: + reg = data->reg_crit; + break; + default: + return -EOPNOTSUPP; + } + break; + case hwmon_in: + switch (attr) { + case hwmon_in_input: + reg = data->reg_input; + break; + case hwmon_in_max: + reg = data->reg_max; + break; + case hwmon_in_crit: + reg = data->reg_crit; + break; + case hwmon_in_min: + reg = data->reg_min; + break; + default: + return -EOPNOTSUPP; + } + break; + case hwmon_curr: + switch (attr) { + case hwmon_curr_input: + reg = data->reg_input; + break; + case hwmon_curr_max: + reg = data->reg_max; + break; + case hwmon_curr_crit: + reg = data->reg_crit; + break; + default: + return -EOPNOTSUPP; + } + break; + case hwmon_power: + switch (attr) { + case hwmon_power_input: + reg = data->reg_input; + break; + default: + return -EOPNOTSUPP; + } + break; + default: + return -EOPNOTSUPP; + } + + if (!reg) + return -EOPNOTSUPP; + + ret = do_sensor_read(hw, data, reg, &value); + if (ret) + return ret; + + if (reg_hyst) { + ret = do_sensor_read(hw, data, reg_hyst, &hyst); + if (ret) + return ret; + + value -= hyst; + } + + *val = value; + + return 0; +} + +static int m10bmc_hwmon_read_string(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + struct m10bmc_hwmon *hw = dev_get_drvdata(dev); + const struct m10bmc_sdata *data; + + data = find_sensor_data(hw, type, channel); + if (IS_ERR(data)) + return PTR_ERR(data); + + *str = data->label; + + return 0; +} + +static const struct hwmon_ops m10bmc_hwmon_ops = { + .is_visible = m10bmc_hwmon_is_visible, + .read = m10bmc_hwmon_read, + .read_string = m10bmc_hwmon_read_string, +}; + +static int m10bmc_hwmon_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + struct intel_m10bmc *m10bmc = dev_get_drvdata(pdev->dev.parent); + struct device *hwmon_dev, *dev = &pdev->dev; + struct m10bmc_hwmon *hw; + int i; + + hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return -ENOMEM; + + hw->dev = dev; + hw->m10bmc = m10bmc; + hw->bdata = (const struct m10bmc_hwmon_board_data *)id->driver_data; + + hw->chip.info = hw->bdata->hinfo; + hw->chip.ops = &m10bmc_hwmon_ops; + + hw->hw_name = devm_kstrdup(dev, id->name, GFP_KERNEL); + if (!hw->hw_name) + return -ENOMEM; + + for (i = 0; hw->hw_name[i]; i++) + if (hwmon_is_bad_char(hw->hw_name[i])) + hw->hw_name[i] = '_'; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, hw->hw_name, + hw, &hw->chip, NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct platform_device_id intel_m10bmc_hwmon_ids[] = { + { + .name = "n3000bmc-hwmon", + .driver_data = (unsigned long)&n3000bmc_hwmon_bdata, + }, + { } +}; + +static struct platform_driver intel_m10bmc_hwmon_driver = { + .probe = m10bmc_hwmon_probe, + .driver = { + .name = "intel-m10-bmc-hwmon", + }, + .id_table = intel_m10bmc_hwmon_ids, +}; +module_platform_driver(intel_m10bmc_hwmon_driver); + +MODULE_DEVICE_TABLE(platform, intel_m10bmc_hwmon_ids); +MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("Intel MAX 10 BMC hardware monitor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index e3f1ebee7130..4a03d010ec5a 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -458,7 +458,7 @@ static const struct hwmon_chip_info jc42_chip_info = { .info = jc42_info, }; -static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int jc42_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -581,7 +581,7 @@ static struct i2c_driver jc42_driver = { .pm = JC42_DEV_PM_OPS, .of_match_table = of_match_ptr(jc42_of_ids), }, - .probe = jc42_probe, + .probe_new = jc42_probe, .remove = jc42_remove, .id_table = jc42_id, .detect = jc42_detect, diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 8f12995ec133..a250481b5a97 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -21,7 +21,6 @@ */ #include <linux/bitops.h> -#include <linux/debugfs.h> #include <linux/err.h> #include <linux/hwmon.h> #include <linux/init.h> @@ -73,22 +72,35 @@ static DEFINE_MUTEX(nb_smu_ind_mutex); #define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET 0xd8200c64 #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4 -/* F17h M01h Access througn SMN */ -#define F17H_M01H_REPORTED_TEMP_CTRL_OFFSET 0x00059800 +/* Common for Zen CPU families (Family 17h and 18h) */ +#define ZEN_REPORTED_TEMP_CTRL_OFFSET 0x00059800 -#define F17H_M70H_CCD_TEMP(x) (0x00059954 + ((x) * 4)) -#define F17H_M70H_CCD_TEMP_VALID BIT(11) -#define F17H_M70H_CCD_TEMP_MASK GENMASK(10, 0) +#define ZEN_CCD_TEMP(x) (0x00059954 + ((x) * 4)) +#define ZEN_CCD_TEMP_VALID BIT(11) +#define ZEN_CCD_TEMP_MASK GENMASK(10, 0) -#define F17H_M01H_SVI 0x0005A000 -#define F17H_M01H_SVI_TEL_PLANE0 (F17H_M01H_SVI + 0xc) -#define F17H_M01H_SVI_TEL_PLANE1 (F17H_M01H_SVI + 0x10) +#define ZEN_CUR_TEMP_SHIFT 21 +#define ZEN_CUR_TEMP_RANGE_SEL_MASK BIT(19) -#define CUR_TEMP_SHIFT 21 -#define CUR_TEMP_RANGE_SEL_MASK BIT(19) +#define ZEN_SVI_BASE 0x0005A000 -#define CFACTOR_ICORE 1000000 /* 1A / LSB */ -#define CFACTOR_ISOC 250000 /* 0.25A / LSB */ +/* F17h thermal registers through SMN */ +#define F17H_M01H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0xc) +#define F17H_M01H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) +#define F17H_M31H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) +#define F17H_M31H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) + +#define F17H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ +#define F17H_M01H_CFACTOR_ISOC 250000 /* 0.25A / LSB */ +#define F17H_M31H_CFACTOR_ICORE 1000000 /* 1A / LSB */ +#define F17H_M31H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ + +/* F19h thermal registers through SMN */ +#define F19H_M01_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) +#define F19H_M01_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) + +#define F19H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ +#define F19H_M01H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ struct k10temp_data { struct pci_dev *pdev; @@ -168,10 +180,10 @@ static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval) F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval); } -static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval) +static void read_tempreg_nb_zen(struct pci_dev *pdev, u32 *regval) { amd_smn_read(amd_pci_dev_to_node_id(pdev), - F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval); + ZEN_REPORTED_TEMP_CTRL_OFFSET, regval); } static long get_raw_temp(struct k10temp_data *data) @@ -180,7 +192,7 @@ static long get_raw_temp(struct k10temp_data *data) long temp; data->read_tempreg(data->pdev, ®val); - temp = (regval >> CUR_TEMP_SHIFT) * 125; + temp = (regval >> ZEN_CUR_TEMP_SHIFT) * 125; if (regval & data->temp_adjust_mask) temp -= 49000; return temp; @@ -288,8 +300,8 @@ static int k10temp_read_temp(struct device *dev, u32 attr, int channel, break; case 2 ... 9: /* Tccd{1-8} */ amd_smn_read(amd_pci_dev_to_node_id(data->pdev), - F17H_M70H_CCD_TEMP(channel - 2), ®val); - *val = (regval & F17H_M70H_CCD_TEMP_MASK) * 125 - 49000; + ZEN_CCD_TEMP(channel - 2), ®val); + *val = (regval & ZEN_CCD_TEMP_MASK) * 125 - 49000; break; default: return -EOPNOTSUPP; @@ -416,76 +428,6 @@ static bool has_erratum_319(struct pci_dev *pdev) (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2); } -#ifdef CONFIG_DEBUG_FS - -static void k10temp_smn_regs_show(struct seq_file *s, struct pci_dev *pdev, - u32 addr, int count) -{ - u32 reg; - int i; - - for (i = 0; i < count; i++) { - if (!(i & 3)) - seq_printf(s, "0x%06x: ", addr + i * 4); - amd_smn_read(amd_pci_dev_to_node_id(pdev), addr + i * 4, ®); - seq_printf(s, "%08x ", reg); - if ((i & 3) == 3) - seq_puts(s, "\n"); - } -} - -static int svi_show(struct seq_file *s, void *unused) -{ - struct k10temp_data *data = s->private; - - k10temp_smn_regs_show(s, data->pdev, F17H_M01H_SVI, 32); - return 0; -} -DEFINE_SHOW_ATTRIBUTE(svi); - -static int thm_show(struct seq_file *s, void *unused) -{ - struct k10temp_data *data = s->private; - - k10temp_smn_regs_show(s, data->pdev, - F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, 256); - return 0; -} -DEFINE_SHOW_ATTRIBUTE(thm); - -static void k10temp_debugfs_cleanup(void *ddir) -{ - debugfs_remove_recursive(ddir); -} - -static void k10temp_init_debugfs(struct k10temp_data *data) -{ - struct dentry *debugfs; - char name[32]; - - /* Only show debugfs data for Family 17h/18h CPUs */ - if (!data->is_zen) - return; - - scnprintf(name, sizeof(name), "k10temp-%s", pci_name(data->pdev)); - - debugfs = debugfs_create_dir(name, NULL); - if (debugfs) { - debugfs_create_file("svi", 0444, debugfs, data, &svi_fops); - debugfs_create_file("thm", 0444, debugfs, data, &thm_fops); - devm_add_action_or_reset(&data->pdev->dev, - k10temp_debugfs_cleanup, debugfs); - } -} - -#else - -static void k10temp_init_debugfs(struct k10temp_data *data) -{ -} - -#endif - static const struct hwmon_channel_info *k10temp_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | @@ -528,8 +470,8 @@ static void k10temp_get_ccd_support(struct pci_dev *pdev, for (i = 0; i < limit; i++) { amd_smn_read(amd_pci_dev_to_node_id(pdev), - F17H_M70H_CCD_TEMP(i), ®val); - if (regval & F17H_M70H_CCD_TEMP_VALID) + ZEN_CCD_TEMP(i), ®val); + if (regval & ZEN_CCD_TEMP_VALID) data->show_temp |= BIT(TCCD_BIT(i)); } } @@ -565,8 +507,8 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) data->read_htcreg = read_htcreg_nb_f15; data->read_tempreg = read_tempreg_nb_f15; } else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) { - data->temp_adjust_mask = CUR_TEMP_RANGE_SEL_MASK; - data->read_tempreg = read_tempreg_nb_f17; + data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; + data->read_tempreg = read_tempreg_nb_zen; data->show_temp |= BIT(TDIE_BIT); /* show Tdie */ data->is_zen = true; @@ -578,17 +520,33 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) data->show_current = !is_threadripper() && !is_epyc(); data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE0; data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE1; - data->cfactor[0] = CFACTOR_ICORE; - data->cfactor[1] = CFACTOR_ISOC; + data->cfactor[0] = F17H_M01H_CFACTOR_ICORE; + data->cfactor[1] = F17H_M01H_CFACTOR_ISOC; k10temp_get_ccd_support(pdev, data, 4); break; case 0x31: /* Zen2 Threadripper */ case 0x71: /* Zen2 */ data->show_current = !is_threadripper() && !is_epyc(); - data->cfactor[0] = CFACTOR_ICORE; - data->cfactor[1] = CFACTOR_ISOC; - data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE1; - data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE0; + data->cfactor[0] = F17H_M31H_CFACTOR_ICORE; + data->cfactor[1] = F17H_M31H_CFACTOR_ISOC; + data->svi_addr[0] = F17H_M31H_SVI_TEL_PLANE0; + data->svi_addr[1] = F17H_M31H_SVI_TEL_PLANE1; + k10temp_get_ccd_support(pdev, data, 8); + break; + } + } else if (boot_cpu_data.x86 == 0x19) { + data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; + data->read_tempreg = read_tempreg_nb_zen; + data->show_temp |= BIT(TDIE_BIT); + data->is_zen = true; + + switch (boot_cpu_data.x86_model) { + case 0x0 ... 0x1: /* Zen3 */ + data->show_current = true; + data->svi_addr[0] = F19H_M01_SVI_TEL_PLANE0; + data->svi_addr[1] = F19H_M01_SVI_TEL_PLANE1; + data->cfactor[0] = F19H_M01H_CFACTOR_ICORE; + data->cfactor[1] = F19H_M01H_CFACTOR_ISOC; k10temp_get_ccd_support(pdev, data, 8); break; } @@ -610,12 +568,7 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) hwmon_dev = devm_hwmon_device_register_with_info(dev, "k10temp", data, &k10temp_chip_info, NULL); - if (IS_ERR(hwmon_dev)) - return PTR_ERR(hwmon_dev); - - k10temp_init_debugfs(data); - - return 0; + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct pci_device_id k10temp_id_table[] = { @@ -634,6 +587,7 @@ static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) }, { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, {} }; diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c index ce5b0598524c..c83eb2fd80eb 100644 --- a/drivers/hwmon/lineage-pem.c +++ b/drivers/hwmon/lineage-pem.c @@ -417,8 +417,7 @@ static const struct attribute_group pem_fan_group = { .attrs = pem_fan_attributes, }; -static int pem_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pem_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -512,7 +511,7 @@ static struct i2c_driver pem_driver = { .driver = { .name = "lineage_pem", }, - .probe = pem_probe, + .probe_new = pem_probe, .id_table = pem_id, }; diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 60a817f58db9..50f67265c71d 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -1087,8 +1087,9 @@ static void lm63_init_client(struct lm63_data *data) (data->config_fan & 0x20) ? "manual" : "auto"); } -static int lm63_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id lm63_id[]; + +static int lm63_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1106,7 +1107,7 @@ static int lm63_probe(struct i2c_client *client, if (client->dev.of_node) data->kind = (enum chips)of_device_get_match_data(&client->dev); else - data->kind = id->driver_data; + data->kind = i2c_match_id(lm63_id, client)->driver_data; if (data->kind == lm64) data->temp2_offset = 16000; @@ -1163,7 +1164,7 @@ static struct i2c_driver lm63_driver = { .name = "lm63", .of_match_table = of_match_ptr(lm63_of_match), }, - .probe = lm63_probe, + .probe_new = lm63_probe, .id_table = lm63_id, .detect = lm63_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 733c48bf6c98..beb0d61bcd82 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -190,7 +190,7 @@ ATTRIBUTE_GROUPS(lm73); /* device probe and removal */ static int -lm73_probe(struct i2c_client *client, const struct i2c_device_id *id) +lm73_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -277,7 +277,7 @@ static struct i2c_driver lm73_driver = { .name = "lm73", .of_match_table = lm73_of_match, }, - .probe = lm73_probe, + .probe_new = lm73_probe, .id_table = lm73_ids, .detect = lm73_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index ba0be48aeadd..e447febd121a 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -17,6 +17,7 @@ #include <linux/of.h> #include <linux/regmap.h> #include <linux/util_macros.h> +#include <linux/regulator/consumer.h> #include "lm75.h" /* @@ -101,6 +102,7 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, struct lm75_data { struct i2c_client *client; struct regmap *regmap; + struct regulator *vs; u8 orig_conf; u8 current_conf; u8 resolution; /* In bits, 9 to 16 */ @@ -534,6 +536,13 @@ static const struct regmap_config lm75_regmap_config = { .use_single_write = true, }; +static void lm75_disable_regulator(void *data) +{ + struct lm75_data *lm75 = data; + + regulator_disable(lm75->vs); +} + static void lm75_remove(void *data) { struct lm75_data *lm75 = data; @@ -542,8 +551,9 @@ static void lm75_remove(void *data) i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf); } -static int -lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) +static const struct i2c_device_id lm75_ids[]; + +static int lm75_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -554,7 +564,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client->dev.of_node) kind = (enum lm75_type)of_device_get_match_data(&client->dev); else - kind = id->driver_data; + kind = i2c_match_id(lm75_ids, client)->driver_data; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) @@ -567,6 +577,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) data->client = client; data->kind = kind; + data->vs = devm_regulator_get(dev, "vs"); + if (IS_ERR(data->vs)) + return PTR_ERR(data->vs); + data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); @@ -581,6 +595,17 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) data->sample_time = data->params->default_sample_time; data->resolution = data->params->default_resolution; + /* Enable the power */ + err = regulator_enable(data->vs); + if (err) { + dev_err(dev, "failed to enable regulator: %d\n", err); + return err; + } + + err = devm_add_action_or_reset(dev, lm75_disable_regulator, data); + if (err) + return err; + /* Cache original configuration */ status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); if (status < 0) { @@ -893,7 +918,7 @@ static struct i2c_driver lm75_driver = { .of_match_table = of_match_ptr(lm75_of_match), .pm = LM75_DEV_PM_OPS, }, - .probe = lm75_probe, + .probe_new = lm75_probe, .id_table = lm75_ids, .detect = lm75_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 671a962fde29..7570c9d50ddc 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -315,7 +315,7 @@ static void lm77_init_client(struct i2c_client *client) lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); } -static int lm77_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int lm77_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -348,7 +348,7 @@ static struct i2c_driver lm77_driver = { .driver = { .name = "lm77", }, - .probe = lm77_probe, + .probe_new = lm77_probe, .id_table = lm77_id, .detect = lm77_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 2119461ec43a..1aa35ca0c6fe 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -627,8 +627,9 @@ static int lm78_i2c_detect(struct i2c_client *client, return -ENODEV; } -static int lm78_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id lm78_i2c_id[]; + +static int lm78_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -639,7 +640,7 @@ static int lm78_i2c_probe(struct i2c_client *client, return -ENOMEM; data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(lm78_i2c_id, client)->driver_data; /* Initialize the LM78 chip */ lm78_init_device(data); @@ -661,7 +662,7 @@ static struct i2c_driver lm78_driver = { .driver = { .name = "lm78", }, - .probe = lm78_i2c_probe, + .probe_new = lm78_i2c_probe, .id_table = lm78_i2c_id, .detect = lm78_i2c_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 80520cef7617..ac4adb44b224 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -591,8 +591,7 @@ static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } -static int lm80_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm80_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -641,7 +640,7 @@ static struct i2c_driver lm80_driver = { .driver = { .name = "lm80", }, - .probe = lm80_probe, + .probe_new = lm80_probe, .id_table = lm80_id, .detect = lm80_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 8fefca9bbbb7..2ff5ecce608e 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -317,8 +317,9 @@ static int lm83_detect(struct i2c_client *new_client, return 0; } -static int lm83_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static const struct i2c_device_id lm83_id[]; + +static int lm83_probe(struct i2c_client *new_client) { struct device *hwmon_dev; struct lm83_data *data; @@ -338,7 +339,7 @@ static int lm83_probe(struct i2c_client *new_client, * declare 1 and 3 common, and then 2 and 4 only for the LM83. */ data->groups[0] = &lm83_group; - if (id->driver_data == lm83) + if (i2c_match_id(lm83_id, new_client)->driver_data == lm83) data->groups[1] = &lm83_group_opt; hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, @@ -363,7 +364,7 @@ static struct i2c_driver lm83_driver = { .driver = { .name = "lm83", }, - .probe = lm83_probe, + .probe_new = lm83_probe, .id_table = lm83_id, .detect = lm83_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index cff0aa505a78..c7bf5de7b70f 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1544,7 +1544,9 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } -static int lm85_probe(struct i2c_client *client, const struct i2c_device_id *id) +static const struct i2c_device_id lm85_id[]; + +static int lm85_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -1559,7 +1561,7 @@ static int lm85_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client->dev.of_node) data->type = (enum chips)of_device_get_match_data(&client->dev); else - data->type = id->driver_data; + data->type = i2c_match_id(lm85_id, client)->driver_data; mutex_init(&data->update_lock); /* Fill in the chip specific driver values */ @@ -1696,7 +1698,7 @@ static struct i2c_driver lm85_driver = { .name = "lm85", .of_match_table = of_match_ptr(lm85_of_match), }, - .probe = lm85_probe, + .probe_new = lm85_probe, .id_table = lm85_id, .detect = lm85_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index c96c4d807e38..b2d820125bb6 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -912,7 +912,7 @@ static int lm87_init_client(struct i2c_client *client) return 0; } -static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int lm87_probe(struct i2c_client *client) { struct lm87_data *data; struct device *hwmon_dev; @@ -994,7 +994,7 @@ static struct i2c_driver lm87_driver = { .name = "lm87", .of_match_table = lm87_of_match, }, - .probe = lm87_probe, + .probe_new = lm87_probe, .id_table = lm87_id, .detect = lm87_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 7bdc664af55b..ebbfd5f352c0 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -1779,8 +1779,7 @@ static const struct hwmon_ops lm90_ops = { .write = lm90_write, }; -static int lm90_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm90_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct i2c_adapter *adapter = client->adapter; @@ -1816,7 +1815,7 @@ static int lm90_probe(struct i2c_client *client, if (client->dev.of_node) data->kind = (enum chips)of_device_get_match_data(&client->dev); else - data->kind = id->driver_data; + data->kind = i2c_match_id(lm90_id, client)->driver_data; if (data->kind == adm1032) { if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) client->flags &= ~I2C_CLIENT_PEC; @@ -1952,7 +1951,7 @@ static struct i2c_driver lm90_driver = { .name = "lm90", .of_match_table = of_match_ptr(lm90_of_match), }, - .probe = lm90_probe, + .probe_new = lm90_probe, .alert = lm90_alert, .id_table = lm90_id, .detect = lm90_detect, diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 84347db5edf3..9bf278cf0bd0 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -292,8 +292,7 @@ static int lm92_detect(struct i2c_client *new_client, return 0; } -static int lm92_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static int lm92_probe(struct i2c_client *new_client) { struct device *hwmon_dev; struct lm92_data *data; @@ -331,7 +330,7 @@ static struct i2c_driver lm92_driver = { .driver = { .name = "lm92", }, - .probe = lm92_probe, + .probe_new = lm92_probe, .id_table = lm92_id, .detect = lm92_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index cea8ea323271..78d6dfaf145b 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -2583,8 +2583,7 @@ static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } -static int lm93_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm93_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct lm93_data *data; @@ -2636,7 +2635,7 @@ static struct i2c_driver lm93_driver = { .driver = { .name = "lm93", }, - .probe = lm93_probe, + .probe_new = lm93_probe, .id_table = lm93_id, .detect = lm93_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c index 8a2a2a490496..ac169a994ae0 100644 --- a/drivers/hwmon/lm95234.c +++ b/drivers/hwmon/lm95234.c @@ -677,8 +677,9 @@ static int lm95234_init_client(struct i2c_client *client) return 0; } -static int lm95234_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id lm95234_id[]; + +static int lm95234_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct lm95234_data *data; @@ -698,7 +699,7 @@ static int lm95234_probe(struct i2c_client *client, return err; data->groups[0] = &lm95234_common_group; - if (id->driver_data == lm95234) + if (i2c_match_id(lm95234_id, client)->driver_data == lm95234) data->groups[1] = &lm95234_group; hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, @@ -719,7 +720,7 @@ static struct i2c_driver lm95234_driver = { .driver = { .name = DRVNAME, }, - .probe = lm95234_probe, + .probe_new = lm95234_probe, .id_table = lm95234_id, .detect = lm95234_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 8d66d6e3c0fc..00dbc170c8c6 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -432,8 +432,7 @@ static const struct hwmon_chip_info lm95241_chip_info = { .info = lm95241_info, }; -static int lm95241_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm95241_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct lm95241_data *data; @@ -469,7 +468,7 @@ static struct i2c_driver lm95241_driver = { .driver = { .name = DEVNAME, }, - .probe = lm95241_probe, + .probe_new = lm95241_probe, .id_table = lm95241_id, .detect = lm95241_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 057614e664e1..29388fcf5f74 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -547,8 +547,7 @@ static const struct hwmon_chip_info lm95245_chip_info = { .info = lm95245_info, }; -static int lm95245_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm95245_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct lm95245_data *data; @@ -598,7 +597,7 @@ static struct i2c_driver lm95245_driver = { .name = "lm95245", .of_match_table = of_match_ptr(lm95245_of_match), }, - .probe = lm95245_probe, + .probe_new = lm95245_probe, .id_table = lm95245_id, .detect = lm95245_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index 2818276ed3d6..ba9c868a8641 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -445,8 +445,7 @@ static const struct regmap_config ltc2945_regmap_config = { .max_register = LTC2945_MIN_ADIN_THRES_L, }; -static int ltc2945_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc2945_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -478,7 +477,7 @@ static struct i2c_driver ltc2945_driver = { .driver = { .name = "ltc2945", }, - .probe = ltc2945_probe, + .probe_new = ltc2945_probe, .id_table = ltc2945_id, }; diff --git a/drivers/hwmon/ltc2947-i2c.c b/drivers/hwmon/ltc2947-i2c.c index cf6074b110ae..ad0dfd3efbf8 100644 --- a/drivers/hwmon/ltc2947-i2c.c +++ b/drivers/hwmon/ltc2947-i2c.c @@ -15,8 +15,7 @@ static const struct regmap_config ltc2947_regmap_config = { .val_bits = 8, }; -static int ltc2947_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ltc2947_probe(struct i2c_client *i2c) { struct regmap *map; @@ -39,7 +38,7 @@ static struct i2c_driver ltc2947_driver = { .of_match_table = ltc2947_of_match, .pm = <c2947_pm_ops, }, - .probe = ltc2947_probe, + .probe_new = ltc2947_probe, .id_table = ltc2947_id, }; module_i2c_driver(ltc2947_driver); diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c index 53ff5051774c..78b191b26bb2 100644 --- a/drivers/hwmon/ltc2990.c +++ b/drivers/hwmon/ltc2990.c @@ -200,8 +200,7 @@ static const struct attribute_group ltc2990_group = { }; __ATTRIBUTE_GROUPS(ltc2990); -static int ltc2990_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ltc2990_i2c_probe(struct i2c_client *i2c) { int ret; struct device *hwmon_dev; @@ -269,7 +268,7 @@ static struct i2c_driver ltc2990_i2c_driver = { .driver = { .name = "ltc2990", }, - .probe = ltc2990_i2c_probe, + .probe_new = ltc2990_i2c_probe, .id_table = ltc2990_i2c_id, }; diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c index 67a529b7ba18..321f54e237bd 100644 --- a/drivers/hwmon/ltc4151.c +++ b/drivers/hwmon/ltc4151.c @@ -154,8 +154,7 @@ static struct attribute *ltc4151_attrs[] = { }; ATTRIBUTE_GROUPS(ltc4151); -static int ltc4151_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4151_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -206,7 +205,7 @@ static struct i2c_driver ltc4151_driver = { .name = "ltc4151", .of_match_table = of_match_ptr(ltc4151_match), }, - .probe = ltc4151_probe, + .probe_new = ltc4151_probe, .id_table = ltc4151_id, }; diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c index f783ac19675e..7cef3cb2962b 100644 --- a/drivers/hwmon/ltc4215.c +++ b/drivers/hwmon/ltc4215.c @@ -218,8 +218,7 @@ static struct attribute *ltc4215_attrs[] = { }; ATTRIBUTE_GROUPS(ltc4215); -static int ltc4215_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4215_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -256,7 +255,7 @@ static struct i2c_driver ltc4215_driver = { .driver = { .name = "ltc4215", }, - .probe = ltc4215_probe, + .probe_new = ltc4215_probe, .id_table = ltc4215_id, }; diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c index d15485e93fb8..3efce6d1cb88 100644 --- a/drivers/hwmon/ltc4222.c +++ b/drivers/hwmon/ltc4222.c @@ -177,8 +177,7 @@ static const struct regmap_config ltc4222_regmap_config = { .max_register = LTC4222_ADC_CONTROL, }; -static int ltc4222_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4222_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -211,7 +210,7 @@ static struct i2c_driver ltc4222_driver = { .driver = { .name = "ltc4222", }, - .probe = ltc4222_probe, + .probe_new = ltc4222_probe, .id_table = ltc4222_id, }; diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index 244a83d675cd..5088d28b3a7c 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -440,8 +440,7 @@ static bool ltc4245_use_extra_gpios(struct i2c_client *client) return false; } -static int ltc4245_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4245_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct ltc4245_data *data; @@ -480,7 +479,7 @@ static struct i2c_driver ltc4245_driver = { .driver = { .name = "ltc4245", }, - .probe = ltc4245_probe, + .probe_new = ltc4245_probe, .id_table = ltc4245_id, }; diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c index 8b8fd4a313ee..d0beb43abf3f 100644 --- a/drivers/hwmon/ltc4260.c +++ b/drivers/hwmon/ltc4260.c @@ -141,8 +141,7 @@ static const struct regmap_config ltc4260_regmap_config = { .max_register = LTC4260_ADIN, }; -static int ltc4260_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4260_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -174,7 +173,7 @@ static struct i2c_driver ltc4260_driver = { .driver = { .name = "ltc4260", }, - .probe = ltc4260_probe, + .probe_new = ltc4260_probe, .id_table = ltc4260_id, }; diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c index c415829ffbf5..1dab84b52df5 100644 --- a/drivers/hwmon/ltc4261.c +++ b/drivers/hwmon/ltc4261.c @@ -190,8 +190,7 @@ static struct attribute *ltc4261_attrs[] = { }; ATTRIBUTE_GROUPS(ltc4261); -static int ltc4261_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4261_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -234,7 +233,7 @@ static struct i2c_driver ltc4261_driver = { .driver = { .name = "ltc4261", }, - .probe = ltc4261_probe, + .probe_new = ltc4261_probe, .id_table = ltc4261_id, }; diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index 49b7e0b6d1bb..a26226e7bc37 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -493,8 +493,9 @@ static const struct attribute_group max16065_max_group = { .is_visible = max16065_secondary_is_visible, }; -static int max16065_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id max16065_id[]; + +static int max16065_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct max16065_data *data; @@ -504,6 +505,7 @@ static int max16065_probe(struct i2c_client *client, bool have_secondary; /* true if chip has secondary limits */ bool secondary_is_max = false; /* secondary limits reflect max */ int groups = 0; + const struct i2c_device_id *id = i2c_match_id(max16065_id, client); if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_READ_WORD_DATA)) @@ -598,7 +600,7 @@ static struct i2c_driver max16065_driver = { .driver = { .name = "max16065", }, - .probe = max16065_probe, + .probe_new = max16065_probe, .id_table = max16065_id, }; diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 87c6665bab3a..8bd941cae4d1 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -261,8 +261,7 @@ static void max1619_init_client(struct i2c_client *client) config & 0xBF); /* run */ } -static int max1619_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static int max1619_probe(struct i2c_client *new_client) { struct max1619_data *data; struct device *hwmon_dev; @@ -306,7 +305,7 @@ static struct i2c_driver max1619_driver = { .name = "max1619", .of_match_table = of_match_ptr(max1619_of_match), }, - .probe = max1619_probe, + .probe_new = max1619_probe, .id_table = max1619_id, .detect = max1619_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index fb6d17287365..5c41c78f0458 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -391,8 +391,9 @@ static int max1668_detect(struct i2c_client *client, return 0; } -static int max1668_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id max1668_id[]; + +static int max1668_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -407,7 +408,7 @@ static int max1668_probe(struct i2c_client *client, return -ENOMEM; data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(max1668_id, client)->driver_data; mutex_init(&data->update_lock); /* sysfs hooks */ @@ -434,7 +435,7 @@ static struct i2c_driver max1668_driver = { .driver = { .name = "max1668", }, - .probe = max1668_probe, + .probe_new = max1668_probe, .id_table = max1668_id, .detect = max1668_detect, .address_list = max1668_addr_list, diff --git a/drivers/hwmon/max31730.c b/drivers/hwmon/max31730.c index eb22a34dc36b..23598b8b8793 100644 --- a/drivers/hwmon/max31730.c +++ b/drivers/hwmon/max31730.c @@ -292,7 +292,7 @@ static void max31730_remove(void *data) } static int -max31730_probe(struct i2c_client *client, const struct i2c_device_id *id) +max31730_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -427,7 +427,7 @@ static struct i2c_driver max31730_driver = { .of_match_table = of_match_ptr(max31730_of_match), .pm = &max31730_pm_ops, }, - .probe = max31730_probe, + .probe_new = max31730_probe, .id_table = max31730_ids, .detect = max31730_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 117fb79ef294..86e6c71db685 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -448,8 +448,7 @@ static int max31790_init_client(struct i2c_client *client, return 0; } -static int max31790_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max31790_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -491,7 +490,7 @@ MODULE_DEVICE_TABLE(i2c, max31790_id); static struct i2c_driver max31790_driver = { .class = I2C_CLASS_HWMON, - .probe = max31790_probe, + .probe_new = max31790_probe, .driver = { .name = "max31790", }, diff --git a/drivers/hwmon/max6621.c b/drivers/hwmon/max6621.c index a8bb5de14230..367855d5edae 100644 --- a/drivers/hwmon/max6621.c +++ b/drivers/hwmon/max6621.c @@ -477,8 +477,7 @@ static const struct hwmon_chip_info max6621_chip_info = { .info = max6621_info, }; -static int max6621_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max6621_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct max6621_data *data; @@ -555,7 +554,7 @@ static struct i2c_driver max6621_driver = { .name = MAX6621_DRV_NAME, .of_match_table = of_match_ptr(max6621_of_match), }, - .probe = max6621_probe, + .probe_new = max6621_probe, .id_table = max6621_id, }; diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 2d56e97aa5fa..b71899c641fa 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -516,8 +516,7 @@ static int max6639_detect(struct i2c_client *client, return 0; } -static int max6639_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max6639_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct max6639_data *data; @@ -581,7 +580,7 @@ static struct i2c_driver max6639_driver = { .name = "max6639", .pm = &max6639_pm_ops, }, - .probe = max6639_probe, + .probe_new = max6639_probe, .id_table = max6639_id, .detect = max6639_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c index 5ab6fdb53b96..23d93142b0b3 100644 --- a/drivers/hwmon/max6642.c +++ b/drivers/hwmon/max6642.c @@ -264,8 +264,7 @@ static struct attribute *max6642_attrs[] = { }; ATTRIBUTE_GROUPS(max6642); -static int max6642_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max6642_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct max6642_data *data; @@ -302,7 +301,7 @@ static struct i2c_driver max6642_driver = { .driver = { .name = "max6642", }, - .probe = max6642_probe, + .probe_new = max6642_probe, .id_table = max6642_id, .detect = max6642_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 3d9d371c35b5..cc7f2980fe83 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -757,8 +757,9 @@ static const struct hwmon_chip_info max6650_chip_info = { .info = max6650_info, }; -static int max6650_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id max6650_id[]; + +static int max6650_probe(struct i2c_client *client) { struct thermal_cooling_device *cooling_dev; struct device *dev = &client->dev; @@ -775,7 +776,8 @@ static int max6650_probe(struct i2c_client *client, data->client = client; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); - data->nr_fans = of_id ? (int)(uintptr_t)of_id->data : id->driver_data; + data->nr_fans = of_id ? (int)(uintptr_t)of_id->data : + i2c_match_id(max6650_id, client)->driver_data; /* * Initialize the max6650 chip @@ -817,7 +819,7 @@ static struct i2c_driver max6650_driver = { .name = "max6650", .of_match_table = of_match_ptr(max6650_dt_match), }, - .probe = max6650_probe, + .probe_new = max6650_probe, .id_table = max6650_id, }; diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index 58781d999caa..fc3241101178 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -685,8 +685,9 @@ done: return 0; } -static int max6697_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id max6697_id[]; + +static int max6697_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -704,7 +705,7 @@ static int max6697_probe(struct i2c_client *client, if (client->dev.of_node) data->type = (enum chips)of_device_get_match_data(&client->dev); else - data->type = id->driver_data; + data->type = i2c_match_id(max6697_id, client)->driver_data; data->chip = &max6697_chip_data[data->type]; data->client = client; mutex_init(&data->update_lock); @@ -785,7 +786,7 @@ static struct i2c_driver max6697_driver = { .name = "max6697", .of_match_table = of_match_ptr(max6697_of_match), }, - .probe = max6697_probe, + .probe_new = max6697_probe, .id_table = max6697_id, }; diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index 4e8f995dc773..ce2780768074 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c @@ -100,8 +100,9 @@ static ssize_t in0_input_show(struct device *dev, static DEVICE_ATTR_RO(in0_input); -static int mcp3021_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id mcp3021_id[]; + +static int mcp3021_probe(struct i2c_client *client) { int err; struct mcp3021_data *data = NULL; @@ -132,7 +133,7 @@ static int mcp3021_probe(struct i2c_client *client, data->vdd = MCP3021_VDD_REF_DEFAULT; } - switch (id->driver_data) { + switch (i2c_match_id(mcp3021_id, client)->driver_data) { case mcp3021: data->sar_shift = MCP3021_SAR_SHIFT; data->sar_mask = MCP3021_SAR_MASK; @@ -197,7 +198,7 @@ static struct i2c_driver mcp3021_driver = { .name = "mcp3021", .of_match_table = of_match_ptr(of_mcp3021_match), }, - .probe = mcp3021_probe, + .probe_new = mcp3021_probe, .remove = mcp3021_remove, .id_table = mcp3021_id, }; diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c new file mode 100644 index 000000000000..18da5a25e89a --- /dev/null +++ b/drivers/hwmon/mr75203.c @@ -0,0 +1,656 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MaxLinear, Inc. + * + * This driver is a hardware monitoring driver for PVT controller + * (MR75203) which is used to configure & control Moortec embedded + * analog IP to enable multiple embedded temperature sensor(TS), + * voltage monitor(VM) & process detector(PD) modules. + */ +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/hwmon.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/reset.h> + +/* PVT Common register */ +#define PVT_IP_CONFIG 0x04 +#define TS_NUM_MSK GENMASK(4, 0) +#define TS_NUM_SFT 0 +#define PD_NUM_MSK GENMASK(12, 8) +#define PD_NUM_SFT 8 +#define VM_NUM_MSK GENMASK(20, 16) +#define VM_NUM_SFT 16 +#define CH_NUM_MSK GENMASK(31, 24) +#define CH_NUM_SFT 24 + +/* Macro Common Register */ +#define CLK_SYNTH 0x00 +#define CLK_SYNTH_LO_SFT 0 +#define CLK_SYNTH_HI_SFT 8 +#define CLK_SYNTH_HOLD_SFT 16 +#define CLK_SYNTH_EN BIT(24) +#define CLK_SYS_CYCLES_MAX 514 +#define CLK_SYS_CYCLES_MIN 2 +#define HZ_PER_MHZ 1000000L + +#define SDIF_DISABLE 0x04 + +#define SDIF_STAT 0x08 +#define SDIF_BUSY BIT(0) +#define SDIF_LOCK BIT(1) + +#define SDIF_W 0x0c +#define SDIF_PROG BIT(31) +#define SDIF_WRN_W BIT(27) +#define SDIF_WRN_R 0x00 +#define SDIF_ADDR_SFT 24 + +#define SDIF_HALT 0x10 +#define SDIF_CTRL 0x14 +#define SDIF_SMPL_CTRL 0x20 + +/* TS & PD Individual Macro Register */ +#define COM_REG_SIZE 0x40 + +#define SDIF_DONE(n) (COM_REG_SIZE + 0x14 + 0x40 * (n)) +#define SDIF_SMPL_DONE BIT(0) + +#define SDIF_DATA(n) (COM_REG_SIZE + 0x18 + 0x40 * (n)) +#define SAMPLE_DATA_MSK GENMASK(15, 0) + +#define HILO_RESET(n) (COM_REG_SIZE + 0x2c + 0x40 * (n)) + +/* VM Individual Macro Register */ +#define VM_COM_REG_SIZE 0x200 +#define VM_SDIF_DONE(n) (VM_COM_REG_SIZE + 0x34 + 0x200 * (n)) +#define VM_SDIF_DATA(n) (VM_COM_REG_SIZE + 0x40 + 0x200 * (n)) + +/* SDA Slave Register */ +#define IP_CTRL 0x00 +#define IP_RST_REL BIT(1) +#define IP_RUN_CONT BIT(3) +#define IP_AUTO BIT(8) +#define IP_VM_MODE BIT(10) + +#define IP_CFG 0x01 +#define CFG0_MODE_2 BIT(0) +#define CFG0_PARALLEL_OUT 0 +#define CFG0_12_BIT 0 +#define CFG1_VOL_MEAS_MODE 0 +#define CFG1_PARALLEL_OUT 0 +#define CFG1_14_BIT 0 + +#define IP_DATA 0x03 + +#define IP_POLL 0x04 +#define VM_CH_INIT BIT(20) +#define VM_CH_REQ BIT(21) + +#define IP_TMR 0x05 +#define POWER_DELAY_CYCLE_256 0x80 +#define POWER_DELAY_CYCLE_64 0x40 + +#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 + +struct pvt_device { + struct regmap *c_map; + struct regmap *t_map; + struct regmap *p_map; + struct regmap *v_map; + struct clk *clk; + struct reset_control *rst; + u32 t_num; + u32 p_num; + u32 v_num; + u32 ip_freq; + u8 *vm_idx; +}; + +static umode_t pvt_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_temp: + if (attr == hwmon_temp_input) + return 0444; + break; + case hwmon_in: + if (attr == hwmon_in_input) + return 0444; + break; + default: + break; + } + return 0; +} + +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: + ret = regmap_read_poll_timeout(t_map, SDIF_DONE(channel), + stat, stat & SDIF_SMPL_DONE, + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + ret = regmap_read(t_map, SDIF_DATA(channel), &nbs); + if(ret < 0) + return ret; + + nbs &= SAMPLE_DATA_MSK; + + /* + * 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; + + return 0; + default: + return -EOPNOTSUPP; + } +} + +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; + u8 vm_idx; + int ret; + + if (channel >= pvt->v_num) + return -EINVAL; + + vm_idx = pvt->vm_idx[channel]; + + switch (attr) { + case hwmon_in_input: + ret = regmap_read_poll_timeout(v_map, VM_SDIF_DONE(vm_idx), + stat, stat & SDIF_SMPL_DONE, + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + ret = regmap_read(v_map, VM_SDIF_DATA(vm_idx), &n); + if(ret < 0) + return ret; + + n &= SAMPLE_DATA_MSK; + /* Convert the N bitstream count into voltage */ + *val = (PVT_N_CONST * n - PVT_R_CONST) >> PVT_CONV_BITS; + + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int pvt_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_temp: + return pvt_read_temp(dev, attr, channel, val); + case hwmon_in: + return pvt_read_in(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static const u32 pvt_chip_config[] = { + HWMON_C_REGISTER_TZ, + 0 +}; + +static const struct hwmon_channel_info pvt_chip = { + .type = hwmon_chip, + .config = pvt_chip_config, +}; + +static struct hwmon_channel_info pvt_temp = { + .type = hwmon_temp, +}; + +static struct hwmon_channel_info pvt_in = { + .type = hwmon_in, +}; + +static const struct hwmon_ops pvt_hwmon_ops = { + .is_visible = pvt_is_visible, + .read = pvt_read, +}; + +static struct hwmon_chip_info pvt_chip_info = { + .ops = &pvt_hwmon_ops, +}; + +static int pvt_init(struct pvt_device *pvt) +{ + u16 sys_freq, key, middle, low = 4, high = 8; + struct regmap *t_map = pvt->t_map; + struct regmap *p_map = pvt->p_map; + struct regmap *v_map = pvt->v_map; + u32 t_num = pvt->t_num; + u32 p_num = pvt->p_num; + u32 v_num = pvt->v_num; + u32 clk_synth, val; + int ret; + + sys_freq = clk_get_rate(pvt->clk) / HZ_PER_MHZ; + while (high >= low) { + middle = (low + high + 1) / 2; + key = DIV_ROUND_CLOSEST(sys_freq, middle); + if (key > CLK_SYS_CYCLES_MAX) { + low = middle + 1; + continue; + } else if (key < CLK_SYS_CYCLES_MIN) { + high = middle - 1; + continue; + } else { + break; + } + } + + /* + * The system supports 'clk_sys' to 'clk_ip' frequency ratios + * from 2:1 to 512:1 + */ + key = clamp_val(key, CLK_SYS_CYCLES_MIN, CLK_SYS_CYCLES_MAX) - 2; + + clk_synth = ((key + 1) >> 1) << CLK_SYNTH_LO_SFT | + (key >> 1) << CLK_SYNTH_HI_SFT | + (key >> 1) << CLK_SYNTH_HOLD_SFT | CLK_SYNTH_EN; + + pvt->ip_freq = sys_freq * 100 / (key + 2); + + if (t_num) { + ret = regmap_write(t_map, SDIF_SMPL_CTRL, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(t_map, SDIF_HALT, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(t_map, CLK_SYNTH, clk_synth); + if(ret < 0) + return ret; + + ret = regmap_write(t_map, SDIF_DISABLE, 0x0); + if(ret < 0) + return ret; + + ret = regmap_read_poll_timeout(t_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + 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) + return ret; + + ret = regmap_read_poll_timeout(t_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + 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) + return ret; + + ret = regmap_read_poll_timeout(t_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + val = IP_RST_REL | IP_RUN_CONT | IP_AUTO | + IP_CTRL << SDIF_ADDR_SFT | + SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(t_map, SDIF_W, val); + if(ret < 0) + return ret; + } + + if (p_num) { + ret = regmap_write(p_map, SDIF_HALT, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(p_map, SDIF_DISABLE, BIT(p_num) - 1); + if(ret < 0) + return ret; + + ret = regmap_write(p_map, CLK_SYNTH, clk_synth); + if(ret < 0) + return ret; + } + + if (v_num) { + ret = regmap_write(v_map, SDIF_SMPL_CTRL, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(v_map, SDIF_HALT, 0x0); + if(ret < 0) + return ret; + + ret = regmap_write(v_map, CLK_SYNTH, clk_synth); + if(ret < 0) + return ret; + + ret = regmap_write(v_map, SDIF_DISABLE, 0x0); + if(ret < 0) + return ret; + + ret = regmap_read_poll_timeout(v_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + val = CFG1_VOL_MEAS_MODE | CFG1_PARALLEL_OUT | + CFG1_14_BIT | IP_CFG << SDIF_ADDR_SFT | + SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(v_map, SDIF_W, val); + if(ret < 0) + return ret; + + ret = regmap_read_poll_timeout(v_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + 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) + return ret; + + ret = regmap_read_poll_timeout(v_map, SDIF_STAT, + val, !(val & SDIF_BUSY), + PVT_POLL_DELAY_US, + PVT_POLL_TIMEOUT_US); + if (ret) + return ret; + + val = IP_RST_REL | IP_RUN_CONT | IP_AUTO | IP_VM_MODE | + IP_CTRL << SDIF_ADDR_SFT | + SDIF_WRN_W | SDIF_PROG; + ret = regmap_write(v_map, SDIF_W, val); + if(ret < 0) + return ret; + } + + return 0; +} + +static struct regmap_config pvt_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static int pvt_get_regmap(struct platform_device *pdev, char *reg_name, + struct pvt_device *pvt) +{ + struct device *dev = &pdev->dev; + struct regmap **reg_map; + void __iomem *io_base; + + if (!strcmp(reg_name, "common")) + reg_map = &pvt->c_map; + else if (!strcmp(reg_name, "ts")) + reg_map = &pvt->t_map; + else if (!strcmp(reg_name, "pd")) + reg_map = &pvt->p_map; + else if (!strcmp(reg_name, "vm")) + reg_map = &pvt->v_map; + else + return -EINVAL; + + io_base = devm_platform_ioremap_resource_byname(pdev, reg_name); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + pvt_regmap_config.name = reg_name; + *reg_map = devm_regmap_init_mmio(dev, io_base, &pvt_regmap_config); + if (IS_ERR(*reg_map)) { + dev_err(dev, "failed to init register map\n"); + return PTR_ERR(*reg_map); + } + + return 0; +} + +static void pvt_clk_disable(void *data) +{ + struct pvt_device *pvt = data; + + clk_disable_unprepare(pvt->clk); +} + +static int pvt_clk_enable(struct device *dev, struct pvt_device *pvt) +{ + int ret; + + ret = clk_prepare_enable(pvt->clk); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, pvt_clk_disable, pvt); +} + +static void pvt_reset_control_assert(void *data) +{ + struct pvt_device *pvt = data; + + reset_control_assert(pvt->rst); +} + +static int pvt_reset_control_deassert(struct device *dev, struct pvt_device *pvt) +{ + int ret; + + ret = reset_control_deassert(pvt->rst); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, pvt_reset_control_assert, pvt); +} + +static int mr75203_probe(struct platform_device *pdev) +{ + const struct hwmon_channel_info **pvt_info; + u32 ts_num, vm_num, pd_num, val, index, i; + struct device *dev = &pdev->dev; + u32 *temp_config, *in_config; + struct device *hwmon_dev; + struct pvt_device *pvt; + int ret; + + pvt = devm_kzalloc(dev, sizeof(*pvt), GFP_KERNEL); + if (!pvt) + return -ENOMEM; + + ret = pvt_get_regmap(pdev, "common", pvt); + if (ret) + return ret; + + pvt->clk = devm_clk_get(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); + 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"); + + ret = regmap_read(pvt->c_map, PVT_IP_CONFIG, &val); + if(ret < 0) + return ret; + + ts_num = (val & TS_NUM_MSK) >> TS_NUM_SFT; + pd_num = (val & PD_NUM_MSK) >> PD_NUM_SFT; + vm_num = (val & VM_NUM_MSK) >> VM_NUM_SFT; + pvt->t_num = ts_num; + pvt->p_num = pd_num; + pvt->v_num = vm_num; + val = 0; + if (ts_num) + val++; + if (vm_num) + val++; + if (!val) + return -ENODEV; + + pvt_info = devm_kcalloc(dev, val + 2, sizeof(*pvt_info), GFP_KERNEL); + if (!pvt_info) + return -ENOMEM; + pvt_info[0] = &pvt_chip; + index = 1; + + if (ts_num) { + ret = pvt_get_regmap(pdev, "ts", pvt); + if (ret) + return ret; + + temp_config = devm_kcalloc(dev, ts_num + 1, + sizeof(*temp_config), GFP_KERNEL); + if (!temp_config) + return -ENOMEM; + + memset32(temp_config, HWMON_T_INPUT, ts_num); + pvt_temp.config = temp_config; + pvt_info[index++] = &pvt_temp; + } + + if (pd_num) { + ret = pvt_get_regmap(pdev, "pd", pvt); + if (ret) + return ret; + } + + if (vm_num) { + u32 num = vm_num; + + 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); + if (ret) { + num = 0; + } else { + for (i = 0; i < vm_num; i++) + if (pvt->vm_idx[i] >= vm_num || + pvt->vm_idx[i] == 0xff) { + num = i; + break; + } + } + + /* + * Incase intel,vm-map property is not defined, we assume + * incremental channel numbers. + */ + for (i = num; i < vm_num; i++) + pvt->vm_idx[i] = i; + + in_config = devm_kcalloc(dev, num + 1, + sizeof(*in_config), GFP_KERNEL); + if (!in_config) + return -ENOMEM; + + memset32(in_config, HWMON_I_INPUT, num); + in_config[num] = 0; + pvt_in.config = in_config; + + pvt_info[index++] = &pvt_in; + } + + ret = pvt_init(pvt); + if (ret) { + dev_err(dev, "failed to init pvt: %d\n", ret); + return ret; + } + + pvt_chip_info.info = pvt_info; + hwmon_dev = devm_hwmon_device_register_with_info(dev, "pvt", + pvt, + &pvt_chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id moortec_pvt_of_match[] = { + { .compatible = "moortec,mr75203" }, + { } +}; +MODULE_DEVICE_TABLE(of, moortec_pvt_of_match); + +static struct platform_driver moortec_pvt_driver = { + .driver = { + .name = "moortec-pvt", + .of_match_table = moortec_pvt_of_match, + }, + .probe = mr75203_probe, +}; +module_platform_driver(moortec_pvt_driver); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 570df8eb5272..604af2f6103a 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -1056,8 +1056,7 @@ static int nct7802_init_chip(struct nct7802_data *data) return regmap_update_bits(data->regmap, REG_VMON_ENABLE, 0x03, 0x03); } -static int nct7802_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int nct7802_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct nct7802_data *data; @@ -1101,7 +1100,7 @@ static struct i2c_driver nct7802_driver = { .name = DRVNAME, }, .detect = nct7802_detect, - .probe = nct7802_probe, + .probe_new = nct7802_probe, .id_table = nct7802_idtable, .address_list = nct7802_address_list, }; diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index 242ff8bee78d..b1c837fc407a 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c @@ -1009,8 +1009,7 @@ static const struct watchdog_ops nct7904_wdt_ops = { .get_timeleft = nct7904_wdt_get_timeleft, }; -static int nct7904_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int nct7904_probe(struct i2c_client *client) { struct nct7904_data *data; struct device *hwmon_dev; @@ -1172,7 +1171,7 @@ static struct i2c_driver nct7904_driver = { .driver = { .name = "nct7904", }, - .probe = nct7904_probe, + .probe_new = nct7904_probe, .id_table = nct7904_id, .detect = nct7904_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/occ/p8_i2c.c b/drivers/hwmon/occ/p8_i2c.c index 76fb7870c7d3..0cf8588be35a 100644 --- a/drivers/hwmon/occ/p8_i2c.c +++ b/drivers/hwmon/occ/p8_i2c.c @@ -203,8 +203,7 @@ static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd) return 0; } -static int p8_i2c_occ_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int p8_i2c_occ_probe(struct i2c_client *client) { struct occ *occ; struct p8_i2c_occ *ctx = devm_kzalloc(&client->dev, sizeof(*ctx), @@ -245,7 +244,7 @@ static struct i2c_driver p8_i2c_occ_driver = { .name = "occ-hwmon", .of_match_table = p8_i2c_occ_of_match, }, - .probe = p8_i2c_occ_probe, + .probe_new = p8_i2c_occ_probe, .remove = p8_i2c_occ_remove, }; diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c index b7a3a292123d..a97a51005c61 100644 --- a/drivers/hwmon/pcf8591.c +++ b/drivers/hwmon/pcf8591.c @@ -179,8 +179,7 @@ static const struct attribute_group pcf8591_attr_group_opt = { * Real code */ -static int pcf8591_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcf8591_probe(struct i2c_client *client) { struct pcf8591_data *data; int err; @@ -295,7 +294,7 @@ static struct i2c_driver pcf8591_driver = { .driver = { .name = "pcf8591", }, - .probe = pcf8591_probe, + .probe_new = pcf8591_probe, .remove = pcf8591_remove, .id_table = pcf8591_id, }; diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index e35db489b76f..a25faf69fce3 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -26,6 +26,17 @@ config SENSORS_PMBUS This driver can also be built as a module. If so, the module will be called pmbus. +config SENSORS_ADM1266 + tristate "Analog Devices ADM1266 Sequencer" + select CRC8 + depends on GPIOLIB + help + If you say yes here you get hardware monitoring support for Analog + Devices ADM1266 Cascadable Super Sequencer. + + This driver can also be built as a module. If so, the module will + be called adm1266. + config SENSORS_ADM1275 tristate "Analog Devices ADM1275 and compatibles" help @@ -200,6 +211,15 @@ config SENSORS_MAX8688 This driver can also be built as a module. If so, the module will be called max8688. +config SENSORS_MP2975 + tristate "MPS MP2975" + help + If you say yes here you get hardware monitoring support for MPS + MP2975 Dual Loop Digital Multi-Phase Controller. + + This driver can also be built as a module. If so, the module will + be called mp2975. + config SENSORS_PXE1610 tristate "Infineon PXE1610" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index c4b15db996ad..4c97ad0bd791 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o +obj-$(CONFIG_SENSORS_ADM1266) += adm1266.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o @@ -23,6 +24,7 @@ obj-$(CONFIG_SENSORS_MAX20751) += max20751.o obj-$(CONFIG_SENSORS_MAX31785) += max31785.o obj-$(CONFIG_SENSORS_MAX34440) += max34440.o obj-$(CONFIG_SENSORS_MAX8688) += max8688.o +obj-$(CONFIG_SENSORS_MP2975) += mp2975.o obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c new file mode 100644 index 000000000000..c7b373ba92f2 --- /dev/null +++ b/drivers/hwmon/pmbus/adm1266.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ADM1266 - Cascadable Super Sequencer with Margin + * Control and Fault Recording + * + * Copyright 2020 Analog Devices Inc. + */ + +#include <linux/bitfield.h> +#include <linux/crc8.h> +#include <linux/debugfs.h> +#include <linux/gpio/driver.h> +#include <linux/i2c.h> +#include <linux/i2c-smbus.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/nvmem-consumer.h> +#include <linux/nvmem-provider.h> +#include "pmbus.h" +#include <linux/slab.h> +#include <linux/timekeeping.h> + +#define ADM1266_BLACKBOX_CONFIG 0xD3 +#define ADM1266_PDIO_CONFIG 0xD4 +#define ADM1266_READ_STATE 0xD9 +#define ADM1266_READ_BLACKBOX 0xDE +#define ADM1266_SET_RTC 0xDF +#define ADM1266_GPIO_CONFIG 0xE1 +#define ADM1266_BLACKBOX_INFO 0xE6 +#define ADM1266_PDIO_STATUS 0xE9 +#define ADM1266_GPIO_STATUS 0xEA + +/* ADM1266 GPIO defines */ +#define ADM1266_GPIO_NR 9 +#define ADM1266_GPIO_FUNCTIONS(x) FIELD_GET(BIT(0), x) +#define ADM1266_GPIO_INPUT_EN(x) FIELD_GET(BIT(2), x) +#define ADM1266_GPIO_OUTPUT_EN(x) FIELD_GET(BIT(3), x) +#define ADM1266_GPIO_OPEN_DRAIN(x) FIELD_GET(BIT(4), x) + +/* ADM1266 PDIO defines */ +#define ADM1266_PDIO_NR 16 +#define ADM1266_PDIO_PIN_CFG(x) FIELD_GET(GENMASK(15, 13), x) +#define ADM1266_PDIO_GLITCH_FILT(x) FIELD_GET(GENMASK(12, 9), x) +#define ADM1266_PDIO_OUT_CFG(x) FIELD_GET(GENMASK(2, 0), x) + +#define ADM1266_BLACKBOX_OFFSET 0 +#define ADM1266_BLACKBOX_SIZE 64 + +#define ADM1266_PMBUS_BLOCK_MAX 255 + +struct adm1266_data { + struct pmbus_driver_info info; + struct gpio_chip gc; + const char *gpio_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR]; + struct i2c_client *client; + struct dentry *debugfs_dir; + struct nvmem_config nvmem_config; + struct nvmem_device *nvmem; + u8 *dev_mem; + struct mutex buf_mutex; + u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; +}; + +static const struct nvmem_cell_info adm1266_nvmem_cells[] = { + { + .name = "blackbox", + .offset = ADM1266_BLACKBOX_OFFSET, + .bytes = 2048, + }, +}; + +DECLARE_CRC8_TABLE(pmbus_crc_table); + +/* + * Different from Block Read as it sends data and waits for the slave to + * return a value dependent on that data. The protocol is simply a Write Block + * followed by a Read Block without the Read-Block command field and the + * Write-Block STOP bit. + */ +static int adm1266_pmbus_block_xfer(struct adm1266_data *data, u8 cmd, u8 w_len, u8 *data_w, + u8 *data_r) +{ + struct i2c_client *client = data->client; + struct i2c_msg msgs[2] = { + { + .addr = client->addr, + .flags = I2C_M_DMA_SAFE, + .buf = data->write_buf, + .len = w_len + 2, + }, + { + .addr = client->addr, + .flags = I2C_M_RD | I2C_M_DMA_SAFE, + .buf = data->read_buf, + .len = ADM1266_PMBUS_BLOCK_MAX + 2, + } + }; + u8 addr; + u8 crc; + int ret; + + mutex_lock(&data->buf_mutex); + + msgs[0].buf[0] = cmd; + msgs[0].buf[1] = w_len; + memcpy(&msgs[0].buf[2], data_w, w_len); + + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret != 2) { + if (ret >= 0) + ret = -EPROTO; + + mutex_unlock(&data->buf_mutex); + + return ret; + } + + if (client->flags & I2C_CLIENT_PEC) { + addr = i2c_8bit_addr_from_msg(&msgs[0]); + crc = crc8(pmbus_crc_table, &addr, 1, 0); + crc = crc8(pmbus_crc_table, msgs[0].buf, msgs[0].len, crc); + + addr = i2c_8bit_addr_from_msg(&msgs[1]); + crc = crc8(pmbus_crc_table, &addr, 1, crc); + crc = crc8(pmbus_crc_table, msgs[1].buf, msgs[1].buf[0] + 1, crc); + + if (crc != msgs[1].buf[msgs[1].buf[0] + 1]) { + mutex_unlock(&data->buf_mutex); + return -EBADMSG; + } + } + + memcpy(data_r, &msgs[1].buf[1], msgs[1].buf[0]); + + ret = msgs[1].buf[0]; + mutex_unlock(&data->buf_mutex); + + return ret; +} + +static const unsigned int adm1266_gpio_mapping[ADM1266_GPIO_NR][2] = { + {1, 0}, + {2, 1}, + {3, 2}, + {4, 8}, + {5, 9}, + {6, 10}, + {7, 11}, + {8, 6}, + {9, 7}, +}; + +static const char *adm1266_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR] = { + "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", "GPIO6", "GPIO7", "GPIO8", + "GPIO9", "PDIO1", "PDIO2", "PDIO3", "PDIO4", "PDIO5", "PDIO6", + "PDIO7", "PDIO8", "PDIO9", "PDIO10", "PDIO11", "PDIO12", "PDIO13", + "PDIO14", "PDIO15", "PDIO16", +}; + +static int adm1266_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct adm1266_data *data = gpiochip_get_data(chip); + u8 read_buf[I2C_SMBUS_BLOCK_MAX + 1]; + unsigned long pins_status; + unsigned int pmbus_cmd; + int ret; + + if (offset < ADM1266_GPIO_NR) + pmbus_cmd = ADM1266_GPIO_STATUS; + else + pmbus_cmd = ADM1266_PDIO_STATUS; + + ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf); + if (ret < 0) + return ret; + + pins_status = read_buf[0] + (read_buf[1] << 8); + if (offset < ADM1266_GPIO_NR) + return test_bit(adm1266_gpio_mapping[offset][1], &pins_status); + + return test_bit(offset - ADM1266_GPIO_NR, &pins_status); +} + +static int adm1266_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct adm1266_data *data = gpiochip_get_data(chip); + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1]; + unsigned long status; + unsigned int gpio_nr; + int ret; + + ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf); + if (ret < 0) + return ret; + + status = read_buf[0] + (read_buf[1] << 8); + + *bits = 0; + for_each_set_bit(gpio_nr, mask, ADM1266_GPIO_NR) { + if (test_bit(adm1266_gpio_mapping[gpio_nr][1], &status)) + set_bit(gpio_nr, bits); + } + + ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, read_buf); + if (ret < 0) + return ret; + + status = read_buf[0] + (read_buf[1] << 8); + + *bits = 0; + for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_STATUS) { + if (test_bit(gpio_nr - ADM1266_GPIO_NR, &status)) + set_bit(gpio_nr, bits); + } + + return 0; +} + +static void adm1266_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct adm1266_data *data = gpiochip_get_data(chip); + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1]; + unsigned long gpio_config; + unsigned long pdio_config; + unsigned long pin_cfg; + u8 write_cmd; + int ret; + int i; + + for (i = 0; i < ADM1266_GPIO_NR; i++) { + write_cmd = adm1266_gpio_mapping[i][1]; + ret = adm1266_pmbus_block_xfer(data, ADM1266_GPIO_CONFIG, 1, &write_cmd, read_buf); + if (ret != 2) + return; + + gpio_config = read_buf[0]; + seq_puts(s, adm1266_names[i]); + + seq_puts(s, " ( "); + if (!ADM1266_GPIO_FUNCTIONS(gpio_config)) { + seq_puts(s, "high-Z )\n"); + continue; + } + if (ADM1266_GPIO_INPUT_EN(gpio_config)) + seq_puts(s, "input "); + if (ADM1266_GPIO_OUTPUT_EN(gpio_config)) + seq_puts(s, "output "); + if (ADM1266_GPIO_OPEN_DRAIN(gpio_config)) + seq_puts(s, "open-drain )\n"); + else + seq_puts(s, "push-pull )\n"); + } + + write_cmd = 0xFF; + ret = adm1266_pmbus_block_xfer(data, ADM1266_PDIO_CONFIG, 1, &write_cmd, read_buf); + if (ret != 32) + return; + + for (i = 0; i < ADM1266_PDIO_NR; i++) { + seq_puts(s, adm1266_names[ADM1266_GPIO_NR + i]); + + pdio_config = read_buf[2 * i]; + pdio_config += (read_buf[2 * i + 1] << 8); + pin_cfg = ADM1266_PDIO_PIN_CFG(pdio_config); + + seq_puts(s, " ( "); + if (!pin_cfg || pin_cfg > 5) { + seq_puts(s, "high-Z )\n"); + continue; + } + + if (pin_cfg & BIT(0)) + seq_puts(s, "output "); + + if (pin_cfg & BIT(1)) + seq_puts(s, "input "); + + seq_puts(s, ")\n"); + } +} + +static int adm1266_config_gpio(struct adm1266_data *data) +{ + const char *name = dev_name(&data->client->dev); + char *gpio_name; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(data->gpio_names); i++) { + gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%x-%s", + data->client->addr, adm1266_names[i]); + if (!gpio_name) + return -ENOMEM; + + data->gpio_names[i] = gpio_name; + } + + data->gc.label = name; + data->gc.parent = &data->client->dev; + data->gc.owner = THIS_MODULE; + data->gc.base = -1; + data->gc.names = data->gpio_names; + data->gc.ngpio = ARRAY_SIZE(data->gpio_names); + data->gc.get = adm1266_gpio_get; + data->gc.get_multiple = adm1266_gpio_get_multiple; + data->gc.dbg_show = adm1266_gpio_dbg_show; + + ret = devm_gpiochip_add_data(&data->client->dev, &data->gc, data); + if (ret) + dev_err(&data->client->dev, "GPIO registering failed (%d)\n", ret); + + return ret; +} + +static int adm1266_state_read(struct seq_file *s, void *pdata) +{ + struct device *dev = s->private; + struct i2c_client *client = to_i2c_client(dev); + int ret; + + ret = i2c_smbus_read_word_data(client, ADM1266_READ_STATE); + if (ret < 0) + return ret; + + seq_printf(s, "%d\n", ret); + + return 0; +} + +static void adm1266_init_debugfs(struct adm1266_data *data) +{ + struct dentry *root; + + root = pmbus_get_debugfs_dir(data->client); + if (!root) + return; + + data->debugfs_dir = debugfs_create_dir(data->client->name, root); + if (!data->debugfs_dir) + return; + + debugfs_create_devm_seqfile(&data->client->dev, "sequencer_state", data->debugfs_dir, + adm1266_state_read); +} + +static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff) +{ + int record_count; + char index; + u8 buf[5]; + int ret; + + ret = i2c_smbus_read_block_data(data->client, ADM1266_BLACKBOX_INFO, buf); + if (ret < 0) + return ret; + + if (ret != 4) + return -EIO; + + record_count = buf[3]; + + for (index = 0; index < record_count; index++) { + ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, read_buff); + if (ret < 0) + return ret; + + if (ret != ADM1266_BLACKBOX_SIZE) + return -EIO; + + read_buff += ADM1266_BLACKBOX_SIZE; + } + + return 0; +} + +static int adm1266_nvmem_read(void *priv, unsigned int offset, void *val, size_t bytes) +{ + struct adm1266_data *data = priv; + int ret; + + if (offset + bytes > data->nvmem_config.size) + return -EINVAL; + + if (offset == 0) { + memset(data->dev_mem, 0, data->nvmem_config.size); + + ret = adm1266_nvmem_read_blackbox(data, data->dev_mem); + if (ret) { + dev_err(&data->client->dev, "Could not read blackbox!"); + return ret; + } + } + + memcpy(val, data->dev_mem + offset, bytes); + + return 0; +} + +static int adm1266_config_nvmem(struct adm1266_data *data) +{ + data->nvmem_config.name = dev_name(&data->client->dev); + data->nvmem_config.dev = &data->client->dev; + data->nvmem_config.root_only = true; + data->nvmem_config.read_only = true; + data->nvmem_config.owner = THIS_MODULE; + data->nvmem_config.reg_read = adm1266_nvmem_read; + data->nvmem_config.cells = adm1266_nvmem_cells; + data->nvmem_config.ncells = ARRAY_SIZE(adm1266_nvmem_cells); + data->nvmem_config.priv = data; + data->nvmem_config.stride = 1; + data->nvmem_config.word_size = 1; + data->nvmem_config.size = adm1266_nvmem_cells[0].bytes; + + data->dev_mem = devm_kzalloc(&data->client->dev, data->nvmem_config.size, GFP_KERNEL); + if (!data->dev_mem) + return -ENOMEM; + + data->nvmem = devm_nvmem_register(&data->client->dev, &data->nvmem_config); + if (IS_ERR(data->nvmem)) { + dev_err(&data->client->dev, "Could not register nvmem!"); + return PTR_ERR(data->nvmem); + } + + return 0; +} + +static int adm1266_set_rtc(struct adm1266_data *data) +{ + time64_t kt; + char write_buf[6]; + int i; + + kt = ktime_get_seconds(); + + memset(write_buf, 0, sizeof(write_buf)); + + for (i = 0; i < 4; i++) + write_buf[2 + i] = (kt >> (i * 8)) & 0xFF; + + return i2c_smbus_write_block_data(data->client, ADM1266_SET_RTC, sizeof(write_buf), + write_buf); +} + +static int adm1266_probe(struct i2c_client *client) +{ + struct adm1266_data *data; + int ret; + int i; + + data = devm_kzalloc(&client->dev, sizeof(struct adm1266_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + data->info.pages = 17; + data->info.format[PSC_VOLTAGE_OUT] = linear; + for (i = 0; i < data->info.pages; i++) + data->info.func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + + crc8_populate_msb(pmbus_crc_table, 0x7); + mutex_init(&data->buf_mutex); + + ret = adm1266_config_gpio(data); + if (ret < 0) + return ret; + + ret = adm1266_set_rtc(data); + if (ret < 0) + return ret; + + ret = adm1266_config_nvmem(data); + if (ret < 0) + return ret; + + ret = pmbus_do_probe(client, &data->info); + if (ret) + return ret; + + adm1266_init_debugfs(data); + + return 0; +} + +static const struct of_device_id adm1266_of_match[] = { + { .compatible = "adi,adm1266" }, + { } +}; +MODULE_DEVICE_TABLE(of, adm1266_of_match); + +static const struct i2c_device_id adm1266_id[] = { + { "adm1266", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adm1266_id); + +static struct i2c_driver adm1266_driver = { + .driver = { + .name = "adm1266", + .of_match_table = adm1266_of_match, + }, + .probe_new = adm1266_probe, + .remove = pmbus_do_remove, + .id_table = adm1266_id, +}; + +module_i2c_driver(adm1266_driver); + +MODULE_AUTHOR("Alexandru Tachici <alexandru.tachici@analog.com>"); +MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1266"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 651846650a9c..e7997f37b266 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -462,8 +462,7 @@ static const struct i2c_device_id adm1275_id[] = { }; MODULE_DEVICE_TABLE(i2c, adm1275_id); -static int adm1275_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1275_probe(struct i2c_client *client) { s32 (*config_read_fn)(const struct i2c_client *client, u8 reg); u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; @@ -506,10 +505,10 @@ static int adm1275_probe(struct i2c_client *client, return -ENODEV; } - if (id->driver_data != mid->driver_data) + if (strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); if (mid->driver_data == adm1272 || mid->driver_data == adm1278 || mid->driver_data == adm1293 || mid->driver_data == adm1294) @@ -790,14 +789,14 @@ static int adm1275_probe(struct i2c_client *client, info->R[PSC_TEMPERATURE] = coefficients[tindex].R; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static struct i2c_driver adm1275_driver = { .driver = { .name = "adm1275", }, - .probe = adm1275_probe, + .probe_new = adm1275_probe, .remove = pmbus_do_remove, .id_table = adm1275_id, }; diff --git a/drivers/hwmon/pmbus/bel-pfe.c b/drivers/hwmon/pmbus/bel-pfe.c index f236e18f45a5..2c5b853d6c7f 100644 --- a/drivers/hwmon/pmbus/bel-pfe.c +++ b/drivers/hwmon/pmbus/bel-pfe.c @@ -87,12 +87,13 @@ static struct pmbus_driver_info pfe_driver_info[] = { }, }; -static int pfe_pmbus_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id pfe_device_id[]; + +static int pfe_pmbus_probe(struct i2c_client *client) { int model; - model = (int)id->driver_data; + model = (int)i2c_match_id(pfe_device_id, client)->driver_data; /* * PFE3000-12-069RA devices may not stay in page 0 during device @@ -104,7 +105,7 @@ static int pfe_pmbus_probe(struct i2c_client *client, i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); } - return pmbus_do_probe(client, id, &pfe_driver_info[model]); + return pmbus_do_probe(client, &pfe_driver_info[model]); } static const struct i2c_device_id pfe_device_id[] = { @@ -119,7 +120,7 @@ static struct i2c_driver pfe_pmbus_driver = { .driver = { .name = "bel-pfe", }, - .probe = pfe_pmbus_probe, + .probe_new = pfe_pmbus_probe, .remove = pmbus_do_remove, .id_table = pfe_device_id, }; diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index 7d300f2f338d..2fb7540ee952 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -91,6 +91,8 @@ struct ibm_cffps { struct led_classdev led; }; +static const struct i2c_device_id ibm_cffps_id[]; + #define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)]) static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu, @@ -473,8 +475,7 @@ static struct pmbus_platform_data ibm_cffps_pdata = { .flags = PMBUS_SKIP_STATUS_CHECK, }; -static int ibm_cffps_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ibm_cffps_probe(struct i2c_client *client) { int i, rc; enum versions vs = cffps_unknown; @@ -482,11 +483,15 @@ static int ibm_cffps_probe(struct i2c_client *client, struct dentry *ibm_cffps_dir; struct ibm_cffps *psu; const void *md = of_device_get_match_data(&client->dev); + const struct i2c_device_id *id; - if (md) + if (md) { vs = (enum versions)md; - else if (id) - vs = (enum versions)id->driver_data; + } else { + id = i2c_match_id(ibm_cffps_id, client); + if (id) + vs = (enum versions)id->driver_data; + } if (vs == cffps_unknown) { u16 ccin_revision = 0; @@ -519,7 +524,7 @@ static int ibm_cffps_probe(struct i2c_client *client, } client->dev.platform_data = &ibm_cffps_pdata; - rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]); + rc = pmbus_do_probe(client, &ibm_cffps_info[vs]); if (rc) return rc; @@ -611,7 +616,7 @@ static struct i2c_driver ibm_cffps_driver = { .name = "ibm-cffps", .of_match_table = ibm_cffps_of_match, }, - .probe = ibm_cffps_probe, + .probe_new = ibm_cffps_probe, .remove = pmbus_do_remove, .id_table = ibm_cffps_id, }; diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c index 42e01549184a..be493182174d 100644 --- a/drivers/hwmon/pmbus/inspur-ipsps.c +++ b/drivers/hwmon/pmbus/inspur-ipsps.c @@ -190,11 +190,10 @@ static struct pmbus_platform_data ipsps_pdata = { .flags = PMBUS_SKIP_STATUS_CHECK, }; -static int ipsps_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ipsps_probe(struct i2c_client *client) { client->dev.platform_data = &ipsps_pdata; - return pmbus_do_probe(client, id, &ipsps_info); + return pmbus_do_probe(client, &ipsps_info); } static const struct i2c_device_id ipsps_id[] = { @@ -216,7 +215,7 @@ static struct i2c_driver ipsps_driver = { .name = "inspur-ipsps", .of_match_table = of_match_ptr(ipsps_of_match), }, - .probe = ipsps_probe, + .probe_new = ipsps_probe, .remove = pmbus_do_remove, .id_table = ipsps_id, }; diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c index 3eea3e006a96..5fadb1def49f 100644 --- a/drivers/hwmon/pmbus/ir35221.c +++ b/drivers/hwmon/pmbus/ir35221.c @@ -67,8 +67,7 @@ static int ir35221_read_word_data(struct i2c_client *client, int page, return ret; } -static int ir35221_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ir35221_probe(struct i2c_client *client) { struct pmbus_driver_info *info; u8 buf[I2C_SMBUS_BLOCK_MAX]; @@ -123,7 +122,7 @@ static int ir35221_probe(struct i2c_client *client, | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP; info->func[1] = info->func[0]; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id ir35221_id[] = { @@ -137,7 +136,7 @@ static struct i2c_driver ir35221_driver = { .driver = { .name = "ir35221", }, - .probe = ir35221_probe, + .probe_new = ir35221_probe, .remove = pmbus_do_remove, .id_table = ir35221_id, }; diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c index 1820f5077f66..9ac563ce7dd8 100644 --- a/drivers/hwmon/pmbus/ir38064.c +++ b/drivers/hwmon/pmbus/ir38064.c @@ -35,10 +35,9 @@ static struct pmbus_driver_info ir38064_info = { | PMBUS_HAVE_POUT, }; -static int ir38064_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ir38064_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &ir38064_info); + return pmbus_do_probe(client, &ir38064_info); } static const struct i2c_device_id ir38064_id[] = { @@ -53,7 +52,7 @@ static struct i2c_driver ir38064_driver = { .driver = { .name = "ir38064", }, - .probe = ir38064_probe, + .probe_new = ir38064_probe, .remove = pmbus_do_remove, .id_table = ir38064_id, }; diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c index d37daa001fb3..44aeafcbd56c 100644 --- a/drivers/hwmon/pmbus/irps5401.c +++ b/drivers/hwmon/pmbus/irps5401.c @@ -38,10 +38,9 @@ static struct pmbus_driver_info irps5401_info = { .func[4] = IRPS5401_LDO_FUNC, }; -static int irps5401_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int irps5401_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &irps5401_info); + return pmbus_do_probe(client, &irps5401_info); } static const struct i2c_device_id irps5401_id[] = { @@ -55,7 +54,7 @@ static struct i2c_driver irps5401_driver = { .driver = { .name = "irps5401", }, - .probe = irps5401_probe, + .probe_new = irps5401_probe, .remove = pmbus_do_remove, .id_table = irps5401_id, }; diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 58aa95a3c010..7cad76e07f70 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -72,6 +72,8 @@ enum variants { raa_dmpvr2_hv, }; +static const struct i2c_device_id raa_dmpvr_id[]; + static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, int page, char *buf) @@ -218,8 +220,7 @@ static struct pmbus_driver_info raa_dmpvr_info = { | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, }; -static int isl68137_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int isl68137_probe(struct i2c_client *client) { struct pmbus_driver_info *info; @@ -228,7 +229,7 @@ static int isl68137_probe(struct i2c_client *client, return -ENOMEM; memcpy(info, &raa_dmpvr_info, sizeof(*info)); - switch (id->driver_data) { + switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) { case raa_dmpvr1_2rail: info->pages = 2; info->R[PSC_VOLTAGE_IN] = 3; @@ -267,7 +268,7 @@ static int isl68137_probe(struct i2c_client *client, return -ENODEV; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id raa_dmpvr_id[] = { @@ -322,7 +323,7 @@ static struct i2c_driver isl68137_driver = { .driver = { .name = "isl68137", }, - .probe = isl68137_probe, + .probe_new = isl68137_probe, .remove = pmbus_do_remove, .id_table = raa_dmpvr_id, }; diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 9e4cf0800186..429172a42902 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -211,6 +211,8 @@ struct lm25066_data { #define to_lm25066_data(x) container_of(x, struct lm25066_data, info) +static const struct i2c_device_id lm25066_id[]; + static int lm25066_read_word_data(struct i2c_client *client, int page, int phase, int reg) { @@ -416,8 +418,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, return ret; } -static int lm25066_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm25066_probe(struct i2c_client *client) { int config; struct lm25066_data *data; @@ -437,7 +438,7 @@ static int lm25066_probe(struct i2c_client *client, if (config < 0) return config; - data->id = id->driver_data; + data->id = i2c_match_id(lm25066_id, client)->driver_data; info = &data->info; info->pages = 1; @@ -487,7 +488,7 @@ static int lm25066_probe(struct i2c_client *client, info->b[PSC_POWER] = coeff[PSC_POWER].b; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id lm25066_id[] = { @@ -506,7 +507,7 @@ static struct i2c_driver lm25066_driver = { .driver = { .name = "lm25066", }, - .probe = lm25066_probe, + .probe_new = lm25066_probe, .remove = pmbus_do_remove, .id_table = lm25066_id, }; diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 7b0e6b37e247..9a024cf70145 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -649,12 +649,12 @@ static int ltc2978_get_id(struct i2c_client *client) return -ENODEV; } -static int ltc2978_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc2978_probe(struct i2c_client *client) { int i, chip_id; struct ltc2978_data *data; struct pmbus_driver_info *info; + const struct i2c_device_id *id; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) @@ -670,11 +670,13 @@ static int ltc2978_probe(struct i2c_client *client, return chip_id; data->id = chip_id; + id = i2c_match_id(ltc2978_id, client); if (data->id != id->driver_data) dev_warn(&client->dev, - "Device mismatch: Configured %s, detected %s\n", + "Device mismatch: Configured %s (%d), detected %d\n", id->name, - ltc2978_id[data->id].name); + (int) id->driver_data, + chip_id); info = &data->info; info->write_word_data = ltc2978_write_word_data; @@ -832,7 +834,7 @@ static int ltc2978_probe(struct i2c_client *client, } #endif - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } @@ -872,7 +874,7 @@ static struct i2c_driver ltc2978_driver = { .name = "ltc2978", .of_match_table = of_match_ptr(ltc2978_of_match), }, - .probe = ltc2978_probe, + .probe_new = ltc2978_probe, .remove = pmbus_do_remove, .id_table = ltc2978_id, }; diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c index 3036263e0a66..8328fb367ad6 100644 --- a/drivers/hwmon/pmbus/ltc3815.c +++ b/drivers/hwmon/pmbus/ltc3815.c @@ -178,8 +178,7 @@ static struct pmbus_driver_info ltc3815_info = { .write_word_data = ltc3815_write_word_data, }; -static int ltc3815_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc3815_probe(struct i2c_client *client) { int chip_id; @@ -193,14 +192,14 @@ static int ltc3815_probe(struct i2c_client *client, if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID) return -ENODEV; - return pmbus_do_probe(client, id, <c3815_info); + return pmbus_do_probe(client, <c3815_info); } static struct i2c_driver ltc3815_driver = { .driver = { .name = "ltc3815", }, - .probe = ltc3815_probe, + .probe_new = ltc3815_probe, .remove = pmbus_do_remove, .id_table = ltc3815_id, }; diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index 288e93f74c28..26e7f5ef9d7f 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -85,10 +85,9 @@ static struct pmbus_driver_info max16064_info = { .write_word_data = max16064_write_word_data, }; -static int max16064_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max16064_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &max16064_info); + return pmbus_do_probe(client, &max16064_info); } static const struct i2c_device_id max16064_id[] = { @@ -103,7 +102,7 @@ static struct i2c_driver max16064_driver = { .driver = { .name = "max16064", }, - .probe = max16064_probe, + .probe_new = max16064_probe, .remove = pmbus_do_remove, .id_table = max16064_id, }; diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index 51cdfaf9023c..71bb74e27a5c 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -239,8 +239,7 @@ static void max16601_remove(void *_data) i2c_unregister_device(data->vsa); } -static int max16601_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max16601_probe(struct i2c_client *client) { struct device *dev = &client->dev; u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; @@ -288,7 +287,7 @@ static int max16601_probe(struct i2c_client *client, data->info = max16601_info; - return pmbus_do_probe(client, id, &data->info); + return pmbus_do_probe(client, &data->info); } static const struct i2c_device_id max16601_id[] = { @@ -302,7 +301,7 @@ static struct i2c_driver max16601_driver = { .driver = { .name = "max16601", }, - .probe = max16601_probe, + .probe_new = max16601_probe, .remove = pmbus_do_remove, .id_table = max16601_id, }; diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index a151a2b588a5..57923d72490c 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -8,6 +8,7 @@ */ #include <linux/bits.h> +#include <linux/debugfs.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/init.h> @@ -26,16 +27,370 @@ enum chips { max20743 }; +enum { + MAX20730_DEBUGFS_VOUT_MIN = 0, + MAX20730_DEBUGFS_FREQUENCY, + MAX20730_DEBUGFS_PG_DELAY, + MAX20730_DEBUGFS_INTERNAL_GAIN, + MAX20730_DEBUGFS_BOOT_VOLTAGE, + MAX20730_DEBUGFS_OUT_V_RAMP_RATE, + MAX20730_DEBUGFS_OC_PROTECT_MODE, + MAX20730_DEBUGFS_SS_TIMING, + MAX20730_DEBUGFS_IMAX, + MAX20730_DEBUGFS_OPERATION, + MAX20730_DEBUGFS_ON_OFF_CONFIG, + MAX20730_DEBUGFS_SMBALERT_MASK, + MAX20730_DEBUGFS_VOUT_MODE, + MAX20730_DEBUGFS_VOUT_COMMAND, + MAX20730_DEBUGFS_VOUT_MAX, + MAX20730_DEBUGFS_NUM_ENTRIES +}; + struct max20730_data { enum chips id; struct pmbus_driver_info info; struct mutex lock; /* Used to protect against parallel writes */ u16 mfr_devset1; + u16 mfr_devset2; + u16 mfr_voutmin; + u32 vout_voltage_divider[2]; }; #define to_max20730_data(x) container_of(x, struct max20730_data, info) +#define VOLT_FROM_REG(val) DIV_ROUND_CLOSEST((val), 1 << 9) + +#define PMBUS_SMB_ALERT_MASK 0x1B + +#define MAX20730_MFR_VOUT_MIN 0xd1 #define MAX20730_MFR_DEVSET1 0xd2 +#define MAX20730_MFR_DEVSET2 0xd3 + +#define MAX20730_MFR_VOUT_MIN_MASK GENMASK(9, 0) +#define MAX20730_MFR_VOUT_MIN_BIT_POS 0 + +#define MAX20730_MFR_DEVSET1_RGAIN_MASK (BIT(13) | BIT(14)) +#define MAX20730_MFR_DEVSET1_OTP_MASK (BIT(11) | BIT(12)) +#define MAX20730_MFR_DEVSET1_VBOOT_MASK (BIT(8) | BIT(9)) +#define MAX20730_MFR_DEVSET1_OCP_MASK (BIT(5) | BIT(6)) +#define MAX20730_MFR_DEVSET1_FSW_MASK GENMASK(4, 2) +#define MAX20730_MFR_DEVSET1_TSTAT_MASK (BIT(0) | BIT(1)) + +#define MAX20730_MFR_DEVSET1_RGAIN_BIT_POS 13 +#define MAX20730_MFR_DEVSET1_OTP_BIT_POS 11 +#define MAX20730_MFR_DEVSET1_VBOOT_BIT_POS 8 +#define MAX20730_MFR_DEVSET1_OCP_BIT_POS 5 +#define MAX20730_MFR_DEVSET1_FSW_BIT_POS 2 +#define MAX20730_MFR_DEVSET1_TSTAT_BIT_POS 0 + +#define MAX20730_MFR_DEVSET2_IMAX_MASK GENMASK(10, 8) +#define MAX20730_MFR_DEVSET2_VRATE (BIT(6) | BIT(7)) +#define MAX20730_MFR_DEVSET2_OCPM_MASK BIT(5) +#define MAX20730_MFR_DEVSET2_SS_MASK (BIT(0) | BIT(1)) + +#define MAX20730_MFR_DEVSET2_IMAX_BIT_POS 8 +#define MAX20730_MFR_DEVSET2_VRATE_BIT_POS 6 +#define MAX20730_MFR_DEVSET2_OCPM_BIT_POS 5 +#define MAX20730_MFR_DEVSET2_SS_BIT_POS 0 + +#define DEBUG_FS_DATA_MAX 16 + +struct max20730_debugfs_data { + struct i2c_client *client; + int debugfs_entries[MAX20730_DEBUGFS_NUM_ENTRIES]; +}; + +#define to_psu(x, y) container_of((x), \ + struct max20730_debugfs_data, debugfs_entries[(y)]) + +#ifdef CONFIG_DEBUG_FS +static ssize_t max20730_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int ret, len; + int *idxp = file->private_data; + int idx = *idxp; + struct max20730_debugfs_data *psu = to_psu(idxp, idx); + const struct pmbus_driver_info *info; + const struct max20730_data *data; + char tbuf[DEBUG_FS_DATA_MAX] = { 0 }; + u16 val; + + info = pmbus_get_driver_info(psu->client); + data = to_max20730_data(info); + + switch (idx) { + case MAX20730_DEBUGFS_VOUT_MIN: + ret = VOLT_FROM_REG(data->mfr_voutmin * 10000); + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d.%d\n", + ret / 10000, ret % 10000); + break; + case MAX20730_DEBUGFS_FREQUENCY: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_FSW_MASK) + >> MAX20730_MFR_DEVSET1_FSW_BIT_POS; + + if (val == 0) + ret = 400; + else if (val == 1) + ret = 500; + else if (val == 2 || val == 3) + ret = 600; + else if (val == 4) + ret = 700; + else if (val == 5) + ret = 800; + else + ret = 900; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_PG_DELAY: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_TSTAT_MASK) + >> MAX20730_MFR_DEVSET1_TSTAT_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "2000\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "125\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "62.5\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "32\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_INTERNAL_GAIN: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_RGAIN_MASK) + >> MAX20730_MFR_DEVSET1_RGAIN_BIT_POS; + + if (data->id == max20734) { + /* AN6209 */ + if (val == 0) + len = strlcpy(tbuf, "0.8\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "3.2\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1.6\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "6.4\n", DEBUG_FS_DATA_MAX); + } else if (data->id == max20730 || data->id == max20710) { + /* AN6042 or AN6140 */ + if (val == 0) + len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "7.2\n", DEBUG_FS_DATA_MAX); + } else if (data->id == max20743) { + /* AN6042 */ + if (val == 0) + len = strlcpy(tbuf, "0.45\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX); + } else { + len = strlcpy(tbuf, "Not supported\n", DEBUG_FS_DATA_MAX); + } + break; + case MAX20730_DEBUGFS_BOOT_VOLTAGE: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_VBOOT_MASK) + >> MAX20730_MFR_DEVSET1_VBOOT_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "0.6484\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "0.8984\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1.0\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_OUT_V_RAMP_RATE: + val = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_VRATE) + >> MAX20730_MFR_DEVSET2_VRATE_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "4\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "2\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_OC_PROTECT_MODE: + ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_OCPM_MASK) + >> MAX20730_MFR_DEVSET2_OCPM_BIT_POS; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_SS_TIMING: + val = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_SS_MASK) + >> MAX20730_MFR_DEVSET2_SS_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "0.75\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "1.5\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "3\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "6\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_IMAX: + ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_IMAX_MASK) + >> MAX20730_MFR_DEVSET2_IMAX_BIT_POS; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_OPERATION: + ret = i2c_smbus_read_byte_data(psu->client, PMBUS_OPERATION); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_ON_OFF_CONFIG: + ret = i2c_smbus_read_byte_data(psu->client, PMBUS_ON_OFF_CONFIG); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_SMBALERT_MASK: + ret = i2c_smbus_read_word_data(psu->client, + PMBUS_SMB_ALERT_MASK); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_VOUT_MODE: + ret = i2c_smbus_read_byte_data(psu->client, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_VOUT_COMMAND: + ret = i2c_smbus_read_word_data(psu->client, PMBUS_VOUT_COMMAND); + if (ret < 0) + return ret; + + ret = VOLT_FROM_REG(ret * 10000); + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, + "%d.%d\n", ret / 10000, ret % 10000); + break; + case MAX20730_DEBUGFS_VOUT_MAX: + ret = i2c_smbus_read_word_data(psu->client, PMBUS_VOUT_MAX); + if (ret < 0) + return ret; + + ret = VOLT_FROM_REG(ret * 10000); + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, + "%d.%d\n", ret / 10000, ret % 10000); + break; + default: + len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX); + } + + return simple_read_from_buffer(buf, count, ppos, tbuf, len); +} + +static const struct file_operations max20730_fops = { + .llseek = noop_llseek, + .read = max20730_debugfs_read, + .write = NULL, + .open = simple_open, +}; + +static int max20730_init_debugfs(struct i2c_client *client, + struct max20730_data *data) +{ + int ret, i; + struct dentry *debugfs; + struct dentry *max20730_dir; + struct max20730_debugfs_data *psu; + + ret = i2c_smbus_read_word_data(client, MAX20730_MFR_DEVSET2); + if (ret < 0) + return ret; + data->mfr_devset2 = ret; + + ret = i2c_smbus_read_word_data(client, MAX20730_MFR_VOUT_MIN); + if (ret < 0) + return ret; + data->mfr_voutmin = ret; + + psu = devm_kzalloc(&client->dev, sizeof(*psu), GFP_KERNEL); + if (!psu) + return -ENOMEM; + psu->client = client; + + debugfs = pmbus_get_debugfs_dir(client); + if (!debugfs) + return -ENOENT; + + max20730_dir = debugfs_create_dir(client->name, debugfs); + if (!max20730_dir) + return -ENOENT; + + for (i = 0; i < MAX20730_DEBUGFS_NUM_ENTRIES; ++i) + psu->debugfs_entries[i] = i; + + debugfs_create_file("vout_min", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_MIN], + &max20730_fops); + debugfs_create_file("frequency", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_FREQUENCY], + &max20730_fops); + debugfs_create_file("power_good_delay", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_PG_DELAY], + &max20730_fops); + debugfs_create_file("internal_gain", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_INTERNAL_GAIN], + &max20730_fops); + debugfs_create_file("boot_voltage", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_BOOT_VOLTAGE], + &max20730_fops); + debugfs_create_file("out_voltage_ramp_rate", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_OUT_V_RAMP_RATE], + &max20730_fops); + debugfs_create_file("oc_protection_mode", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_OC_PROTECT_MODE], + &max20730_fops); + debugfs_create_file("soft_start_timing", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_SS_TIMING], + &max20730_fops); + debugfs_create_file("imax", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_IMAX], + &max20730_fops); + debugfs_create_file("operation", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_OPERATION], + &max20730_fops); + debugfs_create_file("on_off_config", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_ON_OFF_CONFIG], + &max20730_fops); + debugfs_create_file("smbalert_mask", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_SMBALERT_MASK], + &max20730_fops); + debugfs_create_file("vout_mode", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_MODE], + &max20730_fops); + debugfs_create_file("vout_command", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_COMMAND], + &max20730_fops); + debugfs_create_file("vout_max", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_MAX], + &max20730_fops); + + return 0; +} +#else +static int max20730_init_debugfs(struct i2c_client *client, + struct max20730_data *data) +{ + return 0; +} +#endif /* CONFIG_DEBUG_FS */ + +static const struct i2c_device_id max20730_id[]; /* * Convert discreet value to direct data format. Strictly speaking, all passed @@ -114,6 +469,14 @@ static int max20730_read_word_data(struct i2c_client *client, int page, max_c = max_current[data->id][(data->mfr_devset1 >> 5) & 0x3]; ret = val_to_direct(max_c, PSC_CURRENT_OUT, info); break; + case PMBUS_READ_VOUT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret > 0 && data->vout_voltage_divider[0] && data->vout_voltage_divider[1]) { + u64 temp = DIV_ROUND_CLOSEST_ULL((u64)ret * data->vout_voltage_divider[1], + data->vout_voltage_divider[0]); + ret = clamp_val(temp, 0, 0xffff); + } + break; default: ret = -ENODATA; break; @@ -295,8 +658,7 @@ static const struct pmbus_driver_info max20730_info[] = { }, }; -static int max20730_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max20730_probe(struct i2c_client *client) { struct device *dev = &client->dev; u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; @@ -356,7 +718,7 @@ static int max20730_probe(struct i2c_client *client, if (client->dev.of_node) chip_id = (enum chips)of_device_get_match_data(dev); else - chip_id = id->driver_data; + chip_id = i2c_match_id(max20730_id, client)->driver_data; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -364,13 +726,31 @@ static int max20730_probe(struct i2c_client *client, data->id = chip_id; mutex_init(&data->lock); memcpy(&data->info, &max20730_info[chip_id], sizeof(data->info)); + if (of_property_read_u32_array(client->dev.of_node, "vout-voltage-divider", + data->vout_voltage_divider, + ARRAY_SIZE(data->vout_voltage_divider)) != 0) + memset(data->vout_voltage_divider, 0, sizeof(data->vout_voltage_divider)); + if (data->vout_voltage_divider[1] < data->vout_voltage_divider[0]) { + dev_err(dev, + "The total resistance of voltage divider is less than output resistance\n"); + return -EINVAL; + } ret = i2c_smbus_read_word_data(client, MAX20730_MFR_DEVSET1); if (ret < 0) return ret; data->mfr_devset1 = ret; - return pmbus_do_probe(client, id, &data->info); + ret = pmbus_do_probe(client, &data->info); + if (ret < 0) + return ret; + + ret = max20730_init_debugfs(client, data); + if (ret) + dev_warn(dev, "Failed to register debugfs: %d\n", + ret); + + return 0; } static const struct i2c_device_id max20730_id[] = { @@ -398,7 +778,7 @@ static struct i2c_driver max20730_driver = { .name = "max20730", .of_match_table = max20730_of_match, }, - .probe = max20730_probe, + .probe_new = max20730_probe, .remove = pmbus_do_remove, .id_table = max20730_id, }; diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c index da3c38cb9a5c..921e92d82aec 100644 --- a/drivers/hwmon/pmbus/max20751.c +++ b/drivers/hwmon/pmbus/max20751.c @@ -26,10 +26,9 @@ static struct pmbus_driver_info max20751_info = { PMBUS_HAVE_POUT, }; -static int max20751_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max20751_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &max20751_info); + return pmbus_do_probe(client, &max20751_info); } static const struct i2c_device_id max20751_id[] = { @@ -43,7 +42,7 @@ static struct i2c_driver max20751_driver = { .driver = { .name = "max20751", }, - .probe = max20751_probe, + .probe_new = max20751_probe, .remove = pmbus_do_remove, .id_table = max20751_id, }; diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index d9aa5c873d21..839b957bc03e 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -324,8 +324,7 @@ static int max31785_configure_dual_tach(struct i2c_client *client, return 0; } -static int max31785_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max31785_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct pmbus_driver_info *info; @@ -354,7 +353,7 @@ static int max31785_probe(struct i2c_client *client, if (ret == MAX31785A) { dual_tach = true; } else if (ret == MAX31785) { - if (!strcmp("max31785a", id->name)) + if (!strcmp("max31785a", client->name)) dev_warn(dev, "Expected max3175a, found max31785: cannot provide secondary tachometer readings\n"); } else { return -ENODEV; @@ -366,7 +365,7 @@ static int max31785_probe(struct i2c_client *client, return ret; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id max31785_id[] = { @@ -390,7 +389,7 @@ static struct i2c_driver max31785_driver = { .name = "max31785", .of_match_table = max31785_of_match, }, - .probe = max31785_probe, + .probe_new = max31785_probe, .remove = pmbus_do_remove, .id_table = max31785_id, }; diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 18b4e071067f..f4cb196aaaf3 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -31,6 +31,13 @@ enum chips { max34440, max34441, max34446, max34451, max34460, max34461 }; #define MAX34440_STATUS_OT_FAULT BIT(5) #define MAX34440_STATUS_OT_WARN BIT(6) +/* + * The whole max344* family have IOUT_OC_WARN_LIMIT and IOUT_OC_FAULT_LIMIT + * swapped from the standard pmbus spec addresses. + */ +#define MAX34440_IOUT_OC_WARN_LIMIT 0x46 +#define MAX34440_IOUT_OC_FAULT_LIMIT 0x4A + #define MAX34451_MFR_CHANNEL_CONFIG 0xe4 #define MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK 0x3f @@ -41,6 +48,8 @@ struct max34440_data { #define to_max34440_data(x) container_of(x, struct max34440_data, info) +static const struct i2c_device_id max34440_id[]; + static int max34440_read_word_data(struct i2c_client *client, int page, int phase, int reg) { @@ -49,6 +58,14 @@ static int max34440_read_word_data(struct i2c_client *client, int page, const struct max34440_data *data = to_max34440_data(info); switch (reg) { + case PMBUS_IOUT_OC_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, phase, + MAX34440_IOUT_OC_FAULT_LIMIT); + break; + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = pmbus_read_word_data(client, page, phase, + MAX34440_IOUT_OC_WARN_LIMIT); + break; case PMBUS_VIRT_READ_VOUT_MIN: ret = pmbus_read_word_data(client, page, phase, MAX34440_MFR_VOUT_MIN); @@ -115,6 +132,14 @@ static int max34440_write_word_data(struct i2c_client *client, int page, int ret; switch (reg) { + case PMBUS_IOUT_OC_FAULT_LIMIT: + ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_FAULT_LIMIT, + word); + break; + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_WARN_LIMIT, + word); + break; case PMBUS_VIRT_RESET_POUT_HISTORY: ret = pmbus_write_word_data(client, page, MAX34446_MFR_POUT_PEAK, 0); @@ -388,7 +413,6 @@ static struct pmbus_driver_info max34440_info[] = { .func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, - .read_byte_data = max34440_read_byte_data, .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, @@ -419,7 +443,6 @@ static struct pmbus_driver_info max34440_info[] = { .func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, - .read_byte_data = max34440_read_byte_data, .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, @@ -455,14 +478,12 @@ static struct pmbus_driver_info max34440_info[] = { .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, - .read_byte_data = max34440_read_byte_data, .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, }; -static int max34440_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max34440_probe(struct i2c_client *client) { struct max34440_data *data; int rv; @@ -471,8 +492,8 @@ static int max34440_probe(struct i2c_client *client, GFP_KERNEL); if (!data) return -ENOMEM; - data->id = id->driver_data; - data->info = max34440_info[id->driver_data]; + data->id = i2c_match_id(max34440_id, client)->driver_data; + data->info = max34440_info[data->id]; if (data->id == max34451) { rv = max34451_set_supported_funcs(client, data); @@ -480,7 +501,7 @@ static int max34440_probe(struct i2c_client *client, return rv; } - return pmbus_do_probe(client, id, &data->info); + return pmbus_do_probe(client, &data->info); } static const struct i2c_device_id max34440_id[] = { @@ -499,7 +520,7 @@ static struct i2c_driver max34440_driver = { .driver = { .name = "max34440", }, - .probe = max34440_probe, + .probe_new = max34440_probe, .remove = pmbus_do_remove, .id_table = max34440_id, }; diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index 643ccfc05106..4b2239a6afd3 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -165,10 +165,9 @@ static struct pmbus_driver_info max8688_info = { .write_word_data = max8688_write_word_data, }; -static int max8688_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max8688_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &max8688_info); + return pmbus_do_probe(client, &max8688_info); } static const struct i2c_device_id max8688_id[] = { @@ -183,7 +182,7 @@ static struct i2c_driver max8688_driver = { .driver = { .name = "max8688", }, - .probe = max8688_probe, + .probe_new = max8688_probe, .remove = pmbus_do_remove, .id_table = max8688_id, }; diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c new file mode 100644 index 000000000000..1c3e2a9453b1 --- /dev/null +++ b/drivers/hwmon/pmbus/mp2975.c @@ -0,0 +1,769 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers + * + * Copyright (C) 2020 Nvidia Technologies Ltd. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include "pmbus.h" + +/* Vendor specific registers. */ +#define MP2975_MFR_APS_HYS_R2 0x0d +#define MP2975_MFR_SLOPE_TRIM3 0x1d +#define MP2975_MFR_VR_MULTI_CONFIG_R1 0x0d +#define MP2975_MFR_VR_MULTI_CONFIG_R2 0x1d +#define MP2975_MFR_APS_DECAY_ADV 0x56 +#define MP2975_MFR_DC_LOOP_CTRL 0x59 +#define MP2975_MFR_OCP_UCP_PHASE_SET 0x65 +#define MP2975_MFR_VR_CONFIG1 0x68 +#define MP2975_MFR_READ_CS1_2 0x82 +#define MP2975_MFR_READ_CS3_4 0x83 +#define MP2975_MFR_READ_CS5_6 0x84 +#define MP2975_MFR_READ_CS7_8 0x85 +#define MP2975_MFR_READ_CS9_10 0x86 +#define MP2975_MFR_READ_CS11_12 0x87 +#define MP2975_MFR_READ_IOUT_PK 0x90 +#define MP2975_MFR_READ_POUT_PK 0x91 +#define MP2975_MFR_READ_VREF_R1 0xa1 +#define MP2975_MFR_READ_VREF_R2 0xa3 +#define MP2975_MFR_OVP_TH_SET 0xe5 +#define MP2975_MFR_UVP_SET 0xe6 + +#define MP2975_VOUT_FORMAT BIT(15) +#define MP2975_VID_STEP_SEL_R1 BIT(4) +#define MP2975_IMVP9_EN_R1 BIT(13) +#define MP2975_VID_STEP_SEL_R2 BIT(3) +#define MP2975_IMVP9_EN_R2 BIT(12) +#define MP2975_PRT_THRES_DIV_OV_EN BIT(14) +#define MP2975_DRMOS_KCS GENMASK(13, 12) +#define MP2975_PROT_DEV_OV_OFF 10 +#define MP2975_PROT_DEV_OV_ON 5 +#define MP2975_SENSE_AMPL BIT(11) +#define MP2975_SENSE_AMPL_UNIT 1 +#define MP2975_SENSE_AMPL_HALF 2 +#define MP2975_VIN_UV_LIMIT_UNIT 8 + +#define MP2975_MAX_PHASE_RAIL1 8 +#define MP2975_MAX_PHASE_RAIL2 4 +#define MP2975_PAGE_NUM 2 + +#define MP2975_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_PHASE_VIRTUAL) + +struct mp2975_data { + struct pmbus_driver_info info; + int vout_scale; + int vid_step[MP2975_PAGE_NUM]; + int vref[MP2975_PAGE_NUM]; + int vref_off[MP2975_PAGE_NUM]; + int vout_max[MP2975_PAGE_NUM]; + int vout_ov_fixed[MP2975_PAGE_NUM]; + int vout_format[MP2975_PAGE_NUM]; + int curr_sense_gain[MP2975_PAGE_NUM]; +}; + +#define to_mp2975_data(x) container_of(x, struct mp2975_data, info) + +static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg) +{ + switch (reg) { + case PMBUS_VOUT_MODE: + /* + * Enforce VOUT direct format, since device allows to set the + * different formats for the different rails. Conversion from + * VID to direct provided by driver internally, in case it is + * necessary. + */ + return PB_VOUT_MODE_DIRECT; + default: + return -ENODATA; + } +} + +static int +mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg, + u16 mask) +{ + int ret = pmbus_read_word_data(client, page, phase, reg); + + return (ret > 0) ? ret & mask : ret; +} + +static int +mp2975_vid2direct(int vrf, int val) +{ + switch (vrf) { + case vr12: + if (val >= 0x01) + return 250 + (val - 1) * 5; + break; + case vr13: + if (val >= 0x01) + return 500 + (val - 1) * 10; + break; + case imvp9: + if (val >= 0x01) + return 200 + (val - 1) * 10; + break; + default: + return -EINVAL; + } + return 0; +} + +static int +mp2975_read_phase(struct i2c_client *client, struct mp2975_data *data, + int page, int phase, u8 reg) +{ + int ph_curr, ret; + + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + if (!((phase + 1) % MP2975_PAGE_NUM)) + ret >>= 8; + ret &= 0xff; + + /* + * Output value is calculated as: (READ_CSx / 80 – 1.23) / (Kcs * Rcs) + * where: + * - Kcs is the DrMOS current sense gain of power stage, which is + * obtained from the register MP2975_MFR_VR_CONFIG1, bits 13-12 with + * the following selection of DrMOS (data->curr_sense_gain[page]): + * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. + * - Rcs is the internal phase current sense resistor which is constant + * value 1kΩ. + */ + ph_curr = ret * 100 - 9800; + + /* + * Current phase sensing, providing by the device is not accurate + * for the light load. This because sampling of current occurrence of + * bit weight has a big deviation for light load. For handling such + * case phase current is represented as the maximum between the value + * calculated above and total rail current divided by number phases. + */ + ret = pmbus_read_word_data(client, page, phase, PMBUS_READ_IOUT); + if (ret < 0) + return ret; + + return max_t(int, DIV_ROUND_CLOSEST(ret, data->info.phases[page]), + DIV_ROUND_CLOSEST(ph_curr, data->curr_sense_gain[page])); +} + +static int +mp2975_read_phases(struct i2c_client *client, struct mp2975_data *data, + int page, int phase) +{ + int ret; + + if (page) { + switch (phase) { + case 0 ... 1: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS7_8); + break; + case 2 ... 3: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS9_10); + break; + case 4 ... 5: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS11_12); + break; + default: + return -ENODATA; + } + } else { + switch (phase) { + case 0 ... 1: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS1_2); + break; + case 2 ... 3: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS3_4); + break; + case 4 ... 5: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS5_6); + break; + case 6 ... 7: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS7_8); + break; + case 8 ... 9: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS9_10); + break; + case 10 ... 11: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS11_12); + break; + default: + return -ENODATA; + } + } + return ret; +} + +static int mp2975_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct mp2975_data *data = to_mp2975_data(info); + int ret; + + switch (reg) { + case PMBUS_OT_FAULT_LIMIT: + ret = mp2975_read_word_helper(client, page, phase, reg, + GENMASK(7, 0)); + break; + case PMBUS_VIN_OV_FAULT_LIMIT: + ret = mp2975_read_word_helper(client, page, phase, reg, + GENMASK(7, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT); + break; + case PMBUS_VOUT_OV_FAULT_LIMIT: + /* + * Register provides two values for over-voltage protection + * threshold for fixed (ovp2) and tracking (ovp1) modes. The + * minimum of these two values is provided as over-voltage + * fault alarm. + */ + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_OVP_TH_SET, + GENMASK(2, 0)); + if (ret < 0) + return ret; + + ret = min_t(int, data->vout_max[page] + 50 * (ret + 1), + data->vout_ov_fixed[page]); + break; + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_UVP_SET, + GENMASK(2, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(data->vref[page] * 10 - 50 * + (ret + 1) * data->vout_scale, 10); + break; + case PMBUS_READ_VOUT: + ret = mp2975_read_word_helper(client, page, phase, reg, + GENMASK(11, 0)); + if (ret < 0) + return ret; + + /* + * READ_VOUT can be provided in VID or direct format. The + * format type is specified by bit 15 of the register + * MP2975_MFR_DC_LOOP_CTRL. The driver enforces VOUT direct + * format, since device allows to set the different formats for + * the different rails and also all VOUT limits registers are + * provided in a direct format. In case format is VID - convert + * to direct. + */ + if (data->vout_format[page] == vid) + ret = mp2975_vid2direct(info->vrm_version[page], ret); + break; + case PMBUS_VIRT_READ_POUT_MAX: + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_READ_POUT_PK, + GENMASK(12, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(ret, 4); + break; + case PMBUS_VIRT_READ_IOUT_MAX: + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_READ_IOUT_PK, + GENMASK(12, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(ret, 4); + break; + case PMBUS_READ_IOUT: + ret = mp2975_read_phases(client, data, page, phase); + if (ret < 0) + return ret; + + break; + case PMBUS_UT_WARN_LIMIT: + case PMBUS_UT_FAULT_LIMIT: + case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_VOUT_UV_WARN_LIMIT: + case PMBUS_VOUT_OV_WARN_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_IIN_OC_FAULT_LIMIT: + case PMBUS_IOUT_OC_LV_FAULT_LIMIT: + case PMBUS_IIN_OC_WARN_LIMIT: + case PMBUS_IOUT_OC_WARN_LIMIT: + case PMBUS_IOUT_OC_FAULT_LIMIT: + case PMBUS_IOUT_UC_FAULT_LIMIT: + case PMBUS_POUT_OP_FAULT_LIMIT: + case PMBUS_POUT_OP_WARN_LIMIT: + case PMBUS_PIN_OP_WARN_LIMIT: + return -ENXIO; + default: + return -ENODATA; + } + + return ret; +} + +static int mp2975_identify_multiphase_rail2(struct i2c_client *client) +{ + int ret; + + /* + * Identify multiphase for rail 2 - could be from 0 to 4. + * In case phase number is zero – only page zero is supported + */ + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + /* Identify multiphase for rail 2 - could be from 0 to 4. */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R2); + if (ret < 0) + return ret; + + ret &= GENMASK(2, 0); + return (ret >= 4) ? 4 : ret; +} + +static void mp2975_set_phase_rail1(struct pmbus_driver_info *info) +{ + int i; + + for (i = 0 ; i < info->phases[0]; i++) + info->pfunc[i] = PMBUS_HAVE_IOUT; +} + +static void +mp2975_set_phase_rail2(struct pmbus_driver_info *info, int num_phases) +{ + int i; + + /* Set phases for rail 2 from upper to lower. */ + for (i = 1; i <= num_phases; i++) + info->pfunc[MP2975_MAX_PHASE_RAIL1 - i] = PMBUS_HAVE_IOUT; +} + +static int +mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int num_phases2, ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + /* Identify multiphase for rail 1 - could be from 1 to 8. */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R1); + if (ret <= 0) + return ret; + + info->phases[0] = ret & GENMASK(3, 0); + + /* + * The device provides a total of 8 PWM pins, and can be configured + * to different phase count applications for rail 1 and rail 2. + * Rail 1 can be set to 8 phases, while rail 2 can only be set to 4 + * phases at most. When rail 1’s phase count is configured as 0, rail + * 1 operates with 1-phase DCM. When rail 2 phase count is configured + * as 0, rail 2 is disabled. + */ + if (info->phases[0] > MP2975_MAX_PHASE_RAIL1) + return -EINVAL; + + mp2975_set_phase_rail1(info); + num_phases2 = min(MP2975_MAX_PHASE_RAIL1 - info->phases[0], + MP2975_MAX_PHASE_RAIL2); + if (info->phases[1] && info->phases[1] <= num_phases2) + mp2975_set_phase_rail2(info, num_phases2); + + return 0; +} + +static int +mp2975_identify_vid(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info, u32 reg, int page, + u32 imvp_bit, u32 vr_bit) +{ + int ret; + + /* Identify VID mode and step selection. */ + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + + if (ret & imvp_bit) { + info->vrm_version[page] = imvp9; + data->vid_step[page] = MP2975_PROT_DEV_OV_OFF; + } else if (ret & vr_bit) { + info->vrm_version[page] = vr12; + data->vid_step[page] = MP2975_PROT_DEV_OV_ON; + } else { + info->vrm_version[page] = vr13; + data->vid_step[page] = MP2975_PROT_DEV_OV_OFF; + } + + return 0; +} + +static int +mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + /* Identify VID mode for rail 1. */ + ret = mp2975_identify_vid(client, data, info, + MP2975_MFR_VR_MULTI_CONFIG_R1, 0, + MP2975_IMVP9_EN_R1, MP2975_VID_STEP_SEL_R1); + if (ret < 0) + return ret; + + /* Identify VID mode for rail 2, if connected. */ + if (info->phases[1]) + ret = mp2975_identify_vid(client, data, info, + MP2975_MFR_VR_MULTI_CONFIG_R2, 1, + MP2975_IMVP9_EN_R2, + MP2975_VID_STEP_SEL_R2); + return ret; +} + +static int +mp2975_current_sense_gain_get(struct i2c_client *client, + struct mp2975_data *data) +{ + int i, ret; + + /* + * Obtain DrMOS current sense gain of power stage from the register + * MP2975_MFR_VR_CONFIG1, bits 13-12. The value is selected as below: + * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. Other + * values are invalid. + */ + for (i = 0 ; i < data->info.pages; i++) { + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); + if (ret < 0) + return ret; + ret = i2c_smbus_read_word_data(client, + MP2975_MFR_VR_CONFIG1); + if (ret < 0) + return ret; + + switch ((ret & MP2975_DRMOS_KCS) >> 12) { + case 0: + data->curr_sense_gain[i] = 50; + break; + case 1: + data->curr_sense_gain[i] = 85; + break; + case 2: + data->curr_sense_gain[i] = 97; + break; + default: + data->curr_sense_gain[i] = 100; + break; + } + } + + return 0; +} + +static int +mp2975_vref_get(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 3); + if (ret < 0) + return ret; + + /* Get voltage reference value for rail 1. */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_READ_VREF_R1); + if (ret < 0) + return ret; + + data->vref[0] = ret * data->vid_step[0]; + + /* Get voltage reference value for rail 2, if connected. */ + if (data->info.pages == MP2975_PAGE_NUM) { + ret = i2c_smbus_read_word_data(client, MP2975_MFR_READ_VREF_R2); + if (ret < 0) + return ret; + + data->vref[1] = ret * data->vid_step[1]; + } + return 0; +} + +static int +mp2975_vref_offset_get(struct i2c_client *client, struct mp2975_data *data, + int page) +{ + int ret; + + ret = i2c_smbus_read_word_data(client, MP2975_MFR_OVP_TH_SET); + if (ret < 0) + return ret; + + switch ((ret & GENMASK(5, 3)) >> 3) { + case 1: + data->vref_off[page] = 140; + break; + case 2: + data->vref_off[page] = 220; + break; + case 4: + data->vref_off[page] = 400; + break; + default: + return -EINVAL; + } + return 0; +} + +static int +mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info, int page) +{ + int ret; + + /* Get maximum reference voltage of VID-DAC in VID format. */ + ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_MAX); + if (ret < 0) + return ret; + + data->vout_max[page] = mp2975_vid2direct(info->vrm_version[page], ret & + GENMASK(8, 0)); + return 0; +} + +static int +mp2975_identify_vout_format(struct i2c_client *client, + struct mp2975_data *data, int page) +{ + int ret; + + ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL); + if (ret < 0) + return ret; + + if (ret & MP2975_VOUT_FORMAT) + data->vout_format[page] = vid; + else + data->vout_format[page] = direct; + return 0; +} + +static int +mp2975_vout_ov_scale_get(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int thres_dev, sense_ampl, ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + if (ret < 0) + return ret; + + /* + * Get divider for over- and under-voltage protection thresholds + * configuration from the Advanced Options of Auto Phase Shedding and + * decay register. + */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_APS_DECAY_ADV); + if (ret < 0) + return ret; + thres_dev = ret & MP2975_PRT_THRES_DIV_OV_EN ? MP2975_PROT_DEV_OV_ON : + MP2975_PROT_DEV_OV_OFF; + + /* Select the gain of remote sense amplifier. */ + ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_SCALE_LOOP); + if (ret < 0) + return ret; + sense_ampl = ret & MP2975_SENSE_AMPL ? MP2975_SENSE_AMPL_HALF : + MP2975_SENSE_AMPL_UNIT; + + data->vout_scale = sense_ampl * thres_dev; + + return 0; +} + +static int +mp2975_vout_per_rail_config_get(struct i2c_client *client, + struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int i, ret; + + for (i = 0; i < data->info.pages; i++) { + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); + if (ret < 0) + return ret; + + /* Obtain voltage reference offsets. */ + ret = mp2975_vref_offset_get(client, data, i); + if (ret < 0) + return ret; + + /* Obtain maximum voltage values. */ + ret = mp2975_vout_max_get(client, data, info, i); + if (ret < 0) + return ret; + + /* + * Get VOUT format for READ_VOUT command : VID or direct. + * Pages on same device can be configured with different + * formats. + */ + ret = mp2975_identify_vout_format(client, data, i); + if (ret < 0) + return ret; + + /* + * Set over-voltage fixed value. Thresholds are provided as + * fixed value, and tracking value. The minimum of them are + * exposed as over-voltage critical threshold. + */ + data->vout_ov_fixed[i] = data->vref[i] + + DIV_ROUND_CLOSEST(data->vref_off[i] * + data->vout_scale, + 10); + } + + return 0; +} + +static struct pmbus_driver_info mp2975_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .m[PSC_TEMPERATURE] = 1, + .m[PSC_VOLTAGE_OUT] = 1, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_CURRENT_OUT] = 1, + .m[PSC_POWER] = 1, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT | + PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL, + .read_byte_data = mp2975_read_byte_data, + .read_word_data = mp2975_read_word_data, +}; + +static int mp2975_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + struct mp2975_data *data; + int ret; + + data = devm_kzalloc(&client->dev, sizeof(struct mp2975_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + memcpy(&data->info, &mp2975_info, sizeof(*info)); + info = &data->info; + + /* Identify multiphase configuration for rail 2. */ + ret = mp2975_identify_multiphase_rail2(client); + if (ret < 0) + return ret; + + if (ret) { + /* Two rails are connected. */ + data->info.pages = MP2975_PAGE_NUM; + data->info.phases[1] = ret; + data->info.func[1] = MP2975_RAIL2_FUNC; + } + + /* Identify multiphase configuration. */ + ret = mp2975_identify_multiphase(client, data, info); + if (ret) + return ret; + + /* Identify VID setting per rail. */ + ret = mp2975_identify_rails_vid(client, data, info); + if (ret < 0) + return ret; + + /* Obtain current sense gain of power stage. */ + ret = mp2975_current_sense_gain_get(client, data); + if (ret) + return ret; + + /* Obtain voltage reference values. */ + ret = mp2975_vref_get(client, data, info); + if (ret) + return ret; + + /* Obtain vout over-voltage scales. */ + ret = mp2975_vout_ov_scale_get(client, data, info); + if (ret < 0) + return ret; + + /* Obtain offsets, maximum and format for vout. */ + ret = mp2975_vout_per_rail_config_get(client, data, info); + if (ret) + return ret; + + return pmbus_do_probe(client, info); +} + +static const struct i2c_device_id mp2975_id[] = { + {"mp2975", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mp2975_id); + +static const struct of_device_id __maybe_unused mp2975_of_match[] = { + {.compatible = "mps,mp2975"}, + {} +}; +MODULE_DEVICE_TABLE(of, mp2975_of_match); + +static struct i2c_driver mp2975_driver = { + .driver = { + .name = "mp2975", + .of_match_table = of_match_ptr(mp2975_of_match), + }, + .probe_new = mp2975_probe, + .remove = pmbus_do_remove, + .id_table = mp2975_id, +}; + +module_i2c_driver(mp2975_driver); + +MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>"); +MODULE_DESCRIPTION("PMBus driver for MPS MP2975 device"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 6d384e8ee1db..20f1af9165c2 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -20,6 +20,8 @@ struct pmbus_device_info { u32 flags; }; +static const struct i2c_device_id pmbus_id[]; + /* * Find sensor groups and status registers on each page. */ @@ -159,8 +161,7 @@ abort: return ret; } -static int pmbus_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pmbus_probe(struct i2c_client *client) { struct pmbus_driver_info *info; struct pmbus_platform_data *pdata = NULL; @@ -171,7 +172,7 @@ static int pmbus_probe(struct i2c_client *client, if (!info) return -ENOMEM; - device_info = (struct pmbus_device_info *)id->driver_data; + device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data; if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) { pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data), GFP_KERNEL); @@ -185,7 +186,7 @@ static int pmbus_probe(struct i2c_client *client, info->identify = pmbus_identify; dev->platform_data = pdata; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct pmbus_device_info pmbus_info_one = { @@ -236,7 +237,7 @@ static struct i2c_driver pmbus_driver = { .driver = { .name = "pmbus", }, - .probe = pmbus_probe, + .probe_new = pmbus_probe, .remove = pmbus_do_remove, .id_table = pmbus_id, }; diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 18e06fc6c53f..88a5df2633fb 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -119,9 +119,22 @@ enum pmbus_regs { PMBUS_MFR_DATE = 0x9D, PMBUS_MFR_SERIAL = 0x9E, + PMBUS_MFR_VIN_MIN = 0xA0, + PMBUS_MFR_VIN_MAX = 0xA1, + PMBUS_MFR_IIN_MAX = 0xA2, + PMBUS_MFR_PIN_MAX = 0xA3, + PMBUS_MFR_VOUT_MIN = 0xA4, + PMBUS_MFR_VOUT_MAX = 0xA5, + PMBUS_MFR_IOUT_MAX = 0xA6, + PMBUS_MFR_POUT_MAX = 0xA7, + PMBUS_IC_DEVICE_ID = 0xAD, PMBUS_IC_DEVICE_REV = 0xAE, + PMBUS_MFR_MAX_TEMP_1 = 0xC0, + PMBUS_MFR_MAX_TEMP_2 = 0xC1, + PMBUS_MFR_MAX_TEMP_3 = 0xC2, + /* * Virtual registers. * Useful to support attributes which are not supported by standard PMBus @@ -476,8 +489,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, void pmbus_clear_faults(struct i2c_client *client); bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); -int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, - struct pmbus_driver_info *info); +int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); int pmbus_do_remove(struct i2c_client *client); const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 44535add3a4a..a0842d5ae950 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -16,7 +16,6 @@ #include <linux/i2c.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> -#include <linux/jiffies.h> #include <linux/pmbus.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> @@ -27,21 +26,6 @@ * with each call to krealloc */ #define PMBUS_ATTR_ALLOC_SIZE 32 - -/* - * Index into status register array, per status register group - */ -#define PB_STATUS_BASE 0 -#define PB_STATUS_VOUT_BASE (PB_STATUS_BASE + PMBUS_PAGES) -#define PB_STATUS_IOUT_BASE (PB_STATUS_VOUT_BASE + PMBUS_PAGES) -#define PB_STATUS_FAN_BASE (PB_STATUS_IOUT_BASE + PMBUS_PAGES) -#define PB_STATUS_FAN34_BASE (PB_STATUS_FAN_BASE + PMBUS_PAGES) -#define PB_STATUS_TEMP_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES) -#define PB_STATUS_INPUT_BASE (PB_STATUS_TEMP_BASE + PMBUS_PAGES) -#define PB_STATUS_VMON_BASE (PB_STATUS_INPUT_BASE + 1) - -#define PB_NUM_STATUS_REG (PB_STATUS_VMON_BASE + 1) - #define PMBUS_NAME_SIZE 24 struct pmbus_sensor { @@ -77,6 +61,21 @@ struct pmbus_label { #define to_pmbus_label(_attr) \ container_of(_attr, struct pmbus_label, attribute) +/* Macros for converting between sensor index and register/page/status mask */ + +#define PB_STATUS_MASK 0xffff +#define PB_REG_SHIFT 16 +#define PB_REG_MASK 0x3ff +#define PB_PAGE_SHIFT 26 +#define PB_PAGE_MASK 0x3f + +#define pb_reg_to_index(page, reg, mask) (((page) << PB_PAGE_SHIFT) | \ + ((reg) << PB_REG_SHIFT) | (mask)) + +#define pb_index_to_page(index) (((index) >> PB_PAGE_SHIFT) & PB_PAGE_MASK) +#define pb_index_to_reg(index) (((index) >> PB_REG_SHIFT) & PB_REG_MASK) +#define pb_index_to_mask(index) ((index) & PB_STATUS_MASK) + struct pmbus_data { struct device *dev; struct device *hwmon_dev; @@ -97,14 +96,6 @@ struct pmbus_data { struct pmbus_sensor *sensors; struct mutex update_lock; - bool valid; - unsigned long last_updated; /* in jiffies */ - - /* - * A single status register covers multiple attributes, - * so we keep them all together. - */ - u16 status[PB_NUM_STATUS_REG]; bool has_status_word; /* device uses STATUS_WORD register */ int (*read_status)(struct i2c_client *client, int page); @@ -143,8 +134,10 @@ static const int pmbus_fan_command_registers[] = { void pmbus_clear_cache(struct i2c_client *client) { struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *sensor; - data->valid = false; + for (sensor = data->sensors; sensor; sensor = sensor->next) + sensor->data = -ENODATA; } EXPORT_SYMBOL_GPL(pmbus_clear_cache); @@ -560,68 +553,29 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client) } EXPORT_SYMBOL_GPL(pmbus_get_driver_info); -static struct _pmbus_status { - u32 func; - u16 base; - u16 reg; -} pmbus_status[] = { - { PMBUS_HAVE_STATUS_VOUT, PB_STATUS_VOUT_BASE, PMBUS_STATUS_VOUT }, - { PMBUS_HAVE_STATUS_IOUT, PB_STATUS_IOUT_BASE, PMBUS_STATUS_IOUT }, - { PMBUS_HAVE_STATUS_TEMP, PB_STATUS_TEMP_BASE, - PMBUS_STATUS_TEMPERATURE }, - { PMBUS_HAVE_STATUS_FAN12, PB_STATUS_FAN_BASE, PMBUS_STATUS_FAN_12 }, - { PMBUS_HAVE_STATUS_FAN34, PB_STATUS_FAN34_BASE, PMBUS_STATUS_FAN_34 }, -}; - -static struct pmbus_data *pmbus_update_device(struct device *dev) +static int pmbus_get_status(struct i2c_client *client, int page, int reg) { - struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_data *data = i2c_get_clientdata(client); - const struct pmbus_driver_info *info = data->info; - struct pmbus_sensor *sensor; - - mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - int i, j; - - for (i = 0; i < info->pages; i++) { - data->status[PB_STATUS_BASE + i] - = data->read_status(client, i); - for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) { - struct _pmbus_status *s = &pmbus_status[j]; - - if (!(info->func[i] & s->func)) - continue; - data->status[s->base + i] - = _pmbus_read_byte_data(client, i, - s->reg); - } - } + int status; - if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) - data->status[PB_STATUS_INPUT_BASE] - = _pmbus_read_byte_data(client, 0, - PMBUS_STATUS_INPUT); - - if (info->func[0] & PMBUS_HAVE_STATUS_VMON) - data->status[PB_STATUS_VMON_BASE] - = _pmbus_read_byte_data(client, 0, - PMBUS_VIRT_STATUS_VMON); - - for (sensor = data->sensors; sensor; sensor = sensor->next) { - if (!data->valid || sensor->update) - sensor->data - = _pmbus_read_word_data(client, - sensor->page, - sensor->phase, - sensor->reg); - } - pmbus_clear_faults(client); - data->last_updated = jiffies; - data->valid = 1; + switch (reg) { + case PMBUS_STATUS_WORD: + status = data->read_status(client, page); + break; + default: + status = _pmbus_read_byte_data(client, page, reg); + break; } - mutex_unlock(&data->update_lock); - return data; + if (status < 0) + pmbus_clear_faults(client); + return status; +} + +static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sensor *sensor) +{ + if (sensor->data < 0 || sensor->update) + sensor->data = _pmbus_read_word_data(client, sensor->page, + sensor->phase, sensor->reg); } /* @@ -919,38 +873,51 @@ static u16 pmbus_data2reg(struct pmbus_data *data, * If a negative value is stored in any of the referenced registers, this value * reflects an error code which will be returned. */ -static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b, +static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, int index) { + struct pmbus_data *data = i2c_get_clientdata(client); struct pmbus_sensor *s1 = b->s1; struct pmbus_sensor *s2 = b->s2; - u16 reg = (index >> 16) & 0xffff; - u16 mask = index & 0xffff; + u16 mask = pb_index_to_mask(index); + u8 page = pb_index_to_page(index); + u16 reg = pb_index_to_reg(index); int ret, status; u16 regval; - status = data->status[reg]; - if (status < 0) - return status; + mutex_lock(&data->update_lock); + status = pmbus_get_status(client, page, reg); + if (status < 0) { + ret = status; + goto unlock; + } + + if (s1) + pmbus_update_sensor_data(client, s1); + if (s2) + pmbus_update_sensor_data(client, s2); regval = status & mask; - if (!s1 && !s2) { - ret = !!regval; - } else if (!s1 || !s2) { - WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2); - return 0; - } else { + if (s1 && s2) { s64 v1, v2; - if (s1->data < 0) - return s1->data; - if (s2->data < 0) - return s2->data; + if (s1->data < 0) { + ret = s1->data; + goto unlock; + } + if (s2->data < 0) { + ret = s2->data; + goto unlock; + } v1 = pmbus_reg2data(data, s1); v2 = pmbus_reg2data(data, s2); ret = !!(regval && v1 >= v2); + } else { + ret = !!regval; } +unlock: + mutex_unlock(&data->update_lock); return ret; } @@ -959,10 +926,10 @@ static ssize_t pmbus_show_boolean(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct pmbus_boolean *boolean = to_pmbus_boolean(attr); - struct pmbus_data *data = pmbus_update_device(dev); + struct i2c_client *client = to_i2c_client(dev->parent); int val; - val = pmbus_get_boolean(data, boolean, attr->index); + val = pmbus_get_boolean(client, boolean, attr->index); if (val < 0) return val; return snprintf(buf, PAGE_SIZE, "%d\n", val); @@ -971,9 +938,11 @@ static ssize_t pmbus_show_boolean(struct device *dev, static ssize_t pmbus_show_sensor(struct device *dev, struct device_attribute *devattr, char *buf) { - struct pmbus_data *data = pmbus_update_device(dev); + struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + pmbus_update_sensor_data(client, sensor); if (sensor->data < 0) return sensor->data; @@ -1068,11 +1037,14 @@ static int pmbus_add_boolean(struct pmbus_data *data, const char *name, const char *type, int seq, struct pmbus_sensor *s1, struct pmbus_sensor *s2, - u16 reg, u16 mask) + u8 page, u16 reg, u16 mask) { struct pmbus_boolean *boolean; struct sensor_device_attribute *a; + if (WARN((s1 && !s2) || (!s1 && s2), "Bad s1/s2 parameters\n")) + return -EINVAL; + boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); if (!boolean) return -ENOMEM; @@ -1084,7 +1056,7 @@ static int pmbus_add_boolean(struct pmbus_data *data, boolean->s1 = s1; boolean->s2 = s2; pmbus_attr_init(a, boolean->name, 0444, pmbus_show_boolean, NULL, - (reg << 16) | mask); + pb_reg_to_index(page, reg, mask)); return pmbus_add_attribute(data, &a->dev_attr.attr); } @@ -1121,6 +1093,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, sensor->class = class; sensor->update = update; sensor->convert = convert; + sensor->data = -ENODATA; pmbus_dev_attr_init(a, sensor->name, readonly ? 0444 : 0644, pmbus_show_sensor, pmbus_set_sensor); @@ -1201,7 +1174,7 @@ struct pmbus_sensor_attr { bool compare; /* true if compare function needed */ u32 func; /* sensor mask */ u32 sfunc; /* sensor status mask */ - int sbase; /* status base register */ + int sreg; /* status register */ const struct pmbus_limit_attr *limit;/* limit registers */ }; @@ -1239,7 +1212,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client, : NULL, attr->compare ? l->low ? base : curr : NULL, - attr->sbase + page, l->sbit); + page, attr->sreg, l->sbit); if (ret) return ret; have_alarm = 1; @@ -1289,7 +1262,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, pmbus_check_status_register(client, page)) { ret = pmbus_add_boolean(data, name, "alarm", index, NULL, NULL, - PB_STATUS_BASE + page, + page, PMBUS_STATUS_WORD, attr->gbit); if (ret) return ret; @@ -1404,6 +1377,12 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_VIN_HISTORY, .attr = "reset_history", + }, { + .reg = PMBUS_MFR_VIN_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VIN_MAX, + .attr = "rated_max", }, }; @@ -1467,7 +1446,13 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_VOUT_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VOUT_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr voltage_attributes[] = { @@ -1477,7 +1462,7 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .label = "vin", .func = PMBUS_HAVE_VIN, .sfunc = PMBUS_HAVE_STATUS_INPUT, - .sbase = PB_STATUS_INPUT_BASE, + .sreg = PMBUS_STATUS_INPUT, .gbit = PB_STATUS_VIN_UV, .limit = vin_limit_attrs, .nlimit = ARRAY_SIZE(vin_limit_attrs), @@ -1487,7 +1472,7 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .label = "vmon", .func = PMBUS_HAVE_VMON, .sfunc = PMBUS_HAVE_STATUS_VMON, - .sbase = PB_STATUS_VMON_BASE, + .sreg = PMBUS_VIRT_STATUS_VMON, .limit = vmon_limit_attrs, .nlimit = ARRAY_SIZE(vmon_limit_attrs), }, { @@ -1502,7 +1487,7 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .paged = true, .func = PMBUS_HAVE_VOUT, .sfunc = PMBUS_HAVE_STATUS_VOUT, - .sbase = PB_STATUS_VOUT_BASE, + .sreg = PMBUS_STATUS_VOUT, .gbit = PB_STATUS_VOUT_OV, .limit = vout_limit_attrs, .nlimit = ARRAY_SIZE(vout_limit_attrs), @@ -1537,7 +1522,10 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_IIN_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_IIN_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr iout_limit_attrs[] = { @@ -1571,7 +1559,10 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_IOUT_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr current_attributes[] = { @@ -1581,7 +1572,7 @@ static const struct pmbus_sensor_attr current_attributes[] = { .label = "iin", .func = PMBUS_HAVE_IIN, .sfunc = PMBUS_HAVE_STATUS_INPUT, - .sbase = PB_STATUS_INPUT_BASE, + .sreg = PMBUS_STATUS_INPUT, .gbit = PB_STATUS_INPUT, .limit = iin_limit_attrs, .nlimit = ARRAY_SIZE(iin_limit_attrs), @@ -1592,7 +1583,7 @@ static const struct pmbus_sensor_attr current_attributes[] = { .paged = true, .func = PMBUS_HAVE_IOUT, .sfunc = PMBUS_HAVE_STATUS_IOUT, - .sbase = PB_STATUS_IOUT_BASE, + .sreg = PMBUS_STATUS_IOUT, .gbit = PB_STATUS_IOUT_OC, .limit = iout_limit_attrs, .nlimit = ARRAY_SIZE(iout_limit_attrs), @@ -1622,7 +1613,10 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_PIN_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_PIN_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr pout_limit_attrs[] = { @@ -1656,7 +1650,10 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_POUT_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_POUT_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr power_attributes[] = { @@ -1666,7 +1663,7 @@ static const struct pmbus_sensor_attr power_attributes[] = { .label = "pin", .func = PMBUS_HAVE_PIN, .sfunc = PMBUS_HAVE_STATUS_INPUT, - .sbase = PB_STATUS_INPUT_BASE, + .sreg = PMBUS_STATUS_INPUT, .gbit = PB_STATUS_INPUT, .limit = pin_limit_attrs, .nlimit = ARRAY_SIZE(pin_limit_attrs), @@ -1677,7 +1674,7 @@ static const struct pmbus_sensor_attr power_attributes[] = { .paged = true, .func = PMBUS_HAVE_POUT, .sfunc = PMBUS_HAVE_STATUS_IOUT, - .sbase = PB_STATUS_IOUT_BASE, + .sreg = PMBUS_STATUS_IOUT, .limit = pout_limit_attrs, .nlimit = ARRAY_SIZE(pout_limit_attrs), } @@ -1720,7 +1717,10 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_MAX_TEMP_1, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr temp_limit_attrs2[] = { @@ -1758,7 +1758,10 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = { }, { .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_MAX_TEMP_2, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr temp_limit_attrs3[] = { @@ -1784,7 +1787,10 @@ static const struct pmbus_limit_attr temp_limit_attrs3[] = { .attr = "crit", .alarm = "crit_alarm", .sbit = PB_TEMP_OT_FAULT, - } + }, { + .reg = PMBUS_MFR_MAX_TEMP_3, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr temp_attributes[] = { @@ -1796,7 +1802,7 @@ static const struct pmbus_sensor_attr temp_attributes[] = { .compare = true, .func = PMBUS_HAVE_TEMP, .sfunc = PMBUS_HAVE_STATUS_TEMP, - .sbase = PB_STATUS_TEMP_BASE, + .sreg = PMBUS_STATUS_TEMPERATURE, .gbit = PB_STATUS_TEMPERATURE, .limit = temp_limit_attrs, .nlimit = ARRAY_SIZE(temp_limit_attrs), @@ -1808,7 +1814,7 @@ static const struct pmbus_sensor_attr temp_attributes[] = { .compare = true, .func = PMBUS_HAVE_TEMP2, .sfunc = PMBUS_HAVE_STATUS_TEMP, - .sbase = PB_STATUS_TEMP_BASE, + .sreg = PMBUS_STATUS_TEMPERATURE, .gbit = PB_STATUS_TEMPERATURE, .limit = temp_limit_attrs2, .nlimit = ARRAY_SIZE(temp_limit_attrs2), @@ -1820,7 +1826,7 @@ static const struct pmbus_sensor_attr temp_attributes[] = { .compare = true, .func = PMBUS_HAVE_TEMP3, .sfunc = PMBUS_HAVE_STATUS_TEMP, - .sbase = PB_STATUS_TEMP_BASE, + .sreg = PMBUS_STATUS_TEMPERATURE, .gbit = PB_STATUS_TEMPERATURE, .limit = temp_limit_attrs3, .nlimit = ARRAY_SIZE(temp_limit_attrs3), @@ -1945,19 +1951,19 @@ static int pmbus_add_fan_attributes(struct i2c_client *client, if ((info->func[page] & pmbus_fan_status_flags[f]) && pmbus_check_byte_register(client, page, pmbus_fan_status_registers[f])) { - int base; + int reg; if (f > 1) /* fan 3, 4 */ - base = PB_STATUS_FAN34_BASE + page; + reg = PMBUS_STATUS_FAN_34; else - base = PB_STATUS_FAN_BASE + page; + reg = PMBUS_STATUS_FAN_12; ret = pmbus_add_boolean(data, "fan", - "alarm", index, NULL, NULL, base, + "alarm", index, NULL, NULL, page, reg, PB_FAN_FAN1_WARNING >> (f & 1)); if (ret) return ret; ret = pmbus_add_boolean(data, "fan", - "fault", index, NULL, NULL, base, + "fault", index, NULL, NULL, page, reg, PB_FAN_FAN1_FAULT >> (f & 1)); if (ret) return ret; @@ -2346,6 +2352,42 @@ static int pmbus_debugfs_get_status(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status, NULL, "0x%04llx\n"); +static int pmbus_debugfs_get_pec(void *data, u64 *val) +{ + struct i2c_client *client = data; + + *val = !!(client->flags & I2C_CLIENT_PEC); + + return 0; +} + +static int pmbus_debugfs_set_pec(void *data, u64 val) +{ + int rc; + struct i2c_client *client = data; + + if (!val) { + client->flags &= ~I2C_CLIENT_PEC; + return 0; + } + + if (val != 1) + return -EINVAL; + + rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (rc < 0) + return rc; + + if (!(rc & PB_CAPABILITY_ERROR_CHECK)) + return -EOPNOTSUPP; + + client->flags |= I2C_CLIENT_PEC; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec, + pmbus_debugfs_set_pec, "%llu\n"); + static int pmbus_init_debugfs(struct i2c_client *client, struct pmbus_data *data) { @@ -2374,6 +2416,9 @@ static int pmbus_init_debugfs(struct i2c_client *client, if (!entries) return -ENOMEM; + debugfs_create_file("pec", 0664, data->debugfs, client, + &pmbus_debugfs_ops_pec); + for (i = 0; i < data->info->pages; ++i) { /* Check accessibility of status register if it's not page 0 */ if (!i || pmbus_check_status_register(client, i)) { @@ -2488,8 +2533,7 @@ static int pmbus_init_debugfs(struct i2c_client *client, } #endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ -int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, - struct pmbus_driver_info *info) +int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) { struct device *dev = &client->dev; const struct pmbus_platform_data *pdata = dev_get_platdata(dev); diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c index 517584cff3de..fa5c5dd29b7a 100644 --- a/drivers/hwmon/pmbus/pxe1610.c +++ b/drivers/hwmon/pmbus/pxe1610.c @@ -78,8 +78,7 @@ static struct pmbus_driver_info pxe1610_info = { .identify = pxe1610_identify, }; -static int pxe1610_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pxe1610_probe(struct i2c_client *client) { struct pmbus_driver_info *info; u8 buf[I2C_SMBUS_BLOCK_MAX]; @@ -115,7 +114,7 @@ static int pxe1610_probe(struct i2c_client *client, if (!info) return -ENOMEM; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id pxe1610_id[] = { @@ -131,7 +130,7 @@ static struct i2c_driver pxe1610_driver = { .driver = { .name = "pxe1610", }, - .probe = pxe1610_probe, + .probe_new = pxe1610_probe, .remove = pmbus_do_remove, .id_table = pxe1610_id, }; diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c index 2b83dcda964a..edbdfa809d51 100644 --- a/drivers/hwmon/pmbus/tps40422.c +++ b/drivers/hwmon/pmbus/tps40422.c @@ -25,10 +25,9 @@ static struct pmbus_driver_info tps40422_info = { | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, }; -static int tps40422_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tps40422_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &tps40422_info); + return pmbus_do_probe(client, &tps40422_info); } static const struct i2c_device_id tps40422_id[] = { @@ -43,7 +42,7 @@ static struct i2c_driver tps40422_driver = { .driver = { .name = "tps40422", }, - .probe = tps40422_probe, + .probe_new = tps40422_probe, .remove = pmbus_do_remove, .id_table = tps40422_id, }; diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 157c99ffb52b..db2bdf2a1f02 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -34,6 +34,8 @@ enum chips { #define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ +static const struct i2c_device_id tps53679_id[]; + static int tps53679_identify_mode(struct i2c_client *client, struct pmbus_driver_info *info) { @@ -183,8 +185,7 @@ static struct pmbus_driver_info tps53679_info = { .pfunc[5] = PMBUS_HAVE_IOUT, }; -static int tps53679_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tps53679_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct pmbus_driver_info *info; @@ -193,7 +194,7 @@ static int tps53679_probe(struct i2c_client *client, if (dev->of_node) chip_id = (enum chips)of_device_get_match_data(dev); else - chip_id = id->driver_data; + chip_id = i2c_match_id(tps53679_id, client)->driver_data; info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); if (!info) @@ -220,7 +221,7 @@ static int tps53679_probe(struct i2c_client *client, return -ENODEV; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id tps53679_id[] = { @@ -249,7 +250,7 @@ static struct i2c_driver tps53679_driver = { .name = "tps53679", .of_match_table = of_match_ptr(tps53679_of_match), }, - .probe = tps53679_probe, + .probe_new = tps53679_probe, .remove = pmbus_do_remove, .id_table = tps53679_id, }; diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 81f4c4f166cd..f8017993e2b4 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -487,8 +487,7 @@ static int ucd9000_init_debugfs(struct i2c_client *client, } #endif /* CONFIG_DEBUG_FS */ -static int ucd9000_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ucd9000_probe(struct i2c_client *client) { u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; struct ucd9000_data *data; @@ -523,12 +522,12 @@ static int ucd9000_probe(struct i2c_client *client, if (client->dev.of_node) chip = (enum chips)of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = mid->driver_data; - if (chip != ucd9000 && chip != mid->driver_data) + if (chip != ucd9000 && strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), GFP_KERNEL); @@ -603,7 +602,7 @@ static int ucd9000_probe(struct i2c_client *client, ucd9000_probe_gpio(client, mid, data); - ret = pmbus_do_probe(client, mid, info); + ret = pmbus_do_probe(client, info); if (ret) return ret; @@ -621,7 +620,7 @@ static struct i2c_driver ucd9000_driver = { .name = "ucd9000", .of_match_table = of_match_ptr(ucd9000_of_match), }, - .probe = ucd9000_probe, + .probe_new = ucd9000_probe, .remove = pmbus_do_remove, .id_table = ucd9000_id, }; diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index 7c04745a9709..e111e25e1619 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -71,8 +71,7 @@ static const struct of_device_id __maybe_unused ucd9200_of_match[] = { }; MODULE_DEVICE_TABLE(of, ucd9200_of_match); -static int ucd9200_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ucd9200_probe(struct i2c_client *client) { u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; struct pmbus_driver_info *info; @@ -106,12 +105,12 @@ static int ucd9200_probe(struct i2c_client *client, if (client->dev.of_node) chip = (enum chips)of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = mid->driver_data; - if (chip != ucd9200 && chip != mid->driver_data) + if (chip != ucd9200 && strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); @@ -192,7 +191,7 @@ static int ucd9200_probe(struct i2c_client *client, if (mid->driver_data == ucd9240) info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12; - return pmbus_do_probe(client, mid, info); + return pmbus_do_probe(client, info); } /* This is the driver that will be inserted */ @@ -201,7 +200,7 @@ static struct i2c_driver ucd9200_driver = { .name = "ucd9200", .of_match_table = of_match_ptr(ucd9200_of_match), }, - .probe = ucd9200_probe, + .probe_new = ucd9200_probe, .remove = pmbus_do_remove, .id_table = ucd9200_id, }; diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c index d5103fc9e269..c95ac934fde4 100644 --- a/drivers/hwmon/pmbus/xdpe12284.c +++ b/drivers/hwmon/pmbus/xdpe12284.c @@ -127,8 +127,7 @@ static struct pmbus_driver_info xdpe122_info = { .read_word_data = xdpe122_read_word_data, }; -static int xdpe122_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int xdpe122_probe(struct i2c_client *client) { struct pmbus_driver_info *info; @@ -137,7 +136,7 @@ static int xdpe122_probe(struct i2c_client *client, if (!info) return -ENOMEM; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id xdpe122_id[] = { @@ -160,7 +159,7 @@ static struct i2c_driver xdpe122_driver = { .name = "xdpe12284", .of_match_table = of_match_ptr(xdpe122_of_match), }, - .probe = xdpe122_probe, + .probe_new = xdpe122_probe, .remove = pmbus_do_remove, .id_table = xdpe122_id, }; diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index 3a827d0a881d..e8bda340482b 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -301,8 +301,7 @@ static const struct i2c_device_id zl6100_id[] = { }; MODULE_DEVICE_TABLE(i2c, zl6100_id); -static int zl6100_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int zl6100_probe(struct i2c_client *client) { int ret; struct zl6100_data *data; @@ -333,10 +332,10 @@ static int zl6100_probe(struct i2c_client *client, dev_err(&client->dev, "Unsupported device\n"); return -ENODEV; } - if (id->driver_data != mid->driver_data) + if (strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data), GFP_KERNEL); @@ -389,14 +388,14 @@ static int zl6100_probe(struct i2c_client *client, info->write_word_data = zl6100_write_word_data; info->write_byte = zl6100_write_byte; - return pmbus_do_probe(client, mid, info); + return pmbus_do_probe(client, info); } static struct i2c_driver zl6100_driver = { .driver = { .name = "zl6100", }, - .probe = zl6100_probe, + .probe_new = zl6100_probe, .remove = pmbus_do_remove, .id_table = zl6100_id, }; diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c index a5d1a890d0be..9e086338dcba 100644 --- a/drivers/hwmon/powr1220.c +++ b/drivers/hwmon/powr1220.c @@ -297,8 +297,7 @@ static struct attribute *powr1220_attrs[] = { ATTRIBUTE_GROUPS(powr1220); -static int powr1220_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int powr1220_probe(struct i2c_client *client) { struct powr1220_data *data; struct device *hwmon_dev; @@ -331,7 +330,7 @@ static struct i2c_driver powr1220_driver = { .driver = { .name = "powr1220", }, - .probe = powr1220_probe, + .probe_new = powr1220_probe, .id_table = powr1220_ids, }; diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 17bb64299bfd..bdba2143021a 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -293,14 +293,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); - if (IS_ERR(ctx->pwm)) { - ret = PTR_ERR(ctx->pwm); - - if (ret != -EPROBE_DEFER) - dev_err(dev, "Could not get PWM: %d\n", ret); - - return ret; - } + if (IS_ERR(ctx->pwm)) + return dev_err_probe(dev, PTR_ERR(ctx->pwm), "Could not get PWM\n"); platform_set_drvdata(pdev, ctx); diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c index d421e691318b..09ce30cba54b 100644 --- a/drivers/hwmon/scmi-hwmon.c +++ b/drivers/hwmon/scmi-hwmon.c @@ -202,8 +202,10 @@ static int scmi_hwmon_probe(struct scmi_device *sdev) } } - if (nr_count[hwmon_temp]) - nr_count[hwmon_chip]++, nr_types++; + if (nr_count[hwmon_temp]) { + nr_count[hwmon_chip]++; + nr_types++; + } scmi_hwmon_chan = devm_kcalloc(dev, nr_types, sizeof(*scmi_hwmon_chan), GFP_KERNEL); diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index 8ea5534455f2..7d18ce5d3839 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -250,8 +250,7 @@ static struct attribute *sht21_attrs[] = { ATTRIBUTE_GROUPS(sht21); -static int sht21_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sht21_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -286,7 +285,7 @@ MODULE_DEVICE_TABLE(i2c, sht21_id); static struct i2c_driver sht21_driver = { .driver.name = "sht21", - .probe = sht21_probe, + .probe_new = sht21_probe, .id_table = sht21_id, }; diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 7364764baaeb..3f279aa1cee5 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -662,8 +662,9 @@ static struct attribute *sts3x_attrs[] = { ATTRIBUTE_GROUPS(sht3x); ATTRIBUTE_GROUPS(sts3x); -static int sht3x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id sht3x_ids[]; + +static int sht3x_probe(struct i2c_client *client) { int ret; struct sht3x_data *data; @@ -715,7 +716,7 @@ static int sht3x_probe(struct i2c_client *client, if (ret) return ret; - if (id->driver_data == sts3x) + if (i2c_match_id(sht3x_ids, client)->driver_data == sts3x) attribute_groups = sts3x_groups; else attribute_groups = sht3x_groups; @@ -742,7 +743,7 @@ MODULE_DEVICE_TABLE(i2c, sht3x_ids); static struct i2c_driver sht3x_i2c_driver = { .driver.name = "sht3x", - .probe = sht3x_probe, + .probe_new = sht3x_probe, .id_table = sht3x_ids, }; diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c index a0078ccede03..18546ebc8e9f 100644 --- a/drivers/hwmon/shtc1.c +++ b/drivers/hwmon/shtc1.c @@ -14,6 +14,7 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/platform_data/shtc1.h> +#include <linux/of.h> /* commands (high precision mode) */ static const unsigned char shtc1_cmd_measure_blocking_hpm[] = { 0x7C, 0xA2 }; @@ -185,17 +186,19 @@ static void shtc1_select_command(struct shtc1_data *data) } } -static int shtc1_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id shtc1_id[]; + +static int shtc1_probe(struct i2c_client *client) { int ret; u16 id_reg; char id_reg_buf[2]; struct shtc1_data *data; struct device *hwmon_dev; - enum shtcx_chips chip = id->driver_data; + enum shtcx_chips chip = i2c_match_id(shtc1_id, client)->driver_data; struct i2c_adapter *adap = client->adapter; struct device *dev = &client->dev; + struct device_node *np = dev->of_node; if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) { dev_err(dev, "plain i2c transactions not supported\n"); @@ -233,8 +236,14 @@ static int shtc1_probe(struct i2c_client *client, data->client = client; data->chip = chip; - if (client->dev.platform_data) - data->setup = *(struct shtc1_platform_data *)dev->platform_data; + if (np) { + data->setup.blocking_io = of_property_read_bool(np, "sensirion,blocking-io"); + data->setup.high_precision = !of_property_read_bool(np, "sensicon,low-precision"); + } else { + if (client->dev.platform_data) + data->setup = *(struct shtc1_platform_data *)dev->platform_data; + } + shtc1_select_command(data); mutex_init(&data->update_lock); @@ -257,9 +266,20 @@ static const struct i2c_device_id shtc1_id[] = { }; MODULE_DEVICE_TABLE(i2c, shtc1_id); +static const struct of_device_id shtc1_of_match[] = { + { .compatible = "sensirion,shtc1" }, + { .compatible = "sensirion,shtw1" }, + { .compatible = "sensirion,shtc3" }, + { } +}; +MODULE_DEVICE_TABLE(of, shtc1_of_match); + static struct i2c_driver shtc1_i2c_driver = { - .driver.name = "shtc1", - .probe = shtc1_probe, + .driver = { + .name = "shtc1", + .of_match_table = shtc1_of_match, + }, + .probe_new = shtc1_probe, .id_table = shtc1_id, }; diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c index af01f763f7d1..b6cbe9810a1b 100644 --- a/drivers/hwmon/smm665.c +++ b/drivers/hwmon/smm665.c @@ -562,8 +562,9 @@ static struct attribute *smm665_attrs[] = { ATTRIBUTE_GROUPS(smm665); -static int smm665_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id smm665_id[]; + +static int smm665_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct smm665_data *data; @@ -585,7 +586,7 @@ static int smm665_probe(struct i2c_client *client, mutex_init(&data->update_lock); data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(smm665_id, client)->driver_data; data->cmdreg = i2c_new_dummy_device(adapter, (client->addr & ~SMM665_REGMASK) | SMM665_CMDREG_BASE); if (IS_ERR(data->cmdreg)) @@ -694,7 +695,7 @@ static struct i2c_driver smm665_driver = { .driver = { .name = "smm665", }, - .probe = smm665_probe, + .probe_new = smm665_probe, .remove = smm665_remove, .id_table = smm665_id, }; diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index 6cbb119e3d0e..03a87aa2017a 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -587,8 +587,7 @@ static int smsc47m192_detect(struct i2c_client *client, return 0; } -static int smsc47m192_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int smsc47m192_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -629,7 +628,7 @@ static struct i2c_driver smsc47m192_driver = { .driver = { .name = "smsc47m192", }, - .probe = smsc47m192_probe, + .probe_new = smsc47m192_probe, .id_table = smsc47m192_id, .detect = smsc47m192_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/sparx5-temp.c b/drivers/hwmon/sparx5-temp.c index 1a2b1026b026..98be48e3a22a 100644 --- a/drivers/hwmon/sparx5-temp.c +++ b/drivers/hwmon/sparx5-temp.c @@ -56,7 +56,7 @@ static int s5_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_temp_input: stat = readl_relaxed(hwmon->base + TEMP_STAT); if (!(stat & TEMP_STAT_VALID)) - return -EIO; + return -EAGAIN; value = stat & TEMP_STAT_TEMP; /* * From register documentation: diff --git a/drivers/hwmon/stts751.c b/drivers/hwmon/stts751.c index 35b353c2b0a1..6928be6dbe4e 100644 --- a/drivers/hwmon/stts751.c +++ b/drivers/hwmon/stts751.c @@ -762,8 +762,7 @@ static struct attribute *stts751_attrs[] = { }; ATTRIBUTE_GROUPS(stts751); -static int stts751_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int stts751_probe(struct i2c_client *client) { struct stts751_priv *priv; int ret; @@ -822,7 +821,7 @@ static struct i2c_driver stts751_driver = { .name = DEVNAME, .of_match_table = of_match_ptr(stts751_of_match), }, - .probe = stts751_probe, + .probe_new = stts751_probe, .id_table = stts751_id, .detect = stts751_detect, .alert = stts751_alert, diff --git a/drivers/hwmon/tc654.c b/drivers/hwmon/tc654.c index 3e3b8c61bd76..a52ca72af120 100644 --- a/drivers/hwmon/tc654.c +++ b/drivers/hwmon/tc654.c @@ -446,8 +446,7 @@ ATTRIBUTE_GROUPS(tc654); * device probe and removal */ -static int tc654_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tc654_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tc654_data *data; @@ -488,7 +487,7 @@ static struct i2c_driver tc654_driver = { .driver = { .name = "tc654", }, - .probe = tc654_probe, + .probe_new = tc654_probe, .id_table = tc654_id, }; diff --git a/drivers/hwmon/tc74.c b/drivers/hwmon/tc74.c index fcf638ed16a9..ace55da97fc2 100644 --- a/drivers/hwmon/tc74.c +++ b/drivers/hwmon/tc74.c @@ -103,8 +103,7 @@ static struct attribute *tc74_attrs[] = { ATTRIBUTE_GROUPS(tc74); -static int tc74_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) +static int tc74_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tc74_data *data; @@ -161,7 +160,7 @@ static struct i2c_driver tc74_driver = { .driver = { .name = "tc74", }, - .probe = tc74_probe, + .probe_new = tc74_probe, .id_table = tc74_id, }; diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 3f5a983d9289..fde5e2d0825a 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c @@ -377,8 +377,9 @@ static void thmc50_init_client(struct thmc50_data *data) i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config); } -static int thmc50_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id thmc50_id[]; + +static int thmc50_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct thmc50_data *data; @@ -390,7 +391,7 @@ static int thmc50_probe(struct i2c_client *client, return -ENOMEM; data->client = client; - data->type = id->driver_data; + data->type = i2c_match_id(thmc50_id, client)->driver_data; mutex_init(&data->update_lock); thmc50_init_client(data); @@ -419,7 +420,7 @@ static struct i2c_driver thmc50_driver = { .driver = { .name = "thmc50", }, - .probe = thmc50_probe, + .probe_new = thmc50_probe, .id_table = thmc50_id, .detect = thmc50_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 5fe35e5b2f73..e867a0c2e539 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -189,8 +189,7 @@ static const struct regmap_config tmp102_regmap_config = { .use_single_write = true, }; -static int tmp102_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp102_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -304,7 +303,7 @@ 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, - .probe = tmp102_probe, + .probe_new = tmp102_probe, .id_table = tmp102_id, }; diff --git a/drivers/hwmon/tmp103.c b/drivers/hwmon/tmp103.c index 49851533935e..a7e202cc8323 100644 --- a/drivers/hwmon/tmp103.c +++ b/drivers/hwmon/tmp103.c @@ -109,8 +109,7 @@ static const struct regmap_config tmp103_regmap_config = { .volatile_reg = tmp103_regmap_is_volatile, }; -static int tmp103_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp103_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -172,7 +171,7 @@ static struct i2c_driver tmp103_driver = { .of_match_table = of_match_ptr(tmp103_of_match), .pm = &tmp103_dev_pm_ops, }, - .probe = tmp103_probe, + .probe_new = tmp103_probe, .id_table = tmp103_id, }; diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index fe587d4f9b2d..5435664c3f6e 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -323,8 +323,7 @@ static const struct regmap_config tmp108_regmap_config = { .use_single_write = true, }; -static int tmp108_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp108_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -433,7 +432,7 @@ static struct i2c_driver tmp108_driver = { .pm = &tmp108_dev_pm_ops, .of_match_table = of_match_ptr(tmp108_of_ids), }, - .probe = tmp108_probe, + .probe_new = tmp108_probe, .id_table = tmp108_i2c_ids, }; diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index fa361d9949db..9dc210b55e69 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -683,8 +683,7 @@ static int tmp401_detect(struct i2c_client *client, return 0; } -static int tmp401_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp401_probe(struct i2c_client *client) { static const char * const names[] = { "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461" @@ -700,7 +699,7 @@ static int tmp401_probe(struct i2c_client *client, data->client = client; mutex_init(&data->update_lock); - data->kind = id->driver_data; + data->kind = i2c_match_id(tmp401_id, client)->driver_data; /* Initialize the TMP401 chip */ status = tmp401_init_client(data, client); @@ -736,7 +735,7 @@ static struct i2c_driver tmp401_driver = { .driver = { .name = "tmp401", }, - .probe = tmp401_probe, + .probe_new = tmp401_probe, .id_table = tmp401_id, .detect = tmp401_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index 83a4fab151d2..ede66ea6a730 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -279,8 +279,7 @@ static const struct hwmon_ops tmp421_ops = { .read = tmp421_read, }; -static int tmp421_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp421_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -296,7 +295,7 @@ static int tmp421_probe(struct i2c_client *client, data->channels = (unsigned long) of_device_get_match_data(&client->dev); else - data->channels = id->driver_data; + data->channels = i2c_match_id(tmp421_id, client)->driver_data; data->client = client; err = tmp421_init_client(client); @@ -327,7 +326,7 @@ static struct i2c_driver tmp421_driver = { .name = "tmp421", .of_match_table = of_match_ptr(tmp421_of_match), }, - .probe = tmp421_probe, + .probe_new = tmp421_probe, .id_table = tmp421_id, .detect = tmp421_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index 23908dc5611b..47bbe47e062f 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -192,7 +192,7 @@ static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos, /* * The valus is read in voltage in the chip but reported as * current to the user. - * 2's compliment number shifted by one to four depending + * 2's complement number shifted by one to four depending * on the pga gain setting. 1lsb = 10uV */ *val = sign_extend32(regval, 17 - tmp51x_get_pga_shift(data)); @@ -709,8 +709,7 @@ static int tmp51x_configure(struct device *dev, struct tmp51x_data *data) return 0; } -static int tmp51x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tmp51x_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct tmp51x_data *data; @@ -724,7 +723,7 @@ static int tmp51x_probe(struct i2c_client *client, if (client->dev.of_node) data->id = (enum tmp51x_ids)device_get_match_data(&client->dev); else - data->id = id->driver_data; + data->id = i2c_match_id(tmp51x_id, client)->driver_data; ret = tmp51x_configure(dev, data); if (ret < 0) { @@ -751,7 +750,7 @@ static int tmp51x_probe(struct i2c_client *client, if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); - dev_dbg(dev, "power monitor %s\n", id->name); + dev_dbg(dev, "power monitor %s\n", client->name); return 0; } @@ -761,7 +760,7 @@ static struct i2c_driver tmp51x_driver = { .name = "tmp51x", .of_match_table = of_match_ptr(tmp51x_of_match), }, - .probe = tmp51x_probe, + .probe_new = tmp51x_probe, .id_table = tmp51x_id, }; diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 5a5120121e50..3964ceab2817 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1951,8 +1951,12 @@ static int w83627ehf_probe(struct platform_device *pdev) data, &w83627ehf_chip_info, w83627ehf_groups); + if (IS_ERR(hwmon_dev)) { + err = PTR_ERR(hwmon_dev); + goto exit_release; + } - return PTR_ERR_OR_ZERO(hwmon_dev); + return 0; exit_release: release_region(res->start, IOREGION_LENGTH); diff --git a/drivers/hwmon/w83773g.c b/drivers/hwmon/w83773g.c index 96b695b32572..88d11dc5feb9 100644 --- a/drivers/hwmon/w83773g.c +++ b/drivers/hwmon/w83773g.c @@ -259,8 +259,7 @@ static const struct regmap_config w83773_regmap_config = { .val_bits = 8, }; -static int w83773_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int w83773_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -296,7 +295,7 @@ static struct i2c_driver w83773_driver = { .name = "w83773g", .of_match_table = of_match_ptr(w83773_of_match), }, - .probe = w83773_probe, + .probe_new = w83773_probe, .id_table = w83773_id, }; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index d833a4f16c47..e84aa5604e64 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1192,8 +1192,9 @@ static void w83781d_remove_files(struct device *dev) sysfs_remove_group(&dev->kobj, &w83781d_group_other); } -static int -w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id) +static const struct i2c_device_id w83781d_ids[]; + +static int w83781d_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct w83781d_data *data; @@ -1207,7 +1208,7 @@ w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id) mutex_init(&data->lock); mutex_init(&data->update_lock); - data->type = id->driver_data; + data->type = i2c_match_id(w83781d_ids, client)->driver_data; data->client = client; /* attach secondary i2c lm75-like clients */ @@ -1575,7 +1576,7 @@ static struct i2c_driver w83781d_driver = { .driver = { .name = "w83781d", }, - .probe = w83781d_probe, + .probe_new = w83781d_probe, .remove = w83781d_remove, .id_table = w83781d_ids, .detect = w83781d_detect, diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index aad8d4da5802..37b25a1474c4 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -315,8 +315,7 @@ struct w83791d_data { u8 vrm; /* hwmon-vid */ }; -static int w83791d_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int w83791d_probe(struct i2c_client *client); static int w83791d_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83791d_remove(struct i2c_client *client); @@ -342,7 +341,7 @@ static struct i2c_driver w83791d_driver = { .driver = { .name = "w83791d", }, - .probe = w83791d_probe, + .probe_new = w83791d_probe, .remove = w83791d_remove, .id_table = w83791d_id, .detect = w83791d_detect, @@ -1346,8 +1345,7 @@ static int w83791d_detect(struct i2c_client *client, return 0; } -static int w83791d_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int w83791d_probe(struct i2c_client *client) { struct w83791d_data *data; struct device *dev = &client->dev; diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 7fc8a1160c8f..abd5c3a722b9 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -286,8 +286,7 @@ struct w83792d_data { u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */ }; -static int w83792d_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int w83792d_probe(struct i2c_client *client); static int w83792d_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83792d_remove(struct i2c_client *client); @@ -310,7 +309,7 @@ static struct i2c_driver w83792d_driver = { .driver = { .name = "w83792d", }, - .probe = w83792d_probe, + .probe_new = w83792d_probe, .remove = w83792d_remove, .id_table = w83792d_id, .detect = w83792d_detect, @@ -1359,7 +1358,7 @@ w83792d_detect(struct i2c_client *client, struct i2c_board_info *info) } static int -w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id) +w83792d_probe(struct i2c_client *client) { struct w83792d_data *data; struct device *dev = &client->dev; diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 3f59f2a1a5e3..e7d0484eabe4 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -283,8 +283,7 @@ static void w83793_release_resources(struct kref *ref) static u8 w83793_read_value(struct i2c_client *client, u16 reg); static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value); -static int w83793_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int w83793_probe(struct i2c_client *client); static int w83793_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83793_remove(struct i2c_client *client); @@ -303,7 +302,7 @@ static struct i2c_driver w83793_driver = { .driver = { .name = "w83793", }, - .probe = w83793_probe, + .probe_new = w83793_probe, .remove = w83793_remove, .id_table = w83793_id, .detect = w83793_detect, @@ -1646,8 +1645,7 @@ static int w83793_detect(struct i2c_client *client, return 0; } -static int w83793_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int w83793_probe(struct i2c_client *client) { struct device *dev = &client->dev; static const int watchdog_minors[] = { diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 6d52b530b429..621b05afa837 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -2134,8 +2134,9 @@ static void w83795_apply_temp_config(struct w83795_data *data, u8 config, } } -static int w83795_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id w83795_id[]; + +static int w83795_probe(struct i2c_client *client) { int i; u8 tmp; @@ -2148,7 +2149,7 @@ static int w83795_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, data); - data->chip_type = id->driver_data; + data->chip_type = i2c_match_id(w83795_id, client)->driver_data; data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); mutex_init(&data->update_lock); @@ -2256,7 +2257,7 @@ static struct i2c_driver w83795_driver = { .driver = { .name = "w83795", }, - .probe = w83795_probe, + .probe_new = w83795_probe, .remove = w83795_remove, .id_table = w83795_id, diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index 6f6d925cf017..656a77102ca6 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -62,8 +62,7 @@ static const unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END }; * Functions declaration */ -static int w83l785ts_probe(struct i2c_client *client, - const struct i2c_device_id *id); +static int w83l785ts_probe(struct i2c_client *client); static int w83l785ts_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83l785ts_remove(struct i2c_client *client); @@ -85,7 +84,7 @@ static struct i2c_driver w83l785ts_driver = { .driver = { .name = "w83l785ts", }, - .probe = w83l785ts_probe, + .probe_new = w83l785ts_probe, .remove = w83l785ts_remove, .id_table = w83l785ts_id, .detect = w83l785ts_detect, @@ -163,8 +162,7 @@ static int w83l785ts_detect(struct i2c_client *client, return 0; } -static int w83l785ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int w83l785ts_probe(struct i2c_client *client) { struct w83l785ts_data *data; struct device *dev = &client->dev; diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index ce98ec8794e2..542afff1423b 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -706,7 +706,7 @@ static void w83l786ng_init_client(struct i2c_client *client) } static int -w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id) +w83l786ng_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct w83l786ng_data *data; @@ -752,7 +752,7 @@ static struct i2c_driver w83l786ng_driver = { .driver = { .name = "w83l786ng", }, - .probe = w83l786ng_probe, + .probe_new = w83l786ng_probe, .id_table = w83l786ng_id, .detect = w83l786ng_detect, .address_list = normal_i2c, diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 363d4a814aa1..1e8d6ea8992e 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -85,6 +85,8 @@ enum hwmon_temp_attributes { hwmon_temp_lowest, hwmon_temp_highest, hwmon_temp_reset_history, + hwmon_temp_rated_min, + hwmon_temp_rated_max, }; #define HWMON_T_ENABLE BIT(hwmon_temp_enable) @@ -112,6 +114,8 @@ enum hwmon_temp_attributes { #define HWMON_T_LOWEST BIT(hwmon_temp_lowest) #define HWMON_T_HIGHEST BIT(hwmon_temp_highest) #define HWMON_T_RESET_HISTORY BIT(hwmon_temp_reset_history) +#define HWMON_T_RATED_MIN BIT(hwmon_temp_rated_min) +#define HWMON_T_RATED_MAX BIT(hwmon_temp_rated_max) enum hwmon_in_attributes { hwmon_in_enable, @@ -130,6 +134,8 @@ enum hwmon_in_attributes { hwmon_in_max_alarm, hwmon_in_lcrit_alarm, hwmon_in_crit_alarm, + hwmon_in_rated_min, + hwmon_in_rated_max, }; #define HWMON_I_ENABLE BIT(hwmon_in_enable) @@ -148,6 +154,8 @@ enum hwmon_in_attributes { #define HWMON_I_MAX_ALARM BIT(hwmon_in_max_alarm) #define HWMON_I_LCRIT_ALARM BIT(hwmon_in_lcrit_alarm) #define HWMON_I_CRIT_ALARM BIT(hwmon_in_crit_alarm) +#define HWMON_I_RATED_MIN BIT(hwmon_in_rated_min) +#define HWMON_I_RATED_MAX BIT(hwmon_in_rated_max) enum hwmon_curr_attributes { hwmon_curr_enable, @@ -166,6 +174,8 @@ enum hwmon_curr_attributes { hwmon_curr_max_alarm, hwmon_curr_lcrit_alarm, hwmon_curr_crit_alarm, + hwmon_curr_rated_min, + hwmon_curr_rated_max, }; #define HWMON_C_ENABLE BIT(hwmon_curr_enable) @@ -184,6 +194,8 @@ enum hwmon_curr_attributes { #define HWMON_C_MAX_ALARM BIT(hwmon_curr_max_alarm) #define HWMON_C_LCRIT_ALARM BIT(hwmon_curr_lcrit_alarm) #define HWMON_C_CRIT_ALARM BIT(hwmon_curr_crit_alarm) +#define HWMON_C_RATED_MIN BIT(hwmon_curr_rated_min) +#define HWMON_C_RATED_MAX BIT(hwmon_curr_rated_max) enum hwmon_power_attributes { hwmon_power_enable, @@ -215,6 +227,8 @@ enum hwmon_power_attributes { hwmon_power_max_alarm, hwmon_power_lcrit_alarm, hwmon_power_crit_alarm, + hwmon_power_rated_min, + hwmon_power_rated_max, }; #define HWMON_P_ENABLE BIT(hwmon_power_enable) @@ -246,6 +260,8 @@ enum hwmon_power_attributes { #define HWMON_P_MAX_ALARM BIT(hwmon_power_max_alarm) #define HWMON_P_LCRIT_ALARM BIT(hwmon_power_lcrit_alarm) #define HWMON_P_CRIT_ALARM BIT(hwmon_power_crit_alarm) +#define HWMON_P_RATED_MIN BIT(hwmon_power_rated_min) +#define HWMON_P_RATED_MAX BIT(hwmon_power_rated_max) enum hwmon_energy_attributes { hwmon_energy_enable, @@ -267,6 +283,8 @@ enum hwmon_humidity_attributes { hwmon_humidity_max_hyst, hwmon_humidity_alarm, hwmon_humidity_fault, + hwmon_humidity_rated_min, + hwmon_humidity_rated_max, }; #define HWMON_H_ENABLE BIT(hwmon_humidity_enable) @@ -278,6 +296,8 @@ enum hwmon_humidity_attributes { #define HWMON_H_MAX_HYST BIT(hwmon_humidity_max_hyst) #define HWMON_H_ALARM BIT(hwmon_humidity_alarm) #define HWMON_H_FAULT BIT(hwmon_humidity_fault) +#define HWMON_H_RATED_MIN BIT(hwmon_humidity_rated_min) +#define HWMON_H_RATED_MAX BIT(hwmon_humidity_rated_max) enum hwmon_fan_attributes { hwmon_fan_enable, diff --git a/include/linux/platform_data/gsc_hwmon.h b/include/linux/platform_data/gsc_hwmon.h index 37a8f554da00..281f499eda97 100644 --- a/include/linux/platform_data/gsc_hwmon.h +++ b/include/linux/platform_data/gsc_hwmon.h @@ -7,6 +7,7 @@ enum gsc_hwmon_mode { mode_voltage_24bit, mode_voltage_raw, mode_voltage_16bit, + mode_fan, mode_max, }; |