New drivers for NCT6775, NCT6776, NCT6779, and LM95234.
Added support for LTC2974, LTC3883, LM25056, TMP431, TMP432, ADT7310, and ADT7320 to existing drivers. Various code cleanups and minor improvements. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJRfgHYAAoJEMsfJm/On5mBkJIP/2y4kfcgh+7Ye8nqs0xnPqA0 +8YR1HYboj8L3HHsWpK0Q3H17yN7bbwESSVeSRKx+UDfPXHYxqKPMdVaVdLU4FwA mIdKuOHoTt4dt57XvpXFfCzVeuAeBCoEsGlR5+KeoZV1VyGshSo7nBAZdpUtDghc 6ZDPROaYY3rCLDsFRuctap3pWZodZSkprt1Kw/Akx8kByv7R/esA9IHRsI/VkWCs m2EIaJPfsZANFyGqahauGDA9goj+cqBQqSdFN+hHY5m5Ur7CRfH8z9sDl+r+8L5s Ij68kPTdgn9tbCbiomaH1DMmJO/GUeMEc7LFBIAgbTzSbjmgDp7y13zN5rnzoINX idFJu7XWL7f6BsipYnIKGpGyd6S7Usfdis+RVxn9LTZ06KK+NYuST0cM+jtlmHwr pHNsFsxz5LizPo+ULBSfTb62uRRSfJ7TRaRcZdVS43ha+rsdk/oWf1KUU+U8dpug NSxkgZNSFPC98UUJ8VhwV3m09D3O7p60oA8aeP6CJ+ysML6Gq6xg7eipH3n7eft1 rUbZvVi4vGIFhag0xRTy1IyKXVNYNSAGWzfMpnB6fn5kblmdr0c+wa7rqMDmeThm PWNrYasc61zGexPqib7VPGrlt2SiDE2w+/y3kdDPG89smqlieqVS5tJjig8fFPIB oHw0Yu7v/6DBjp6a/pjd =RxMp -----END PGP SIGNATURE----- Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hwmon update from Guenter Roeck: - New drivers for NCT6775, NCT6776, NCT6779, and LM95234. - Added support for LTC2974, LTC3883, LM25056, TMP431, TMP432, ADT7310, and ADT7320 to existing drivers. - Various code cleanups and minor improvements. * tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (54 commits) hwmon: (nct6775) Fix coding style problems hwmon: (nct6775) Constify strings hwmon: (tmp401) Add support for TMP432 hwmon: (tmp401) Add support for update_interval attribute hwmon: (tmp401) Reset valid flag when resetting temperature history hwmon: (tmp401) Simplification and cleanup hwmon: (tmp401) Use sysfs_create_group / sysfs_remove_group hwmon: (tmp401) Drop unused defines, use BIT for bit masks hwmon: (nct6775) Use ARRAY_SIZE for loops where possible documentation: hwmon: Fix typo in documentation/hwmon hwmon: (nct6775) Enable both AUXTIN and VIN3 on NCT6776 hwmon: (ad7314) use spi_get_drvdata() and spi_set_drvdata() MAINTAINERS: Add myself as maintainer for the NCT6775 driver hwmon: (nct6775) Expand scope of supported chips hwmon: (gpio-fan) Use is_visible to determine if attributes should be created hwmon: (tmp401) Fix device detection for TMP411B and TMP411C hwmon: Add driver for LM95234 hwmon: (tmp401) Add support for TMP431 hwmon: (pmbus/lm25066) Add support for LM25056 hwmon: (pmbus/lm25066) Refactor device specific coefficients ...
This commit is contained in:
		
				commit
				
					
						92ddcf4a01
					
				
			
		
					 77 changed files with 7860 additions and 1791 deletions
				
			
		
							
								
								
									
										29
									
								
								Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					NTC Thermistor hwmon sensors
 | 
				
			||||||
 | 
					-------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Requires node properties:
 | 
				
			||||||
 | 
					- "compatible" value : one of
 | 
				
			||||||
 | 
						"ntc,ncp15wb473"
 | 
				
			||||||
 | 
						"ntc,ncp18wb473"
 | 
				
			||||||
 | 
						"ntc,ncp21wb473"
 | 
				
			||||||
 | 
						"ntc,ncp03wb473"
 | 
				
			||||||
 | 
						"ntc,ncp15wl333"
 | 
				
			||||||
 | 
					- "pullup-uv"	Pull up voltage in micro volts
 | 
				
			||||||
 | 
					- "pullup-ohm"	Pull up resistor value in ohms
 | 
				
			||||||
 | 
					- "pulldown-ohm" Pull down resistor value in ohms
 | 
				
			||||||
 | 
					- "connected-positive" Always ON, If not specified.
 | 
				
			||||||
 | 
							Status change is possible.
 | 
				
			||||||
 | 
					- "io-channels"	Channel node of ADC to be used for
 | 
				
			||||||
 | 
							conversion.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Read more about iio bindings at
 | 
				
			||||||
 | 
						Documentation/devicetree/bindings/iio/iio-bindings.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
						ncp15wb473@0 {
 | 
				
			||||||
 | 
							compatible = "ntc,ncp15wb473";
 | 
				
			||||||
 | 
							pullup-uv = <1800000>;
 | 
				
			||||||
 | 
							pullup-ohm = <47000>;
 | 
				
			||||||
 | 
							pulldown-ohm = <0>;
 | 
				
			||||||
 | 
							io-channels = <&adc 3>;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
| 
						 | 
					@ -12,29 +12,42 @@ Supported chips:
 | 
				
			||||||
    Addresses scanned: None
 | 
					    Addresses scanned: None
 | 
				
			||||||
    Datasheet: Publicly available at the Analog Devices website
 | 
					    Datasheet: Publicly available at the Analog Devices website
 | 
				
			||||||
               http://www.analog.com/static/imported-files/data_sheets/ADT7420.pdf
 | 
					               http://www.analog.com/static/imported-files/data_sheets/ADT7420.pdf
 | 
				
			||||||
 | 
					  * Analog Devices ADT7310
 | 
				
			||||||
 | 
					    Prefix: 'adt7310'
 | 
				
			||||||
 | 
					    Addresses scanned: None
 | 
				
			||||||
 | 
					    Datasheet: Publicly available at the Analog Devices website
 | 
				
			||||||
 | 
					               http://www.analog.com/static/imported-files/data_sheets/ADT7310.pdf
 | 
				
			||||||
 | 
					  * Analog Devices ADT7320
 | 
				
			||||||
 | 
					    Prefix: 'adt7320'
 | 
				
			||||||
 | 
					    Addresses scanned: None
 | 
				
			||||||
 | 
					    Datasheet: Publicly available at the Analog Devices website
 | 
				
			||||||
 | 
					               http://www.analog.com/static/imported-files/data_sheets/ADT7320.pdf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Author: Hartmut Knaack <knaack.h@gmx.de>
 | 
					Author: Hartmut Knaack <knaack.h@gmx.de>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Description
 | 
					Description
 | 
				
			||||||
-----------
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The ADT7410 is a temperature sensor with rated temperature range of -55°C to
 | 
					The ADT7310/ADT7410 is a temperature sensor with rated temperature range of
 | 
				
			||||||
+150°C. It has a high accuracy of +/-0.5°C and can be operated at a resolution
 | 
					-55°C to +150°C. It has a high accuracy of +/-0.5°C and can be operated at a
 | 
				
			||||||
of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an INT pin to
 | 
					resolution of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an
 | 
				
			||||||
indicate that a minimum or maximum temperature set point has been exceeded, as
 | 
					INT pin to indicate that a minimum or maximum temperature set point has been
 | 
				
			||||||
well as a critical temperature (CT) pin to indicate that the critical
 | 
					exceeded, as well as a critical temperature (CT) pin to indicate that the
 | 
				
			||||||
temperature set point has been exceeded. Both pins can be set up with a common
 | 
					critical temperature set point has been exceeded. Both pins can be set up with a
 | 
				
			||||||
hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events. Both
 | 
					common hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events.
 | 
				
			||||||
pins can individually set to be active-low or active-high, while the whole
 | 
					Both pins can individually set to be active-low or active-high, while the whole
 | 
				
			||||||
device can either run in comparator mode or interrupt mode. The ADT7410
 | 
					device can either run in comparator mode or interrupt mode. The ADT7410 supports
 | 
				
			||||||
supports continous temperature sampling, as well as sampling one temperature
 | 
					continuous temperature sampling, as well as sampling one temperature value per
 | 
				
			||||||
value per second or even justget one sample on demand for power saving.
 | 
					second or even just get one sample on demand for power saving. Besides, it can
 | 
				
			||||||
Besides, it can completely power down its ADC, if power management is
 | 
					completely power down its ADC, if power management is required.
 | 
				
			||||||
required.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
The ADT7420 is register compatible, the only differences being the package,
 | 
					The ADT7320/ADT7420 is register compatible, the only differences being the
 | 
				
			||||||
a slightly narrower operating temperature range (-40°C to +150°C), and a
 | 
					package, a slightly narrower operating temperature range (-40°C to +150°C), and
 | 
				
			||||||
better accuracy (0.25°C instead of 0.50°C.)
 | 
					a better accuracy (0.25°C instead of 0.50°C.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The difference between the ADT7310/ADT7320 and ADT7410/ADT7420 is the control
 | 
				
			||||||
 | 
					interface, the ADT7310 and ADT7320 use SPI while the ADT7410 and ADT7420 use
 | 
				
			||||||
 | 
					I2C.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Configuration Notes
 | 
					Configuration Notes
 | 
				
			||||||
-------------------
 | 
					-------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,13 @@
 | 
				
			||||||
Kernel driver max8688
 | 
					Kernel driver lm25066
 | 
				
			||||||
=====================
 | 
					=====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Supported chips:
 | 
					Supported chips:
 | 
				
			||||||
 | 
					  * TI LM25056
 | 
				
			||||||
 | 
					    Prefix: 'lm25056'
 | 
				
			||||||
 | 
					    Addresses scanned: -
 | 
				
			||||||
 | 
					    Datasheets:
 | 
				
			||||||
 | 
						http://www.ti.com/lit/gpn/lm25056
 | 
				
			||||||
 | 
						http://www.ti.com/lit/gpn/lm25056a
 | 
				
			||||||
  * National Semiconductor LM25066
 | 
					  * National Semiconductor LM25066
 | 
				
			||||||
    Prefix: 'lm25066'
 | 
					    Prefix: 'lm25066'
 | 
				
			||||||
    Addresses scanned: -
 | 
					    Addresses scanned: -
 | 
				
			||||||
| 
						 | 
					@ -25,8 +31,9 @@ Author: Guenter Roeck <linux@roeck-us.net>
 | 
				
			||||||
Description
 | 
					Description
 | 
				
			||||||
-----------
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This driver supports hardware montoring for National Semiconductor LM25066,
 | 
					This driver supports hardware montoring for National Semiconductor / TI LM25056,
 | 
				
			||||||
LM5064, and LM5064 Power Management, Monitoring, Control, and Protection ICs.
 | 
					LM25066, LM5064, and LM5064 Power Management, Monitoring, Control, and
 | 
				
			||||||
 | 
					Protection ICs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The driver is a client driver to the core PMBus driver. Please see
 | 
					The driver is a client driver to the core PMBus driver. Please see
 | 
				
			||||||
Documentation/hwmon/pmbus for details on PMBus client drivers.
 | 
					Documentation/hwmon/pmbus for details on PMBus client drivers.
 | 
				
			||||||
| 
						 | 
					@ -60,14 +67,19 @@ in1_max			Maximum input voltage.
 | 
				
			||||||
in1_min_alarm		Input voltage low alarm.
 | 
					in1_min_alarm		Input voltage low alarm.
 | 
				
			||||||
in1_max_alarm		Input voltage high alarm.
 | 
					in1_max_alarm		Input voltage high alarm.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
in2_label		"vout1"
 | 
					in2_label		"vmon"
 | 
				
			||||||
in2_input		Measured output voltage.
 | 
					in2_input		Measured voltage on VAUX pin
 | 
				
			||||||
in2_average		Average measured output voltage.
 | 
					in2_min			Minimum VAUX voltage (LM25056 only).
 | 
				
			||||||
in2_min			Minimum output voltage.
 | 
					in2_max			Maximum VAUX voltage (LM25056 only).
 | 
				
			||||||
in2_min_alarm		Output voltage low alarm.
 | 
					in2_min_alarm		VAUX voltage low alarm (LM25056 only).
 | 
				
			||||||
 | 
					in2_max_alarm		VAUX voltage high alarm (LM25056 only).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
in3_label		"vout2"
 | 
					in3_label		"vout1"
 | 
				
			||||||
in3_input		Measured voltage on vaux pin
 | 
								Not supported on LM25056.
 | 
				
			||||||
 | 
					in3_input		Measured output voltage.
 | 
				
			||||||
 | 
					in3_average		Average measured output voltage.
 | 
				
			||||||
 | 
					in3_min			Minimum output voltage.
 | 
				
			||||||
 | 
					in3_min_alarm		Output voltage low alarm.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
curr1_label		"iin"
 | 
					curr1_label		"iin"
 | 
				
			||||||
curr1_input		Measured input current.
 | 
					curr1_input		Measured input current.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										36
									
								
								Documentation/hwmon/lm95234
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Documentation/hwmon/lm95234
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					Kernel driver lm95234
 | 
				
			||||||
 | 
					=====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Supported chips:
 | 
				
			||||||
 | 
					  * National Semiconductor / Texas Instruments LM95234
 | 
				
			||||||
 | 
					    Addresses scanned: I2C 0x18, 0x4d, 0x4e
 | 
				
			||||||
 | 
					    Datasheet: Publicly available at the Texas Instruments website
 | 
				
			||||||
 | 
					               http://www.ti.com/product/lm95234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Author: Guenter Roeck <linux@roeck-us.net>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Description
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LM95234 is an 11-bit digital temperature sensor with a 2-wire System Management
 | 
				
			||||||
 | 
					Bus (SMBus) interface and TrueTherm technology that can very accurately monitor
 | 
				
			||||||
 | 
					the temperature of four remote diodes as well as its own temperature.
 | 
				
			||||||
 | 
					The four remote diodes can be external devices such as microprocessors,
 | 
				
			||||||
 | 
					graphics processors or diode-connected 2N3904s. The LM95234's TruTherm
 | 
				
			||||||
 | 
					beta compensation technology allows sensing of 90 nm or 65 nm process
 | 
				
			||||||
 | 
					thermal diodes accurately.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All temperature values are given in millidegrees Celsius. Temperature
 | 
				
			||||||
 | 
					is provided within a range of -127 to +255 degrees (+127.875 degrees for
 | 
				
			||||||
 | 
					the internal sensor). Resolution depends on temperature input and range.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each sensor has its own maximum limit, but the hysteresis is common to all
 | 
				
			||||||
 | 
					channels. The hysteresis is configurable with the tem1_max_hyst attribute and
 | 
				
			||||||
 | 
					affects the hysteresis on all channels. The first two external sensors also
 | 
				
			||||||
 | 
					have a critical limit.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The lm95234 driver can change its update interval to a fixed set of values.
 | 
				
			||||||
 | 
					It will round up to the next selectable interval. See the datasheet for exact
 | 
				
			||||||
 | 
					values. Reading sensor values more often will do no harm, but will return
 | 
				
			||||||
 | 
					'old' values.
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,10 @@ Kernel driver ltc2978
 | 
				
			||||||
=====================
 | 
					=====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Supported chips:
 | 
					Supported chips:
 | 
				
			||||||
 | 
					  * Linear Technology LTC2974
 | 
				
			||||||
 | 
					    Prefix: 'ltc2974'
 | 
				
			||||||
 | 
					    Addresses scanned: -
 | 
				
			||||||
 | 
					    Datasheet: http://www.linear.com/product/ltc2974
 | 
				
			||||||
  * Linear Technology LTC2978
 | 
					  * Linear Technology LTC2978
 | 
				
			||||||
    Prefix: 'ltc2978'
 | 
					    Prefix: 'ltc2978'
 | 
				
			||||||
    Addresses scanned: -
 | 
					    Addresses scanned: -
 | 
				
			||||||
| 
						 | 
					@ -10,6 +14,10 @@ Supported chips:
 | 
				
			||||||
    Prefix: 'ltc3880'
 | 
					    Prefix: 'ltc3880'
 | 
				
			||||||
    Addresses scanned: -
 | 
					    Addresses scanned: -
 | 
				
			||||||
    Datasheet: http://www.linear.com/product/ltc3880
 | 
					    Datasheet: http://www.linear.com/product/ltc3880
 | 
				
			||||||
 | 
					  * Linear Technology LTC3883
 | 
				
			||||||
 | 
					    Prefix: 'ltc3883'
 | 
				
			||||||
 | 
					    Addresses scanned: -
 | 
				
			||||||
 | 
					    Datasheet: http://www.linear.com/product/ltc3883
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Author: Guenter Roeck <linux@roeck-us.net>
 | 
					Author: Guenter Roeck <linux@roeck-us.net>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,9 +25,9 @@ Author: Guenter Roeck <linux@roeck-us.net>
 | 
				
			||||||
Description
 | 
					Description
 | 
				
			||||||
-----------
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The LTC2978 is an octal power supply monitor, supervisor, sequencer and
 | 
					LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply
 | 
				
			||||||
margin controller. The LTC3880 is a dual, PolyPhase DC/DC synchronous
 | 
					monitor. LTC3880 is a dual output poly-phase step-down DC/DC controller. LTC3883
 | 
				
			||||||
step-down switching regulator controller.
 | 
					is a single phase step-down DC/DC controller.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Usage Notes
 | 
					Usage Notes
 | 
				
			||||||
| 
						 | 
					@ -41,63 +49,90 @@ Sysfs attributes
 | 
				
			||||||
in1_label		"vin"
 | 
					in1_label		"vin"
 | 
				
			||||||
in1_input		Measured input voltage.
 | 
					in1_input		Measured input voltage.
 | 
				
			||||||
in1_min			Minimum input voltage.
 | 
					in1_min			Minimum input voltage.
 | 
				
			||||||
in1_max			Maximum input voltage.
 | 
					in1_max			Maximum input voltage. LTC2974 and LTC2978 only.
 | 
				
			||||||
in1_lcrit		Critical minimum input voltage.
 | 
					in1_lcrit		Critical minimum input voltage. LTC2974 and LTC2978
 | 
				
			||||||
 | 
								only.
 | 
				
			||||||
in1_crit		Critical maximum input voltage.
 | 
					in1_crit		Critical maximum input voltage.
 | 
				
			||||||
in1_min_alarm		Input voltage low alarm.
 | 
					in1_min_alarm		Input voltage low alarm.
 | 
				
			||||||
in1_max_alarm		Input voltage high alarm.
 | 
					in1_max_alarm		Input voltage high alarm. LTC2974 and LTC2978 only.
 | 
				
			||||||
in1_lcrit_alarm		Input voltage critical low alarm.
 | 
					in1_lcrit_alarm		Input voltage critical low alarm. LTC2974 and LTC2978
 | 
				
			||||||
 | 
								only.
 | 
				
			||||||
in1_crit_alarm		Input voltage critical high alarm.
 | 
					in1_crit_alarm		Input voltage critical high alarm.
 | 
				
			||||||
in1_lowest		Lowest input voltage. LTC2978 only.
 | 
					in1_lowest		Lowest input voltage. LTC2974 and LTC2978 only.
 | 
				
			||||||
in1_highest		Highest input voltage.
 | 
					in1_highest		Highest input voltage.
 | 
				
			||||||
in1_reset_history	Reset history. Writing into this attribute will reset
 | 
					in1_reset_history	Reset input voltage history.
 | 
				
			||||||
			history for all attributes.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
in[2-9]_label		"vout[1-8]". Channels 3 to 9 on LTC2978 only.
 | 
					in[N]_label		"vout[1-8]".
 | 
				
			||||||
in[2-9]_input		Measured output voltage.
 | 
								LTC2974: N=2-5
 | 
				
			||||||
in[2-9]_min		Minimum output voltage.
 | 
								LTC2978: N=2-9
 | 
				
			||||||
in[2-9]_max		Maximum output voltage.
 | 
								LTC3880: N=2-3
 | 
				
			||||||
in[2-9]_lcrit		Critical minimum output voltage.
 | 
								LTC3883: N=2
 | 
				
			||||||
in[2-9]_crit		Critical maximum output voltage.
 | 
					in[N]_input		Measured output voltage.
 | 
				
			||||||
in[2-9]_min_alarm	Output voltage low alarm.
 | 
					in[N]_min		Minimum output voltage.
 | 
				
			||||||
in[2-9]_max_alarm	Output voltage high alarm.
 | 
					in[N]_max		Maximum output voltage.
 | 
				
			||||||
in[2-9]_lcrit_alarm	Output voltage critical low alarm.
 | 
					in[N]_lcrit		Critical minimum output voltage.
 | 
				
			||||||
in[2-9]_crit_alarm	Output voltage critical high alarm.
 | 
					in[N]_crit		Critical maximum output voltage.
 | 
				
			||||||
in[2-9]_lowest		Lowest output voltage. LTC2978 only.
 | 
					in[N]_min_alarm		Output voltage low alarm.
 | 
				
			||||||
in[2-9]_highest		Lowest output voltage.
 | 
					in[N]_max_alarm		Output voltage high alarm.
 | 
				
			||||||
in[2-9]_reset_history	Reset history. Writing into this attribute will reset
 | 
					in[N]_lcrit_alarm	Output voltage critical low alarm.
 | 
				
			||||||
			history for all attributes.
 | 
					in[N]_crit_alarm	Output voltage critical high alarm.
 | 
				
			||||||
 | 
					in[N]_lowest		Lowest output voltage. LTC2974 and LTC2978 only.
 | 
				
			||||||
 | 
					in[N]_highest		Highest output voltage.
 | 
				
			||||||
 | 
					in[N]_reset_history	Reset output voltage history.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
temp[1-3]_input		Measured temperature.
 | 
					temp[N]_input		Measured temperature.
 | 
				
			||||||
 | 
								On LTC2974, temp[1-4] report external temperatures,
 | 
				
			||||||
 | 
								and temp5 reports the chip temperature.
 | 
				
			||||||
			On LTC2978, only one temperature measurement is
 | 
								On LTC2978, only one temperature measurement is
 | 
				
			||||||
			supported and reflects the internal temperature.
 | 
								supported and reports the chip temperature.
 | 
				
			||||||
			On LTC3880, temp1 and temp2 report external
 | 
								On LTC3880, temp1 and temp2 report external
 | 
				
			||||||
			temperatures, and temp3 reports the internal
 | 
								temperatures, and temp3 reports the chip temperature.
 | 
				
			||||||
			temperature.
 | 
								On LTC3883, temp1 reports an external temperature,
 | 
				
			||||||
temp[1-3]_min		Mimimum temperature.
 | 
								and temp2 reports the chip temperature.
 | 
				
			||||||
temp[1-3]_max		Maximum temperature.
 | 
					temp[N]_min		Mimimum temperature. LTC2974 and LTC2978 only.
 | 
				
			||||||
temp[1-3]_lcrit		Critical low temperature.
 | 
					temp[N]_max		Maximum temperature.
 | 
				
			||||||
temp[1-3]_crit		Critical high temperature.
 | 
					temp[N]_lcrit		Critical low temperature.
 | 
				
			||||||
temp[1-3]_min_alarm	Chip temperature low alarm.
 | 
					temp[N]_crit		Critical high temperature.
 | 
				
			||||||
temp[1-3]_max_alarm	Chip temperature high alarm.
 | 
					temp[N]_min_alarm	Temperature low alarm. LTC2974 and LTC2978 only.
 | 
				
			||||||
temp[1-3]_lcrit_alarm	Chip temperature critical low alarm.
 | 
					temp[N]_max_alarm	Temperature high alarm.
 | 
				
			||||||
temp[1-3]_crit_alarm	Chip temperature critical high alarm.
 | 
					temp[N]_lcrit_alarm	Temperature critical low alarm.
 | 
				
			||||||
temp[1-3]_lowest	Lowest measured temperature. LTC2978 only.
 | 
					temp[N]_crit_alarm	Temperature critical high alarm.
 | 
				
			||||||
temp[1-3]_highest	Highest measured temperature.
 | 
					temp[N]_lowest		Lowest measured temperature. LTC2974 and LTC2978 only.
 | 
				
			||||||
temp[1-3]_reset_history	Reset history. Writing into this attribute will reset
 | 
								Not supported for chip temperature sensor on LTC2974.
 | 
				
			||||||
			history for all attributes.
 | 
					temp[N]_highest		Highest measured temperature. Not supported for chip
 | 
				
			||||||
 | 
								temperature sensor on LTC2974.
 | 
				
			||||||
 | 
					temp[N]_reset_history	Reset temperature history. Not supported for chip
 | 
				
			||||||
 | 
								temperature sensor on LTC2974.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
power[1-2]_label	"pout[1-2]". LTC3880 only.
 | 
					power1_label		"pin". LTC3883 only.
 | 
				
			||||||
power[1-2]_input	Measured power.
 | 
					power1_input		Measured input power.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
curr1_label		"iin". LTC3880 only.
 | 
					power[N]_label		"pout[1-4]".
 | 
				
			||||||
 | 
								LTC2974: N=1-4
 | 
				
			||||||
 | 
								LTC2978: Not supported
 | 
				
			||||||
 | 
								LTC3880: N=1-2
 | 
				
			||||||
 | 
								LTC3883: N=2
 | 
				
			||||||
 | 
					power[N]_input		Measured output power.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					curr1_label		"iin". LTC3880 and LTC3883 only.
 | 
				
			||||||
curr1_input		Measured input current.
 | 
					curr1_input		Measured input current.
 | 
				
			||||||
curr1_max		Maximum input current.
 | 
					curr1_max		Maximum input current.
 | 
				
			||||||
curr1_max_alarm		Input current high alarm.
 | 
					curr1_max_alarm		Input current high alarm.
 | 
				
			||||||
 | 
					curr1_highest		Highest input current. LTC3883 only.
 | 
				
			||||||
 | 
					curr1_reset_history	Reset input current history. LTC3883 only.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
curr[2-3]_label		"iout[1-2]". LTC3880 only.
 | 
					curr[N]_label		"iout[1-4]".
 | 
				
			||||||
curr[2-3]_input		Measured input current.
 | 
								LTC2974: N=1-4
 | 
				
			||||||
curr[2-3]_max		Maximum input current.
 | 
								LTC2978: not supported
 | 
				
			||||||
curr[2-3]_crit		Critical input current.
 | 
								LTC3880: N=2-3
 | 
				
			||||||
curr[2-3]_max_alarm	Input current high alarm.
 | 
								LTC3883: N=2
 | 
				
			||||||
curr[2-3]_crit_alarm	Input current critical high alarm.
 | 
					curr[N]_input		Measured output current.
 | 
				
			||||||
 | 
					curr[N]_max		Maximum output current.
 | 
				
			||||||
 | 
					curr[N]_crit		Critical high output current.
 | 
				
			||||||
 | 
					curr[N]_lcrit		Critical low output current. LTC2974 only.
 | 
				
			||||||
 | 
					curr[N]_max_alarm	Output current high alarm.
 | 
				
			||||||
 | 
					curr[N]_crit_alarm	Output current critical high alarm.
 | 
				
			||||||
 | 
					curr[N]_lcrit_alarm	Output current critical low alarm. LTC2974 only.
 | 
				
			||||||
 | 
					curr[N]_lowest		Lowest output current. LTC2974 only.
 | 
				
			||||||
 | 
					curr[N]_highest		Highest output current.
 | 
				
			||||||
 | 
					curr[N]_reset_history	Reset output current history.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										188
									
								
								Documentation/hwmon/nct6775
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								Documentation/hwmon/nct6775
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,188 @@
 | 
				
			||||||
 | 
					Note
 | 
				
			||||||
 | 
					====
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This driver supersedes the NCT6775F and NCT6776F support in the W83627EHF
 | 
				
			||||||
 | 
					driver.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Kernel driver NCT6775
 | 
				
			||||||
 | 
					=====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Supported chips:
 | 
				
			||||||
 | 
					  * Nuvoton NCT5572D/NCT6771F/NCT6772F/NCT6775F/W83677HG-I
 | 
				
			||||||
 | 
					    Prefix: 'nct6775'
 | 
				
			||||||
 | 
					    Addresses scanned: ISA address retrieved from Super I/O registers
 | 
				
			||||||
 | 
					    Datasheet: Available from Nuvoton upon request
 | 
				
			||||||
 | 
					  * Nuvoton NCT5577D/NCT6776D/NCT6776F
 | 
				
			||||||
 | 
					    Prefix: 'nct6776'
 | 
				
			||||||
 | 
					    Addresses scanned: ISA address retrieved from Super I/O registers
 | 
				
			||||||
 | 
					    Datasheet: Available from Nuvoton upon request
 | 
				
			||||||
 | 
					  * Nuvoton NCT5532D/NCT6779D
 | 
				
			||||||
 | 
					    Prefix: 'nct6779'
 | 
				
			||||||
 | 
					    Addresses scanned: ISA address retrieved from Super I/O registers
 | 
				
			||||||
 | 
					    Datasheet: Available from Nuvoton upon request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Authors:
 | 
				
			||||||
 | 
					        Guenter Roeck <linux@roeck-us.net>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Description
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This driver implements support for the Nuvoton NCT6775F, NCT6776F, and NCT6779D
 | 
				
			||||||
 | 
					and compatible super I/O chips.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The chips support up to 25 temperature monitoring sources. Up to 6 of those are
 | 
				
			||||||
 | 
					direct temperature sensor inputs, the others are special sources such as PECI,
 | 
				
			||||||
 | 
					PCH, and SMBUS. Depending on the chip type, 2 to 6 of the temperature sources
 | 
				
			||||||
 | 
					can be monitored and compared against minimum, maximum, and critical
 | 
				
			||||||
 | 
					temperatures. The driver reports up to 10 of the temperatures to the user.
 | 
				
			||||||
 | 
					There are 4 to 5 fan rotation speed sensors, 8 to 15 analog voltage sensors,
 | 
				
			||||||
 | 
					one VID, alarms with beep warnings (control unimplemented), and some automatic
 | 
				
			||||||
 | 
					fan regulation strategies (plus manual fan control mode).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The temperature sensor sources on all chips are configurable. The configured
 | 
				
			||||||
 | 
					source for each of the temperature sensors is provided in tempX_label.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Temperatures are measured in degrees Celsius and measurement resolution is
 | 
				
			||||||
 | 
					either 1 degC or 0.5 degC, depending on the temperature source and
 | 
				
			||||||
 | 
					configuration. An alarm is triggered when the temperature gets higher than
 | 
				
			||||||
 | 
					the high limit; it stays on until the temperature falls below the hysteresis
 | 
				
			||||||
 | 
					value. Alarms are only supported for temp1 to temp6, depending on the chip type.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
 | 
				
			||||||
 | 
					triggered if the rotation speed has dropped below a programmable limit. On
 | 
				
			||||||
 | 
					NCT6775F, fan readings can be divided by a programmable divider (1, 2, 4, 8,
 | 
				
			||||||
 | 
					16, 32, 64 or 128) to give the readings more range or accuracy; the other chips
 | 
				
			||||||
 | 
					do not have a fan speed divider. The driver sets the most suitable fan divisor
 | 
				
			||||||
 | 
					itself; specifically, it increases the divider value each time a fan speed
 | 
				
			||||||
 | 
					reading returns an invalid value, and it reduces it if the fan speed reading
 | 
				
			||||||
 | 
					is lower than optimal. Some fans might not be present because they share pins
 | 
				
			||||||
 | 
					with other functions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Voltage sensors (also known as IN sensors) report their values in millivolts.
 | 
				
			||||||
 | 
					An alarm is triggered if the voltage has crossed a programmable minimum
 | 
				
			||||||
 | 
					or maximum limit.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The driver supports automatic fan control mode known as Thermal Cruise.
 | 
				
			||||||
 | 
					In this mode, the chip attempts to keep the measured temperature in a
 | 
				
			||||||
 | 
					predefined temperature range. If the temperature goes out of range, fan
 | 
				
			||||||
 | 
					is driven slower/faster to reach the predefined range again.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The mode works for fan1-fan5.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sysfs attributes
 | 
				
			||||||
 | 
					----------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pwm[1-5] - this file stores PWM duty cycle or DC value (fan speed) in range:
 | 
				
			||||||
 | 
						   0 (lowest speed) to 255 (full)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pwm[1-5]_enable - this file controls mode of fan/temperature control:
 | 
				
			||||||
 | 
						* 0 Fan control disabled (fans set to maximum speed)
 | 
				
			||||||
 | 
						* 1 Manual mode, write to pwm[0-5] any value 0-255
 | 
				
			||||||
 | 
						* 2 "Thermal Cruise" mode
 | 
				
			||||||
 | 
						* 3 "Fan Speed Cruise" mode
 | 
				
			||||||
 | 
						* 4 "Smart Fan III" mode (NCT6775F only)
 | 
				
			||||||
 | 
						* 5 "Smart Fan IV" mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pwm[1-5]_mode - controls if output is PWM or DC level
 | 
				
			||||||
 | 
					        * 0 DC output
 | 
				
			||||||
 | 
					        * 1 PWM output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Common fan control attributes
 | 
				
			||||||
 | 
					-----------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pwm[1-5]_temp_sel	Temperature source. Value is temperature sensor index.
 | 
				
			||||||
 | 
								For example, select '1' for temp1_input.
 | 
				
			||||||
 | 
					pwm[1-5]_weight_temp_sel
 | 
				
			||||||
 | 
								Secondary temperature source. Value is temperature
 | 
				
			||||||
 | 
								sensor index. For example, select '1' for temp1_input.
 | 
				
			||||||
 | 
								Set to 0 to disable secondary temperature control.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If secondary temperature functionality is enabled, it is controlled with the
 | 
				
			||||||
 | 
					following attributes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pwm[1-5]_weight_duty_step
 | 
				
			||||||
 | 
								Duty step size.
 | 
				
			||||||
 | 
					pwm[1-5]_weight_temp_step
 | 
				
			||||||
 | 
								Temperature step size. With each step over
 | 
				
			||||||
 | 
								temp_step_base, the value of weight_duty_step is added
 | 
				
			||||||
 | 
								to the current pwm value.
 | 
				
			||||||
 | 
					pwm[1-5]_weight_temp_step_base
 | 
				
			||||||
 | 
								Temperature at which secondary temperature control kicks
 | 
				
			||||||
 | 
								in.
 | 
				
			||||||
 | 
					pwm[1-5]_weight_temp_step_tol
 | 
				
			||||||
 | 
								Temperature step tolerance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thermal Cruise mode (2)
 | 
				
			||||||
 | 
					-----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the temperature is in the range defined by:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pwm[1-5]_target_temp	Target temperature, unit millidegree Celsius
 | 
				
			||||||
 | 
								(range 0 - 127000)
 | 
				
			||||||
 | 
					pwm[1-5]_temp_tolerance
 | 
				
			||||||
 | 
								Target temperature tolerance, unit millidegree Celsius
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					there are no changes to fan speed. Once the temperature leaves the interval, fan
 | 
				
			||||||
 | 
					speed increases (if temperature is higher that desired) or decreases (if
 | 
				
			||||||
 | 
					temperature is lower than desired), using the following limits and time
 | 
				
			||||||
 | 
					intervals.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pwm[1-5]_start		fan pwm start value (range 1 - 255), to start fan
 | 
				
			||||||
 | 
								when the temperature is above defined range.
 | 
				
			||||||
 | 
					pwm[1-5]_floor		lowest fan pwm (range 0 - 255) if temperature is below
 | 
				
			||||||
 | 
								the defined range. If set to 0, the fan is expected to
 | 
				
			||||||
 | 
								stop if the temperature is below the defined range.
 | 
				
			||||||
 | 
					pwm[1-5]_step_up_time	milliseconds before fan speed is increased
 | 
				
			||||||
 | 
					pwm[1-5]_step_down_time	milliseconds before fan speed is decreased
 | 
				
			||||||
 | 
					pwm[1-5]_stop_time	how many milliseconds must elapse to switch
 | 
				
			||||||
 | 
								corresponding fan off (when the temperature was below
 | 
				
			||||||
 | 
								defined range).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Speed Cruise mode (3)
 | 
				
			||||||
 | 
					---------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This modes tries to keep the fan speed constant.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fan[1-5]_target		Target fan speed
 | 
				
			||||||
 | 
					fan[1-5]_tolerance
 | 
				
			||||||
 | 
								Target speed tolerance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Untested; use at your own risk.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Smart Fan IV mode (5)
 | 
				
			||||||
 | 
					---------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This mode offers multiple slopes to control the fan speed. The slopes can be
 | 
				
			||||||
 | 
					controlled by setting the pwm and temperature attributes. When the temperature
 | 
				
			||||||
 | 
					rises, the chip will calculate the DC/PWM output based on the current slope.
 | 
				
			||||||
 | 
					There are up to seven data points depending on the chip type. Subsequent data
 | 
				
			||||||
 | 
					points should be set to higher temperatures and higher pwm values to achieve
 | 
				
			||||||
 | 
					higher fan speeds with increasing temperature. The last data point reflects
 | 
				
			||||||
 | 
					critical temperature mode, in which the fans should run at full speed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pwm[1-5]_auto_point[1-7]_pwm
 | 
				
			||||||
 | 
								pwm value to be set if temperature reaches matching
 | 
				
			||||||
 | 
								temperature range.
 | 
				
			||||||
 | 
					pwm[1-5]_auto_point[1-7]_temp
 | 
				
			||||||
 | 
								Temperature over which the matching pwm is enabled.
 | 
				
			||||||
 | 
					pwm[1-5]_temp_tolerance
 | 
				
			||||||
 | 
								Temperature tolerance, unit millidegree Celsius
 | 
				
			||||||
 | 
					pwm[1-5]_crit_temp_tolerance
 | 
				
			||||||
 | 
								Temperature tolerance for critical temperature,
 | 
				
			||||||
 | 
								unit millidegree Celsius
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pwm[1-5]_step_up_time	milliseconds before fan speed is increased
 | 
				
			||||||
 | 
					pwm[1-5]_step_down_time	milliseconds before fan speed is decreased
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Usage Notes
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On various ASUS boards with NCT6776F, it appears that CPUTIN is not really
 | 
				
			||||||
 | 
					connected to anything and floats, or that it is connected to some non-standard
 | 
				
			||||||
 | 
					temperature measurement device. As a result, the temperature reported on CPUTIN
 | 
				
			||||||
 | 
					will not reflect a usable value. It often reports unreasonably high
 | 
				
			||||||
 | 
					temperatures, and in some cases the reported temperature declines if the actual
 | 
				
			||||||
 | 
					temperature increases (similar to the raw PECI temperature value - see PECI
 | 
				
			||||||
 | 
					specification for details). CPUTIN should therefore be be ignored on ASUS
 | 
				
			||||||
 | 
					boards. The CPU temperature on ASUS boards is reported from PECI 0.
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,7 @@ bits for humidity, or 12 bits for temperature and 8 bits for humidity.
 | 
				
			||||||
The humidity calibration coefficients are programmed into an OTP memory on the
 | 
					The humidity calibration coefficients are programmed into an OTP memory on the
 | 
				
			||||||
chip. These coefficients are used to internally calibrate the signals from the
 | 
					chip. These coefficients are used to internally calibrate the signals from the
 | 
				
			||||||
sensors. Disabling the reload of those coefficients allows saving 10ms for each
 | 
					sensors. Disabling the reload of those coefficients allows saving 10ms for each
 | 
				
			||||||
measurement and decrease power consumption, while loosing on precision.
 | 
					measurement and decrease power consumption, while losing on precision.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Some options may be set directly in the sht15_platform_data structure
 | 
					Some options may be set directly in the sht15_platform_data structure
 | 
				
			||||||
or via sysfs attributes.
 | 
					or via sysfs attributes.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,8 +8,16 @@ Supported chips:
 | 
				
			||||||
    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html
 | 
					    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html
 | 
				
			||||||
  * Texas Instruments TMP411
 | 
					  * Texas Instruments TMP411
 | 
				
			||||||
    Prefix: 'tmp411'
 | 
					    Prefix: 'tmp411'
 | 
				
			||||||
    Addresses scanned: I2C 0x4c
 | 
					    Addresses scanned: I2C 0x4c, 0x4d, 0x4e
 | 
				
			||||||
    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html
 | 
					    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html
 | 
				
			||||||
 | 
					  * Texas Instruments TMP431
 | 
				
			||||||
 | 
					    Prefix: 'tmp431'
 | 
				
			||||||
 | 
					    Addresses scanned: I2C 0x4c, 0x4d
 | 
				
			||||||
 | 
					    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp431.html
 | 
				
			||||||
 | 
					  * Texas Instruments TMP432
 | 
				
			||||||
 | 
					    Prefix: 'tmp432'
 | 
				
			||||||
 | 
					    Addresses scanned: I2C 0x4c, 0x4d
 | 
				
			||||||
 | 
					    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp432.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Authors:
 | 
					Authors:
 | 
				
			||||||
         Hans de Goede <hdegoede@redhat.com>
 | 
					         Hans de Goede <hdegoede@redhat.com>
 | 
				
			||||||
| 
						 | 
					@ -18,19 +26,19 @@ Authors:
 | 
				
			||||||
Description
 | 
					Description
 | 
				
			||||||
-----------
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This driver implements support for Texas Instruments TMP401 and
 | 
					This driver implements support for Texas Instruments TMP401, TMP411,
 | 
				
			||||||
TMP411 chips. These chips implements one remote and one local
 | 
					TMP431, and TMP432 chips. These chips implement one or two remote and
 | 
				
			||||||
temperature sensor. Temperature is measured in degrees
 | 
					one local temperature sensors. Temperature is measured in degrees
 | 
				
			||||||
Celsius. Resolution of the remote sensor is 0.0625 degree. Local
 | 
					Celsius. Resolution of the remote sensor is 0.0625 degree. Local
 | 
				
			||||||
sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
 | 
					sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
 | 
				
			||||||
supported by the driver so far, so using the default resolution of 0.5
 | 
					supported by the driver so far, so using the default resolution of 0.5
 | 
				
			||||||
degree).
 | 
					degree).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The driver provides the common sysfs-interface for temperatures (see
 | 
					The driver provides the common sysfs-interface for temperatures (see
 | 
				
			||||||
/Documentation/hwmon/sysfs-interface under Temperatures).
 | 
					Documentation/hwmon/sysfs-interface under Temperatures).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The TMP411 chip is compatible with TMP401. It provides some additional
 | 
					The TMP411 and TMP431 chips are compatible with TMP401. TMP411 provides
 | 
				
			||||||
features.
 | 
					some additional features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Minimum and Maximum temperature measured since power-on, chip-reset
 | 
					* Minimum and Maximum temperature measured since power-on, chip-reset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,3 +48,6 @@ features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Exported via sysfs attribute temp_reset_history. Writing 1 to this
 | 
					  Exported via sysfs attribute temp_reset_history. Writing 1 to this
 | 
				
			||||||
  file triggers a reset.
 | 
					  file triggers a reset.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TMP432 is compatible with TMP401 and TMP431. It supports two external
 | 
				
			||||||
 | 
					temperature sensors.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,7 +125,7 @@ in2_label		"vmon"
 | 
				
			||||||
in2_input		Measured voltage on VMON (ZL2004) or VDRV (ZL9101M,
 | 
					in2_input		Measured voltage on VMON (ZL2004) or VDRV (ZL9101M,
 | 
				
			||||||
			ZL9117M) pin. Reported voltage is 16x the voltage on the
 | 
								ZL9117M) pin. Reported voltage is 16x the voltage on the
 | 
				
			||||||
			pin (adjusted internally by the chip).
 | 
								pin (adjusted internally by the chip).
 | 
				
			||||||
in2_lcrit		Critical minumum VMON/VDRV Voltage.
 | 
					in2_lcrit		Critical minimum VMON/VDRV Voltage.
 | 
				
			||||||
in2_crit		Critical maximum VMON/VDRV voltage.
 | 
					in2_crit		Critical maximum VMON/VDRV voltage.
 | 
				
			||||||
in2_lcrit_alarm		VMON/VDRV voltage critical low alarm.
 | 
					in2_lcrit_alarm		VMON/VDRV voltage critical low alarm.
 | 
				
			||||||
in2_crit_alarm		VMON/VDRV voltage critical high alarm.
 | 
					in2_crit_alarm		VMON/VDRV voltage critical high alarm.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5412,6 +5412,13 @@ L:	linux-scsi@vger.kernel.org
 | 
				
			||||||
S:	Maintained
 | 
					S:	Maintained
 | 
				
			||||||
F:	drivers/scsi/NCR_D700.*
 | 
					F:	drivers/scsi/NCR_D700.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NCT6775 HARDWARE MONITOR DRIVER
 | 
				
			||||||
 | 
					M:	Guenter Roeck <linux@roeck-us.net>
 | 
				
			||||||
 | 
					L:	lm-sensors@lm-sensors.org
 | 
				
			||||||
 | 
					S:	Maintained
 | 
				
			||||||
 | 
					F:	Documentation/hwmon/nct6775
 | 
				
			||||||
 | 
					F:	drivers/hwmon/nct6775.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NETEFFECT IWARP RNIC DRIVER (IW_NES)
 | 
					NETEFFECT IWARP RNIC DRIVER (IW_NES)
 | 
				
			||||||
M:	Faisal Latif <faisal.latif@intel.com>
 | 
					M:	Faisal Latif <faisal.latif@intel.com>
 | 
				
			||||||
L:	linux-rdma@vger.kernel.org
 | 
					L:	linux-rdma@vger.kernel.org
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -179,9 +179,29 @@ config SENSORS_ADM9240
 | 
				
			||||||
	  This driver can also be built as a module.  If so, the module
 | 
						  This driver can also be built as a module.  If so, the module
 | 
				
			||||||
	  will be called adm9240.
 | 
						  will be called adm9240.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SENSORS_ADT7X10
 | 
				
			||||||
 | 
						tristate
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  This module contains common code shared by the ADT7310/ADT7320 and
 | 
				
			||||||
 | 
						  ADT7410/ADT7420 temperature monitoring chip drivers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  If build as a module, the module will be called adt7x10.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SENSORS_ADT7310
 | 
				
			||||||
 | 
						tristate "Analog Devices ADT7310/ADT7320"
 | 
				
			||||||
 | 
						depends on SPI_MASTER
 | 
				
			||||||
 | 
						select SENSORS_ADT7X10
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  If you say yes here you get support for the Analog Devices
 | 
				
			||||||
 | 
						  ADT7310 and ADT7320 temperature monitoring chips.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  This driver can also be built as a module. If so, the module
 | 
				
			||||||
 | 
						  will be called adt7310.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config SENSORS_ADT7410
 | 
					config SENSORS_ADT7410
 | 
				
			||||||
	tristate "Analog Devices ADT7410/ADT7420"
 | 
						tristate "Analog Devices ADT7410/ADT7420"
 | 
				
			||||||
	depends on I2C
 | 
						depends on I2C
 | 
				
			||||||
 | 
						select SENSORS_ADT7X10
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  If you say yes here you get support for the Analog Devices
 | 
						  If you say yes here you get support for the Analog Devices
 | 
				
			||||||
	  ADT7410 and ADT7420 temperature monitoring chips.
 | 
						  ADT7410 and ADT7420 temperature monitoring chips.
 | 
				
			||||||
| 
						 | 
					@ -751,6 +771,16 @@ config SENSORS_LTC4261
 | 
				
			||||||
	  This driver can also be built as a module. If so, the module will
 | 
						  This driver can also be built as a module. If so, the module will
 | 
				
			||||||
	  be called ltc4261.
 | 
						  be called ltc4261.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SENSORS_LM95234
 | 
				
			||||||
 | 
						tristate "National Semiconductor LM95234"
 | 
				
			||||||
 | 
						depends on I2C
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  If you say yes here you get support for the LM95234 temperature
 | 
				
			||||||
 | 
						  sensor.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  This driver can also be built as a module.  If so, the module
 | 
				
			||||||
 | 
						  will be called lm95234.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config SENSORS_LM95241
 | 
					config SENSORS_LM95241
 | 
				
			||||||
	tristate "National Semiconductor LM95241 and compatibles"
 | 
						tristate "National Semiconductor LM95241 and compatibles"
 | 
				
			||||||
	depends on I2C
 | 
						depends on I2C
 | 
				
			||||||
| 
						 | 
					@ -877,8 +907,22 @@ config SENSORS_MCP3021
 | 
				
			||||||
	  This driver can also be built as a module.  If so, the module
 | 
						  This driver can also be built as a module.  If so, the module
 | 
				
			||||||
	  will be called mcp3021.
 | 
						  will be called mcp3021.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SENSORS_NCT6775
 | 
				
			||||||
 | 
						tristate "Nuvoton NCT6775F and compatibles"
 | 
				
			||||||
 | 
						depends on !PPC
 | 
				
			||||||
 | 
						select HWMON_VID
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  If you say yes here you get support for the hardware monitoring
 | 
				
			||||||
 | 
						  functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
 | 
				
			||||||
 | 
						  and compatible Super-I/O chips. This driver replaces the
 | 
				
			||||||
 | 
						  w83627ehf driver for NCT6775F and NCT6776F.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  This driver can also be built as a module.  If so, the module
 | 
				
			||||||
 | 
						  will be called nct6775.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config SENSORS_NTC_THERMISTOR
 | 
					config SENSORS_NTC_THERMISTOR
 | 
				
			||||||
	tristate "NTC thermistor support"
 | 
						tristate "NTC thermistor support"
 | 
				
			||||||
 | 
						depends on (!OF && !IIO) || (OF && IIO)
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  This driver supports NTC thermistors sensor reading and its
 | 
						  This driver supports NTC thermistors sensor reading and its
 | 
				
			||||||
	  interpretation. The driver can also monitor the temperature and
 | 
						  interpretation. The driver can also monitor the temperature and
 | 
				
			||||||
| 
						 | 
					@ -1204,8 +1248,8 @@ config SENSORS_TMP401
 | 
				
			||||||
	tristate "Texas Instruments TMP401 and compatibles"
 | 
						tristate "Texas Instruments TMP401 and compatibles"
 | 
				
			||||||
	depends on I2C
 | 
						depends on I2C
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  If you say yes here you get support for Texas Instruments TMP401 and
 | 
						  If you say yes here you get support for Texas Instruments TMP401,
 | 
				
			||||||
	  TMP411 temperature sensor chips.
 | 
						  TMP411, TMP431, and TMP432 temperature sensor chips.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  This driver can also be built as a module.  If so, the module
 | 
						  This driver can also be built as a module.  If so, the module
 | 
				
			||||||
	  will be called tmp401.
 | 
						  will be called tmp401.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
 | 
					obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
 | 
					obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
 | 
					obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_SENSORS_ADT7X10)	+= adt7x10.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_SENSORS_ADT7310)	+= adt7310.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
 | 
					obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
 | 
					obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
 | 
					obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
 | 
				
			||||||
| 
						 | 
					@ -86,6 +88,7 @@ obj-$(CONFIG_SENSORS_LM87)	+= lm87.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
 | 
					obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_LM92)	+= lm92.o
 | 
					obj-$(CONFIG_SENSORS_LM92)	+= lm92.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_LM93)	+= lm93.o
 | 
					obj-$(CONFIG_SENSORS_LM93)	+= lm93.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_SENSORS_LM95234)	+= lm95234.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_LM95241)	+= lm95241.o
 | 
					obj-$(CONFIG_SENSORS_LM95241)	+= lm95241.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_LM95245)	+= lm95245.o
 | 
					obj-$(CONFIG_SENSORS_LM95245)	+= lm95245.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_LTC4151)	+= ltc4151.o
 | 
					obj-$(CONFIG_SENSORS_LTC4151)	+= ltc4151.o
 | 
				
			||||||
| 
						 | 
					@ -103,6 +106,7 @@ obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_MAX6697)	+= max6697.o
 | 
					obj-$(CONFIG_SENSORS_MAX6697)	+= max6697.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 | 
					obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_MCP3021)	+= mcp3021.o
 | 
					obj-$(CONFIG_SENSORS_MCP3021)	+= mcp3021.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_SENSORS_NCT6775)	+= nct6775.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_NTC_THERMISTOR)	+= ntc_thermistor.o
 | 
					obj-$(CONFIG_SENSORS_NTC_THERMISTOR)	+= ntc_thermistor.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
 | 
					obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
 | 
				
			||||||
obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
 | 
					obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,9 +96,12 @@
 | 
				
			||||||
#define ABIT_UGURU_MAX_TIMEOUTS			2
 | 
					#define ABIT_UGURU_MAX_TIMEOUTS			2
 | 
				
			||||||
/* utility macros */
 | 
					/* utility macros */
 | 
				
			||||||
#define ABIT_UGURU_NAME				"abituguru"
 | 
					#define ABIT_UGURU_NAME				"abituguru"
 | 
				
			||||||
#define ABIT_UGURU_DEBUG(level, format, arg...)				\
 | 
					#define ABIT_UGURU_DEBUG(level, format, arg...)		\
 | 
				
			||||||
	if (level <= verbose)						\
 | 
						do {						\
 | 
				
			||||||
		printk(KERN_DEBUG ABIT_UGURU_NAME ": "	format , ## arg)
 | 
							if (level <= verbose)			\
 | 
				
			||||||
 | 
								pr_debug(format , ## arg);	\
 | 
				
			||||||
 | 
						} while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Macros to help calculate the sysfs_names array length */
 | 
					/* Macros to help calculate the sysfs_names array length */
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
 | 
					 * sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
 | 
				
			||||||
| 
						 | 
					@ -1533,7 +1536,7 @@ static int abituguru_resume(struct device *dev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static SIMPLE_DEV_PM_OPS(abituguru_pm, abituguru_suspend, abituguru_resume);
 | 
					static SIMPLE_DEV_PM_OPS(abituguru_pm, abituguru_suspend, abituguru_resume);
 | 
				
			||||||
#define ABIT_UGURU_PM	&abituguru_pm
 | 
					#define ABIT_UGURU_PM	(&abituguru_pm)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define ABIT_UGURU_PM	NULL
 | 
					#define ABIT_UGURU_PM	NULL
 | 
				
			||||||
#endif /* CONFIG_PM */
 | 
					#endif /* CONFIG_PM */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,9 +76,11 @@
 | 
				
			||||||
#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT		5
 | 
					#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT		5
 | 
				
			||||||
/* utility macros */
 | 
					/* utility macros */
 | 
				
			||||||
#define ABIT_UGURU3_NAME			"abituguru3"
 | 
					#define ABIT_UGURU3_NAME			"abituguru3"
 | 
				
			||||||
#define ABIT_UGURU3_DEBUG(format, arg...)	\
 | 
					#define ABIT_UGURU3_DEBUG(format, arg...)		\
 | 
				
			||||||
	if (verbose)				\
 | 
						do {						\
 | 
				
			||||||
		printk(KERN_DEBUG ABIT_UGURU3_NAME ": "	format , ## arg)
 | 
							if (verbose)				\
 | 
				
			||||||
 | 
								pr_debug(format , ## arg);	\
 | 
				
			||||||
 | 
						} while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Macros to help calculate the sysfs_names array length */
 | 
					/* Macros to help calculate the sysfs_names array length */
 | 
				
			||||||
#define ABIT_UGURU3_MAX_NO_SENSORS 26
 | 
					#define ABIT_UGURU3_MAX_NO_SENSORS 26
 | 
				
			||||||
| 
						 | 
					@ -1159,7 +1161,7 @@ static int abituguru3_resume(struct device *dev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume);
 | 
					static SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume);
 | 
				
			||||||
#define ABIT_UGURU3_PM	&abituguru3_pm
 | 
					#define ABIT_UGURU3_PM	(&abituguru3_pm)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define ABIT_UGURU3_PM	NULL
 | 
					#define ABIT_UGURU3_PM	NULL
 | 
				
			||||||
#endif /* CONFIG_PM */
 | 
					#endif /* CONFIG_PM */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,7 +116,7 @@ static int ad7314_probe(struct spi_device *spi_dev)
 | 
				
			||||||
	if (chip == NULL)
 | 
						if (chip == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_set_drvdata(&spi_dev->dev, chip);
 | 
						spi_set_drvdata(spi_dev, chip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
 | 
						ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
| 
						 | 
					@ -137,7 +137,7 @@ error_remove_group:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ad7314_remove(struct spi_device *spi_dev)
 | 
					static int ad7314_remove(struct spi_device *spi_dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev);
 | 
						struct ad7314_data *chip = spi_get_drvdata(spi_dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hwmon_device_unregister(chip->hwmon_dev);
 | 
						hwmon_device_unregister(chip->hwmon_dev);
 | 
				
			||||||
	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
 | 
						sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
 | 
				
			||||||
| 
						 | 
					@ -166,6 +166,5 @@ static struct spi_driver ad7314_driver = {
 | 
				
			||||||
module_spi_driver(ad7314_driver);
 | 
					module_spi_driver(ad7314_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
 | 
					MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
 | 
				
			||||||
MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
 | 
					MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
 | 
				
			||||||
			" temperature sensor driver");
 | 
					 | 
				
			||||||
MODULE_LICENSE("GPL v2");
 | 
					MODULE_LICENSE("GPL v2");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -312,8 +312,7 @@ static int adm1021_detect(struct i2c_client *client,
 | 
				
			||||||
	int conv_rate, status, config, man_id, dev_id;
 | 
						int conv_rate, status, config, man_id, dev_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 | 
						if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 | 
				
			||||||
		pr_debug("adm1021: detect failed, "
 | 
							pr_debug("detect failed, smbus byte data not supported!\n");
 | 
				
			||||||
			 "smbus byte data not supported!\n");
 | 
					 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -324,7 +323,7 @@ static int adm1021_detect(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check unused bits */
 | 
						/* Check unused bits */
 | 
				
			||||||
	if ((status & 0x03) || (config & 0x3F) || (conv_rate & 0xF8)) {
 | 
						if ((status & 0x03) || (config & 0x3F) || (conv_rate & 0xF8)) {
 | 
				
			||||||
		pr_debug("adm1021: detect failed, chip not detected!\n");
 | 
							pr_debug("detect failed, chip not detected!\n");
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -353,7 +352,7 @@ static int adm1021_detect(struct i2c_client *client,
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		type_name = "max1617";
 | 
							type_name = "max1617";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
 | 
						pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n",
 | 
				
			||||||
		 type_name, i2c_adapter_id(adapter), client->addr);
 | 
							 type_name, i2c_adapter_id(adapter), client->addr);
 | 
				
			||||||
	strlcpy(info->type, type_name, I2C_NAME_SIZE);
 | 
						strlcpy(info->type, type_name, I2C_NAME_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -368,10 +367,8 @@ static int adm1021_probe(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data = devm_kzalloc(&client->dev, sizeof(struct adm1021_data),
 | 
						data = devm_kzalloc(&client->dev, sizeof(struct adm1021_data),
 | 
				
			||||||
			    GFP_KERNEL);
 | 
								    GFP_KERNEL);
 | 
				
			||||||
	if (!data) {
 | 
						if (!data)
 | 
				
			||||||
		pr_debug("adm1021: detect failed, devm_kzalloc failed!\n");
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i2c_set_clientdata(client, data);
 | 
						i2c_set_clientdata(client, data);
 | 
				
			||||||
	data->type = id->driver_data;
 | 
						data->type = id->driver_data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,14 +49,14 @@ static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
 | 
				
			||||||
module_param_array(gpio_input, int, NULL, 0);
 | 
					module_param_array(gpio_input, int, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(gpio_input, "List of GPIO pins (0-16) to program as inputs");
 | 
					MODULE_PARM_DESC(gpio_input, "List of GPIO pins (0-16) to program as inputs");
 | 
				
			||||||
module_param_array(gpio_output, int, NULL, 0);
 | 
					module_param_array(gpio_output, int, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(gpio_output, "List of GPIO pins (0-16) to program as "
 | 
					MODULE_PARM_DESC(gpio_output,
 | 
				
			||||||
	"outputs");
 | 
							 "List of GPIO pins (0-16) to program as outputs");
 | 
				
			||||||
module_param_array(gpio_inverted, int, NULL, 0);
 | 
					module_param_array(gpio_inverted, int, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(gpio_inverted, "List of GPIO pins (0-16) to program as "
 | 
					MODULE_PARM_DESC(gpio_inverted,
 | 
				
			||||||
	"inverted");
 | 
							 "List of GPIO pins (0-16) to program as inverted");
 | 
				
			||||||
module_param_array(gpio_normal, int, NULL, 0);
 | 
					module_param_array(gpio_normal, int, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(gpio_normal, "List of GPIO pins (0-16) to program as "
 | 
					MODULE_PARM_DESC(gpio_normal,
 | 
				
			||||||
	"normal/non-inverted");
 | 
							 "List of GPIO pins (0-16) to program as normal/non-inverted");
 | 
				
			||||||
module_param_array(gpio_fan, int, NULL, 0);
 | 
					module_param_array(gpio_fan, int, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs");
 | 
					MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -372,31 +372,31 @@ static void adm1026_init_client(struct i2c_client *client)
 | 
				
			||||||
	dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n",
 | 
						dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n",
 | 
				
			||||||
		data->config1);
 | 
							data->config1);
 | 
				
			||||||
	if ((data->config1 & CFG1_MONITOR) == 0) {
 | 
						if ((data->config1 & CFG1_MONITOR) == 0) {
 | 
				
			||||||
		dev_dbg(&client->dev, "Monitoring not currently "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"enabled.\n");
 | 
								"Monitoring not currently enabled.\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (data->config1 & CFG1_INT_ENABLE) {
 | 
						if (data->config1 & CFG1_INT_ENABLE) {
 | 
				
			||||||
		dev_dbg(&client->dev, "SMBALERT interrupts are "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"enabled.\n");
 | 
								"SMBALERT interrupts are enabled.\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (data->config1 & CFG1_AIN8_9) {
 | 
						if (data->config1 & CFG1_AIN8_9) {
 | 
				
			||||||
		dev_dbg(&client->dev, "in8 and in9 enabled. "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"temp3 disabled.\n");
 | 
								"in8 and in9 enabled. temp3 disabled.\n");
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		dev_dbg(&client->dev, "temp3 enabled.  in8 and "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"in9 disabled.\n");
 | 
								"temp3 enabled.  in8 and in9 disabled.\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (data->config1 & CFG1_THERM_HOT) {
 | 
						if (data->config1 & CFG1_THERM_HOT) {
 | 
				
			||||||
		dev_dbg(&client->dev, "Automatic THERM, PWM, "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"and temp limits enabled.\n");
 | 
								"Automatic THERM, PWM, and temp limits enabled.\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data->config3 & CFG3_GPIO16_ENABLE) {
 | 
						if (data->config3 & CFG3_GPIO16_ENABLE) {
 | 
				
			||||||
		dev_dbg(&client->dev, "GPIO16 enabled.  THERM "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"pin disabled.\n");
 | 
								"GPIO16 enabled.  THERM pin disabled.\n");
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		dev_dbg(&client->dev, "THERM pin enabled.  "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"GPIO16 disabled.\n");
 | 
								"THERM pin enabled.  GPIO16 disabled.\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (data->config3 & CFG3_VREF_250)
 | 
						if (data->config3 & CFG3_VREF_250)
 | 
				
			||||||
		dev_dbg(&client->dev, "Vref is 2.50 Volts.\n");
 | 
							dev_dbg(&client->dev, "Vref is 2.50 Volts.\n");
 | 
				
			||||||
| 
						 | 
					@ -1798,8 +1798,8 @@ static int adm1026_detect(struct i2c_client *client,
 | 
				
			||||||
	company = adm1026_read_value(client, ADM1026_REG_COMPANY);
 | 
						company = adm1026_read_value(client, ADM1026_REG_COMPANY);
 | 
				
			||||||
	verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
 | 
						verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with"
 | 
						dev_dbg(&adapter->dev,
 | 
				
			||||||
		" COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
 | 
							"Detecting device at %d,0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
 | 
				
			||||||
		i2c_adapter_id(client->adapter), client->addr,
 | 
							i2c_adapter_id(client->adapter), client->addr,
 | 
				
			||||||
		company, verstep);
 | 
							company, verstep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1811,11 +1811,12 @@ static int adm1026_detect(struct i2c_client *client,
 | 
				
			||||||
		/* Analog Devices ADM1026 */
 | 
							/* Analog Devices ADM1026 */
 | 
				
			||||||
	} else if (company == ADM1026_COMPANY_ANALOG_DEV
 | 
						} else if (company == ADM1026_COMPANY_ANALOG_DEV
 | 
				
			||||||
		&& (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
 | 
							&& (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
 | 
				
			||||||
		dev_err(&adapter->dev, "Unrecognized stepping "
 | 
							dev_err(&adapter->dev,
 | 
				
			||||||
			"0x%02x. Defaulting to ADM1026.\n", verstep);
 | 
								"Unrecognized stepping 0x%02x. Defaulting to ADM1026.\n",
 | 
				
			||||||
 | 
								verstep);
 | 
				
			||||||
	} else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
 | 
						} else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
 | 
				
			||||||
		dev_err(&adapter->dev, "Found version/stepping "
 | 
							dev_err(&adapter->dev,
 | 
				
			||||||
			"0x%02x. Assuming generic ADM1026.\n",
 | 
								"Found version/stepping 0x%02x. Assuming generic ADM1026.\n",
 | 
				
			||||||
			verstep);
 | 
								verstep);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		dev_dbg(&adapter->dev, "Autodetection failed\n");
 | 
							dev_dbg(&adapter->dev, "Autodetection failed\n");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -224,8 +224,9 @@ static ssize_t set_fan_div(struct device *dev,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		mutex_unlock(&data->update_lock);
 | 
							mutex_unlock(&data->update_lock);
 | 
				
			||||||
		dev_err(&client->dev, "fan_div value %ld not "
 | 
							dev_err(&client->dev,
 | 
				
			||||||
			"supported. Choose one of 1, 2 or 4!\n", val);
 | 
								"fan_div value %ld not supported. Choose one of 1, 2 or 4!\n",
 | 
				
			||||||
 | 
								val);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Update the value */
 | 
						/* Update the value */
 | 
				
			||||||
| 
						 | 
					@ -326,8 +327,8 @@ static int adm1029_detect(struct i2c_client *client,
 | 
				
			||||||
		 * There are no "official" CHIP ID, so actually
 | 
							 * There are no "official" CHIP ID, so actually
 | 
				
			||||||
		 * we use Major/Minor revision for that
 | 
							 * we use Major/Minor revision for that
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		pr_info("adm1029: Unknown major revision %x, "
 | 
							pr_info("Unknown major revision %x, please let us know\n",
 | 
				
			||||||
			"please let us know\n", chip_id);
 | 
								chip_id);
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -351,8 +351,9 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr,
 | 
				
			||||||
	reg &= ~(3 << shift);
 | 
						reg &= ~(3 << shift);
 | 
				
			||||||
	reg |= (fan_div << shift);
 | 
						reg |= (fan_div << shift);
 | 
				
			||||||
	i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg);
 | 
						i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg);
 | 
				
			||||||
	dev_dbg(&client->dev, "fan%d clock divider changed from %u "
 | 
						dev_dbg(&client->dev,
 | 
				
			||||||
			"to %u\n", nr + 1, 1 << old, 1 << fan_div);
 | 
							"fan%d clock divider changed from %u to %u\n",
 | 
				
			||||||
 | 
							nr + 1, 1 << old, 1 << fan_div);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -699,8 +700,8 @@ static void adm9240_init_client(struct i2c_client *client)
 | 
				
			||||||
		/* start measurement cycle */
 | 
							/* start measurement cycle */
 | 
				
			||||||
		i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1);
 | 
							i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dev_info(&client->dev, "cold start: config was 0x%02x "
 | 
							dev_info(&client->dev,
 | 
				
			||||||
				"mode %u\n", conf, mode);
 | 
								 "cold start: config was 0x%02x mode %u\n", conf, mode);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,25 +40,25 @@
 | 
				
			||||||
 * the instruction byte
 | 
					 * the instruction byte
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
/*Instruction Bit masks*/
 | 
					/*Instruction Bit masks*/
 | 
				
			||||||
#define INST_MODE_bm	(1<<7)
 | 
					#define INST_MODE_BM	(1 << 7)
 | 
				
			||||||
#define INST_READ_bm	(1<<6)
 | 
					#define INST_READ_BM	(1 << 6)
 | 
				
			||||||
#define INST_16BIT_bm	(1<<5)
 | 
					#define INST_16BIT_BM	(1 << 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*From figure 18 in the datasheet*/
 | 
					/*From figure 18 in the datasheet*/
 | 
				
			||||||
/*bit masks for Rev/Oscillator Control Register*/
 | 
					/*bit masks for Rev/Oscillator Control Register*/
 | 
				
			||||||
#define MUX_CNV_bv	7
 | 
					#define MUX_CNV_BV	7
 | 
				
			||||||
#define MUX_CNV_bm	(1<<MUX_CNV_bv)
 | 
					#define MUX_CNV_BM	(1 << MUX_CNV_BV)
 | 
				
			||||||
#define MUX_M3_bm	(1<<3) /*M3 selects single ended*/
 | 
					#define MUX_M3_BM	(1 << 3) /*M3 selects single ended*/
 | 
				
			||||||
#define MUX_G_bv	4 /*allows for reg = (gain << MUX_G_bv) | ...*/
 | 
					#define MUX_G_BV	4 /*allows for reg = (gain << MUX_G_BV) | ...*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*From figure 18 in the datasheet*/
 | 
					/*From figure 18 in the datasheet*/
 | 
				
			||||||
/*bit masks for Rev/Oscillator Control Register*/
 | 
					/*bit masks for Rev/Oscillator Control Register*/
 | 
				
			||||||
#define OSC_OSCR_bm	(1<<5)
 | 
					#define OSC_OSCR_BM	(1 << 5)
 | 
				
			||||||
#define OSC_OSCE_bm	(1<<4)
 | 
					#define OSC_OSCE_BM	(1 << 4)
 | 
				
			||||||
#define OSC_REFE_bm	(1<<3)
 | 
					#define OSC_REFE_BM	(1 << 3)
 | 
				
			||||||
#define OSC_BUFE_bm	(1<<2)
 | 
					#define OSC_BUFE_BM	(1 << 2)
 | 
				
			||||||
#define OSC_R2V_bm	(1<<1)
 | 
					#define OSC_R2V_BM	(1 << 1)
 | 
				
			||||||
#define OSC_RBG_bm	(1<<0)
 | 
					#define OSC_RBG_BM	(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/init.h>
 | 
					#include <linux/init.h>
 | 
				
			||||||
| 
						 | 
					@ -79,7 +79,7 @@ struct ads7871_data {
 | 
				
			||||||
static int ads7871_read_reg8(struct spi_device *spi, int reg)
 | 
					static int ads7871_read_reg8(struct spi_device *spi, int reg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	reg = reg | INST_READ_bm;
 | 
						reg = reg | INST_READ_BM;
 | 
				
			||||||
	ret = spi_w8r8(spi, reg);
 | 
						ret = spi_w8r8(spi, reg);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -87,7 +87,7 @@ static int ads7871_read_reg8(struct spi_device *spi, int reg)
 | 
				
			||||||
static int ads7871_read_reg16(struct spi_device *spi, int reg)
 | 
					static int ads7871_read_reg16(struct spi_device *spi, int reg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	reg = reg | INST_READ_bm | INST_16BIT_bm;
 | 
						reg = reg | INST_READ_BM | INST_16BIT_BM;
 | 
				
			||||||
	ret = spi_w8r16(spi, reg);
 | 
						ret = spi_w8r16(spi, reg);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -111,13 +111,13 @@ static ssize_t show_voltage(struct device *dev,
 | 
				
			||||||
	 * TODO: add support for conversions
 | 
						 * TODO: add support for conversions
 | 
				
			||||||
	 * other than single ended with a gain of 1
 | 
						 * other than single ended with a gain of 1
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	/*MUX_M3_bm forces single ended*/
 | 
						/*MUX_M3_BM forces single ended*/
 | 
				
			||||||
	/*This is also where the gain of the PGA would be set*/
 | 
						/*This is also where the gain of the PGA would be set*/
 | 
				
			||||||
	ads7871_write_reg8(spi, REG_GAIN_MUX,
 | 
						ads7871_write_reg8(spi, REG_GAIN_MUX,
 | 
				
			||||||
		(MUX_CNV_bm | MUX_M3_bm | channel));
 | 
							(MUX_CNV_BM | MUX_M3_BM | channel));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
 | 
						ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
 | 
				
			||||||
	mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
 | 
						mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * on 400MHz arm9 platform the conversion
 | 
						 * on 400MHz arm9 platform the conversion
 | 
				
			||||||
	 * is already done when we do this test
 | 
						 * is already done when we do this test
 | 
				
			||||||
| 
						 | 
					@ -125,14 +125,14 @@ static ssize_t show_voltage(struct device *dev,
 | 
				
			||||||
	while ((i < 2) && mux_cnv) {
 | 
						while ((i < 2) && mux_cnv) {
 | 
				
			||||||
		i++;
 | 
							i++;
 | 
				
			||||||
		ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
 | 
							ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
 | 
				
			||||||
		mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
 | 
							mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
 | 
				
			||||||
		msleep_interruptible(1);
 | 
							msleep_interruptible(1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mux_cnv == 0) {
 | 
						if (mux_cnv == 0) {
 | 
				
			||||||
		val = ads7871_read_reg16(spi, REG_LS_BYTE);
 | 
							val = ads7871_read_reg16(spi, REG_LS_BYTE);
 | 
				
			||||||
		/*result in volts*10000 = (val/8192)*2.5*10000*/
 | 
							/*result in volts*10000 = (val/8192)*2.5*10000*/
 | 
				
			||||||
		val = ((val>>2) * 25000) / 8192;
 | 
							val = ((val >> 2) * 25000) / 8192;
 | 
				
			||||||
		return sprintf(buf, "%d\n", val);
 | 
							return sprintf(buf, "%d\n", val);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
| 
						 | 
					@ -189,7 +189,7 @@ static int ads7871_probe(struct spi_device *spi)
 | 
				
			||||||
	ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
 | 
						ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
 | 
				
			||||||
	ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
 | 
						ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	val = (OSC_OSCR_bm | OSC_OSCE_bm | OSC_REFE_bm | OSC_BUFE_bm);
 | 
						val = (OSC_OSCR_BM | OSC_OSCE_BM | OSC_REFE_BM | OSC_BUFE_BM);
 | 
				
			||||||
	ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
 | 
						ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
 | 
				
			||||||
	ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
 | 
						ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										123
									
								
								drivers/hwmon/adt7310.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								drivers/hwmon/adt7310.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,123 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ADT7310/ADT7310 digital temperature sensor driver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2012-2013 Analog Devices Inc.
 | 
				
			||||||
 | 
					 *   Author: Lars-Peter Clausen <lars@metafoo.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the GPL-2 or later.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/spi/spi.h>
 | 
				
			||||||
 | 
					#include <asm/unaligned.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adt7x10.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ADT7310_STATUS			0
 | 
				
			||||||
 | 
					#define ADT7310_CONFIG			1
 | 
				
			||||||
 | 
					#define ADT7310_TEMPERATURE		2
 | 
				
			||||||
 | 
					#define ADT7310_ID			3
 | 
				
			||||||
 | 
					#define ADT7310_T_CRIT			4
 | 
				
			||||||
 | 
					#define ADT7310_T_HYST			5
 | 
				
			||||||
 | 
					#define ADT7310_T_ALARM_HIGH		6
 | 
				
			||||||
 | 
					#define ADT7310_T_ALARM_LOW		7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const u8 adt7310_reg_table[] = {
 | 
				
			||||||
 | 
						[ADT7X10_TEMPERATURE]   = ADT7310_TEMPERATURE,
 | 
				
			||||||
 | 
						[ADT7X10_STATUS]	= ADT7310_STATUS,
 | 
				
			||||||
 | 
						[ADT7X10_CONFIG]	= ADT7310_CONFIG,
 | 
				
			||||||
 | 
						[ADT7X10_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
 | 
				
			||||||
 | 
						[ADT7X10_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
 | 
				
			||||||
 | 
						[ADT7X10_T_CRIT]	= ADT7310_T_CRIT,
 | 
				
			||||||
 | 
						[ADT7X10_T_HYST]	= ADT7310_T_HYST,
 | 
				
			||||||
 | 
						[ADT7X10_ID]		= ADT7310_ID,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ADT7310_CMD_REG_OFFSET	3
 | 
				
			||||||
 | 
					#define ADT7310_CMD_READ	0x40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AD7310_COMMAND(reg) (adt7310_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7310_spi_read_word(struct device *dev, u8 reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = to_spi_device(dev);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = spi_w8r16(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return be16_to_cpu((__force __be16)ret);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = to_spi_device(dev);
 | 
				
			||||||
 | 
						u8 buf[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf[0] = AD7310_COMMAND(reg);
 | 
				
			||||||
 | 
						put_unaligned_be16(data, &buf[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_write(spi, buf, sizeof(buf));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7310_spi_read_byte(struct device *dev, u8 reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = to_spi_device(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_w8r8(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7310_spi_write_byte(struct device *dev, u8 reg,
 | 
				
			||||||
 | 
						u8 data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = to_spi_device(dev);
 | 
				
			||||||
 | 
						u8 buf[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf[0] = AD7310_COMMAND(reg);
 | 
				
			||||||
 | 
						buf[1] = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_write(spi, buf, sizeof(buf));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct adt7x10_ops adt7310_spi_ops = {
 | 
				
			||||||
 | 
						.read_word = adt7310_spi_read_word,
 | 
				
			||||||
 | 
						.write_word = adt7310_spi_write_word,
 | 
				
			||||||
 | 
						.read_byte = adt7310_spi_read_byte,
 | 
				
			||||||
 | 
						.write_byte = adt7310_spi_write_byte,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7310_spi_probe(struct spi_device *spi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return adt7x10_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
 | 
				
			||||||
 | 
								&adt7310_spi_ops);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7310_spi_remove(struct spi_device *spi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return adt7x10_remove(&spi->dev, spi->irq);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct spi_device_id adt7310_id[] = {
 | 
				
			||||||
 | 
						{ "adt7310", 0 },
 | 
				
			||||||
 | 
						{ "adt7320", 0 },
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(spi, adt7310_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct spi_driver adt7310_driver = {
 | 
				
			||||||
 | 
						.driver = {
 | 
				
			||||||
 | 
							.name	= "adt7310",
 | 
				
			||||||
 | 
							.owner	= THIS_MODULE,
 | 
				
			||||||
 | 
							.pm	= ADT7X10_DEV_PM_OPS,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						.probe		= adt7310_spi_probe,
 | 
				
			||||||
 | 
						.remove		= adt7310_spi_remove,
 | 
				
			||||||
 | 
						.id_table	= adt7310_id,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					module_spi_driver(adt7310_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("ADT7310/ADT7320 driver");
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
| 
						 | 
					@ -1,460 +1,80 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
 | 
					 * ADT7410/ADT7420 digital temperature sensor driver
 | 
				
			||||||
 *	 monitoring
 | 
					 | 
				
			||||||
 * This driver handles the ADT7410 and compatible digital temperature sensors.
 | 
					 | 
				
			||||||
 * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
 | 
					 | 
				
			||||||
 * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
 | 
					 | 
				
			||||||
 * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 * Copyright 2012-2013 Analog Devices Inc.
 | 
				
			||||||
 * it under the terms of the GNU General Public License as published by
 | 
					 *   Author: Lars-Peter Clausen <lars@metafoo.de>
 | 
				
			||||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
					 | 
				
			||||||
 * (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This program is distributed in the hope that it will be useful,
 | 
					 * Licensed under the GPL-2 or later.
 | 
				
			||||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 * GNU General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
 * along with this program; if not, write to the Free Software
 | 
					 | 
				
			||||||
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/init.h>
 | 
					#include <linux/init.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					 | 
				
			||||||
#include <linux/jiffies.h>
 | 
					 | 
				
			||||||
#include <linux/i2c.h>
 | 
					#include <linux/i2c.h>
 | 
				
			||||||
#include <linux/hwmon.h>
 | 
					 | 
				
			||||||
#include <linux/hwmon-sysfs.h>
 | 
					 | 
				
			||||||
#include <linux/err.h>
 | 
					 | 
				
			||||||
#include <linux/mutex.h>
 | 
					 | 
				
			||||||
#include <linux/delay.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					#include "adt7x10.h"
 | 
				
			||||||
 * ADT7410 registers definition
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ADT7410_TEMPERATURE		0
 | 
					static int adt7410_i2c_read_word(struct device *dev, u8 reg)
 | 
				
			||||||
#define ADT7410_STATUS			2
 | 
					{
 | 
				
			||||||
#define ADT7410_CONFIG			3
 | 
						return i2c_smbus_read_word_swapped(to_i2c_client(dev), reg);
 | 
				
			||||||
#define ADT7410_T_ALARM_HIGH		4
 | 
					}
 | 
				
			||||||
#define ADT7410_T_ALARM_LOW		6
 | 
					 | 
				
			||||||
#define ADT7410_T_CRIT			8
 | 
					 | 
				
			||||||
#define ADT7410_T_HYST			0xA
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
 | 
				
			||||||
 * ADT7410 status
 | 
					{
 | 
				
			||||||
 */
 | 
						return i2c_smbus_write_word_swapped(to_i2c_client(dev), reg, data);
 | 
				
			||||||
#define ADT7410_STAT_T_LOW		(1 << 4)
 | 
					}
 | 
				
			||||||
#define ADT7410_STAT_T_HIGH		(1 << 5)
 | 
					 | 
				
			||||||
#define ADT7410_STAT_T_CRIT		(1 << 6)
 | 
					 | 
				
			||||||
#define ADT7410_STAT_NOT_RDY		(1 << 7)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					static int adt7410_i2c_read_byte(struct device *dev, u8 reg)
 | 
				
			||||||
 * ADT7410 config
 | 
					{
 | 
				
			||||||
 */
 | 
						return i2c_smbus_read_byte_data(to_i2c_client(dev), reg);
 | 
				
			||||||
#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
 | 
					}
 | 
				
			||||||
#define ADT7410_CT_POLARITY		(1 << 2)
 | 
					 | 
				
			||||||
#define ADT7410_INT_POLARITY		(1 << 3)
 | 
					 | 
				
			||||||
#define ADT7410_EVENT_MODE		(1 << 4)
 | 
					 | 
				
			||||||
#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
 | 
					 | 
				
			||||||
#define ADT7410_FULL			(0 << 5 | 0 << 6)
 | 
					 | 
				
			||||||
#define ADT7410_PD			(1 << 5 | 1 << 6)
 | 
					 | 
				
			||||||
#define ADT7410_RESOLUTION		(1 << 7)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
 | 
				
			||||||
 * ADT7410 masks
 | 
					{
 | 
				
			||||||
 */
 | 
						return i2c_smbus_write_byte_data(to_i2c_client(dev), reg, data);
 | 
				
			||||||
#define ADT7410_T13_VALUE_MASK			0xFFF8
 | 
					}
 | 
				
			||||||
#define ADT7410_T_HYST_MASK			0xF
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* straight from the datasheet */
 | 
					static const struct adt7x10_ops adt7410_i2c_ops = {
 | 
				
			||||||
#define ADT7410_TEMP_MIN (-55000)
 | 
						.read_word = adt7410_i2c_read_word,
 | 
				
			||||||
#define ADT7410_TEMP_MAX 150000
 | 
						.write_word = adt7410_i2c_write_word,
 | 
				
			||||||
 | 
						.read_byte = adt7410_i2c_read_byte,
 | 
				
			||||||
enum adt7410_type {		/* keep sorted in alphabetical order */
 | 
						.write_byte = adt7410_i2c_write_byte,
 | 
				
			||||||
	adt7410,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const u8 ADT7410_REG_TEMP[4] = {
 | 
					static int adt7410_i2c_probe(struct i2c_client *client,
 | 
				
			||||||
	ADT7410_TEMPERATURE,		/* input */
 | 
						const struct i2c_device_id *id)
 | 
				
			||||||
	ADT7410_T_ALARM_HIGH,		/* high */
 | 
					 | 
				
			||||||
	ADT7410_T_ALARM_LOW,		/* low */
 | 
					 | 
				
			||||||
	ADT7410_T_CRIT,			/* critical */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Each client has this additional data */
 | 
					 | 
				
			||||||
struct adt7410_data {
 | 
					 | 
				
			||||||
	struct device		*hwmon_dev;
 | 
					 | 
				
			||||||
	struct mutex		update_lock;
 | 
					 | 
				
			||||||
	u8			config;
 | 
					 | 
				
			||||||
	u8			oldconfig;
 | 
					 | 
				
			||||||
	bool			valid;		/* true if registers valid */
 | 
					 | 
				
			||||||
	unsigned long		last_updated;	/* In jiffies */
 | 
					 | 
				
			||||||
	s16			temp[4];	/* Register values,
 | 
					 | 
				
			||||||
						   0 = input
 | 
					 | 
				
			||||||
						   1 = high
 | 
					 | 
				
			||||||
						   2 = low
 | 
					 | 
				
			||||||
						   3 = critical */
 | 
					 | 
				
			||||||
	u8			hyst;		/* hysteresis offset */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * adt7410 register access by I2C
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int adt7410_temp_ready(struct i2c_client *client)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i, status;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < 6; i++) {
 | 
					 | 
				
			||||||
		status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
 | 
					 | 
				
			||||||
		if (status < 0)
 | 
					 | 
				
			||||||
			return status;
 | 
					 | 
				
			||||||
		if (!(status & ADT7410_STAT_NOT_RDY))
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		msleep(60);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return -ETIMEDOUT;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct adt7410_data *adt7410_update_device(struct device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(dev);
 | 
					 | 
				
			||||||
	struct adt7410_data *data = i2c_get_clientdata(client);
 | 
					 | 
				
			||||||
	struct adt7410_data *ret = data;
 | 
					 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 | 
					 | 
				
			||||||
	    || !data->valid) {
 | 
					 | 
				
			||||||
		int i, status;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dev_dbg(&client->dev, "Starting update\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		status = adt7410_temp_ready(client); /* check for new value */
 | 
					 | 
				
			||||||
		if (unlikely(status)) {
 | 
					 | 
				
			||||||
			ret = ERR_PTR(status);
 | 
					 | 
				
			||||||
			goto abort;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
 | 
					 | 
				
			||||||
			status = i2c_smbus_read_word_swapped(client,
 | 
					 | 
				
			||||||
							ADT7410_REG_TEMP[i]);
 | 
					 | 
				
			||||||
			if (unlikely(status < 0)) {
 | 
					 | 
				
			||||||
				dev_dbg(dev,
 | 
					 | 
				
			||||||
					"Failed to read value: reg %d, error %d\n",
 | 
					 | 
				
			||||||
					ADT7410_REG_TEMP[i], status);
 | 
					 | 
				
			||||||
				ret = ERR_PTR(status);
 | 
					 | 
				
			||||||
				goto abort;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			data->temp[i] = status;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
 | 
					 | 
				
			||||||
		if (unlikely(status < 0)) {
 | 
					 | 
				
			||||||
			dev_dbg(dev,
 | 
					 | 
				
			||||||
				"Failed to read value: reg %d, error %d\n",
 | 
					 | 
				
			||||||
				ADT7410_T_HYST, status);
 | 
					 | 
				
			||||||
			ret = ERR_PTR(status);
 | 
					 | 
				
			||||||
			goto abort;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		data->hyst = status;
 | 
					 | 
				
			||||||
		data->last_updated = jiffies;
 | 
					 | 
				
			||||||
		data->valid = true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
abort:
 | 
					 | 
				
			||||||
	mutex_unlock(&data->update_lock);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static s16 ADT7410_TEMP_TO_REG(long temp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
 | 
					 | 
				
			||||||
					   ADT7410_TEMP_MAX) * 128, 1000);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
 | 
					 | 
				
			||||||
	if (!(data->config & ADT7410_RESOLUTION))
 | 
					 | 
				
			||||||
		reg &= ADT7410_T13_VALUE_MASK;
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * temperature is stored in twos complement format, in steps of
 | 
					 | 
				
			||||||
	 * 1/128°C
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	return DIV_ROUND_CLOSEST(reg * 1000, 128);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*-----------------------------------------------------------------------*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* sysfs attributes for hwmon */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t adt7410_show_temp(struct device *dev,
 | 
					 | 
				
			||||||
				 struct device_attribute *da, char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 | 
					 | 
				
			||||||
	struct adt7410_data *data = adt7410_update_device(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (IS_ERR(data))
 | 
					 | 
				
			||||||
		return PTR_ERR(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
 | 
					 | 
				
			||||||
		       data->temp[attr->index]));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t adt7410_set_temp(struct device *dev,
 | 
					 | 
				
			||||||
				struct device_attribute *da,
 | 
					 | 
				
			||||||
				const char *buf, size_t count)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 | 
					 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(dev);
 | 
					 | 
				
			||||||
	struct adt7410_data *data = i2c_get_clientdata(client);
 | 
					 | 
				
			||||||
	int nr = attr->index;
 | 
					 | 
				
			||||||
	long temp;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = kstrtol(buf, 10, &temp);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
					 | 
				
			||||||
	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
 | 
					 | 
				
			||||||
	ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
 | 
					 | 
				
			||||||
					   data->temp[nr]);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		count = ret;
 | 
					 | 
				
			||||||
	mutex_unlock(&data->update_lock);
 | 
					 | 
				
			||||||
	return count;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t adt7410_show_t_hyst(struct device *dev,
 | 
					 | 
				
			||||||
				   struct device_attribute *da,
 | 
					 | 
				
			||||||
				   char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 | 
					 | 
				
			||||||
	struct adt7410_data *data;
 | 
					 | 
				
			||||||
	int nr = attr->index;
 | 
					 | 
				
			||||||
	int hyst;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	data = adt7410_update_device(dev);
 | 
					 | 
				
			||||||
	if (IS_ERR(data))
 | 
					 | 
				
			||||||
		return PTR_ERR(data);
 | 
					 | 
				
			||||||
	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * hysteresis is stored as a 4 bit offset in the device, convert it
 | 
					 | 
				
			||||||
	 * to an absolute value
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (nr == 2)	/* min has positive offset, others have negative */
 | 
					 | 
				
			||||||
		hyst = -hyst;
 | 
					 | 
				
			||||||
	return sprintf(buf, "%d\n",
 | 
					 | 
				
			||||||
		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t adt7410_set_t_hyst(struct device *dev,
 | 
					 | 
				
			||||||
				  struct device_attribute *da,
 | 
					 | 
				
			||||||
				  const char *buf, size_t count)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(dev);
 | 
					 | 
				
			||||||
	struct adt7410_data *data = i2c_get_clientdata(client);
 | 
					 | 
				
			||||||
	int limit, ret;
 | 
					 | 
				
			||||||
	long hyst;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = kstrtol(buf, 10, &hyst);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	/* convert absolute hysteresis value to a 4 bit delta value */
 | 
					 | 
				
			||||||
	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
 | 
					 | 
				
			||||||
	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
 | 
					 | 
				
			||||||
	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
 | 
					 | 
				
			||||||
			       ADT7410_T_HYST_MASK);
 | 
					 | 
				
			||||||
	ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return count;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t adt7410_show_alarm(struct device *dev,
 | 
					 | 
				
			||||||
				  struct device_attribute *da,
 | 
					 | 
				
			||||||
				  char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(dev);
 | 
					 | 
				
			||||||
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
 | 
					 | 
				
			||||||
	if (ret < 0)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sprintf(buf, "%d\n", !!(ret & attr->index));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
 | 
					 | 
				
			||||||
			  adt7410_show_temp, adt7410_set_temp, 1);
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
 | 
					 | 
				
			||||||
			  adt7410_show_temp, adt7410_set_temp, 2);
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
 | 
					 | 
				
			||||||
			  adt7410_show_temp, adt7410_set_temp, 3);
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
 | 
					 | 
				
			||||||
			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
 | 
					 | 
				
			||||||
			  adt7410_show_t_hyst, NULL, 2);
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
 | 
					 | 
				
			||||||
			  adt7410_show_t_hyst, NULL, 3);
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
 | 
					 | 
				
			||||||
			  NULL, ADT7410_STAT_T_LOW);
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
 | 
					 | 
				
			||||||
			  NULL, ADT7410_STAT_T_HIGH);
 | 
					 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
 | 
					 | 
				
			||||||
			  NULL, ADT7410_STAT_T_CRIT);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct attribute *adt7410_attributes[] = {
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_input.dev_attr.attr,
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_max.dev_attr.attr,
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_min.dev_attr.attr,
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_crit.dev_attr.attr,
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 | 
					 | 
				
			||||||
	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
 | 
					 | 
				
			||||||
	NULL
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct attribute_group adt7410_group = {
 | 
					 | 
				
			||||||
	.attrs = adt7410_attributes,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*-----------------------------------------------------------------------*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* device probe and removal */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int adt7410_probe(struct i2c_client *client,
 | 
					 | 
				
			||||||
			 const struct i2c_device_id *id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct adt7410_data *data;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!i2c_check_functionality(client->adapter,
 | 
						if (!i2c_check_functionality(client->adapter,
 | 
				
			||||||
			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
 | 
								I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
 | 
						return adt7x10_probe(&client->dev, NULL, client->irq, &adt7410_i2c_ops);
 | 
				
			||||||
			    GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!data)
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	i2c_set_clientdata(client, data);
 | 
					 | 
				
			||||||
	mutex_init(&data->update_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* configure as specified */
 | 
					 | 
				
			||||||
	ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
 | 
					 | 
				
			||||||
	if (ret < 0) {
 | 
					 | 
				
			||||||
		dev_dbg(&client->dev, "Can't read config? %d\n", ret);
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	data->oldconfig = ret;
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Set to 16 bit resolution, continous conversion and comparator mode.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	ret &= ~ADT7410_MODE_MASK;
 | 
					 | 
				
			||||||
	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
 | 
					 | 
				
			||||||
			ADT7410_EVENT_MODE;
 | 
					 | 
				
			||||||
	if (data->config != data->oldconfig) {
 | 
					 | 
				
			||||||
		ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
 | 
					 | 
				
			||||||
						data->config);
 | 
					 | 
				
			||||||
		if (ret)
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	dev_dbg(&client->dev, "Config %02x\n", data->config);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Register sysfs hooks */
 | 
					 | 
				
			||||||
	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto exit_restore;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	data->hwmon_dev = hwmon_device_register(&client->dev);
 | 
					 | 
				
			||||||
	if (IS_ERR(data->hwmon_dev)) {
 | 
					 | 
				
			||||||
		ret = PTR_ERR(data->hwmon_dev);
 | 
					 | 
				
			||||||
		goto exit_remove;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dev_info(&client->dev, "sensor '%s'\n", client->name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
exit_remove:
 | 
					 | 
				
			||||||
	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
 | 
					 | 
				
			||||||
exit_restore:
 | 
					 | 
				
			||||||
	i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int adt7410_remove(struct i2c_client *client)
 | 
					static int adt7410_i2c_remove(struct i2c_client *client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct adt7410_data *data = i2c_get_clientdata(client);
 | 
						return adt7x10_remove(&client->dev, client->irq);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	hwmon_device_unregister(data->hwmon_dev);
 | 
					 | 
				
			||||||
	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
 | 
					 | 
				
			||||||
	if (data->oldconfig != data->config)
 | 
					 | 
				
			||||||
		i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
 | 
					 | 
				
			||||||
					  data->oldconfig);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct i2c_device_id adt7410_ids[] = {
 | 
					static const struct i2c_device_id adt7410_ids[] = {
 | 
				
			||||||
	{ "adt7410", adt7410, },
 | 
						{ "adt7410", 0 },
 | 
				
			||||||
	{ "adt7420", adt7410, },
 | 
						{ "adt7420", 0 },
 | 
				
			||||||
	{ /* LIST END */ }
 | 
						{}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MODULE_DEVICE_TABLE(i2c, adt7410_ids);
 | 
					MODULE_DEVICE_TABLE(i2c, adt7410_ids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PM_SLEEP
 | 
					 | 
				
			||||||
static int adt7410_suspend(struct device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(dev);
 | 
					 | 
				
			||||||
	struct adt7410_data *data = i2c_get_clientdata(client);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
 | 
					 | 
				
			||||||
					data->config | ADT7410_PD);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int adt7410_resume(struct device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(dev);
 | 
					 | 
				
			||||||
	struct adt7410_data *data = i2c_get_clientdata(client);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define ADT7410_DEV_PM_OPS NULL
 | 
					 | 
				
			||||||
#endif /* CONFIG_PM */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct i2c_driver adt7410_driver = {
 | 
					static struct i2c_driver adt7410_driver = {
 | 
				
			||||||
	.class		= I2C_CLASS_HWMON,
 | 
						.class		= I2C_CLASS_HWMON,
 | 
				
			||||||
	.driver = {
 | 
						.driver = {
 | 
				
			||||||
		.name	= "adt7410",
 | 
							.name	= "adt7410",
 | 
				
			||||||
		.pm	= ADT7410_DEV_PM_OPS,
 | 
							.pm	= ADT7X10_DEV_PM_OPS,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	.probe		= adt7410_probe,
 | 
						.probe		= adt7410_i2c_probe,
 | 
				
			||||||
	.remove		= adt7410_remove,
 | 
						.remove		= adt7410_i2c_remove,
 | 
				
			||||||
	.id_table	= adt7410_ids,
 | 
						.id_table	= adt7410_ids,
 | 
				
			||||||
	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
 | 
						.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
module_i2c_driver(adt7410_driver);
 | 
					module_i2c_driver(adt7410_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_AUTHOR("Hartmut Knaack");
 | 
					MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 | 
				
			||||||
MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
 | 
					MODULE_DESCRIPTION("ADT7410/AD7420 driver");
 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -259,15 +259,17 @@ static int adt7411_detect(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	val = i2c_smbus_read_byte_data(client, ADT7411_REG_MANUFACTURER_ID);
 | 
						val = i2c_smbus_read_byte_data(client, ADT7411_REG_MANUFACTURER_ID);
 | 
				
			||||||
	if (val < 0 || val != ADT7411_MANUFACTURER_ID) {
 | 
						if (val < 0 || val != ADT7411_MANUFACTURER_ID) {
 | 
				
			||||||
		dev_dbg(&client->dev, "Wrong manufacturer ID. Got %d, "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"expected %d\n", val, ADT7411_MANUFACTURER_ID);
 | 
								"Wrong manufacturer ID. Got %d, expected %d\n",
 | 
				
			||||||
 | 
								val, ADT7411_MANUFACTURER_ID);
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	val = i2c_smbus_read_byte_data(client, ADT7411_REG_DEVICE_ID);
 | 
						val = i2c_smbus_read_byte_data(client, ADT7411_REG_DEVICE_ID);
 | 
				
			||||||
	if (val < 0 || val != ADT7411_DEVICE_ID) {
 | 
						if (val < 0 || val != ADT7411_DEVICE_ID) {
 | 
				
			||||||
		dev_dbg(&client->dev, "Wrong device ID. Got %d, "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"expected %d\n", val, ADT7411_DEVICE_ID);
 | 
								"Wrong device ID. Got %d, expected %d\n",
 | 
				
			||||||
 | 
								val, ADT7411_DEVICE_ID);
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										511
									
								
								drivers/hwmon/adt7x10.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										511
									
								
								drivers/hwmon/adt7x10.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,511 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * adt7x10.c - Part of lm_sensors, Linux kernel modules for hardware
 | 
				
			||||||
 | 
					 *	 monitoring
 | 
				
			||||||
 | 
					 * This driver handles the ADT7410 and compatible digital temperature sensors.
 | 
				
			||||||
 | 
					 * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
 | 
				
			||||||
 | 
					 * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
 | 
				
			||||||
 | 
					 * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/jiffies.h>
 | 
				
			||||||
 | 
					#include <linux/hwmon.h>
 | 
				
			||||||
 | 
					#include <linux/hwmon-sysfs.h>
 | 
				
			||||||
 | 
					#include <linux/err.h>
 | 
				
			||||||
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					#include <linux/delay.h>
 | 
				
			||||||
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adt7x10.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ADT7X10 status
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ADT7X10_STAT_T_LOW		(1 << 4)
 | 
				
			||||||
 | 
					#define ADT7X10_STAT_T_HIGH		(1 << 5)
 | 
				
			||||||
 | 
					#define ADT7X10_STAT_T_CRIT		(1 << 6)
 | 
				
			||||||
 | 
					#define ADT7X10_STAT_NOT_RDY		(1 << 7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ADT7X10 config
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ADT7X10_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
 | 
				
			||||||
 | 
					#define ADT7X10_CT_POLARITY		(1 << 2)
 | 
				
			||||||
 | 
					#define ADT7X10_INT_POLARITY		(1 << 3)
 | 
				
			||||||
 | 
					#define ADT7X10_EVENT_MODE		(1 << 4)
 | 
				
			||||||
 | 
					#define ADT7X10_MODE_MASK		(1 << 5 | 1 << 6)
 | 
				
			||||||
 | 
					#define ADT7X10_FULL			(0 << 5 | 0 << 6)
 | 
				
			||||||
 | 
					#define ADT7X10_PD			(1 << 5 | 1 << 6)
 | 
				
			||||||
 | 
					#define ADT7X10_RESOLUTION		(1 << 7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ADT7X10 masks
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ADT7X10_T13_VALUE_MASK		0xFFF8
 | 
				
			||||||
 | 
					#define ADT7X10_T_HYST_MASK		0xF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* straight from the datasheet */
 | 
				
			||||||
 | 
					#define ADT7X10_TEMP_MIN (-55000)
 | 
				
			||||||
 | 
					#define ADT7X10_TEMP_MAX 150000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Each client has this additional data */
 | 
				
			||||||
 | 
					struct adt7x10_data {
 | 
				
			||||||
 | 
						const struct adt7x10_ops *ops;
 | 
				
			||||||
 | 
						const char		*name;
 | 
				
			||||||
 | 
						struct device		*hwmon_dev;
 | 
				
			||||||
 | 
						struct mutex		update_lock;
 | 
				
			||||||
 | 
						u8			config;
 | 
				
			||||||
 | 
						u8			oldconfig;
 | 
				
			||||||
 | 
						bool			valid;		/* true if registers valid */
 | 
				
			||||||
 | 
						unsigned long		last_updated;	/* In jiffies */
 | 
				
			||||||
 | 
						s16			temp[4];	/* Register values,
 | 
				
			||||||
 | 
											   0 = input
 | 
				
			||||||
 | 
											   1 = high
 | 
				
			||||||
 | 
											   2 = low
 | 
				
			||||||
 | 
											   3 = critical */
 | 
				
			||||||
 | 
						u8			hyst;		/* hysteresis offset */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7x10_read_byte(struct device *dev, u8 reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *d = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						return d->ops->read_byte(dev, reg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7x10_write_byte(struct device *dev, u8 reg, u8 data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *d = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						return d->ops->write_byte(dev, reg, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7x10_read_word(struct device *dev, u8 reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *d = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						return d->ops->read_word(dev, reg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7x10_write_word(struct device *dev, u8 reg, u16 data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *d = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						return d->ops->write_word(dev, reg, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const u8 ADT7X10_REG_TEMP[4] = {
 | 
				
			||||||
 | 
						ADT7X10_TEMPERATURE,		/* input */
 | 
				
			||||||
 | 
						ADT7X10_T_ALARM_HIGH,		/* high */
 | 
				
			||||||
 | 
						ADT7X10_T_ALARM_LOW,		/* low */
 | 
				
			||||||
 | 
						ADT7X10_T_CRIT,			/* critical */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static irqreturn_t adt7x10_irq_handler(int irq, void *private)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device *dev = private;
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = adt7x10_read_byte(dev, ADT7X10_STATUS);
 | 
				
			||||||
 | 
						if (status < 0)
 | 
				
			||||||
 | 
							return IRQ_HANDLED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (status & ADT7X10_STAT_T_HIGH)
 | 
				
			||||||
 | 
							sysfs_notify(&dev->kobj, NULL, "temp1_max_alarm");
 | 
				
			||||||
 | 
						if (status & ADT7X10_STAT_T_LOW)
 | 
				
			||||||
 | 
							sysfs_notify(&dev->kobj, NULL, "temp1_min_alarm");
 | 
				
			||||||
 | 
						if (status & ADT7X10_STAT_T_CRIT)
 | 
				
			||||||
 | 
							sysfs_notify(&dev->kobj, NULL, "temp1_crit_alarm");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return IRQ_HANDLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7x10_temp_ready(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i, status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 6; i++) {
 | 
				
			||||||
 | 
							status = adt7x10_read_byte(dev, ADT7X10_STATUS);
 | 
				
			||||||
 | 
							if (status < 0)
 | 
				
			||||||
 | 
								return status;
 | 
				
			||||||
 | 
							if (!(status & ADT7X10_STAT_NOT_RDY))
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							msleep(60);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return -ETIMEDOUT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7x10_update_temp(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 | 
				
			||||||
 | 
						    || !data->valid) {
 | 
				
			||||||
 | 
							int temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dev_dbg(dev, "Starting update\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = adt7x10_temp_ready(dev); /* check for new value */
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								goto abort;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							temp = adt7x10_read_word(dev, ADT7X10_REG_TEMP[0]);
 | 
				
			||||||
 | 
							if (temp < 0) {
 | 
				
			||||||
 | 
								ret = temp;
 | 
				
			||||||
 | 
								dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
 | 
				
			||||||
 | 
									ADT7X10_REG_TEMP[0], ret);
 | 
				
			||||||
 | 
								goto abort;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							data->temp[0] = temp;
 | 
				
			||||||
 | 
							data->last_updated = jiffies;
 | 
				
			||||||
 | 
							data->valid = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abort:
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7x10_fill_cache(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
 | 
				
			||||||
 | 
							ret = adt7x10_read_word(dev, ADT7X10_REG_TEMP[i]);
 | 
				
			||||||
 | 
							if (ret < 0) {
 | 
				
			||||||
 | 
								dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
 | 
				
			||||||
 | 
									ADT7X10_REG_TEMP[i], ret);
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							data->temp[i] = ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = adt7x10_read_byte(dev, ADT7X10_T_HYST);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
 | 
				
			||||||
 | 
									ADT7X10_T_HYST, ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						data->hyst = ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static s16 ADT7X10_TEMP_TO_REG(long temp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7X10_TEMP_MIN,
 | 
				
			||||||
 | 
										       ADT7X10_TEMP_MAX) * 128, 1000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* in 13 bit mode, bits 0-2 are status flags - mask them out */
 | 
				
			||||||
 | 
						if (!(data->config & ADT7X10_RESOLUTION))
 | 
				
			||||||
 | 
							reg &= ADT7X10_T13_VALUE_MASK;
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * temperature is stored in twos complement format, in steps of
 | 
				
			||||||
 | 
						 * 1/128°C
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						return DIV_ROUND_CLOSEST(reg * 1000, 128);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*-----------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* sysfs attributes for hwmon */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t adt7x10_show_temp(struct device *dev,
 | 
				
			||||||
 | 
									 struct device_attribute *da,
 | 
				
			||||||
 | 
									 char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (attr->index == 0) {
 | 
				
			||||||
 | 
							int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = adt7x10_update_temp(dev);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data,
 | 
				
			||||||
 | 
							       data->temp[attr->index]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t adt7x10_set_temp(struct device *dev,
 | 
				
			||||||
 | 
									struct device_attribute *da,
 | 
				
			||||||
 | 
									const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						int nr = attr->index;
 | 
				
			||||||
 | 
						long temp;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = kstrtol(buf, 10, &temp);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
						data->temp[nr] = ADT7X10_TEMP_TO_REG(temp);
 | 
				
			||||||
 | 
						ret = adt7x10_write_word(dev, ADT7X10_REG_TEMP[nr], data->temp[nr]);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							count = ret;
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t adt7x10_show_t_hyst(struct device *dev,
 | 
				
			||||||
 | 
									   struct device_attribute *da,
 | 
				
			||||||
 | 
									   char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						int nr = attr->index;
 | 
				
			||||||
 | 
						int hyst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hyst = (data->hyst & ADT7X10_T_HYST_MASK) * 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * hysteresis is stored as a 4 bit offset in the device, convert it
 | 
				
			||||||
 | 
						 * to an absolute value
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (nr == 2)	/* min has positive offset, others have negative */
 | 
				
			||||||
 | 
							hyst = -hyst;
 | 
				
			||||||
 | 
						return sprintf(buf, "%d\n",
 | 
				
			||||||
 | 
							       ADT7X10_REG_TO_TEMP(data, data->temp[nr]) - hyst);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t adt7x10_set_t_hyst(struct device *dev,
 | 
				
			||||||
 | 
									  struct device_attribute *da,
 | 
				
			||||||
 | 
									  const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						int limit, ret;
 | 
				
			||||||
 | 
						long hyst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = kstrtol(buf, 10, &hyst);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						/* convert absolute hysteresis value to a 4 bit delta value */
 | 
				
			||||||
 | 
						limit = ADT7X10_REG_TO_TEMP(data, data->temp[1]);
 | 
				
			||||||
 | 
						hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX);
 | 
				
			||||||
 | 
						data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
 | 
				
			||||||
 | 
									   0, ADT7X10_T_HYST_MASK);
 | 
				
			||||||
 | 
						ret = adt7x10_write_byte(dev, ADT7X10_T_HYST, data->hyst);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t adt7x10_show_alarm(struct device *dev,
 | 
				
			||||||
 | 
									  struct device_attribute *da,
 | 
				
			||||||
 | 
									  char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = adt7x10_read_byte(dev, ADT7X10_STATUS);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%d\n", !!(ret & attr->index));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t adt7x10_show_name(struct device *dev,
 | 
				
			||||||
 | 
									 struct device_attribute *da,
 | 
				
			||||||
 | 
									 char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%s\n", data->name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7x10_show_temp, NULL, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
 | 
				
			||||||
 | 
								  adt7x10_show_temp, adt7x10_set_temp, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
 | 
				
			||||||
 | 
								  adt7x10_show_temp, adt7x10_set_temp, 2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
 | 
				
			||||||
 | 
								  adt7x10_show_temp, adt7x10_set_temp, 3);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
 | 
				
			||||||
 | 
								  adt7x10_show_t_hyst, adt7x10_set_t_hyst, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
 | 
				
			||||||
 | 
								  adt7x10_show_t_hyst, NULL, 2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
 | 
				
			||||||
 | 
								  adt7x10_show_t_hyst, NULL, 3);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7x10_show_alarm,
 | 
				
			||||||
 | 
								  NULL, ADT7X10_STAT_T_LOW);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7x10_show_alarm,
 | 
				
			||||||
 | 
								  NULL, ADT7X10_STAT_T_HIGH);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7x10_show_alarm,
 | 
				
			||||||
 | 
								  NULL, ADT7X10_STAT_T_CRIT);
 | 
				
			||||||
 | 
					static DEVICE_ATTR(name, S_IRUGO, adt7x10_show_name, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct attribute *adt7x10_attributes[] = {
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_min.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_crit.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						NULL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct attribute_group adt7x10_group = {
 | 
				
			||||||
 | 
						.attrs = adt7x10_attributes,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int adt7x10_probe(struct device *dev, const char *name, int irq,
 | 
				
			||||||
 | 
							  const struct adt7x10_ops *ops)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *data;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!data)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data->ops = ops;
 | 
				
			||||||
 | 
						data->name = name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_set_drvdata(dev, data);
 | 
				
			||||||
 | 
						mutex_init(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* configure as specified */
 | 
				
			||||||
 | 
						ret = adt7x10_read_byte(dev, ADT7X10_CONFIG);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							dev_dbg(dev, "Can't read config? %d\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						data->oldconfig = ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Set to 16 bit resolution, continous conversion and comparator mode.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						data->config = data->oldconfig;
 | 
				
			||||||
 | 
						data->config &= ~(ADT7X10_MODE_MASK | ADT7X10_CT_POLARITY |
 | 
				
			||||||
 | 
								ADT7X10_INT_POLARITY);
 | 
				
			||||||
 | 
						data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data->config != data->oldconfig) {
 | 
				
			||||||
 | 
							ret = adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dev_dbg(dev, "Config %02x\n", data->config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = adt7x10_fill_cache(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto exit_restore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Register sysfs hooks */
 | 
				
			||||||
 | 
						ret = sysfs_create_group(&dev->kobj, &adt7x10_group);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto exit_restore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The I2C device will already have it's own 'name' attribute, but for
 | 
				
			||||||
 | 
						 * the SPI device we need to register it. name will only be non NULL if
 | 
				
			||||||
 | 
						 * the device doesn't register the 'name' attribute on its own.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (name) {
 | 
				
			||||||
 | 
							ret = device_create_file(dev, &dev_attr_name);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								goto exit_remove;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data->hwmon_dev = hwmon_device_register(dev);
 | 
				
			||||||
 | 
						if (IS_ERR(data->hwmon_dev)) {
 | 
				
			||||||
 | 
							ret = PTR_ERR(data->hwmon_dev);
 | 
				
			||||||
 | 
							goto exit_remove_name;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (irq > 0) {
 | 
				
			||||||
 | 
							ret = request_threaded_irq(irq, NULL, adt7x10_irq_handler,
 | 
				
			||||||
 | 
									IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 | 
				
			||||||
 | 
									dev_name(dev), dev);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								goto exit_hwmon_device_unregister;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit_hwmon_device_unregister:
 | 
				
			||||||
 | 
						hwmon_device_unregister(data->hwmon_dev);
 | 
				
			||||||
 | 
					exit_remove_name:
 | 
				
			||||||
 | 
						if (name)
 | 
				
			||||||
 | 
							device_remove_file(dev, &dev_attr_name);
 | 
				
			||||||
 | 
					exit_remove:
 | 
				
			||||||
 | 
						sysfs_remove_group(&dev->kobj, &adt7x10_group);
 | 
				
			||||||
 | 
					exit_restore:
 | 
				
			||||||
 | 
						adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(adt7x10_probe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int adt7x10_remove(struct device *dev, int irq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (irq > 0)
 | 
				
			||||||
 | 
							free_irq(irq, dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hwmon_device_unregister(data->hwmon_dev);
 | 
				
			||||||
 | 
						if (data->name)
 | 
				
			||||||
 | 
							device_remove_file(dev, &dev_attr_name);
 | 
				
			||||||
 | 
						sysfs_remove_group(&dev->kobj, &adt7x10_group);
 | 
				
			||||||
 | 
						if (data->oldconfig != data->config)
 | 
				
			||||||
 | 
							adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(adt7x10_remove);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_PM_SLEEP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7x10_suspend(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return adt7x10_write_byte(dev, ADT7X10_CONFIG,
 | 
				
			||||||
 | 
							data->config | ADT7X10_PD);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int adt7x10_resume(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct adt7x10_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume);
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(adt7x10_dev_pm_ops);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CONFIG_PM_SLEEP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Hartmut Knaack");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code");
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
							
								
								
									
										37
									
								
								drivers/hwmon/adt7x10.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								drivers/hwmon/adt7x10.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					#ifndef __HWMON_ADT7X10_H__
 | 
				
			||||||
 | 
					#define __HWMON_ADT7X10_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					#include <linux/pm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ADT7410 registers definition */
 | 
				
			||||||
 | 
					#define ADT7X10_TEMPERATURE		0
 | 
				
			||||||
 | 
					#define ADT7X10_STATUS			2
 | 
				
			||||||
 | 
					#define ADT7X10_CONFIG			3
 | 
				
			||||||
 | 
					#define ADT7X10_T_ALARM_HIGH		4
 | 
				
			||||||
 | 
					#define ADT7X10_T_ALARM_LOW		6
 | 
				
			||||||
 | 
					#define ADT7X10_T_CRIT			8
 | 
				
			||||||
 | 
					#define ADT7X10_T_HYST			0xA
 | 
				
			||||||
 | 
					#define ADT7X10_ID			0xB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct adt7x10_ops {
 | 
				
			||||||
 | 
						int (*read_byte)(struct device *, u8 reg);
 | 
				
			||||||
 | 
						int (*write_byte)(struct device *, u8 reg, u8 data);
 | 
				
			||||||
 | 
						int (*read_word)(struct device *, u8 reg);
 | 
				
			||||||
 | 
						int (*write_word)(struct device *, u8 reg, u16 data);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int adt7x10_probe(struct device *dev, const char *name, int irq,
 | 
				
			||||||
 | 
						const struct adt7x10_ops *ops);
 | 
				
			||||||
 | 
					int adt7x10_remove(struct device *dev, int irq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_PM_SLEEP
 | 
				
			||||||
 | 
					extern const struct dev_pm_ops adt7x10_dev_pm_ops;
 | 
				
			||||||
 | 
					#define ADT7X10_DEV_PM_OPS (&adt7x10_dev_pm_ops)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define ADT7X10_DEV_PM_OPS NULL
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -922,7 +922,7 @@ static void applesmc_brightness_set(struct led_classdev *led_cdev,
 | 
				
			||||||
	ret = queue_work(applesmc_led_wq, &backlight_work);
 | 
						ret = queue_work(applesmc_led_wq, &backlight_work);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (debug && (!ret))
 | 
						if (debug && (!ret))
 | 
				
			||||||
		printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
 | 
							dev_dbg(led_cdev->dev, "work was already on the queue.\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t applesmc_key_count_show(struct device *dev,
 | 
					static ssize_t applesmc_key_count_show(struct device *dev,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,8 +55,8 @@ static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned short force_subclients[4];
 | 
					static unsigned short force_subclients[4];
 | 
				
			||||||
module_param_array(force_subclients, short, NULL, 0);
 | 
					module_param_array(force_subclients, short, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
 | 
					MODULE_PARM_DESC(force_subclients,
 | 
				
			||||||
	"{bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
						"List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Voltage IN registers 0-6 */
 | 
					/* Voltage IN registers 0-6 */
 | 
				
			||||||
#define ASB100_REG_IN(nr)	(0x20 + (nr))
 | 
					#define ASB100_REG_IN(nr)	(0x20 + (nr))
 | 
				
			||||||
| 
						 | 
					@ -689,8 +689,8 @@ static int asb100_detect_subclients(struct i2c_client *client)
 | 
				
			||||||
		for (i = 2; i <= 3; i++) {
 | 
							for (i = 2; i <= 3; i++) {
 | 
				
			||||||
			if (force_subclients[i] < 0x48 ||
 | 
								if (force_subclients[i] < 0x48 ||
 | 
				
			||||||
			    force_subclients[i] > 0x4f) {
 | 
								    force_subclients[i] > 0x4f) {
 | 
				
			||||||
				dev_err(&client->dev, "invalid subclient "
 | 
									dev_err(&client->dev,
 | 
				
			||||||
					"address %d; must be 0x48-0x4f\n",
 | 
										"invalid subclient address %d; must be 0x48-0x4f\n",
 | 
				
			||||||
					force_subclients[i]);
 | 
										force_subclients[i]);
 | 
				
			||||||
				err = -ENODEV;
 | 
									err = -ENODEV;
 | 
				
			||||||
				goto ERROR_SC_2;
 | 
									goto ERROR_SC_2;
 | 
				
			||||||
| 
						 | 
					@ -708,24 +708,27 @@ static int asb100_detect_subclients(struct i2c_client *client)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sc_addr[0] == sc_addr[1]) {
 | 
						if (sc_addr[0] == sc_addr[1]) {
 | 
				
			||||||
		dev_err(&client->dev, "duplicate addresses 0x%x "
 | 
							dev_err(&client->dev,
 | 
				
			||||||
				"for subclients\n", sc_addr[0]);
 | 
								"duplicate addresses 0x%x for subclients\n",
 | 
				
			||||||
 | 
								sc_addr[0]);
 | 
				
			||||||
		err = -ENODEV;
 | 
							err = -ENODEV;
 | 
				
			||||||
		goto ERROR_SC_2;
 | 
							goto ERROR_SC_2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
 | 
						data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
 | 
				
			||||||
	if (!data->lm75[0]) {
 | 
						if (!data->lm75[0]) {
 | 
				
			||||||
		dev_err(&client->dev, "subclient %d registration "
 | 
							dev_err(&client->dev,
 | 
				
			||||||
			"at address 0x%x failed.\n", 1, sc_addr[0]);
 | 
								"subclient %d registration at address 0x%x failed.\n",
 | 
				
			||||||
 | 
								1, sc_addr[0]);
 | 
				
			||||||
		err = -ENOMEM;
 | 
							err = -ENOMEM;
 | 
				
			||||||
		goto ERROR_SC_2;
 | 
							goto ERROR_SC_2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
 | 
						data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
 | 
				
			||||||
	if (!data->lm75[1]) {
 | 
						if (!data->lm75[1]) {
 | 
				
			||||||
		dev_err(&client->dev, "subclient %d registration "
 | 
							dev_err(&client->dev,
 | 
				
			||||||
			"at address 0x%x failed.\n", 2, sc_addr[1]);
 | 
								"subclient %d registration at address 0x%x failed.\n",
 | 
				
			||||||
 | 
								2, sc_addr[1]);
 | 
				
			||||||
		err = -ENOMEM;
 | 
							err = -ENOMEM;
 | 
				
			||||||
		goto ERROR_SC_3;
 | 
							goto ERROR_SC_3;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,12 +159,12 @@ static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
 | 
				
			||||||
 * and retrieval of like parameters.
 | 
					 * and retrieval of like parameters.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SETUP_SHOW_data_param(d, a) \
 | 
					#define SETUP_SHOW_DATA_PARAM(d, a) \
 | 
				
			||||||
	struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
 | 
						struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
 | 
				
			||||||
	struct asc7621_data *data = asc7621_update_device(d); \
 | 
						struct asc7621_data *data = asc7621_update_device(d); \
 | 
				
			||||||
	struct asc7621_param *param = to_asc7621_param(sda)
 | 
						struct asc7621_param *param = to_asc7621_param(sda)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SETUP_STORE_data_param(d, a) \
 | 
					#define SETUP_STORE_DATA_PARAM(d, a) \
 | 
				
			||||||
	struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
 | 
						struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(d); \
 | 
						struct i2c_client *client = to_i2c_client(d); \
 | 
				
			||||||
	struct asc7621_data *data = i2c_get_clientdata(client); \
 | 
						struct asc7621_data *data = i2c_get_clientdata(client); \
 | 
				
			||||||
| 
						 | 
					@ -177,7 +177,7 @@ static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
 | 
				
			||||||
static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
 | 
					static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
		       char *buf)
 | 
							       char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%u\n", data->reg[param->msb[0]]);
 | 
						return sprintf(buf, "%u\n", data->reg[param->msb[0]]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -185,7 +185,7 @@ static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
 | 
					static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
			const char *buf, size_t count)
 | 
								const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval;
 | 
						long reqval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (kstrtol(buf, 10, &reqval))
 | 
						if (kstrtol(buf, 10, &reqval))
 | 
				
			||||||
| 
						 | 
					@ -206,7 +206,7 @@ static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
static ssize_t show_bitmask(struct device *dev,
 | 
					static ssize_t show_bitmask(struct device *dev,
 | 
				
			||||||
			    struct device_attribute *attr, char *buf)
 | 
								    struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%u\n",
 | 
						return sprintf(buf, "%u\n",
 | 
				
			||||||
		       (data->reg[param->msb[0]] >> param->
 | 
							       (data->reg[param->msb[0]] >> param->
 | 
				
			||||||
| 
						 | 
					@ -217,7 +217,7 @@ static ssize_t store_bitmask(struct device *dev,
 | 
				
			||||||
			     struct device_attribute *attr,
 | 
								     struct device_attribute *attr,
 | 
				
			||||||
			     const char *buf, size_t count)
 | 
								     const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval;
 | 
						long reqval;
 | 
				
			||||||
	u8 currval;
 | 
						u8 currval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -246,7 +246,7 @@ static ssize_t store_bitmask(struct device *dev,
 | 
				
			||||||
static ssize_t show_fan16(struct device *dev,
 | 
					static ssize_t show_fan16(struct device *dev,
 | 
				
			||||||
			  struct device_attribute *attr, char *buf)
 | 
								  struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u16 regval;
 | 
						u16 regval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
| 
						 | 
					@ -262,7 +262,7 @@ static ssize_t store_fan16(struct device *dev,
 | 
				
			||||||
			   struct device_attribute *attr, const char *buf,
 | 
								   struct device_attribute *attr, const char *buf,
 | 
				
			||||||
			   size_t count)
 | 
								   size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval;
 | 
						long reqval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (kstrtol(buf, 10, &reqval))
 | 
						if (kstrtol(buf, 10, &reqval))
 | 
				
			||||||
| 
						 | 
					@ -307,7 +307,7 @@ static int asc7621_in_scaling[] = {
 | 
				
			||||||
static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
 | 
					static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
			 char *buf)
 | 
								 char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u16 regval;
 | 
						u16 regval;
 | 
				
			||||||
	u8 nr = sda->index;
 | 
						u8 nr = sda->index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -325,7 +325,7 @@ static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
 | 
					static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
			char *buf)
 | 
								char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u8 nr = sda->index;
 | 
						u8 nr = sda->index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%u\n",
 | 
						return sprintf(buf, "%u\n",
 | 
				
			||||||
| 
						 | 
					@ -336,7 +336,7 @@ static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
 | 
					static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
			 const char *buf, size_t count)
 | 
								 const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval;
 | 
						long reqval;
 | 
				
			||||||
	u8 nr = sda->index;
 | 
						u8 nr = sda->index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -360,7 +360,7 @@ static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
static ssize_t show_temp8(struct device *dev,
 | 
					static ssize_t show_temp8(struct device *dev,
 | 
				
			||||||
			  struct device_attribute *attr, char *buf)
 | 
								  struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%d\n", ((s8) data->reg[param->msb[0]]) * 1000);
 | 
						return sprintf(buf, "%d\n", ((s8) data->reg[param->msb[0]]) * 1000);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -369,7 +369,7 @@ static ssize_t store_temp8(struct device *dev,
 | 
				
			||||||
			   struct device_attribute *attr, const char *buf,
 | 
								   struct device_attribute *attr, const char *buf,
 | 
				
			||||||
			   size_t count)
 | 
								   size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval;
 | 
						long reqval;
 | 
				
			||||||
	s8 temp;
 | 
						s8 temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -397,7 +397,7 @@ static ssize_t store_temp8(struct device *dev,
 | 
				
			||||||
static ssize_t show_temp10(struct device *dev,
 | 
					static ssize_t show_temp10(struct device *dev,
 | 
				
			||||||
			   struct device_attribute *attr, char *buf)
 | 
								   struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u8 msb, lsb;
 | 
						u8 msb, lsb;
 | 
				
			||||||
	int temp;
 | 
						int temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -414,7 +414,7 @@ static ssize_t show_temp10(struct device *dev,
 | 
				
			||||||
static ssize_t show_temp62(struct device *dev,
 | 
					static ssize_t show_temp62(struct device *dev,
 | 
				
			||||||
			   struct device_attribute *attr, char *buf)
 | 
								   struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u8 regval = data->reg[param->msb[0]];
 | 
						u8 regval = data->reg[param->msb[0]];
 | 
				
			||||||
	int temp = ((s8) (regval & 0xfc) * 1000) + ((regval & 0x03) * 250);
 | 
						int temp = ((s8) (regval & 0xfc) * 1000) + ((regval & 0x03) * 250);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -425,7 +425,7 @@ static ssize_t store_temp62(struct device *dev,
 | 
				
			||||||
			    struct device_attribute *attr, const char *buf,
 | 
								    struct device_attribute *attr, const char *buf,
 | 
				
			||||||
			    size_t count)
 | 
								    size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval, i, f;
 | 
						long reqval, i, f;
 | 
				
			||||||
	s8 temp;
 | 
						s8 temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -459,7 +459,7 @@ static u32 asc7621_range_map[] = {
 | 
				
			||||||
static ssize_t show_ap2_temp(struct device *dev,
 | 
					static ssize_t show_ap2_temp(struct device *dev,
 | 
				
			||||||
			     struct device_attribute *attr, char *buf)
 | 
								     struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long auto_point1;
 | 
						long auto_point1;
 | 
				
			||||||
	u8 regval;
 | 
						u8 regval;
 | 
				
			||||||
	int temp;
 | 
						int temp;
 | 
				
			||||||
| 
						 | 
					@ -479,7 +479,7 @@ static ssize_t store_ap2_temp(struct device *dev,
 | 
				
			||||||
			      struct device_attribute *attr,
 | 
								      struct device_attribute *attr,
 | 
				
			||||||
			      const char *buf, size_t count)
 | 
								      const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval, auto_point1;
 | 
						long reqval, auto_point1;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	u8 currval, newval = 0;
 | 
						u8 currval, newval = 0;
 | 
				
			||||||
| 
						 | 
					@ -510,7 +510,7 @@ static ssize_t store_ap2_temp(struct device *dev,
 | 
				
			||||||
static ssize_t show_pwm_ac(struct device *dev,
 | 
					static ssize_t show_pwm_ac(struct device *dev,
 | 
				
			||||||
			   struct device_attribute *attr, char *buf)
 | 
								   struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u8 config, altbit, regval;
 | 
						u8 config, altbit, regval;
 | 
				
			||||||
	u8 map[] = {
 | 
						u8 map[] = {
 | 
				
			||||||
		0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10,
 | 
							0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10,
 | 
				
			||||||
| 
						 | 
					@ -530,7 +530,7 @@ static ssize_t store_pwm_ac(struct device *dev,
 | 
				
			||||||
			    struct device_attribute *attr,
 | 
								    struct device_attribute *attr,
 | 
				
			||||||
			    const char *buf, size_t count)
 | 
								    const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	unsigned long reqval;
 | 
						unsigned long reqval;
 | 
				
			||||||
	u8 currval, config, altbit, newval;
 | 
						u8 currval, config, altbit, newval;
 | 
				
			||||||
	u16 map[] = {
 | 
						u16 map[] = {
 | 
				
			||||||
| 
						 | 
					@ -569,7 +569,7 @@ static ssize_t store_pwm_ac(struct device *dev,
 | 
				
			||||||
static ssize_t show_pwm_enable(struct device *dev,
 | 
					static ssize_t show_pwm_enable(struct device *dev,
 | 
				
			||||||
			       struct device_attribute *attr, char *buf)
 | 
								       struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u8 config, altbit, minoff, val, newval;
 | 
						u8 config, altbit, minoff, val, newval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
| 
						 | 
					@ -599,7 +599,7 @@ static ssize_t store_pwm_enable(struct device *dev,
 | 
				
			||||||
				struct device_attribute *attr,
 | 
									struct device_attribute *attr,
 | 
				
			||||||
				const char *buf, size_t count)
 | 
									const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval;
 | 
						long reqval;
 | 
				
			||||||
	u8 currval, config, altbit, newval, minoff = 255;
 | 
						u8 currval, config, altbit, newval, minoff = 255;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -659,7 +659,7 @@ static u32 asc7621_pwm_freq_map[] = {
 | 
				
			||||||
static ssize_t show_pwm_freq(struct device *dev,
 | 
					static ssize_t show_pwm_freq(struct device *dev,
 | 
				
			||||||
			     struct device_attribute *attr, char *buf)
 | 
								     struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u8 regval =
 | 
						u8 regval =
 | 
				
			||||||
	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 | 
						    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -672,7 +672,7 @@ static ssize_t store_pwm_freq(struct device *dev,
 | 
				
			||||||
			      struct device_attribute *attr,
 | 
								      struct device_attribute *attr,
 | 
				
			||||||
			      const char *buf, size_t count)
 | 
								      const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	unsigned long reqval;
 | 
						unsigned long reqval;
 | 
				
			||||||
	u8 currval, newval = 255;
 | 
						u8 currval, newval = 255;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
| 
						 | 
					@ -707,7 +707,7 @@ static u32 asc7621_pwm_auto_spinup_map[] =  {
 | 
				
			||||||
static ssize_t show_pwm_ast(struct device *dev,
 | 
					static ssize_t show_pwm_ast(struct device *dev,
 | 
				
			||||||
			    struct device_attribute *attr, char *buf)
 | 
								    struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u8 regval =
 | 
						u8 regval =
 | 
				
			||||||
	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 | 
						    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -721,7 +721,7 @@ static ssize_t store_pwm_ast(struct device *dev,
 | 
				
			||||||
			     struct device_attribute *attr,
 | 
								     struct device_attribute *attr,
 | 
				
			||||||
			     const char *buf, size_t count)
 | 
								     const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval;
 | 
						long reqval;
 | 
				
			||||||
	u8 currval, newval = 255;
 | 
						u8 currval, newval = 255;
 | 
				
			||||||
	u32 i;
 | 
						u32 i;
 | 
				
			||||||
| 
						 | 
					@ -756,7 +756,7 @@ static u32 asc7621_temp_smoothing_time_map[] = {
 | 
				
			||||||
static ssize_t show_temp_st(struct device *dev,
 | 
					static ssize_t show_temp_st(struct device *dev,
 | 
				
			||||||
			    struct device_attribute *attr, char *buf)
 | 
								    struct device_attribute *attr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_SHOW_data_param(dev, attr);
 | 
						SETUP_SHOW_DATA_PARAM(dev, attr);
 | 
				
			||||||
	u8 regval =
 | 
						u8 regval =
 | 
				
			||||||
	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 | 
						    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 | 
				
			||||||
	regval = clamp_val(regval, 0, 7);
 | 
						regval = clamp_val(regval, 0, 7);
 | 
				
			||||||
| 
						 | 
					@ -768,7 +768,7 @@ static ssize_t store_temp_st(struct device *dev,
 | 
				
			||||||
			     struct device_attribute *attr,
 | 
								     struct device_attribute *attr,
 | 
				
			||||||
			     const char *buf, size_t count)
 | 
								     const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	SETUP_STORE_data_param(dev, attr);
 | 
						SETUP_STORE_DATA_PARAM(dev, attr);
 | 
				
			||||||
	long reqval;
 | 
						long reqval;
 | 
				
			||||||
	u8 currval, newval = 255;
 | 
						u8 currval, newval = 255;
 | 
				
			||||||
	u32 i;
 | 
						u32 i;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -411,8 +411,7 @@ static int __cpuinit chk_ucode_version(unsigned int cpu)
 | 
				
			||||||
	 * fixed for stepping D0 (6EC).
 | 
						 * fixed for stepping D0 (6EC).
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) {
 | 
						if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) {
 | 
				
			||||||
		pr_err("Errata AE18 not fixed, update BIOS or "
 | 
							pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n");
 | 
				
			||||||
		       "microcode of the CPU!\n");
 | 
					 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,19 +43,19 @@ static const char * const input_names[] = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Conversion function for VDDOUT and VBAT */
 | 
					/* Conversion function for VDDOUT and VBAT */
 | 
				
			||||||
static inline int volt_reg_to_mV(int value)
 | 
					static inline int volt_reg_to_mv(int value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return DIV_ROUND_CLOSEST(value * 1000, 512) + 2500;
 | 
						return DIV_ROUND_CLOSEST(value * 1000, 512) + 2500;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Conversion function for ADC channels 4, 5 and 6 */
 | 
					/* Conversion function for ADC channels 4, 5 and 6 */
 | 
				
			||||||
static inline int input_reg_to_mV(int value)
 | 
					static inline int input_reg_to_mv(int value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return DIV_ROUND_CLOSEST(value * 2500, 1023);
 | 
						return DIV_ROUND_CLOSEST(value * 2500, 1023);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Conversion function for VBBAT */
 | 
					/* Conversion function for VBBAT */
 | 
				
			||||||
static inline int vbbat_reg_to_mV(int value)
 | 
					static inline int vbbat_reg_to_mv(int value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return DIV_ROUND_CLOSEST(value * 2500, 512);
 | 
						return DIV_ROUND_CLOSEST(value * 2500, 512);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -96,7 +96,7 @@ static ssize_t da9052_read_vddout(struct device *dev,
 | 
				
			||||||
		goto hwmon_err;
 | 
							goto hwmon_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&hwmon->hwmon_lock);
 | 
						mutex_unlock(&hwmon->hwmon_lock);
 | 
				
			||||||
	return sprintf(buf, "%d\n", volt_reg_to_mV(vdd));
 | 
						return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
hwmon_err_release:
 | 
					hwmon_err_release:
 | 
				
			||||||
	da9052_disable_vddout_channel(hwmon->da9052);
 | 
						da9052_disable_vddout_channel(hwmon->da9052);
 | 
				
			||||||
| 
						 | 
					@ -137,7 +137,7 @@ static ssize_t da9052_read_vbat(struct device *dev,
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%d\n", volt_reg_to_mV(ret));
 | 
						return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t da9052_read_misc_channel(struct device *dev,
 | 
					static ssize_t da9052_read_misc_channel(struct device *dev,
 | 
				
			||||||
| 
						 | 
					@ -152,7 +152,7 @@ static ssize_t da9052_read_misc_channel(struct device *dev,
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%d\n", input_reg_to_mV(ret));
 | 
						return sprintf(buf, "%d\n", input_reg_to_mv(ret));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t da9052_read_tjunc(struct device *dev,
 | 
					static ssize_t da9052_read_tjunc(struct device *dev,
 | 
				
			||||||
| 
						 | 
					@ -187,7 +187,7 @@ static ssize_t da9052_read_vbbat(struct device *dev,
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%d\n", vbbat_reg_to_mV(ret));
 | 
						return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t da9052_hwmon_show_name(struct device *dev,
 | 
					static ssize_t da9052_hwmon_show_name(struct device *dev,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,7 +119,7 @@ static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Conversion function for VSYS and ADCINx */
 | 
					/* Conversion function for VSYS and ADCINx */
 | 
				
			||||||
static inline int volt_reg_to_mV(int value, int channel)
 | 
					static inline int volt_reg_to_mv(int value, int channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (channel == DA9055_ADC_VSYS)
 | 
						if (channel == DA9055_ADC_VSYS)
 | 
				
			||||||
		return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500;
 | 
							return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500;
 | 
				
			||||||
| 
						 | 
					@ -168,7 +168,7 @@ static ssize_t da9055_read_auto_ch(struct device *dev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&hwmon->hwmon_lock);
 | 
						mutex_unlock(&hwmon->hwmon_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%d\n", volt_reg_to_mV(adc, channel));
 | 
						return sprintf(buf, "%d\n", volt_reg_to_mv(adc, channel));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
hwmon_err_release:
 | 
					hwmon_err_release:
 | 
				
			||||||
	da9055_disable_auto_mode(hwmon->da9055, channel);
 | 
						da9055_disable_auto_mode(hwmon->da9055, channel);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,14 +55,16 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool probe_all_addr;
 | 
					static bool probe_all_addr;
 | 
				
			||||||
module_param(probe_all_addr, bool, 0);
 | 
					module_param(probe_all_addr, bool, 0);
 | 
				
			||||||
MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
 | 
					MODULE_PARM_DESC(probe_all_addr,
 | 
				
			||||||
		 "addresses");
 | 
							 "Include probing of non-standard LPC addresses");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Addresses to scan */
 | 
					/* Addresses to scan */
 | 
				
			||||||
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
 | 
					static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum chips { dme1737, sch5027, sch311x, sch5127 };
 | 
					enum chips { dme1737, sch5027, sch311x, sch5127 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define	DO_REPORT "Please report to the driver maintainer."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ---------------------------------------------------------------------
 | 
					/* ---------------------------------------------------------------------
 | 
				
			||||||
 * Registers
 | 
					 * Registers
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -566,9 +568,9 @@ static u8 dme1737_read(const struct dme1737_data *data, u8 reg)
 | 
				
			||||||
		val = i2c_smbus_read_byte_data(client, reg);
 | 
							val = i2c_smbus_read_byte_data(client, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (val < 0) {
 | 
							if (val < 0) {
 | 
				
			||||||
			dev_warn(&client->dev, "Read from register "
 | 
								dev_warn(&client->dev,
 | 
				
			||||||
				 "0x%02x failed! Please report to the driver "
 | 
									 "Read from register 0x%02x failed! %s\n",
 | 
				
			||||||
				 "maintainer.\n", reg);
 | 
									 reg, DO_REPORT);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else { /* ISA device */
 | 
						} else { /* ISA device */
 | 
				
			||||||
		outb(reg, data->addr);
 | 
							outb(reg, data->addr);
 | 
				
			||||||
| 
						 | 
					@ -587,9 +589,9 @@ static s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
 | 
				
			||||||
		res = i2c_smbus_write_byte_data(client, reg, val);
 | 
							res = i2c_smbus_write_byte_data(client, reg, val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (res < 0) {
 | 
							if (res < 0) {
 | 
				
			||||||
			dev_warn(&client->dev, "Write to register "
 | 
								dev_warn(&client->dev,
 | 
				
			||||||
				 "0x%02x failed! Please report to the driver "
 | 
									 "Write to register 0x%02x failed! %s\n",
 | 
				
			||||||
				 "maintainer.\n", reg);
 | 
									 reg, DO_REPORT);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else { /* ISA device */
 | 
						} else { /* ISA device */
 | 
				
			||||||
		outb(reg, data->addr);
 | 
							outb(reg, data->addr);
 | 
				
			||||||
| 
						 | 
					@ -1167,8 +1169,8 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
		/* Only valid for fan[1-4] */
 | 
							/* Only valid for fan[1-4] */
 | 
				
			||||||
		if (!(val == 1 || val == 2 || val == 4)) {
 | 
							if (!(val == 1 || val == 2 || val == 4)) {
 | 
				
			||||||
			count = -EINVAL;
 | 
								count = -EINVAL;
 | 
				
			||||||
			dev_warn(dev, "Fan type value %ld not "
 | 
								dev_warn(dev,
 | 
				
			||||||
				 "supported. Choose one of 1, 2, or 4.\n",
 | 
									 "Fan type value %ld not supported. Choose one of 1, 2, or 4.\n",
 | 
				
			||||||
				 val);
 | 
									 val);
 | 
				
			||||||
			goto exit;
 | 
								goto exit;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1294,8 +1296,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
		/* Only valid for pwm[1-3] */
 | 
							/* Only valid for pwm[1-3] */
 | 
				
			||||||
		if (val < 0 || val > 2) {
 | 
							if (val < 0 || val > 2) {
 | 
				
			||||||
			count = -EINVAL;
 | 
								count = -EINVAL;
 | 
				
			||||||
			dev_warn(dev, "PWM enable %ld not "
 | 
								dev_warn(dev,
 | 
				
			||||||
				 "supported. Choose one of 0, 1, or 2.\n",
 | 
									 "PWM enable %ld not supported. Choose one of 0, 1, or 2.\n",
 | 
				
			||||||
				 val);
 | 
									 val);
 | 
				
			||||||
			goto exit;
 | 
								goto exit;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1399,8 +1401,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
		if (!(val == 1 || val == 2 || val == 4 ||
 | 
							if (!(val == 1 || val == 2 || val == 4 ||
 | 
				
			||||||
		      val == 6 || val == 7)) {
 | 
							      val == 6 || val == 7)) {
 | 
				
			||||||
			count = -EINVAL;
 | 
								count = -EINVAL;
 | 
				
			||||||
			dev_warn(dev, "PWM auto channels zone %ld "
 | 
								dev_warn(dev,
 | 
				
			||||||
				 "not supported. Choose one of 1, 2, 4, 6, "
 | 
									 "PWM auto channels zone %ld not supported. Choose one of 1, 2, 4, 6, "
 | 
				
			||||||
				 "or 7.\n", val);
 | 
									 "or 7.\n", val);
 | 
				
			||||||
			goto exit;
 | 
								goto exit;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -2178,8 +2180,8 @@ static int dme1737_create_files(struct device *dev)
 | 
				
			||||||
	 * selected attributes from read-only to read-writeable.
 | 
						 * selected attributes from read-only to read-writeable.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (data->config & 0x02) {
 | 
						if (data->config & 0x02) {
 | 
				
			||||||
		dev_info(dev, "Device is locked. Some attributes "
 | 
							dev_info(dev,
 | 
				
			||||||
			 "will be read-only.\n");
 | 
								 "Device is locked. Some attributes will be read-only.\n");
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/* Change permissions of zone sysfs attributes */
 | 
							/* Change permissions of zone sysfs attributes */
 | 
				
			||||||
		dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
 | 
							dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
 | 
				
			||||||
| 
						 | 
					@ -2247,9 +2249,8 @@ static int dme1737_init_device(struct device *dev)
 | 
				
			||||||
	/* Inform if part is not monitoring/started */
 | 
						/* Inform if part is not monitoring/started */
 | 
				
			||||||
	if (!(data->config & 0x01)) {
 | 
						if (!(data->config & 0x01)) {
 | 
				
			||||||
		if (!force_start) {
 | 
							if (!force_start) {
 | 
				
			||||||
			dev_err(dev, "Device is not monitoring. "
 | 
								dev_err(dev,
 | 
				
			||||||
				"Use the force_start load parameter to "
 | 
									"Device is not monitoring. Use the force_start load parameter to override.\n");
 | 
				
			||||||
				"override.\n");
 | 
					 | 
				
			||||||
			return -EFAULT;
 | 
								return -EFAULT;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2289,8 +2290,8 @@ static int dme1737_init_device(struct device *dev)
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (dme1737_i2c_get_features(0x2e, data) &&
 | 
							if (dme1737_i2c_get_features(0x2e, data) &&
 | 
				
			||||||
		    dme1737_i2c_get_features(0x4e, data)) {
 | 
							    dme1737_i2c_get_features(0x4e, data)) {
 | 
				
			||||||
			dev_warn(dev, "Failed to query Super-IO for optional "
 | 
								dev_warn(dev,
 | 
				
			||||||
				 "features.\n");
 | 
									 "Failed to query Super-IO for optional features.\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2317,8 +2318,8 @@ static int dme1737_init_device(struct device *dev)
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
 | 
						dev_info(dev,
 | 
				
			||||||
		 "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
 | 
							 "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
 | 
				
			||||||
		 (data->has_features & HAS_PWM(2)) ? "yes" : "no",
 | 
							 (data->has_features & HAS_PWM(2)) ? "yes" : "no",
 | 
				
			||||||
		 (data->has_features & HAS_PWM(4)) ? "yes" : "no",
 | 
							 (data->has_features & HAS_PWM(4)) ? "yes" : "no",
 | 
				
			||||||
		 (data->has_features & HAS_PWM(5)) ? "yes" : "no",
 | 
							 (data->has_features & HAS_PWM(5)) ? "yes" : "no",
 | 
				
			||||||
| 
						 | 
					@ -2330,18 +2331,16 @@ static int dme1737_init_device(struct device *dev)
 | 
				
			||||||
	reg = dme1737_read(data, DME1737_REG_TACH_PWM);
 | 
						reg = dme1737_read(data, DME1737_REG_TACH_PWM);
 | 
				
			||||||
	/* Inform if fan-to-pwm mapping differs from the default */
 | 
						/* Inform if fan-to-pwm mapping differs from the default */
 | 
				
			||||||
	if (client && reg != 0xa4) {   /* I2C chip */
 | 
						if (client && reg != 0xa4) {   /* I2C chip */
 | 
				
			||||||
		dev_warn(dev, "Non-standard fan to pwm mapping: "
 | 
							dev_warn(dev,
 | 
				
			||||||
			 "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
 | 
								 "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, fan4->pwm%d. %s\n",
 | 
				
			||||||
			 "fan4->pwm%d. Please report to the driver "
 | 
					 | 
				
			||||||
			 "maintainer.\n",
 | 
					 | 
				
			||||||
			 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
 | 
								 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
 | 
				
			||||||
			 ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
 | 
								 ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1,
 | 
				
			||||||
 | 
								 DO_REPORT);
 | 
				
			||||||
	} else if (!client && reg != 0x24) {   /* ISA chip */
 | 
						} else if (!client && reg != 0x24) {   /* ISA chip */
 | 
				
			||||||
		dev_warn(dev, "Non-standard fan to pwm mapping: "
 | 
							dev_warn(dev,
 | 
				
			||||||
			 "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
 | 
								 "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. %s\n",
 | 
				
			||||||
			 "Please report to the driver maintainer.\n",
 | 
					 | 
				
			||||||
			 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
 | 
								 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
 | 
				
			||||||
			 ((reg >> 4) & 0x03) + 1);
 | 
								 ((reg >> 4) & 0x03) + 1, DO_REPORT);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -2355,8 +2354,9 @@ static int dme1737_init_device(struct device *dev)
 | 
				
			||||||
						DME1737_REG_PWM_CONFIG(ix));
 | 
											DME1737_REG_PWM_CONFIG(ix));
 | 
				
			||||||
			if ((data->has_features & HAS_PWM(ix)) &&
 | 
								if ((data->has_features & HAS_PWM(ix)) &&
 | 
				
			||||||
			    (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
 | 
								    (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
 | 
				
			||||||
				dev_info(dev, "Switching pwm%d to "
 | 
									dev_info(dev,
 | 
				
			||||||
					 "manual mode.\n", ix + 1);
 | 
										 "Switching pwm%d to manual mode.\n",
 | 
				
			||||||
 | 
										 ix + 1);
 | 
				
			||||||
				data->pwm_config[ix] = PWM_EN_TO_REG(1,
 | 
									data->pwm_config[ix] = PWM_EN_TO_REG(1,
 | 
				
			||||||
							data->pwm_config[ix]);
 | 
												data->pwm_config[ix]);
 | 
				
			||||||
				dme1737_write(data, DME1737_REG_PWM(ix), 0);
 | 
									dme1737_write(data, DME1737_REG_PWM(ix), 0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1350,8 +1350,7 @@ static void f71805f_init_device(struct f71805f_data *data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reg = f71805f_read8(data, F71805F_REG_START);
 | 
						reg = f71805f_read8(data, F71805F_REG_START);
 | 
				
			||||||
	if ((reg & 0x41) != 0x01) {
 | 
						if ((reg & 0x41) != 0x01) {
 | 
				
			||||||
		printk(KERN_DEBUG DRVNAME ": Starting monitoring "
 | 
							pr_debug("Starting monitoring operations\n");
 | 
				
			||||||
		       "operations\n");
 | 
					 | 
				
			||||||
		f71805f_write8(data, F71805F_REG_START, (reg | 0x01) & ~0x40);
 | 
							f71805f_write8(data, F71805F_REG_START, (reg | 0x01) & ~0x40);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -189,8 +189,8 @@ static void fam15h_power_init_data(struct pci_dev *f4,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* result not allowed to be >= 256W */
 | 
						/* result not allowed to be >= 256W */
 | 
				
			||||||
	if ((tmp >> 16) >= 256)
 | 
						if ((tmp >> 16) >= 256)
 | 
				
			||||||
		dev_warn(&f4->dev, "Bogus value for ProcessorPwrWatts "
 | 
							dev_warn(&f4->dev,
 | 
				
			||||||
			 "(processor_pwr_watts>=%u)\n",
 | 
								 "Bogus value for ProcessorPwrWatts (processor_pwr_watts>=%u)\n",
 | 
				
			||||||
			 (unsigned int) (tmp >> 16));
 | 
								 (unsigned int) (tmp >> 16));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* convert to microWatt */
 | 
						/* convert to microWatt */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -463,8 +463,9 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute
 | 
				
			||||||
		v = 3;
 | 
							v = 3;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		dev_err(dev, "fan_div value %lu not supported. "
 | 
							dev_err(dev,
 | 
				
			||||||
			"Choose one of 2, 4 or 8!\n", v);
 | 
								"fan_div value %lu not supported. Choose one of 2, 4 or 8!\n",
 | 
				
			||||||
 | 
								v);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1249,8 +1250,8 @@ static int fschmd_probe(struct i2c_client *client,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (i == ARRAY_SIZE(watchdog_minors)) {
 | 
						if (i == ARRAY_SIZE(watchdog_minors)) {
 | 
				
			||||||
		data->watchdog_miscdev.minor = 0;
 | 
							data->watchdog_miscdev.minor = 0;
 | 
				
			||||||
		dev_warn(&client->dev, "Couldn't register watchdog chardev "
 | 
							dev_warn(&client->dev,
 | 
				
			||||||
			"(due to no free minor)\n");
 | 
								 "Couldn't register watchdog chardev (due to no free minor)\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mutex_unlock(&watchdog_data_mutex);
 | 
						mutex_unlock(&watchdog_data_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -344,8 +344,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
		val = 3;
 | 
							val = 3;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		dev_err(dev, "Invalid fan clock divider %lu, choose one "
 | 
							dev_err(dev,
 | 
				
			||||||
			"of 1, 2, 4 or 8\n", val);
 | 
								"Invalid fan clock divider %lu, choose one of 1, 2, 4 or 8\n",
 | 
				
			||||||
 | 
								val);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,10 +105,6 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = device_create_file(&pdev->dev, &dev_attr_fan1_alarm);
 | 
					 | 
				
			||||||
	if (err)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If the alarm GPIO don't support interrupts, just leave
 | 
						 * If the alarm GPIO don't support interrupts, just leave
 | 
				
			||||||
	 * without initializing the fail notification support.
 | 
						 * without initializing the fail notification support.
 | 
				
			||||||
| 
						 | 
					@ -121,23 +117,9 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
 | 
				
			||||||
	irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
 | 
						irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
 | 
				
			||||||
	err = devm_request_irq(&pdev->dev, alarm_irq, fan_alarm_irq_handler,
 | 
						err = devm_request_irq(&pdev->dev, alarm_irq, fan_alarm_irq_handler,
 | 
				
			||||||
			       IRQF_SHARED, "GPIO fan alarm", fan_data);
 | 
								       IRQF_SHARED, "GPIO fan alarm", fan_data);
 | 
				
			||||||
	if (err)
 | 
					 | 
				
			||||||
		goto err_free_sysfs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err_free_sysfs:
 | 
					 | 
				
			||||||
	device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void fan_alarm_free(struct gpio_fan_data *fan_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct platform_device *pdev = fan_data->pdev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Control GPIOs.
 | 
					 * Control GPIOs.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -327,6 +309,12 @@ exit_unlock:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_name(struct device *dev,
 | 
				
			||||||
 | 
								 struct device_attribute *attr, char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return sprintf(buf, "gpio-fan\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
 | 
					static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
 | 
				
			||||||
static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
 | 
					static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
 | 
				
			||||||
		   show_pwm_enable, set_pwm_enable);
 | 
							   show_pwm_enable, set_pwm_enable);
 | 
				
			||||||
| 
						 | 
					@ -336,8 +324,26 @@ static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL);
 | 
				
			||||||
static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
 | 
					static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
 | 
				
			||||||
static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
 | 
					static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct attribute *gpio_fan_ctrl_attributes[] = {
 | 
					static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 | 
				
			||||||
	&dev_attr_pwm1.attr,
 | 
					
 | 
				
			||||||
 | 
					static umode_t gpio_fan_is_visible(struct kobject *kobj,
 | 
				
			||||||
 | 
									   struct attribute *attr, int index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device *dev = container_of(kobj, struct device, kobj);
 | 
				
			||||||
 | 
						struct gpio_fan_data *data = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (index == 1 && !data->alarm)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						if (index > 1 && !data->ctrl)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return attr->mode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct attribute *gpio_fan_attributes[] = {
 | 
				
			||||||
 | 
						&dev_attr_name.attr,
 | 
				
			||||||
 | 
						&dev_attr_fan1_alarm.attr,		/* 1 */
 | 
				
			||||||
 | 
						&dev_attr_pwm1.attr,			/* 2 */
 | 
				
			||||||
	&dev_attr_pwm1_enable.attr,
 | 
						&dev_attr_pwm1_enable.attr,
 | 
				
			||||||
	&dev_attr_pwm1_mode.attr,
 | 
						&dev_attr_pwm1_mode.attr,
 | 
				
			||||||
	&dev_attr_fan1_input.attr,
 | 
						&dev_attr_fan1_input.attr,
 | 
				
			||||||
| 
						 | 
					@ -347,8 +353,9 @@ static struct attribute *gpio_fan_ctrl_attributes[] = {
 | 
				
			||||||
	NULL
 | 
						NULL
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct attribute_group gpio_fan_ctrl_group = {
 | 
					static const struct attribute_group gpio_fan_group = {
 | 
				
			||||||
	.attrs = gpio_fan_ctrl_attributes,
 | 
						.attrs = gpio_fan_attributes,
 | 
				
			||||||
 | 
						.is_visible = gpio_fan_is_visible,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int fan_ctrl_init(struct gpio_fan_data *fan_data,
 | 
					static int fan_ctrl_init(struct gpio_fan_data *fan_data,
 | 
				
			||||||
| 
						 | 
					@ -379,30 +386,9 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
 | 
				
			||||||
	if (fan_data->speed_index < 0)
 | 
						if (fan_data->speed_index < 0)
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
 | 
						return 0;
 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void fan_ctrl_free(struct gpio_fan_data *fan_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct platform_device *pdev = fan_data->pdev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Platform driver.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t show_name(struct device *dev,
 | 
					 | 
				
			||||||
			 struct device_attribute *attr, char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return sprintf(buf, "gpio-fan\n");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_OF_GPIO
 | 
					#ifdef CONFIG_OF_GPIO
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Translate OpenFirmware node properties into platform_data
 | 
					 * Translate OpenFirmware node properties into platform_data
 | 
				
			||||||
| 
						 | 
					@ -546,38 +532,30 @@ static int gpio_fan_probe(struct platform_device *pdev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Configure control GPIOs if available. */
 | 
						/* Configure control GPIOs if available. */
 | 
				
			||||||
	if (pdata->ctrl && pdata->num_ctrl > 0) {
 | 
						if (pdata->ctrl && pdata->num_ctrl > 0) {
 | 
				
			||||||
		if (!pdata->speed || pdata->num_speed <= 1) {
 | 
							if (!pdata->speed || pdata->num_speed <= 1)
 | 
				
			||||||
			err = -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
			goto err_free_alarm;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = fan_ctrl_init(fan_data, pdata);
 | 
							err = fan_ctrl_init(fan_data, pdata);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto err_free_alarm;
 | 
								return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = device_create_file(&pdev->dev, &dev_attr_name);
 | 
						err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_group);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto err_free_ctrl;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make this driver part of hwmon class. */
 | 
						/* Make this driver part of hwmon class. */
 | 
				
			||||||
	fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
 | 
						fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
 | 
				
			||||||
	if (IS_ERR(fan_data->hwmon_dev)) {
 | 
						if (IS_ERR(fan_data->hwmon_dev)) {
 | 
				
			||||||
		err = PTR_ERR(fan_data->hwmon_dev);
 | 
							err = PTR_ERR(fan_data->hwmon_dev);
 | 
				
			||||||
		goto err_remove_name;
 | 
							goto err_remove;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_info(&pdev->dev, "GPIO fan initialized\n");
 | 
						dev_info(&pdev->dev, "GPIO fan initialized\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_remove_name:
 | 
					err_remove:
 | 
				
			||||||
	device_remove_file(&pdev->dev, &dev_attr_name);
 | 
						sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group);
 | 
				
			||||||
err_free_ctrl:
 | 
					 | 
				
			||||||
	if (fan_data->ctrl)
 | 
					 | 
				
			||||||
		fan_ctrl_free(fan_data);
 | 
					 | 
				
			||||||
err_free_alarm:
 | 
					 | 
				
			||||||
	if (fan_data->alarm)
 | 
					 | 
				
			||||||
		fan_alarm_free(fan_data);
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -586,11 +564,7 @@ static int gpio_fan_remove(struct platform_device *pdev)
 | 
				
			||||||
	struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
 | 
						struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hwmon_device_unregister(fan_data->hwmon_dev);
 | 
						hwmon_device_unregister(fan_data->hwmon_dev);
 | 
				
			||||||
	device_remove_file(&pdev->dev, &dev_attr_name);
 | 
						sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group);
 | 
				
			||||||
	if (fan_data->alarm)
 | 
					 | 
				
			||||||
		fan_alarm_free(fan_data);
 | 
					 | 
				
			||||||
	if (fan_data->ctrl)
 | 
					 | 
				
			||||||
		fan_ctrl_free(fan_data);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -619,7 +593,7 @@ static int gpio_fan_resume(struct device *dev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
 | 
					static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
 | 
				
			||||||
#define GPIO_FAN_PM	&gpio_fan_pm
 | 
					#define GPIO_FAN_PM	(&gpio_fan_pm)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define GPIO_FAN_PM	NULL
 | 
					#define GPIO_FAN_PM	NULL
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -289,8 +289,9 @@ static int aem_init_ipmi_data(struct aem_ipmi_data *data, int iface,
 | 
				
			||||||
	err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
 | 
						err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
 | 
				
			||||||
			       data, &data->user);
 | 
								       data, &data->user);
 | 
				
			||||||
	if (err < 0) {
 | 
						if (err < 0) {
 | 
				
			||||||
		dev_err(bmc, "Unable to register user with IPMI "
 | 
							dev_err(bmc,
 | 
				
			||||||
			"interface %d\n", data->interface);
 | 
								"Unable to register user with IPMI interface %d\n",
 | 
				
			||||||
 | 
								data->interface);
 | 
				
			||||||
		return -EACCES;
 | 
							return -EACCES;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -328,8 +329,8 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
 | 
				
			||||||
	struct aem_ipmi_data *data = user_msg_data;
 | 
						struct aem_ipmi_data *data = user_msg_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (msg->msgid != data->tx_msgid) {
 | 
						if (msg->msgid != data->tx_msgid) {
 | 
				
			||||||
		dev_err(data->bmc_device, "Mismatch between received msgid "
 | 
							dev_err(data->bmc_device,
 | 
				
			||||||
			"(%02x) and transmitted msgid (%02x)!\n",
 | 
								"Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
 | 
				
			||||||
			(int)msg->msgid,
 | 
								(int)msg->msgid,
 | 
				
			||||||
			(int)data->tx_msgid);
 | 
								(int)data->tx_msgid);
 | 
				
			||||||
		ipmi_free_recv_msg(msg);
 | 
							ipmi_free_recv_msg(msg);
 | 
				
			||||||
| 
						 | 
					@ -575,8 +576,8 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
 | 
				
			||||||
	/* Register with hwmon */
 | 
						/* Register with hwmon */
 | 
				
			||||||
	data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
 | 
						data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
 | 
				
			||||||
	if (IS_ERR(data->hwmon_dev)) {
 | 
						if (IS_ERR(data->hwmon_dev)) {
 | 
				
			||||||
		dev_err(&data->pdev->dev, "Unable to register hwmon "
 | 
							dev_err(&data->pdev->dev,
 | 
				
			||||||
			"device for IPMI interface %d\n",
 | 
								"Unable to register hwmon device for IPMI interface %d\n",
 | 
				
			||||||
			probe->interface);
 | 
								probe->interface);
 | 
				
			||||||
		res = PTR_ERR(data->hwmon_dev);
 | 
							res = PTR_ERR(data->hwmon_dev);
 | 
				
			||||||
		goto hwmon_reg_err;
 | 
							goto hwmon_reg_err;
 | 
				
			||||||
| 
						 | 
					@ -715,8 +716,8 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
 | 
				
			||||||
	/* Register with hwmon */
 | 
						/* Register with hwmon */
 | 
				
			||||||
	data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
 | 
						data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
 | 
				
			||||||
	if (IS_ERR(data->hwmon_dev)) {
 | 
						if (IS_ERR(data->hwmon_dev)) {
 | 
				
			||||||
		dev_err(&data->pdev->dev, "Unable to register hwmon "
 | 
							dev_err(&data->pdev->dev,
 | 
				
			||||||
			"device for IPMI interface %d\n",
 | 
								"Unable to register hwmon device for IPMI interface %d\n",
 | 
				
			||||||
			probe->interface);
 | 
								probe->interface);
 | 
				
			||||||
		res = PTR_ERR(data->hwmon_dev);
 | 
							res = PTR_ERR(data->hwmon_dev);
 | 
				
			||||||
		goto hwmon_reg_err;
 | 
							goto hwmon_reg_err;
 | 
				
			||||||
| 
						 | 
					@ -768,8 +769,8 @@ static void aem_init_aem2(struct aem_ipmi_data *probe)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (!aem_find_aem2(probe, &fi_resp, i)) {
 | 
						while (!aem_find_aem2(probe, &fi_resp, i)) {
 | 
				
			||||||
		if (fi_resp.major != 2) {
 | 
							if (fi_resp.major != 2) {
 | 
				
			||||||
			dev_err(probe->bmc_device, "Unknown AEM v%d; please "
 | 
								dev_err(probe->bmc_device,
 | 
				
			||||||
				"report this to the maintainer.\n",
 | 
									"Unknown AEM v%d; please report this to the maintainer.\n",
 | 
				
			||||||
				fi_resp.major);
 | 
									fi_resp.major);
 | 
				
			||||||
			i++;
 | 
								i++;
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,8 +163,8 @@ static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
 | 
				
			||||||
	data->sensor_major = data->rx_msg_data[0];
 | 
						data->sensor_major = data->rx_msg_data[0];
 | 
				
			||||||
	data->sensor_minor = data->rx_msg_data[1];
 | 
						data->sensor_minor = data->rx_msg_data[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_info(data->bmc_device, "Found BMC with sensor interface "
 | 
						dev_info(data->bmc_device,
 | 
				
			||||||
		 "v%d.%d %d-%02d-%02d on interface %d\n",
 | 
							 "Found BMC with sensor interface v%d.%d %d-%02d-%02d on interface %d\n",
 | 
				
			||||||
		 data->sensor_major,
 | 
							 data->sensor_major,
 | 
				
			||||||
		 data->sensor_minor,
 | 
							 data->sensor_minor,
 | 
				
			||||||
		 extract_value(data->rx_msg_data, 2),
 | 
							 extract_value(data->rx_msg_data, 2),
 | 
				
			||||||
| 
						 | 
					@ -478,8 +478,9 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
 | 
				
			||||||
	err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
 | 
						err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
 | 
				
			||||||
			       data, &data->user);
 | 
								       data, &data->user);
 | 
				
			||||||
	if (err < 0) {
 | 
						if (err < 0) {
 | 
				
			||||||
		dev_err(dev, "Unable to register user with IPMI "
 | 
							dev_err(dev,
 | 
				
			||||||
			"interface %d\n", data->interface);
 | 
								"Unable to register user with IPMI interface %d\n",
 | 
				
			||||||
 | 
								data->interface);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -501,8 +502,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
 | 
				
			||||||
	data->hwmon_dev = hwmon_device_register(data->bmc_device);
 | 
						data->hwmon_dev = hwmon_device_register(data->bmc_device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (IS_ERR(data->hwmon_dev)) {
 | 
						if (IS_ERR(data->hwmon_dev)) {
 | 
				
			||||||
		dev_err(data->bmc_device, "Unable to register hwmon "
 | 
							dev_err(data->bmc_device,
 | 
				
			||||||
			"device for IPMI interface %d\n",
 | 
								"Unable to register hwmon device for IPMI interface %d\n",
 | 
				
			||||||
			data->interface);
 | 
								data->interface);
 | 
				
			||||||
		goto out_user;
 | 
							goto out_user;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -567,8 +568,8 @@ static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
 | 
				
			||||||
	struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
 | 
						struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (msg->msgid != data->tx_msgid) {
 | 
						if (msg->msgid != data->tx_msgid) {
 | 
				
			||||||
		dev_err(data->bmc_device, "Mismatch between received msgid "
 | 
							dev_err(data->bmc_device,
 | 
				
			||||||
			"(%02x) and transmitted msgid (%02x)!\n",
 | 
								"Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
 | 
				
			||||||
			(int)msg->msgid,
 | 
								(int)msg->msgid,
 | 
				
			||||||
			(int)data->tx_msgid);
 | 
								(int)data->tx_msgid);
 | 
				
			||||||
		ipmi_free_recv_msg(msg);
 | 
							ipmi_free_recv_msg(msg);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -186,20 +186,20 @@ static ssize_t ina2xx_show_value(struct device *dev,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* shunt voltage */
 | 
					/* shunt voltage */
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
 | 
					static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
 | 
				
			||||||
	ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
 | 
								  INA2XX_SHUNT_VOLTAGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* bus voltage */
 | 
					/* bus voltage */
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
 | 
					static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina2xx_show_value, NULL,
 | 
				
			||||||
	ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
 | 
								  INA2XX_BUS_VOLTAGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* calculated current */
 | 
					/* calculated current */
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
 | 
					static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL,
 | 
				
			||||||
	ina2xx_show_value, NULL, INA2XX_CURRENT);
 | 
								  INA2XX_CURRENT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* calculated power */
 | 
					/* calculated power */
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
 | 
					static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL,
 | 
				
			||||||
	ina2xx_show_value, NULL, INA2XX_POWER);
 | 
								  INA2XX_POWER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* pointers to created device attributes */
 | 
					/* pointers to created device attributes */
 | 
				
			||||||
static struct attribute *ina2xx_attributes[] = {
 | 
					static struct attribute *ina2xx_attributes[] = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1778,7 +1778,7 @@ static int __init it87_find(unsigned short *address,
 | 
				
			||||||
		superio_select(5);
 | 
							superio_select(5);
 | 
				
			||||||
		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
 | 
							sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
 | 
				
			||||||
	} else if (sio_data->type == it8783) {
 | 
						} else if (sio_data->type == it8783) {
 | 
				
			||||||
		int reg25, reg27, reg2A, reg2C, regEF;
 | 
							int reg25, reg27, reg2a, reg2c, regef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sio_data->skip_vid = 1;	/* No VID */
 | 
							sio_data->skip_vid = 1;	/* No VID */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1786,15 +1786,15 @@ static int __init it87_find(unsigned short *address,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		reg25 = superio_inb(IT87_SIO_GPIO1_REG);
 | 
							reg25 = superio_inb(IT87_SIO_GPIO1_REG);
 | 
				
			||||||
		reg27 = superio_inb(IT87_SIO_GPIO3_REG);
 | 
							reg27 = superio_inb(IT87_SIO_GPIO3_REG);
 | 
				
			||||||
		reg2A = superio_inb(IT87_SIO_PINX1_REG);
 | 
							reg2a = superio_inb(IT87_SIO_PINX1_REG);
 | 
				
			||||||
		reg2C = superio_inb(IT87_SIO_PINX2_REG);
 | 
							reg2c = superio_inb(IT87_SIO_PINX2_REG);
 | 
				
			||||||
		regEF = superio_inb(IT87_SIO_SPI_REG);
 | 
							regef = superio_inb(IT87_SIO_SPI_REG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Check if fan3 is there or not */
 | 
							/* Check if fan3 is there or not */
 | 
				
			||||||
		if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2)))
 | 
							if ((reg27 & (1 << 0)) || !(reg2c & (1 << 2)))
 | 
				
			||||||
			sio_data->skip_fan |= (1 << 2);
 | 
								sio_data->skip_fan |= (1 << 2);
 | 
				
			||||||
		if ((reg25 & (1 << 4))
 | 
							if ((reg25 & (1 << 4))
 | 
				
			||||||
		    || (!(reg2A & (1 << 1)) && (regEF & (1 << 0))))
 | 
							    || (!(reg2a & (1 << 1)) && (regef & (1 << 0))))
 | 
				
			||||||
			sio_data->skip_pwm |= (1 << 2);
 | 
								sio_data->skip_pwm |= (1 << 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Check if fan2 is there or not */
 | 
							/* Check if fan2 is there or not */
 | 
				
			||||||
| 
						 | 
					@ -1804,7 +1804,7 @@ static int __init it87_find(unsigned short *address,
 | 
				
			||||||
			sio_data->skip_pwm |= (1 << 1);
 | 
								sio_data->skip_pwm |= (1 << 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* VIN5 */
 | 
							/* VIN5 */
 | 
				
			||||||
		if ((reg27 & (1 << 0)) || (reg2C & (1 << 2)))
 | 
							if ((reg27 & (1 << 0)) || (reg2c & (1 << 2)))
 | 
				
			||||||
			sio_data->skip_in |= (1 << 5); /* No VIN5 */
 | 
								sio_data->skip_in |= (1 << 5); /* No VIN5 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* VIN6 */
 | 
							/* VIN6 */
 | 
				
			||||||
| 
						 | 
					@ -1829,18 +1829,18 @@ static int __init it87_find(unsigned short *address,
 | 
				
			||||||
			 * not the case, and ask the user to report if the
 | 
								 * not the case, and ask the user to report if the
 | 
				
			||||||
			 * resulting voltage is sane.
 | 
								 * resulting voltage is sane.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			if (!(reg2C & (1 << 1))) {
 | 
								if (!(reg2c & (1 << 1))) {
 | 
				
			||||||
				reg2C |= (1 << 1);
 | 
									reg2c |= (1 << 1);
 | 
				
			||||||
				superio_outb(IT87_SIO_PINX2_REG, reg2C);
 | 
									superio_outb(IT87_SIO_PINX2_REG, reg2c);
 | 
				
			||||||
				pr_notice("Routing internal VCCH5V to in7.\n");
 | 
									pr_notice("Routing internal VCCH5V to in7.\n");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
 | 
								pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
 | 
				
			||||||
			pr_notice("Please report if it displays a reasonable voltage.\n");
 | 
								pr_notice("Please report if it displays a reasonable voltage.\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (reg2C & (1 << 0))
 | 
							if (reg2c & (1 << 0))
 | 
				
			||||||
			sio_data->internal |= (1 << 0);
 | 
								sio_data->internal |= (1 << 0);
 | 
				
			||||||
		if (reg2C & (1 << 1))
 | 
							if (reg2c & (1 << 1))
 | 
				
			||||||
			sio_data->internal |= (1 << 1);
 | 
								sio_data->internal |= (1 << 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
 | 
							sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,8 +200,8 @@ static int k8temp_probe(struct pci_dev *pdev,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (model >= 0x40) {
 | 
						if (model >= 0x40) {
 | 
				
			||||||
		data->swap_core_select = 1;
 | 
							data->swap_core_select = 1;
 | 
				
			||||||
		dev_warn(&pdev->dev, "Temperature readouts might be wrong - "
 | 
							dev_warn(&pdev->dev,
 | 
				
			||||||
			 "check erratum #141\n");
 | 
								 "Temperature readouts might be wrong - check erratum #141\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -386,8 +386,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
 | 
				
			||||||
		data->fan_div[nr] = 3;
 | 
							data->fan_div[nr] = 3;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		dev_err(dev, "fan_div value %ld not "
 | 
							dev_err(dev,
 | 
				
			||||||
			"supported. Choose one of 1, 2, 4 or 8!\n", val);
 | 
								"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
 | 
				
			||||||
 | 
								val);
 | 
				
			||||||
		mutex_unlock(&data->update_lock);
 | 
							mutex_unlock(&data->update_lock);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -636,8 +637,9 @@ static int lm78_i2c_detect(struct i2c_client *client,
 | 
				
			||||||
		goto err_nodev;
 | 
							goto err_nodev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (lm78_alias_detect(client, i)) {
 | 
						if (lm78_alias_detect(client, i)) {
 | 
				
			||||||
		dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
 | 
							dev_dbg(&adapter->dev,
 | 
				
			||||||
			"be the same as ISA device\n", address);
 | 
								"Device at 0x%02x appears to be the same as ISA device\n",
 | 
				
			||||||
 | 
								address);
 | 
				
			||||||
		goto err_nodev;
 | 
							goto err_nodev;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -286,8 +286,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
		data->fan_div[nr] = 3;
 | 
							data->fan_div[nr] = 3;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		dev_err(&client->dev, "fan_div value %ld not "
 | 
							dev_err(&client->dev,
 | 
				
			||||||
			"supported. Choose one of 1, 2, 4 or 8!\n", val);
 | 
								"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
 | 
				
			||||||
 | 
								val);
 | 
				
			||||||
		mutex_unlock(&data->update_lock);
 | 
							mutex_unlock(&data->update_lock);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1293,8 +1293,8 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
 | 
				
			||||||
	company = lm85_read_value(client, LM85_REG_COMPANY);
 | 
						company = lm85_read_value(client, LM85_REG_COMPANY);
 | 
				
			||||||
	verstep = lm85_read_value(client, LM85_REG_VERSTEP);
 | 
						verstep = lm85_read_value(client, LM85_REG_VERSTEP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_dbg(&adapter->dev, "Detecting device at 0x%02x with "
 | 
						dev_dbg(&adapter->dev,
 | 
				
			||||||
		"COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
 | 
							"Detecting device at 0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
 | 
				
			||||||
		address, company, verstep);
 | 
							address, company, verstep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* All supported chips have the version in common */
 | 
						/* All supported chips have the version in common */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -354,12 +354,12 @@ static const unsigned long lm93_vin_val_max[16] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
 | 
					static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const long uV_max = lm93_vin_val_max[nr] * 1000;
 | 
						const long uv_max = lm93_vin_val_max[nr] * 1000;
 | 
				
			||||||
	const long uV_min = lm93_vin_val_min[nr] * 1000;
 | 
						const long uv_min = lm93_vin_val_min[nr] * 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const long slope = (uV_max - uV_min) /
 | 
						const long slope = (uv_max - uv_min) /
 | 
				
			||||||
		(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
 | 
							(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
 | 
				
			||||||
	const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
 | 
						const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (slope * reg + intercept + 500) / 1000;
 | 
						return (slope * reg + intercept + 500) / 1000;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -371,20 +371,20 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
 | 
				
			||||||
static u8 LM93_IN_TO_REG(int nr, unsigned val)
 | 
					static u8 LM93_IN_TO_REG(int nr, unsigned val)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* range limit */
 | 
						/* range limit */
 | 
				
			||||||
	const long mV = clamp_val(val,
 | 
						const long mv = clamp_val(val,
 | 
				
			||||||
				  lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
 | 
									  lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* try not to lose too much precision here */
 | 
						/* try not to lose too much precision here */
 | 
				
			||||||
	const long uV = mV * 1000;
 | 
						const long uv = mv * 1000;
 | 
				
			||||||
	const long uV_max = lm93_vin_val_max[nr] * 1000;
 | 
						const long uv_max = lm93_vin_val_max[nr] * 1000;
 | 
				
			||||||
	const long uV_min = lm93_vin_val_min[nr] * 1000;
 | 
						const long uv_min = lm93_vin_val_min[nr] * 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* convert */
 | 
						/* convert */
 | 
				
			||||||
	const long slope = (uV_max - uV_min) /
 | 
						const long slope = (uv_max - uv_min) /
 | 
				
			||||||
		(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
 | 
							(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
 | 
				
			||||||
	const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
 | 
						const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u8 result = ((uV - intercept + (slope/2)) / slope);
 | 
						u8 result = ((uv - intercept + (slope/2)) / slope);
 | 
				
			||||||
	result = clamp_val(result,
 | 
						result = clamp_val(result,
 | 
				
			||||||
			   lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
 | 
								   lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -393,10 +393,10 @@ static u8 LM93_IN_TO_REG(int nr, unsigned val)
 | 
				
			||||||
/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
 | 
					/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
 | 
				
			||||||
static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
 | 
					static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
 | 
						const long uv_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
 | 
				
			||||||
				(((reg >> 0 & 0x0f) + 1) * -25000);
 | 
									(((reg >> 0 & 0x0f) + 1) * -25000);
 | 
				
			||||||
	const long uV_vid = vid * 1000;
 | 
						const long uv_vid = vid * 1000;
 | 
				
			||||||
	return (uV_vid + uV_offset + 5000) / 10000;
 | 
						return (uv_vid + uv_offset + 5000) / 10000;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LM93_IN_MIN_FROM_REG(reg, vid)	LM93_IN_REL_FROM_REG((reg), 0, (vid))
 | 
					#define LM93_IN_MIN_FROM_REG(reg, vid)	LM93_IN_REL_FROM_REG((reg), 0, (vid))
 | 
				
			||||||
| 
						 | 
					@ -409,13 +409,13 @@ static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
 | 
					static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	long uV_offset = vid * 1000 - val * 10000;
 | 
						long uv_offset = vid * 1000 - val * 10000;
 | 
				
			||||||
	if (upper) {
 | 
						if (upper) {
 | 
				
			||||||
		uV_offset = clamp_val(uV_offset, 12500, 200000);
 | 
							uv_offset = clamp_val(uv_offset, 12500, 200000);
 | 
				
			||||||
		return (u8)((uV_offset /  12500 - 1) << 4);
 | 
							return (u8)((uv_offset /  12500 - 1) << 4);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		uV_offset = clamp_val(uV_offset, -400000, -25000);
 | 
							uv_offset = clamp_val(uv_offset, -400000, -25000);
 | 
				
			||||||
		return (u8)((uV_offset / -25000 - 1) << 0);
 | 
							return (u8)((uv_offset / -25000 - 1) << 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -818,8 +818,9 @@ static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
 | 
				
			||||||
		if (value >= 0) {
 | 
							if (value >= 0) {
 | 
				
			||||||
			return value;
 | 
								return value;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			dev_warn(&client->dev, "lm93: read byte data failed, "
 | 
								dev_warn(&client->dev,
 | 
				
			||||||
				"address 0x%02x.\n", reg);
 | 
									 "lm93: read byte data failed, address 0x%02x.\n",
 | 
				
			||||||
 | 
									 reg);
 | 
				
			||||||
			mdelay(i + 3);
 | 
								mdelay(i + 3);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -838,8 +839,9 @@ static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value)
 | 
				
			||||||
	result = i2c_smbus_write_byte_data(client, reg, value);
 | 
						result = i2c_smbus_write_byte_data(client, reg, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (result < 0)
 | 
						if (result < 0)
 | 
				
			||||||
		dev_warn(&client->dev, "lm93: write byte data failed, "
 | 
							dev_warn(&client->dev,
 | 
				
			||||||
			 "0x%02x at address 0x%02x.\n", value, reg);
 | 
								 "lm93: write byte data failed, 0x%02x at address 0x%02x.\n",
 | 
				
			||||||
 | 
								 value, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -854,8 +856,9 @@ static u16 lm93_read_word(struct i2c_client *client, u8 reg)
 | 
				
			||||||
		if (value >= 0) {
 | 
							if (value >= 0) {
 | 
				
			||||||
			return value;
 | 
								return value;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			dev_warn(&client->dev, "lm93: read word data failed, "
 | 
								dev_warn(&client->dev,
 | 
				
			||||||
				 "address 0x%02x.\n", reg);
 | 
									 "lm93: read word data failed, address 0x%02x.\n",
 | 
				
			||||||
 | 
									 reg);
 | 
				
			||||||
			mdelay(i + 3);
 | 
								mdelay(i + 3);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -874,8 +877,9 @@ static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
 | 
				
			||||||
	result = i2c_smbus_write_word_data(client, reg, value);
 | 
						result = i2c_smbus_write_word_data(client, reg, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (result < 0)
 | 
						if (result < 0)
 | 
				
			||||||
		dev_warn(&client->dev, "lm93: write word data failed, "
 | 
							dev_warn(&client->dev,
 | 
				
			||||||
			 "0x%04x at address 0x%02x.\n", value, reg);
 | 
								 "lm93: write word data failed, 0x%04x at address 0x%02x.\n",
 | 
				
			||||||
 | 
								 value, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -898,8 +902,8 @@ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
 | 
				
			||||||
		if (result == lm93_block_read_cmds[fbn].len) {
 | 
							if (result == lm93_block_read_cmds[fbn].len) {
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			dev_warn(&client->dev, "lm93: block read data failed, "
 | 
								dev_warn(&client->dev,
 | 
				
			||||||
				 "command 0x%02x.\n",
 | 
									 "lm93: block read data failed, command 0x%02x.\n",
 | 
				
			||||||
				 lm93_block_read_cmds[fbn].cmd);
 | 
									 lm93_block_read_cmds[fbn].cmd);
 | 
				
			||||||
			mdelay(i + 3);
 | 
								mdelay(i + 3);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -2672,8 +2676,8 @@ static void lm93_init_client(struct i2c_client *client)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_warn(&client->dev, "timed out waiting for sensor "
 | 
						dev_warn(&client->dev,
 | 
				
			||||||
		 "chip to signal ready!\n");
 | 
							 "timed out waiting for sensor chip to signal ready!\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Return 0 if detection is successful, -ENODEV otherwise */
 | 
					/* Return 0 if detection is successful, -ENODEV otherwise */
 | 
				
			||||||
| 
						 | 
					@ -2733,12 +2737,12 @@ static int lm93_probe(struct i2c_client *client,
 | 
				
			||||||
		dev_dbg(&client->dev, "using SMBus block data transactions\n");
 | 
							dev_dbg(&client->dev, "using SMBus block data transactions\n");
 | 
				
			||||||
		update = lm93_update_client_full;
 | 
							update = lm93_update_client_full;
 | 
				
			||||||
	} else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
 | 
						} else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
 | 
				
			||||||
		dev_dbg(&client->dev, "disabled SMBus block data "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"transactions\n");
 | 
								"disabled SMBus block data transactions\n");
 | 
				
			||||||
		update = lm93_update_client_min;
 | 
							update = lm93_update_client_min;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		dev_dbg(&client->dev, "detect failed, "
 | 
							dev_dbg(&client->dev,
 | 
				
			||||||
			"smbus byte and/or word data not supported!\n");
 | 
								"detect failed, smbus byte and/or word data not supported!\n");
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										769
									
								
								drivers/hwmon/lm95234.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										769
									
								
								drivers/hwmon/lm95234.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,769 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Driver for Texas Instruments / National Semiconductor LM95234
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Derived from lm95241.c
 | 
				
			||||||
 | 
					 * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/jiffies.h>
 | 
				
			||||||
 | 
					#include <linux/i2c.h>
 | 
				
			||||||
 | 
					#include <linux/hwmon.h>
 | 
				
			||||||
 | 
					#include <linux/hwmon-sysfs.h>
 | 
				
			||||||
 | 
					#include <linux/err.h>
 | 
				
			||||||
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					#include <linux/sysfs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DRVNAME "lm95234"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* LM95234 registers */
 | 
				
			||||||
 | 
					#define LM95234_REG_MAN_ID		0xFE
 | 
				
			||||||
 | 
					#define LM95234_REG_CHIP_ID		0xFF
 | 
				
			||||||
 | 
					#define LM95234_REG_STATUS		0x02
 | 
				
			||||||
 | 
					#define LM95234_REG_CONFIG		0x03
 | 
				
			||||||
 | 
					#define LM95234_REG_CONVRATE		0x04
 | 
				
			||||||
 | 
					#define LM95234_REG_STS_FAULT		0x07
 | 
				
			||||||
 | 
					#define LM95234_REG_STS_TCRIT1		0x08
 | 
				
			||||||
 | 
					#define LM95234_REG_STS_TCRIT2		0x09
 | 
				
			||||||
 | 
					#define LM95234_REG_TEMPH(x)		((x) + 0x10)
 | 
				
			||||||
 | 
					#define LM95234_REG_TEMPL(x)		((x) + 0x20)
 | 
				
			||||||
 | 
					#define LM95234_REG_UTEMPH(x)		((x) + 0x19)	/* Remote only */
 | 
				
			||||||
 | 
					#define LM95234_REG_UTEMPL(x)		((x) + 0x29)
 | 
				
			||||||
 | 
					#define LM95234_REG_REM_MODEL		0x30
 | 
				
			||||||
 | 
					#define LM95234_REG_REM_MODEL_STS	0x38
 | 
				
			||||||
 | 
					#define LM95234_REG_OFFSET(x)		((x) + 0x31)	/* Remote only */
 | 
				
			||||||
 | 
					#define LM95234_REG_TCRIT1(x)		((x) + 0x40)
 | 
				
			||||||
 | 
					#define LM95234_REG_TCRIT2(x)		((x) + 0x49)	/* Remote channel 1,2 */
 | 
				
			||||||
 | 
					#define LM95234_REG_TCRIT_HYST		0x5a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NATSEMI_MAN_ID			0x01
 | 
				
			||||||
 | 
					#define LM95234_CHIP_ID			0x79
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Client data (each client gets its own) */
 | 
				
			||||||
 | 
					struct lm95234_data {
 | 
				
			||||||
 | 
						struct device *hwmon_dev;
 | 
				
			||||||
 | 
						struct mutex update_lock;
 | 
				
			||||||
 | 
						unsigned long last_updated, interval;	/* in jiffies */
 | 
				
			||||||
 | 
						bool valid;		/* false until following fields are valid */
 | 
				
			||||||
 | 
						/* registers values */
 | 
				
			||||||
 | 
						int temp[5];		/* temperature (signed) */
 | 
				
			||||||
 | 
						u32 status;		/* fault/alarm status */
 | 
				
			||||||
 | 
						u8 tcrit1[5];		/* critical temperature limit */
 | 
				
			||||||
 | 
						u8 tcrit2[2];		/* high temperature limit */
 | 
				
			||||||
 | 
						s8 toffset[4];		/* remote temperature offset */
 | 
				
			||||||
 | 
						u8 thyst;		/* common hysteresis */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8 sensor_type;		/* temperature sensor type */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lm95234_read_temp(struct i2c_client *client, int index, int *t)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int val;
 | 
				
			||||||
 | 
						u16 temp = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (index) {
 | 
				
			||||||
 | 
							val = i2c_smbus_read_byte_data(client,
 | 
				
			||||||
 | 
										       LM95234_REG_UTEMPH(index - 1));
 | 
				
			||||||
 | 
							if (val < 0)
 | 
				
			||||||
 | 
								return val;
 | 
				
			||||||
 | 
							temp = val << 8;
 | 
				
			||||||
 | 
							val = i2c_smbus_read_byte_data(client,
 | 
				
			||||||
 | 
										       LM95234_REG_UTEMPL(index - 1));
 | 
				
			||||||
 | 
							if (val < 0)
 | 
				
			||||||
 | 
								return val;
 | 
				
			||||||
 | 
							temp |= val;
 | 
				
			||||||
 | 
							*t = temp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Read signed temperature if unsigned temperature is 0,
 | 
				
			||||||
 | 
						 * or if this is the local sensor.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!temp) {
 | 
				
			||||||
 | 
							val = i2c_smbus_read_byte_data(client,
 | 
				
			||||||
 | 
										       LM95234_REG_TEMPH(index));
 | 
				
			||||||
 | 
							if (val < 0)
 | 
				
			||||||
 | 
								return val;
 | 
				
			||||||
 | 
							temp = val << 8;
 | 
				
			||||||
 | 
							val = i2c_smbus_read_byte_data(client,
 | 
				
			||||||
 | 
										       LM95234_REG_TEMPL(index));
 | 
				
			||||||
 | 
							if (val < 0)
 | 
				
			||||||
 | 
								return val;
 | 
				
			||||||
 | 
							temp |= val;
 | 
				
			||||||
 | 
							*t = (s16)temp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u16 update_intervals[] = { 143, 364, 1000, 2500 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Fill value cache. Must be called with update lock held. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lm95234_fill_cache(struct i2c_client *client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int i, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data->interval = msecs_to_jiffies(update_intervals[ret & 0x03]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(data->tcrit1); i++) {
 | 
				
			||||||
 | 
							ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT1(i));
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							data->tcrit1[i] = ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(data->tcrit2); i++) {
 | 
				
			||||||
 | 
							ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT2(i));
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							data->tcrit2[i] = ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(data->toffset); i++) {
 | 
				
			||||||
 | 
							ret = i2c_smbus_read_byte_data(client, LM95234_REG_OFFSET(i));
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							data->toffset[i] = ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT_HYST);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						data->thyst = ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						data->sensor_type = ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lm95234_update_device(struct i2c_client *client,
 | 
				
			||||||
 | 
									 struct lm95234_data *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (time_after(jiffies, data->last_updated + data->interval) ||
 | 
				
			||||||
 | 
						    !data->valid) {
 | 
				
			||||||
 | 
							int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!data->valid) {
 | 
				
			||||||
 | 
								ret = lm95234_fill_cache(client);
 | 
				
			||||||
 | 
								if (ret < 0)
 | 
				
			||||||
 | 
									goto abort;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							data->valid = false;
 | 
				
			||||||
 | 
							for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
 | 
				
			||||||
 | 
								ret = lm95234_read_temp(client, i, &data->temp[i]);
 | 
				
			||||||
 | 
								if (ret < 0)
 | 
				
			||||||
 | 
									goto abort;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_FAULT);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								goto abort;
 | 
				
			||||||
 | 
							data->status = ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT1);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								goto abort;
 | 
				
			||||||
 | 
							data->status |= ret << 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT2);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								goto abort;
 | 
				
			||||||
 | 
							data->status |= ret << 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							data->last_updated = jiffies;
 | 
				
			||||||
 | 
							data->valid = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = 0;
 | 
				
			||||||
 | 
					abort:
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								 char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%d\n",
 | 
				
			||||||
 | 
							       DIV_ROUND_CLOSEST(data->temp[index] * 125, 32));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_alarm(struct device *dev,
 | 
				
			||||||
 | 
								  struct device_attribute *attr, char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						u32 mask = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%u", !!(data->status & mask));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_type(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								 char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						u8 mask = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, data->sensor_type & mask ? "1\n" : "2\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t set_type(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						unsigned long val;
 | 
				
			||||||
 | 
						u8 mask = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = kstrtoul(buf, 10, &val);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (val != 1 && val != 2)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
						if (val == 1)
 | 
				
			||||||
 | 
							data->sensor_type |= mask;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							data->sensor_type &= ~mask;
 | 
				
			||||||
 | 
						data->valid = false;
 | 
				
			||||||
 | 
						i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
 | 
				
			||||||
 | 
									  data->sensor_type);
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_tcrit2(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								   char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%u", data->tcrit2[index] * 1000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t set_tcrit2(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								  const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						long val;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = kstrtol(buf, 10, &val);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, index ? 255 : 127);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
						data->tcrit2[index] = val;
 | 
				
			||||||
 | 
						i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT2(index), val);
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_tcrit2_hyst(struct device *dev,
 | 
				
			||||||
 | 
									struct device_attribute *attr, char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Result can be negative, so be careful with unsigned operands */
 | 
				
			||||||
 | 
						return sprintf(buf, "%d",
 | 
				
			||||||
 | 
							       ((int)data->tcrit2[index] - (int)data->thyst) * 1000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_tcrit1(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								   char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%u", data->tcrit1[index] * 1000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t set_tcrit1(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								  const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						long val;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = kstrtol(buf, 10, &val);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
						data->tcrit1[index] = val;
 | 
				
			||||||
 | 
						i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT1(index), val);
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_tcrit1_hyst(struct device *dev,
 | 
				
			||||||
 | 
									struct device_attribute *attr, char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Result can be negative, so be careful with unsigned operands */
 | 
				
			||||||
 | 
						return sprintf(buf, "%d",
 | 
				
			||||||
 | 
							       ((int)data->tcrit1[index] - (int)data->thyst) * 1000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t set_tcrit1_hyst(struct device *dev,
 | 
				
			||||||
 | 
								       struct device_attribute *attr,
 | 
				
			||||||
 | 
								       const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						long val;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = kstrtol(buf, 10, &val);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = DIV_ROUND_CLOSEST(val, 1000);
 | 
				
			||||||
 | 
						val = clamp_val((int)data->tcrit1[index] - val, 0, 31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
						data->thyst = val;
 | 
				
			||||||
 | 
						i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT_HYST, val);
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_offset(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								   char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%d", data->toffset[index] * 500);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t set_offset(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								  const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr(attr)->index;
 | 
				
			||||||
 | 
						long val;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = kstrtol(buf, 10, &val);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Accuracy is 1/2 degrees C */
 | 
				
			||||||
 | 
						val = clamp_val(DIV_ROUND_CLOSEST(val, 500), -128, 127);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
						data->toffset[index] = val;
 | 
				
			||||||
 | 
						i2c_smbus_write_byte_data(client, LM95234_REG_OFFSET(index), val);
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								     char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%lu\n",
 | 
				
			||||||
 | 
							       DIV_ROUND_CLOSEST(data->interval * 1000, HZ));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
 | 
								    const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						unsigned long val;
 | 
				
			||||||
 | 
						u8 regval;
 | 
				
			||||||
 | 
						int ret = lm95234_update_device(client, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = kstrtoul(buf, 10, &val);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (regval = 0; regval < 3; regval++) {
 | 
				
			||||||
 | 
							if (val <= update_intervals[regval])
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
						data->interval = msecs_to_jiffies(update_intervals[regval]);
 | 
				
			||||||
 | 
						i2c_smbus_write_byte_data(client, LM95234_REG_CONVRATE, regval);
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(0) | BIT(1));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(2) | BIT(3));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(4) | BIT(5));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(6) | BIT(7));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type,
 | 
				
			||||||
 | 
								  BIT(1));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type,
 | 
				
			||||||
 | 
								  BIT(2));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp4_type, S_IWUSR | S_IRUGO, show_type, set_type,
 | 
				
			||||||
 | 
								  BIT(3));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp5_type, S_IWUSR | S_IRUGO, show_type, set_type,
 | 
				
			||||||
 | 
								  BIT(4));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_tcrit1,
 | 
				
			||||||
 | 
								  set_tcrit1, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_tcrit2,
 | 
				
			||||||
 | 
								  set_tcrit2, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_tcrit2,
 | 
				
			||||||
 | 
								  set_tcrit2, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_tcrit1,
 | 
				
			||||||
 | 
								  set_tcrit1, 3);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_tcrit1,
 | 
				
			||||||
 | 
								  set_tcrit1, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_tcrit1_hyst,
 | 
				
			||||||
 | 
								  set_tcrit1_hyst, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 3);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp5_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(0 + 8));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(1 + 16));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(2 + 16));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(3 + 8));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(4 + 8));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_tcrit1,
 | 
				
			||||||
 | 
								  set_tcrit1, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_tcrit1,
 | 
				
			||||||
 | 
								  set_tcrit1, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(1 + 8));
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL,
 | 
				
			||||||
 | 
								  BIT(2 + 8));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_offset,
 | 
				
			||||||
 | 
								  set_offset, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_offset, S_IWUSR | S_IRUGO, show_offset,
 | 
				
			||||||
 | 
								  set_offset, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp4_offset, S_IWUSR | S_IRUGO, show_offset,
 | 
				
			||||||
 | 
								  set_offset, 2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset,
 | 
				
			||||||
 | 
								  set_offset, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
 | 
				
			||||||
 | 
							   set_interval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct attribute *lm95234_attributes[] = {
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp4_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp5_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_fault.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_fault.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp4_fault.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp5_fault.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_type.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_type.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp4_type.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp5_type.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp4_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp5_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_crit.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_crit.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_offset.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_offset.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp4_offset.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp5_offset.dev_attr.attr,
 | 
				
			||||||
 | 
						&dev_attr_update_interval.attr,
 | 
				
			||||||
 | 
						NULL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct attribute_group lm95234_group = {
 | 
				
			||||||
 | 
						.attrs = lm95234_attributes,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lm95234_detect(struct i2c_client *client,
 | 
				
			||||||
 | 
								  struct i2c_board_info *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_adapter *adapter = client->adapter;
 | 
				
			||||||
 | 
						int mfg_id, chip_id, val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mfg_id = i2c_smbus_read_byte_data(client, LM95234_REG_MAN_ID);
 | 
				
			||||||
 | 
						if (mfg_id != NATSEMI_MAN_ID)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID);
 | 
				
			||||||
 | 
						if (chip_id != LM95234_CHIP_ID)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS);
 | 
				
			||||||
 | 
						if (val & 0x30)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
 | 
				
			||||||
 | 
						if (val & 0xbc)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
 | 
				
			||||||
 | 
						if (val & 0xfc)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
 | 
				
			||||||
 | 
						if (val & 0xe1)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
 | 
				
			||||||
 | 
						if (val & 0xe1)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strlcpy(info->type, "lm95234", I2C_NAME_SIZE);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lm95234_init_client(struct i2c_client *client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int val, model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* start conversion if necessary */
 | 
				
			||||||
 | 
						val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
 | 
				
			||||||
 | 
						if (val < 0)
 | 
				
			||||||
 | 
							return val;
 | 
				
			||||||
 | 
						if (val & 0x40)
 | 
				
			||||||
 | 
							i2c_smbus_write_byte_data(client, LM95234_REG_CONFIG,
 | 
				
			||||||
 | 
										  val & ~0x40);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If diode type status reports an error, try to fix it */
 | 
				
			||||||
 | 
						val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
 | 
				
			||||||
 | 
						if (val < 0)
 | 
				
			||||||
 | 
							return val;
 | 
				
			||||||
 | 
						model = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
 | 
				
			||||||
 | 
						if (model < 0)
 | 
				
			||||||
 | 
							return model;
 | 
				
			||||||
 | 
						if (model & val) {
 | 
				
			||||||
 | 
							dev_notice(&client->dev,
 | 
				
			||||||
 | 
								   "Fixing remote diode type misconfiguration (0x%x)\n",
 | 
				
			||||||
 | 
								   val);
 | 
				
			||||||
 | 
							i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
 | 
				
			||||||
 | 
										  model & ~val);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lm95234_probe(struct i2c_client *client,
 | 
				
			||||||
 | 
								 const struct i2c_device_id *id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device *dev = &client->dev;
 | 
				
			||||||
 | 
						struct lm95234_data *data;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = devm_kzalloc(dev, sizeof(struct lm95234_data), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!data)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i2c_set_clientdata(client, data);
 | 
				
			||||||
 | 
						mutex_init(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Initialize the LM95234 chip */
 | 
				
			||||||
 | 
						err = lm95234_init_client(client);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Register sysfs hooks */
 | 
				
			||||||
 | 
						err = sysfs_create_group(&dev->kobj, &lm95234_group);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data->hwmon_dev = hwmon_device_register(dev);
 | 
				
			||||||
 | 
						if (IS_ERR(data->hwmon_dev)) {
 | 
				
			||||||
 | 
							err = PTR_ERR(data->hwmon_dev);
 | 
				
			||||||
 | 
							goto exit_remove_files;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit_remove_files:
 | 
				
			||||||
 | 
						sysfs_remove_group(&dev->kobj, &lm95234_group);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lm95234_remove(struct i2c_client *client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct lm95234_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hwmon_device_unregister(data->hwmon_dev);
 | 
				
			||||||
 | 
						sysfs_remove_group(&client->dev.kobj, &lm95234_group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Driver data (common to all clients) */
 | 
				
			||||||
 | 
					static const struct i2c_device_id lm95234_id[] = {
 | 
				
			||||||
 | 
						{ "lm95234", 0 },
 | 
				
			||||||
 | 
						{ }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(i2c, lm95234_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct i2c_driver lm95234_driver = {
 | 
				
			||||||
 | 
						.class		= I2C_CLASS_HWMON,
 | 
				
			||||||
 | 
						.driver = {
 | 
				
			||||||
 | 
							.name	= DRVNAME,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						.probe		= lm95234_probe,
 | 
				
			||||||
 | 
						.remove		= lm95234_remove,
 | 
				
			||||||
 | 
						.id_table	= lm95234_id,
 | 
				
			||||||
 | 
						.detect		= lm95234_detect,
 | 
				
			||||||
 | 
						.address_list	= normal_i2c,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_i2c_driver(lm95234_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("LM95234 sensor driver");
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
| 
						 | 
					@ -146,14 +146,14 @@ static ssize_t ltc4151_show_value(struct device *dev,
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Input voltages.
 | 
					 * Input voltages.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
 | 
					static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4151_show_value, NULL,
 | 
				
			||||||
	ltc4151_show_value, NULL, LTC4151_VIN_H);
 | 
								  LTC4151_VIN_H);
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, \
 | 
					static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4151_show_value, NULL,
 | 
				
			||||||
	ltc4151_show_value, NULL, LTC4151_ADIN_H);
 | 
								  LTC4151_ADIN_H);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Currents (via sense resistor) */
 | 
					/* Currents (via sense resistor) */
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
 | 
					static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4151_show_value, NULL,
 | 
				
			||||||
	ltc4151_show_value, NULL, LTC4151_SENSE_H);
 | 
								  LTC4151_SENSE_H);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Finally, construct an array of pointers to members of the above objects,
 | 
					 * Finally, construct an array of pointers to members of the above objects,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -172,12 +172,12 @@ static ssize_t ltc4215_show_alarm(struct device *dev,
 | 
				
			||||||
					  struct device_attribute *da,
 | 
										  struct device_attribute *da,
 | 
				
			||||||
					  char *buf)
 | 
										  char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
 | 
						struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 | 
				
			||||||
	struct ltc4215_data *data = ltc4215_update_device(dev);
 | 
						struct ltc4215_data *data = ltc4215_update_device(dev);
 | 
				
			||||||
	const u8 reg = data->regs[attr->index];
 | 
						const u8 reg = data->regs[LTC4215_STATUS];
 | 
				
			||||||
	const u32 mask = attr->nr;
 | 
						const u32 mask = attr->index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
 | 
						return snprintf(buf, PAGE_SIZE, "%u\n", !!(reg & mask));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -186,39 +186,29 @@ static ssize_t ltc4215_show_alarm(struct device *dev,
 | 
				
			||||||
 * for each register.
 | 
					 * for each register.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LTC4215_VOLTAGE(name, ltc4215_cmd_idx) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4215_show_voltage, NULL, ltc4215_cmd_idx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4215_CURRENT(name) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4215_show_current, NULL, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4215_POWER(name) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4215_show_power, NULL, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4215_ALARM(name, mask, reg) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4215_show_alarm, NULL, (mask), reg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Construct a sensor_device_attribute structure for each register */
 | 
					/* Construct a sensor_device_attribute structure for each register */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Current */
 | 
					/* Current */
 | 
				
			||||||
LTC4215_CURRENT(curr1_input);
 | 
					static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4215_show_current, NULL, 0);
 | 
				
			||||||
LTC4215_ALARM(curr1_max_alarm,	(1 << 2),	LTC4215_STATUS);
 | 
					static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
 | 
				
			||||||
 | 
								  1 << 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Power (virtual) */
 | 
					/* Power (virtual) */
 | 
				
			||||||
LTC4215_POWER(power1_input);
 | 
					static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4215_show_power, NULL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Input Voltage */
 | 
					/* Input Voltage */
 | 
				
			||||||
LTC4215_VOLTAGE(in1_input,			LTC4215_ADIN);
 | 
					static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4215_show_voltage, NULL,
 | 
				
			||||||
LTC4215_ALARM(in1_max_alarm,	(1 << 0),	LTC4215_STATUS);
 | 
								  LTC4215_ADIN);
 | 
				
			||||||
LTC4215_ALARM(in1_min_alarm,	(1 << 1),	LTC4215_STATUS);
 | 
					static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
 | 
				
			||||||
 | 
								  1 << 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
 | 
				
			||||||
 | 
								  1 << 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Output Voltage */
 | 
					/* Output Voltage */
 | 
				
			||||||
LTC4215_VOLTAGE(in2_input,			LTC4215_SOURCE);
 | 
					static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4215_show_voltage, NULL,
 | 
				
			||||||
LTC4215_ALARM(in2_min_alarm,	(1 << 3),	LTC4215_STATUS);
 | 
								  LTC4215_SOURCE);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
 | 
				
			||||||
 | 
								  1 << 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Finally, construct an array of pointers to members of the above objects,
 | 
					 * Finally, construct an array of pointers to members of the above objects,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -319,80 +319,82 @@ static ssize_t ltc4245_show_gpio(struct device *dev,
 | 
				
			||||||
	return snprintf(buf, PAGE_SIZE, "%u\n", val * 10);
 | 
						return snprintf(buf, PAGE_SIZE, "%u\n", val * 10);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * These macros are used below in constructing device attribute objects
 | 
					 | 
				
			||||||
 * for use with sysfs_create_group() to make a sysfs device file
 | 
					 | 
				
			||||||
 * for each register.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4245_VOLTAGE(name, ltc4245_cmd_idx) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4245_show_voltage, NULL, ltc4245_cmd_idx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4245_CURRENT(name, ltc4245_cmd_idx) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4245_show_current, NULL, ltc4245_cmd_idx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4245_POWER(name, ltc4245_cmd_idx) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4245_show_power, NULL, ltc4245_cmd_idx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4245_ALARM(name, mask, reg) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4245_show_alarm, NULL, (mask), reg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4245_GPIO_VOLTAGE(name, gpio_num) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4245_show_gpio, NULL, gpio_num)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Construct a sensor_device_attribute structure for each register */
 | 
					/* Construct a sensor_device_attribute structure for each register */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Input voltages */
 | 
					/* Input voltages */
 | 
				
			||||||
LTC4245_VOLTAGE(in1_input,			LTC4245_12VIN);
 | 
					static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4245_show_voltage, NULL,
 | 
				
			||||||
LTC4245_VOLTAGE(in2_input,			LTC4245_5VIN);
 | 
								  LTC4245_12VIN);
 | 
				
			||||||
LTC4245_VOLTAGE(in3_input,			LTC4245_3VIN);
 | 
					static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4245_show_voltage, NULL,
 | 
				
			||||||
LTC4245_VOLTAGE(in4_input,			LTC4245_VEEIN);
 | 
								  LTC4245_5VIN);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4245_show_voltage, NULL,
 | 
				
			||||||
 | 
								  LTC4245_3VIN);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4245_show_voltage, NULL,
 | 
				
			||||||
 | 
								  LTC4245_VEEIN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Input undervoltage alarms */
 | 
					/* Input undervoltage alarms */
 | 
				
			||||||
LTC4245_ALARM(in1_min_alarm,	(1 << 0),	LTC4245_FAULT1);
 | 
					static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
LTC4245_ALARM(in2_min_alarm,	(1 << 1),	LTC4245_FAULT1);
 | 
								    1 << 0, LTC4245_FAULT1);
 | 
				
			||||||
LTC4245_ALARM(in3_min_alarm,	(1 << 2),	LTC4245_FAULT1);
 | 
					static SENSOR_DEVICE_ATTR_2(in2_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
LTC4245_ALARM(in4_min_alarm,	(1 << 3),	LTC4245_FAULT1);
 | 
								    1 << 1, LTC4245_FAULT1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
 | 
								    1 << 2, LTC4245_FAULT1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(in4_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
 | 
								    1 << 3, LTC4245_FAULT1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Currents (via sense resistor) */
 | 
					/* Currents (via sense resistor) */
 | 
				
			||||||
LTC4245_CURRENT(curr1_input,			LTC4245_12VSENSE);
 | 
					static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4245_show_current, NULL,
 | 
				
			||||||
LTC4245_CURRENT(curr2_input,			LTC4245_5VSENSE);
 | 
								  LTC4245_12VSENSE);
 | 
				
			||||||
LTC4245_CURRENT(curr3_input,			LTC4245_3VSENSE);
 | 
					static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4245_show_current, NULL,
 | 
				
			||||||
LTC4245_CURRENT(curr4_input,			LTC4245_VEESENSE);
 | 
								  LTC4245_5VSENSE);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO, ltc4245_show_current, NULL,
 | 
				
			||||||
 | 
								  LTC4245_3VSENSE);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(curr4_input, S_IRUGO, ltc4245_show_current, NULL,
 | 
				
			||||||
 | 
								  LTC4245_VEESENSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Overcurrent alarms */
 | 
					/* Overcurrent alarms */
 | 
				
			||||||
LTC4245_ALARM(curr1_max_alarm,	(1 << 4),	LTC4245_FAULT1);
 | 
					static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
LTC4245_ALARM(curr2_max_alarm,	(1 << 5),	LTC4245_FAULT1);
 | 
								    1 << 4, LTC4245_FAULT1);
 | 
				
			||||||
LTC4245_ALARM(curr3_max_alarm,	(1 << 6),	LTC4245_FAULT1);
 | 
					static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
LTC4245_ALARM(curr4_max_alarm,	(1 << 7),	LTC4245_FAULT1);
 | 
								    1 << 5, LTC4245_FAULT1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(curr3_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
 | 
								    1 << 6, LTC4245_FAULT1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(curr4_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
 | 
								    1 << 7, LTC4245_FAULT1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Output voltages */
 | 
					/* Output voltages */
 | 
				
			||||||
LTC4245_VOLTAGE(in5_input,			LTC4245_12VOUT);
 | 
					static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ltc4245_show_voltage, NULL,
 | 
				
			||||||
LTC4245_VOLTAGE(in6_input,			LTC4245_5VOUT);
 | 
								  LTC4245_12VOUT);
 | 
				
			||||||
LTC4245_VOLTAGE(in7_input,			LTC4245_3VOUT);
 | 
					static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ltc4245_show_voltage, NULL,
 | 
				
			||||||
LTC4245_VOLTAGE(in8_input,			LTC4245_VEEOUT);
 | 
								  LTC4245_5VOUT);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ltc4245_show_voltage, NULL,
 | 
				
			||||||
 | 
								  LTC4245_3VOUT);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, ltc4245_show_voltage, NULL,
 | 
				
			||||||
 | 
								  LTC4245_VEEOUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Power Bad alarms */
 | 
					/* Power Bad alarms */
 | 
				
			||||||
LTC4245_ALARM(in5_min_alarm,	(1 << 0),	LTC4245_FAULT2);
 | 
					static SENSOR_DEVICE_ATTR_2(in5_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
LTC4245_ALARM(in6_min_alarm,	(1 << 1),	LTC4245_FAULT2);
 | 
								    1 << 0, LTC4245_FAULT2);
 | 
				
			||||||
LTC4245_ALARM(in7_min_alarm,	(1 << 2),	LTC4245_FAULT2);
 | 
					static SENSOR_DEVICE_ATTR_2(in6_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
LTC4245_ALARM(in8_min_alarm,	(1 << 3),	LTC4245_FAULT2);
 | 
								    1 << 1, LTC4245_FAULT2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(in7_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
 | 
								    1 << 2, LTC4245_FAULT2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(in8_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
 | 
				
			||||||
 | 
								    1 << 3, LTC4245_FAULT2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* GPIO voltages */
 | 
					/* GPIO voltages */
 | 
				
			||||||
LTC4245_GPIO_VOLTAGE(in9_input,			0);
 | 
					static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, ltc4245_show_gpio, NULL, 0);
 | 
				
			||||||
LTC4245_GPIO_VOLTAGE(in10_input,		1);
 | 
					static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, ltc4245_show_gpio, NULL, 1);
 | 
				
			||||||
LTC4245_GPIO_VOLTAGE(in11_input,		2);
 | 
					static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, ltc4245_show_gpio, NULL, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Power Consumption (virtual) */
 | 
					/* Power Consumption (virtual) */
 | 
				
			||||||
LTC4245_POWER(power1_input,			LTC4245_12VSENSE);
 | 
					static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4245_show_power, NULL,
 | 
				
			||||||
LTC4245_POWER(power2_input,			LTC4245_5VSENSE);
 | 
								  LTC4245_12VSENSE);
 | 
				
			||||||
LTC4245_POWER(power3_input,			LTC4245_3VSENSE);
 | 
					static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, ltc4245_show_power, NULL,
 | 
				
			||||||
LTC4245_POWER(power4_input,			LTC4245_VEESENSE);
 | 
								  LTC4245_5VSENSE);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO, ltc4245_show_power, NULL,
 | 
				
			||||||
 | 
								  LTC4245_3VSENSE);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(power4_input, S_IRUGO, ltc4245_show_power, NULL,
 | 
				
			||||||
 | 
								  LTC4245_VEESENSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Finally, construct an array of pointers to members of the above objects,
 | 
					 * Finally, construct an array of pointers to members of the above objects,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,25 +164,13 @@ static ssize_t ltc4261_show_bool(struct device *dev,
 | 
				
			||||||
	return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
 | 
						return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * These macros are used below in constructing device attribute objects
 | 
					 | 
				
			||||||
 * for use with sysfs_create_group() to make a sysfs device file
 | 
					 | 
				
			||||||
 * for each register.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4261_VALUE(name, ltc4261_cmd_idx) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4261_show_value, NULL, ltc4261_cmd_idx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LTC4261_BOOL(name, mask) \
 | 
					 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
 | 
					 | 
				
			||||||
	ltc4261_show_bool, NULL, (mask))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Input voltages.
 | 
					 * Input voltages.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
LTC4261_VALUE(in1_input, LTC4261_ADIN_H);
 | 
					static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4261_show_value, NULL,
 | 
				
			||||||
LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
 | 
								  LTC4261_ADIN_H);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4261_show_value, NULL,
 | 
				
			||||||
 | 
								  LTC4261_ADIN2_H);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Voltage alarms. The chip has only one set of voltage alarm status bits,
 | 
					 * Voltage alarms. The chip has only one set of voltage alarm status bits,
 | 
				
			||||||
| 
						 | 
					@ -192,16 +180,22 @@ LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
 | 
				
			||||||
 * To ensure that the alarm condition is reported to the user, report it
 | 
					 * To ensure that the alarm condition is reported to the user, report it
 | 
				
			||||||
 * with both voltage sensors.
 | 
					 * with both voltage sensors.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
LTC4261_BOOL(in1_min_alarm, FAULT_UV);
 | 
					static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
 | 
				
			||||||
LTC4261_BOOL(in1_max_alarm, FAULT_OV);
 | 
								  FAULT_UV);
 | 
				
			||||||
LTC4261_BOOL(in2_min_alarm, FAULT_UV);
 | 
					static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
 | 
				
			||||||
LTC4261_BOOL(in2_max_alarm, FAULT_OV);
 | 
								  FAULT_OV);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
 | 
				
			||||||
 | 
								  FAULT_UV);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
 | 
				
			||||||
 | 
								  FAULT_OV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Currents (via sense resistor) */
 | 
					/* Currents (via sense resistor) */
 | 
				
			||||||
LTC4261_VALUE(curr1_input, LTC4261_SENSE_H);
 | 
					static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4261_show_value, NULL,
 | 
				
			||||||
 | 
								  LTC4261_SENSE_H);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Overcurrent alarm */
 | 
					/* Overcurrent alarm */
 | 
				
			||||||
LTC4261_BOOL(curr1_max_alarm, FAULT_OC);
 | 
					static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
 | 
				
			||||||
 | 
								  FAULT_OC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct attribute *ltc4261_attributes[] = {
 | 
					static struct attribute *ltc4261_attributes[] = {
 | 
				
			||||||
	&sensor_dev_attr_in1_input.dev_attr.attr,
 | 
						&sensor_dev_attr_in1_input.dev_attr.attr,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -399,82 +399,95 @@ static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_alarm, NULL, 5);
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6);
 | 
					static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6);
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7);
 | 
					static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct attribute *max6697_attributes[8][7] = {
 | 
					static DEVICE_ATTR(dummy, 0, NULL, NULL);
 | 
				
			||||||
	{
 | 
					
 | 
				
			||||||
		&sensor_dev_attr_temp1_input.dev_attr.attr,
 | 
					static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr,
 | 
				
			||||||
		&sensor_dev_attr_temp1_max.dev_attr.attr,
 | 
									  int index)
 | 
				
			||||||
		&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 | 
					{
 | 
				
			||||||
		&sensor_dev_attr_temp1_crit.dev_attr.attr,
 | 
						struct device *dev = container_of(kobj, struct device, kobj);
 | 
				
			||||||
		&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
		NULL
 | 
						struct max6697_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
	}, {
 | 
						const struct max6697_chip_data *chip = data->chip;
 | 
				
			||||||
		&sensor_dev_attr_temp2_input.dev_attr.attr,
 | 
						int channel = index / 6;	/* channel number */
 | 
				
			||||||
		&sensor_dev_attr_temp2_max.dev_attr.attr,
 | 
						int nr = index % 6;		/* attribute index within channel */
 | 
				
			||||||
		&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
 | 
					
 | 
				
			||||||
		&sensor_dev_attr_temp2_crit.dev_attr.attr,
 | 
						if (channel >= chip->channels)
 | 
				
			||||||
		&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
 | 
							return 0;
 | 
				
			||||||
		&sensor_dev_attr_temp2_fault.dev_attr.attr,
 | 
					
 | 
				
			||||||
		NULL
 | 
						if ((nr == 3 || nr == 4) && !(chip->have_crit & (1 << channel)))
 | 
				
			||||||
	}, {
 | 
							return 0;
 | 
				
			||||||
		&sensor_dev_attr_temp3_input.dev_attr.attr,
 | 
						if (nr == 5 && !(chip->have_fault & (1 << channel)))
 | 
				
			||||||
		&sensor_dev_attr_temp3_max.dev_attr.attr,
 | 
							return 0;
 | 
				
			||||||
		&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
 | 
					
 | 
				
			||||||
		&sensor_dev_attr_temp3_crit.dev_attr.attr,
 | 
						return attr->mode;
 | 
				
			||||||
		&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
 | 
					}
 | 
				
			||||||
		&sensor_dev_attr_temp3_fault.dev_attr.attr,
 | 
					
 | 
				
			||||||
		NULL
 | 
					/*
 | 
				
			||||||
	}, {
 | 
					 * max6697_is_visible uses the index into the following array to determine
 | 
				
			||||||
		&sensor_dev_attr_temp4_input.dev_attr.attr,
 | 
					 * if attributes should be created or not. Any change in order or content
 | 
				
			||||||
		&sensor_dev_attr_temp4_max.dev_attr.attr,
 | 
					 * must be matched in max6697_is_visible.
 | 
				
			||||||
		&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
 | 
					 */
 | 
				
			||||||
		&sensor_dev_attr_temp4_crit.dev_attr.attr,
 | 
					static struct attribute *max6697_attributes[] = {
 | 
				
			||||||
		&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
 | 
						&sensor_dev_attr_temp1_input.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp4_fault.dev_attr.attr,
 | 
						&sensor_dev_attr_temp1_max.dev_attr.attr,
 | 
				
			||||||
		NULL
 | 
						&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 | 
				
			||||||
	}, {
 | 
						&sensor_dev_attr_temp1_crit.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp5_input.dev_attr.attr,
 | 
						&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp5_max.dev_attr.attr,
 | 
						&dev_attr_dummy.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
 | 
					
 | 
				
			||||||
		&sensor_dev_attr_temp5_crit.dev_attr.attr,
 | 
						&sensor_dev_attr_temp2_input.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
 | 
						&sensor_dev_attr_temp2_max.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp5_fault.dev_attr.attr,
 | 
						&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
 | 
				
			||||||
		NULL
 | 
						&sensor_dev_attr_temp2_crit.dev_attr.attr,
 | 
				
			||||||
	}, {
 | 
						&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp6_input.dev_attr.attr,
 | 
						&sensor_dev_attr_temp2_fault.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp6_max.dev_attr.attr,
 | 
					
 | 
				
			||||||
		&sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
 | 
						&sensor_dev_attr_temp3_input.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp6_crit.dev_attr.attr,
 | 
						&sensor_dev_attr_temp3_max.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
 | 
						&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp6_fault.dev_attr.attr,
 | 
						&sensor_dev_attr_temp3_crit.dev_attr.attr,
 | 
				
			||||||
		NULL
 | 
						&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
 | 
				
			||||||
	}, {
 | 
						&sensor_dev_attr_temp3_fault.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp7_input.dev_attr.attr,
 | 
					
 | 
				
			||||||
		&sensor_dev_attr_temp7_max.dev_attr.attr,
 | 
						&sensor_dev_attr_temp4_input.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
 | 
						&sensor_dev_attr_temp4_max.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp7_crit.dev_attr.attr,
 | 
						&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
 | 
						&sensor_dev_attr_temp4_crit.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp7_fault.dev_attr.attr,
 | 
						&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
 | 
				
			||||||
		NULL
 | 
						&sensor_dev_attr_temp4_fault.dev_attr.attr,
 | 
				
			||||||
	}, {
 | 
					
 | 
				
			||||||
		&sensor_dev_attr_temp8_input.dev_attr.attr,
 | 
						&sensor_dev_attr_temp5_input.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp8_max.dev_attr.attr,
 | 
						&sensor_dev_attr_temp5_max.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
 | 
						&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp8_crit.dev_attr.attr,
 | 
						&sensor_dev_attr_temp5_crit.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
 | 
						&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
 | 
				
			||||||
		&sensor_dev_attr_temp8_fault.dev_attr.attr,
 | 
						&sensor_dev_attr_temp5_fault.dev_attr.attr,
 | 
				
			||||||
		NULL
 | 
					
 | 
				
			||||||
	}
 | 
						&sensor_dev_attr_temp6_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp6_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp6_crit.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp6_fault.dev_attr.attr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp7_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp7_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp7_crit.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp7_fault.dev_attr.attr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp8_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp8_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp8_crit.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp8_fault.dev_attr.attr,
 | 
				
			||||||
 | 
						NULL
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct attribute_group max6697_group[8] = {
 | 
					static const struct attribute_group max6697_group = {
 | 
				
			||||||
	{ .attrs = max6697_attributes[0] },
 | 
						.attrs = max6697_attributes, .is_visible = max6697_is_visible,
 | 
				
			||||||
	{ .attrs = max6697_attributes[1] },
 | 
					 | 
				
			||||||
	{ .attrs = max6697_attributes[2] },
 | 
					 | 
				
			||||||
	{ .attrs = max6697_attributes[3] },
 | 
					 | 
				
			||||||
	{ .attrs = max6697_attributes[4] },
 | 
					 | 
				
			||||||
	{ .attrs = max6697_attributes[5] },
 | 
					 | 
				
			||||||
	{ .attrs = max6697_attributes[6] },
 | 
					 | 
				
			||||||
	{ .attrs = max6697_attributes[7] },
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void max6697_get_config_of(struct device_node *node,
 | 
					static void max6697_get_config_of(struct device_node *node,
 | 
				
			||||||
| 
						 | 
					@ -606,21 +619,13 @@ done:
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void max6697_remove_files(struct i2c_client *client)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(max6697_group); i++)
 | 
					 | 
				
			||||||
		sysfs_remove_group(&client->dev.kobj, &max6697_group[i]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int max6697_probe(struct i2c_client *client,
 | 
					static int max6697_probe(struct i2c_client *client,
 | 
				
			||||||
			 const struct i2c_device_id *id)
 | 
								 const struct i2c_device_id *id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct i2c_adapter *adapter = client->adapter;
 | 
						struct i2c_adapter *adapter = client->adapter;
 | 
				
			||||||
	struct device *dev = &client->dev;
 | 
						struct device *dev = &client->dev;
 | 
				
			||||||
	struct max6697_data *data;
 | 
						struct max6697_data *data;
 | 
				
			||||||
	int i, err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 | 
						if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
| 
						 | 
					@ -639,37 +644,9 @@ static int max6697_probe(struct i2c_client *client,
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < data->chip->channels; i++) {
 | 
						err = sysfs_create_group(&client->dev.kobj, &max6697_group);
 | 
				
			||||||
		err = sysfs_create_file(&dev->kobj,
 | 
						if (err)
 | 
				
			||||||
					max6697_attributes[i][0]);
 | 
							return err;
 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			goto error;
 | 
					 | 
				
			||||||
		err = sysfs_create_file(&dev->kobj,
 | 
					 | 
				
			||||||
					max6697_attributes[i][1]);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			goto error;
 | 
					 | 
				
			||||||
		err = sysfs_create_file(&dev->kobj,
 | 
					 | 
				
			||||||
					max6697_attributes[i][2]);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			goto error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (data->chip->have_crit & (1 << i)) {
 | 
					 | 
				
			||||||
			err = sysfs_create_file(&dev->kobj,
 | 
					 | 
				
			||||||
						max6697_attributes[i][3]);
 | 
					 | 
				
			||||||
			if (err)
 | 
					 | 
				
			||||||
				goto error;
 | 
					 | 
				
			||||||
			err = sysfs_create_file(&dev->kobj,
 | 
					 | 
				
			||||||
						max6697_attributes[i][4]);
 | 
					 | 
				
			||||||
			if (err)
 | 
					 | 
				
			||||||
				goto error;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (data->chip->have_fault & (1 << i)) {
 | 
					 | 
				
			||||||
			err = sysfs_create_file(&dev->kobj,
 | 
					 | 
				
			||||||
						max6697_attributes[i][5]);
 | 
					 | 
				
			||||||
			if (err)
 | 
					 | 
				
			||||||
				goto error;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->hwmon_dev = hwmon_device_register(dev);
 | 
						data->hwmon_dev = hwmon_device_register(dev);
 | 
				
			||||||
	if (IS_ERR(data->hwmon_dev)) {
 | 
						if (IS_ERR(data->hwmon_dev)) {
 | 
				
			||||||
| 
						 | 
					@ -680,7 +657,7 @@ static int max6697_probe(struct i2c_client *client,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	max6697_remove_files(client);
 | 
						sysfs_remove_group(&client->dev.kobj, &max6697_group);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -689,7 +666,7 @@ static int max6697_remove(struct i2c_client *client)
 | 
				
			||||||
	struct max6697_data *data = i2c_get_clientdata(client);
 | 
						struct max6697_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hwmon_device_unregister(data->hwmon_dev);
 | 
						hwmon_device_unregister(data->hwmon_dev);
 | 
				
			||||||
	max6697_remove_files(client);
 | 
						sysfs_remove_group(&client->dev.kobj, &max6697_group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -273,18 +273,7 @@ static struct platform_driver mc13783_adc_driver = {
 | 
				
			||||||
	.id_table	= mc13783_adc_idtable,
 | 
						.id_table	= mc13783_adc_idtable,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init mc13783_adc_init(void)
 | 
					module_platform_driver_probe(mc13783_adc_driver, mc13783_adc_probe);
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return platform_driver_probe(&mc13783_adc_driver, mc13783_adc_probe);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __exit mc13783_adc_exit(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	platform_driver_unregister(&mc13783_adc_driver);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module_init(mc13783_adc_init);
 | 
					 | 
				
			||||||
module_exit(mc13783_adc_exit);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_DESCRIPTION("MC13783 ADC driver");
 | 
					MODULE_DESCRIPTION("MC13783 ADC driver");
 | 
				
			||||||
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
 | 
					MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4191
									
								
								drivers/hwmon/nct6775.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4191
									
								
								drivers/hwmon/nct6775.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -26,17 +26,33 @@
 | 
				
			||||||
#include <linux/math64.h>
 | 
					#include <linux/math64.h>
 | 
				
			||||||
#include <linux/platform_device.h>
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
#include <linux/err.h>
 | 
					#include <linux/err.h>
 | 
				
			||||||
 | 
					#include <linux/of.h>
 | 
				
			||||||
 | 
					#include <linux/of_device.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/platform_data/ntc_thermistor.h>
 | 
					#include <linux/platform_data/ntc_thermistor.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/iio/iio.h>
 | 
				
			||||||
 | 
					#include <linux/iio/machine.h>
 | 
				
			||||||
 | 
					#include <linux/iio/driver.h>
 | 
				
			||||||
 | 
					#include <linux/iio/consumer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/hwmon.h>
 | 
					#include <linux/hwmon.h>
 | 
				
			||||||
#include <linux/hwmon-sysfs.h>
 | 
					#include <linux/hwmon-sysfs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ntc_compensation {
 | 
					struct ntc_compensation {
 | 
				
			||||||
	int		temp_C;
 | 
						int		temp_c;
 | 
				
			||||||
	unsigned int	ohm;
 | 
						unsigned int	ohm;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct platform_device_id ntc_thermistor_id[] = {
 | 
				
			||||||
 | 
						{ "ncp15wb473", TYPE_NCPXXWB473 },
 | 
				
			||||||
 | 
						{ "ncp18wb473", TYPE_NCPXXWB473 },
 | 
				
			||||||
 | 
						{ "ncp21wb473", TYPE_NCPXXWB473 },
 | 
				
			||||||
 | 
						{ "ncp03wb473", TYPE_NCPXXWB473 },
 | 
				
			||||||
 | 
						{ "ncp15wl333", TYPE_NCPXXWL333 },
 | 
				
			||||||
 | 
						{ },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * A compensation table should be sorted by the values of .ohm
 | 
					 * A compensation table should be sorted by the values of .ohm
 | 
				
			||||||
 * in descending order.
 | 
					 * in descending order.
 | 
				
			||||||
| 
						 | 
					@ -44,76 +60,76 @@ struct ntc_compensation {
 | 
				
			||||||
 * Thermistors Datasheet
 | 
					 * Thermistors Datasheet
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static const struct ntc_compensation ncpXXwb473[] = {
 | 
					static const struct ntc_compensation ncpXXwb473[] = {
 | 
				
			||||||
	{ .temp_C	= -40, .ohm	= 1747920 },
 | 
						{ .temp_c	= -40, .ohm	= 1747920 },
 | 
				
			||||||
	{ .temp_C	= -35, .ohm	= 1245428 },
 | 
						{ .temp_c	= -35, .ohm	= 1245428 },
 | 
				
			||||||
	{ .temp_C	= -30, .ohm	= 898485 },
 | 
						{ .temp_c	= -30, .ohm	= 898485 },
 | 
				
			||||||
	{ .temp_C	= -25, .ohm	= 655802 },
 | 
						{ .temp_c	= -25, .ohm	= 655802 },
 | 
				
			||||||
	{ .temp_C	= -20, .ohm	= 483954 },
 | 
						{ .temp_c	= -20, .ohm	= 483954 },
 | 
				
			||||||
	{ .temp_C	= -15, .ohm	= 360850 },
 | 
						{ .temp_c	= -15, .ohm	= 360850 },
 | 
				
			||||||
	{ .temp_C	= -10, .ohm	= 271697 },
 | 
						{ .temp_c	= -10, .ohm	= 271697 },
 | 
				
			||||||
	{ .temp_C	= -5, .ohm	= 206463 },
 | 
						{ .temp_c	= -5, .ohm	= 206463 },
 | 
				
			||||||
	{ .temp_C	= 0, .ohm	= 158214 },
 | 
						{ .temp_c	= 0, .ohm	= 158214 },
 | 
				
			||||||
	{ .temp_C	= 5, .ohm	= 122259 },
 | 
						{ .temp_c	= 5, .ohm	= 122259 },
 | 
				
			||||||
	{ .temp_C	= 10, .ohm	= 95227 },
 | 
						{ .temp_c	= 10, .ohm	= 95227 },
 | 
				
			||||||
	{ .temp_C	= 15, .ohm	= 74730 },
 | 
						{ .temp_c	= 15, .ohm	= 74730 },
 | 
				
			||||||
	{ .temp_C	= 20, .ohm	= 59065 },
 | 
						{ .temp_c	= 20, .ohm	= 59065 },
 | 
				
			||||||
	{ .temp_C	= 25, .ohm	= 47000 },
 | 
						{ .temp_c	= 25, .ohm	= 47000 },
 | 
				
			||||||
	{ .temp_C	= 30, .ohm	= 37643 },
 | 
						{ .temp_c	= 30, .ohm	= 37643 },
 | 
				
			||||||
	{ .temp_C	= 35, .ohm	= 30334 },
 | 
						{ .temp_c	= 35, .ohm	= 30334 },
 | 
				
			||||||
	{ .temp_C	= 40, .ohm	= 24591 },
 | 
						{ .temp_c	= 40, .ohm	= 24591 },
 | 
				
			||||||
	{ .temp_C	= 45, .ohm	= 20048 },
 | 
						{ .temp_c	= 45, .ohm	= 20048 },
 | 
				
			||||||
	{ .temp_C	= 50, .ohm	= 16433 },
 | 
						{ .temp_c	= 50, .ohm	= 16433 },
 | 
				
			||||||
	{ .temp_C	= 55, .ohm	= 13539 },
 | 
						{ .temp_c	= 55, .ohm	= 13539 },
 | 
				
			||||||
	{ .temp_C	= 60, .ohm	= 11209 },
 | 
						{ .temp_c	= 60, .ohm	= 11209 },
 | 
				
			||||||
	{ .temp_C	= 65, .ohm	= 9328 },
 | 
						{ .temp_c	= 65, .ohm	= 9328 },
 | 
				
			||||||
	{ .temp_C	= 70, .ohm	= 7798 },
 | 
						{ .temp_c	= 70, .ohm	= 7798 },
 | 
				
			||||||
	{ .temp_C	= 75, .ohm	= 6544 },
 | 
						{ .temp_c	= 75, .ohm	= 6544 },
 | 
				
			||||||
	{ .temp_C	= 80, .ohm	= 5518 },
 | 
						{ .temp_c	= 80, .ohm	= 5518 },
 | 
				
			||||||
	{ .temp_C	= 85, .ohm	= 4674 },
 | 
						{ .temp_c	= 85, .ohm	= 4674 },
 | 
				
			||||||
	{ .temp_C	= 90, .ohm	= 3972 },
 | 
						{ .temp_c	= 90, .ohm	= 3972 },
 | 
				
			||||||
	{ .temp_C	= 95, .ohm	= 3388 },
 | 
						{ .temp_c	= 95, .ohm	= 3388 },
 | 
				
			||||||
	{ .temp_C	= 100, .ohm	= 2902 },
 | 
						{ .temp_c	= 100, .ohm	= 2902 },
 | 
				
			||||||
	{ .temp_C	= 105, .ohm	= 2494 },
 | 
						{ .temp_c	= 105, .ohm	= 2494 },
 | 
				
			||||||
	{ .temp_C	= 110, .ohm	= 2150 },
 | 
						{ .temp_c	= 110, .ohm	= 2150 },
 | 
				
			||||||
	{ .temp_C	= 115, .ohm	= 1860 },
 | 
						{ .temp_c	= 115, .ohm	= 1860 },
 | 
				
			||||||
	{ .temp_C	= 120, .ohm	= 1615 },
 | 
						{ .temp_c	= 120, .ohm	= 1615 },
 | 
				
			||||||
	{ .temp_C	= 125, .ohm	= 1406 },
 | 
						{ .temp_c	= 125, .ohm	= 1406 },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
static const struct ntc_compensation ncpXXwl333[] = {
 | 
					static const struct ntc_compensation ncpXXwl333[] = {
 | 
				
			||||||
	{ .temp_C	= -40, .ohm	= 1610154 },
 | 
						{ .temp_c	= -40, .ohm	= 1610154 },
 | 
				
			||||||
	{ .temp_C	= -35, .ohm	= 1130850 },
 | 
						{ .temp_c	= -35, .ohm	= 1130850 },
 | 
				
			||||||
	{ .temp_C	= -30, .ohm	= 802609 },
 | 
						{ .temp_c	= -30, .ohm	= 802609 },
 | 
				
			||||||
	{ .temp_C	= -25, .ohm	= 575385 },
 | 
						{ .temp_c	= -25, .ohm	= 575385 },
 | 
				
			||||||
	{ .temp_C	= -20, .ohm	= 416464 },
 | 
						{ .temp_c	= -20, .ohm	= 416464 },
 | 
				
			||||||
	{ .temp_C	= -15, .ohm	= 304219 },
 | 
						{ .temp_c	= -15, .ohm	= 304219 },
 | 
				
			||||||
	{ .temp_C	= -10, .ohm	= 224193 },
 | 
						{ .temp_c	= -10, .ohm	= 224193 },
 | 
				
			||||||
	{ .temp_C	= -5, .ohm	= 166623 },
 | 
						{ .temp_c	= -5, .ohm	= 166623 },
 | 
				
			||||||
	{ .temp_C	= 0, .ohm	= 124850 },
 | 
						{ .temp_c	= 0, .ohm	= 124850 },
 | 
				
			||||||
	{ .temp_C	= 5, .ohm	= 94287 },
 | 
						{ .temp_c	= 5, .ohm	= 94287 },
 | 
				
			||||||
	{ .temp_C	= 10, .ohm	= 71747 },
 | 
						{ .temp_c	= 10, .ohm	= 71747 },
 | 
				
			||||||
	{ .temp_C	= 15, .ohm	= 54996 },
 | 
						{ .temp_c	= 15, .ohm	= 54996 },
 | 
				
			||||||
	{ .temp_C	= 20, .ohm	= 42455 },
 | 
						{ .temp_c	= 20, .ohm	= 42455 },
 | 
				
			||||||
	{ .temp_C	= 25, .ohm	= 33000 },
 | 
						{ .temp_c	= 25, .ohm	= 33000 },
 | 
				
			||||||
	{ .temp_C	= 30, .ohm	= 25822 },
 | 
						{ .temp_c	= 30, .ohm	= 25822 },
 | 
				
			||||||
	{ .temp_C	= 35, .ohm	= 20335 },
 | 
						{ .temp_c	= 35, .ohm	= 20335 },
 | 
				
			||||||
	{ .temp_C	= 40, .ohm	= 16115 },
 | 
						{ .temp_c	= 40, .ohm	= 16115 },
 | 
				
			||||||
	{ .temp_C	= 45, .ohm	= 12849 },
 | 
						{ .temp_c	= 45, .ohm	= 12849 },
 | 
				
			||||||
	{ .temp_C	= 50, .ohm	= 10306 },
 | 
						{ .temp_c	= 50, .ohm	= 10306 },
 | 
				
			||||||
	{ .temp_C	= 55, .ohm	= 8314 },
 | 
						{ .temp_c	= 55, .ohm	= 8314 },
 | 
				
			||||||
	{ .temp_C	= 60, .ohm	= 6746 },
 | 
						{ .temp_c	= 60, .ohm	= 6746 },
 | 
				
			||||||
	{ .temp_C	= 65, .ohm	= 5503 },
 | 
						{ .temp_c	= 65, .ohm	= 5503 },
 | 
				
			||||||
	{ .temp_C	= 70, .ohm	= 4513 },
 | 
						{ .temp_c	= 70, .ohm	= 4513 },
 | 
				
			||||||
	{ .temp_C	= 75, .ohm	= 3721 },
 | 
						{ .temp_c	= 75, .ohm	= 3721 },
 | 
				
			||||||
	{ .temp_C	= 80, .ohm	= 3084 },
 | 
						{ .temp_c	= 80, .ohm	= 3084 },
 | 
				
			||||||
	{ .temp_C	= 85, .ohm	= 2569 },
 | 
						{ .temp_c	= 85, .ohm	= 2569 },
 | 
				
			||||||
	{ .temp_C	= 90, .ohm	= 2151 },
 | 
						{ .temp_c	= 90, .ohm	= 2151 },
 | 
				
			||||||
	{ .temp_C	= 95, .ohm	= 1809 },
 | 
						{ .temp_c	= 95, .ohm	= 1809 },
 | 
				
			||||||
	{ .temp_C	= 100, .ohm	= 1529 },
 | 
						{ .temp_c	= 100, .ohm	= 1529 },
 | 
				
			||||||
	{ .temp_C	= 105, .ohm	= 1299 },
 | 
						{ .temp_c	= 105, .ohm	= 1299 },
 | 
				
			||||||
	{ .temp_C	= 110, .ohm	= 1108 },
 | 
						{ .temp_c	= 110, .ohm	= 1108 },
 | 
				
			||||||
	{ .temp_C	= 115, .ohm	= 949 },
 | 
						{ .temp_c	= 115, .ohm	= 949 },
 | 
				
			||||||
	{ .temp_C	= 120, .ohm	= 817 },
 | 
						{ .temp_c	= 120, .ohm	= 817 },
 | 
				
			||||||
	{ .temp_C	= 125, .ohm	= 707 },
 | 
						{ .temp_c	= 125, .ohm	= 707 },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ntc_data {
 | 
					struct ntc_data {
 | 
				
			||||||
| 
						 | 
					@ -125,6 +141,92 @@ struct ntc_data {
 | 
				
			||||||
	char name[PLATFORM_NAME_SIZE];
 | 
						char name[PLATFORM_NAME_SIZE];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_OF
 | 
				
			||||||
 | 
					static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct iio_channel *channel = pdata->chan;
 | 
				
			||||||
 | 
						unsigned int result;
 | 
				
			||||||
 | 
						int val, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = iio_read_channel_raw(channel, &val);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							pr_err("read channel() error: %d\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* unit: mV */
 | 
				
			||||||
 | 
						result = pdata->pullup_uv * val;
 | 
				
			||||||
 | 
						result >>= 12;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct of_device_id ntc_match[] = {
 | 
				
			||||||
 | 
						{ .compatible = "ntc,ncp15wb473",
 | 
				
			||||||
 | 
							.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
 | 
				
			||||||
 | 
						{ .compatible = "ntc,ncp18wb473",
 | 
				
			||||||
 | 
							.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
 | 
				
			||||||
 | 
						{ .compatible = "ntc,ncp21wb473",
 | 
				
			||||||
 | 
							.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
 | 
				
			||||||
 | 
						{ .compatible = "ntc,ncp03wb473",
 | 
				
			||||||
 | 
							.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
 | 
				
			||||||
 | 
						{ .compatible = "ntc,ncp15wl333",
 | 
				
			||||||
 | 
							.data = &ntc_thermistor_id[TYPE_NCPXXWL333] },
 | 
				
			||||||
 | 
						{ },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(of, ntc_match);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ntc_thermistor_platform_data *
 | 
				
			||||||
 | 
					ntc_thermistor_parse_dt(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct iio_channel *chan;
 | 
				
			||||||
 | 
						struct device_node *np = pdev->dev.of_node;
 | 
				
			||||||
 | 
						struct ntc_thermistor_platform_data *pdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!np)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!pdata)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chan = iio_channel_get(&pdev->dev, NULL);
 | 
				
			||||||
 | 
						if (IS_ERR(chan))
 | 
				
			||||||
 | 
							return ERR_CAST(chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv))
 | 
				
			||||||
 | 
							return ERR_PTR(-ENODEV);
 | 
				
			||||||
 | 
						if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm))
 | 
				
			||||||
 | 
							return ERR_PTR(-ENODEV);
 | 
				
			||||||
 | 
						if (of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm))
 | 
				
			||||||
 | 
							return ERR_PTR(-ENODEV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (of_find_property(np, "connected-positive", NULL))
 | 
				
			||||||
 | 
							pdata->connect = NTC_CONNECTED_POSITIVE;
 | 
				
			||||||
 | 
						else /* status change should be possible if not always on. */
 | 
				
			||||||
 | 
							pdata->connect = NTC_CONNECTED_GROUND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdata->chan = chan;
 | 
				
			||||||
 | 
						pdata->read_uv = ntc_adc_iio_read;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pdata;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (pdata->chan)
 | 
				
			||||||
 | 
							iio_channel_release(pdata->chan);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static struct ntc_thermistor_platform_data *
 | 
				
			||||||
 | 
					ntc_thermistor_parse_dt(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
 | 
				
			||||||
 | 
					{ }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
 | 
					static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (divisor == 0 && dividend == 0)
 | 
						if (divisor == 0 && dividend == 0)
 | 
				
			||||||
| 
						 | 
					@ -134,37 +236,37 @@ static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
 | 
				
			||||||
	return div64_u64(dividend, divisor);
 | 
						return div64_u64(dividend, divisor);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV)
 | 
					static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ntc_thermistor_platform_data *pdata = data->pdata;
 | 
						struct ntc_thermistor_platform_data *pdata = data->pdata;
 | 
				
			||||||
	u64 mV = uV / 1000;
 | 
						u64 mv = uv / 1000;
 | 
				
			||||||
	u64 pmV = pdata->pullup_uV / 1000;
 | 
						u64 pmv = pdata->pullup_uv / 1000;
 | 
				
			||||||
	u64 N, puO, pdO;
 | 
						u64 n, puo, pdo;
 | 
				
			||||||
	puO = pdata->pullup_ohm;
 | 
						puo = pdata->pullup_ohm;
 | 
				
			||||||
	pdO = pdata->pulldown_ohm;
 | 
						pdo = pdata->pulldown_ohm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mV == 0) {
 | 
						if (mv == 0) {
 | 
				
			||||||
		if (pdata->connect == NTC_CONNECTED_POSITIVE)
 | 
							if (pdata->connect == NTC_CONNECTED_POSITIVE)
 | 
				
			||||||
			return INT_MAX;
 | 
								return INT_MAX;
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (mV >= pmV)
 | 
						if (mv >= pmv)
 | 
				
			||||||
		return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
 | 
							return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
 | 
				
			||||||
			0 : INT_MAX;
 | 
								0 : INT_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
 | 
						if (pdata->connect == NTC_CONNECTED_POSITIVE && puo == 0)
 | 
				
			||||||
		N = div64_u64_safe(pdO * (pmV - mV), mV);
 | 
							n = div64_u64_safe(pdo * (pmv - mv), mv);
 | 
				
			||||||
	else if (pdata->connect == NTC_CONNECTED_GROUND && pdO == 0)
 | 
						else if (pdata->connect == NTC_CONNECTED_GROUND && pdo == 0)
 | 
				
			||||||
		N = div64_u64_safe(puO * mV, pmV - mV);
 | 
							n = div64_u64_safe(puo * mv, pmv - mv);
 | 
				
			||||||
	else if (pdata->connect == NTC_CONNECTED_POSITIVE)
 | 
						else if (pdata->connect == NTC_CONNECTED_POSITIVE)
 | 
				
			||||||
		N = div64_u64_safe(pdO * puO * (pmV - mV),
 | 
							n = div64_u64_safe(pdo * puo * (pmv - mv),
 | 
				
			||||||
				puO * mV - pdO * (pmV - mV));
 | 
									puo * mv - pdo * (pmv - mv));
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
 | 
							n = div64_u64_safe(pdo * puo * mv, pdo * (pmv - mv) - puo * mv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (N > INT_MAX)
 | 
						if (n > INT_MAX)
 | 
				
			||||||
		N = INT_MAX;
 | 
							n = INT_MAX;
 | 
				
			||||||
	return N;
 | 
						return n;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void lookup_comp(struct ntc_data *data, unsigned int ohm,
 | 
					static void lookup_comp(struct ntc_data *data, unsigned int ohm,
 | 
				
			||||||
| 
						 | 
					@ -233,7 +335,7 @@ static void lookup_comp(struct ntc_data *data, unsigned int ohm,
 | 
				
			||||||
		*i_high = end - 1;
 | 
							*i_high = end - 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
 | 
					static int get_temp_mc(struct ntc_data *data, unsigned int ohm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int low, high;
 | 
						int low, high;
 | 
				
			||||||
	int temp;
 | 
						int temp;
 | 
				
			||||||
| 
						 | 
					@ -241,10 +343,10 @@ static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
 | 
				
			||||||
	lookup_comp(data, ohm, &low, &high);
 | 
						lookup_comp(data, ohm, &low, &high);
 | 
				
			||||||
	if (low == high) {
 | 
						if (low == high) {
 | 
				
			||||||
		/* Unable to use linear approximation */
 | 
							/* Unable to use linear approximation */
 | 
				
			||||||
		temp = data->comp[low].temp_C * 1000;
 | 
							temp = data->comp[low].temp_c * 1000;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		temp = data->comp[low].temp_C * 1000 +
 | 
							temp = data->comp[low].temp_c * 1000 +
 | 
				
			||||||
			((data->comp[high].temp_C - data->comp[low].temp_C) *
 | 
								((data->comp[high].temp_c - data->comp[low].temp_c) *
 | 
				
			||||||
			 1000 * ((int)ohm - (int)data->comp[low].ohm)) /
 | 
								 1000 * ((int)ohm - (int)data->comp[low].ohm)) /
 | 
				
			||||||
			((int)data->comp[high].ohm - (int)data->comp[low].ohm);
 | 
								((int)data->comp[high].ohm - (int)data->comp[low].ohm);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -253,16 +355,16 @@ static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ntc_thermistor_get_ohm(struct ntc_data *data)
 | 
					static int ntc_thermistor_get_ohm(struct ntc_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int read_uV;
 | 
						int read_uv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data->pdata->read_ohm)
 | 
						if (data->pdata->read_ohm)
 | 
				
			||||||
		return data->pdata->read_ohm();
 | 
							return data->pdata->read_ohm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data->pdata->read_uV) {
 | 
						if (data->pdata->read_uv) {
 | 
				
			||||||
		read_uV = data->pdata->read_uV();
 | 
							read_uv = data->pdata->read_uv(data->pdata);
 | 
				
			||||||
		if (read_uV < 0)
 | 
							if (read_uv < 0)
 | 
				
			||||||
			return read_uV;
 | 
								return read_uv;
 | 
				
			||||||
		return get_ohm_of_thermistor(data, read_uV);
 | 
							return get_ohm_of_thermistor(data, read_uv);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -291,7 +393,7 @@ static ssize_t ntc_show_temp(struct device *dev,
 | 
				
			||||||
	if (ohm < 0)
 | 
						if (ohm < 0)
 | 
				
			||||||
		return ohm;
 | 
							return ohm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%d\n", get_temp_mC(data, ohm));
 | 
						return sprintf(buf, "%d\n", get_temp_mc(data, ohm));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
 | 
					static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
 | 
				
			||||||
| 
						 | 
					@ -311,9 +413,18 @@ static const struct attribute_group ntc_attr_group = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ntc_thermistor_probe(struct platform_device *pdev)
 | 
					static int ntc_thermistor_probe(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						const struct of_device_id *of_id =
 | 
				
			||||||
 | 
								of_match_device(of_match_ptr(ntc_match), &pdev->dev);
 | 
				
			||||||
 | 
						const struct platform_device_id *pdev_id;
 | 
				
			||||||
 | 
						struct ntc_thermistor_platform_data *pdata;
 | 
				
			||||||
	struct ntc_data *data;
 | 
						struct ntc_data *data;
 | 
				
			||||||
	struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data;
 | 
						int ret;
 | 
				
			||||||
	int ret = 0;
 | 
					
 | 
				
			||||||
 | 
						pdata = ntc_thermistor_parse_dt(pdev);
 | 
				
			||||||
 | 
						if (IS_ERR(pdata))
 | 
				
			||||||
 | 
							return PTR_ERR(pdata);
 | 
				
			||||||
 | 
						else if (pdata == NULL)
 | 
				
			||||||
 | 
							pdata = pdev->dev.platform_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pdata) {
 | 
						if (!pdata) {
 | 
				
			||||||
		dev_err(&pdev->dev, "No platform init data supplied.\n");
 | 
							dev_err(&pdev->dev, "No platform init data supplied.\n");
 | 
				
			||||||
| 
						 | 
					@ -321,19 +432,19 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Either one of the two is required. */
 | 
						/* Either one of the two is required. */
 | 
				
			||||||
	if (!pdata->read_uV && !pdata->read_ohm) {
 | 
						if (!pdata->read_uv && !pdata->read_ohm) {
 | 
				
			||||||
		dev_err(&pdev->dev,
 | 
							dev_err(&pdev->dev,
 | 
				
			||||||
			"Both read_uV and read_ohm missing. Need either one of the two.\n");
 | 
								"Both read_uv and read_ohm missing. Need either one of the two.\n");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pdata->read_uV && pdata->read_ohm) {
 | 
						if (pdata->read_uv && pdata->read_ohm) {
 | 
				
			||||||
		dev_warn(&pdev->dev,
 | 
							dev_warn(&pdev->dev,
 | 
				
			||||||
			 "Only one of read_uV and read_ohm is needed; ignoring read_uV.\n");
 | 
								 "Only one of read_uv and read_ohm is needed; ignoring read_uv.\n");
 | 
				
			||||||
		pdata->read_uV = NULL;
 | 
							pdata->read_uv = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pdata->read_uV && (pdata->pullup_uV == 0 ||
 | 
						if (pdata->read_uv && (pdata->pullup_uv == 0 ||
 | 
				
			||||||
				(pdata->pullup_ohm == 0 && pdata->connect ==
 | 
									(pdata->pullup_ohm == 0 && pdata->connect ==
 | 
				
			||||||
				 NTC_CONNECTED_GROUND) ||
 | 
									 NTC_CONNECTED_GROUND) ||
 | 
				
			||||||
				(pdata->pulldown_ohm == 0 && pdata->connect ==
 | 
									(pdata->pulldown_ohm == 0 && pdata->connect ==
 | 
				
			||||||
| 
						 | 
					@ -341,7 +452,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
 | 
				
			||||||
				(pdata->connect != NTC_CONNECTED_POSITIVE &&
 | 
									(pdata->connect != NTC_CONNECTED_POSITIVE &&
 | 
				
			||||||
				 pdata->connect != NTC_CONNECTED_GROUND))) {
 | 
									 pdata->connect != NTC_CONNECTED_GROUND))) {
 | 
				
			||||||
		dev_err(&pdev->dev,
 | 
							dev_err(&pdev->dev,
 | 
				
			||||||
			"Required data to use read_uV not supplied.\n");
 | 
								"Required data to use read_uv not supplied.\n");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -349,11 +460,13 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
 | 
				
			||||||
	if (!data)
 | 
						if (!data)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->dev = &pdev->dev;
 | 
						data->dev = &pdev->dev;
 | 
				
			||||||
	data->pdata = pdata;
 | 
						data->pdata = pdata;
 | 
				
			||||||
	strlcpy(data->name, pdev->id_entry->name, sizeof(data->name));
 | 
						strlcpy(data->name, pdev_id->name, sizeof(data->name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (pdev->id_entry->driver_data) {
 | 
						switch (pdev_id->driver_data) {
 | 
				
			||||||
	case TYPE_NCPXXWB473:
 | 
						case TYPE_NCPXXWB473:
 | 
				
			||||||
		data->comp = ncpXXwb473;
 | 
							data->comp = ncpXXwb473;
 | 
				
			||||||
		data->n_comp = ARRAY_SIZE(ncpXXwb473);
 | 
							data->n_comp = ARRAY_SIZE(ncpXXwb473);
 | 
				
			||||||
| 
						 | 
					@ -364,8 +477,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
 | 
							dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
 | 
				
			||||||
				pdev->id_entry->driver_data,
 | 
									pdev_id->driver_data, pdev_id->name);
 | 
				
			||||||
				pdev->id_entry->name);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -384,39 +496,34 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
 | 
				
			||||||
		goto err_after_sysfs;
 | 
							goto err_after_sysfs;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_info(&pdev->dev, "Thermistor %s:%d (type: %s/%lu) successfully probed.\n",
 | 
						dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n",
 | 
				
			||||||
			pdev->name, pdev->id, pdev->id_entry->name,
 | 
													pdev->name);
 | 
				
			||||||
			pdev->id_entry->driver_data);
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
err_after_sysfs:
 | 
					err_after_sysfs:
 | 
				
			||||||
	sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
 | 
						sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
 | 
				
			||||||
 | 
						ntc_iio_channel_release(pdata);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ntc_thermistor_remove(struct platform_device *pdev)
 | 
					static int ntc_thermistor_remove(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ntc_data *data = platform_get_drvdata(pdev);
 | 
						struct ntc_data *data = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
						struct ntc_thermistor_platform_data *pdata = data->pdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hwmon_device_unregister(data->hwmon_dev);
 | 
						hwmon_device_unregister(data->hwmon_dev);
 | 
				
			||||||
	sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
 | 
						sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
 | 
				
			||||||
 | 
						ntc_iio_channel_release(pdata);
 | 
				
			||||||
	platform_set_drvdata(pdev, NULL);
 | 
						platform_set_drvdata(pdev, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct platform_device_id ntc_thermistor_id[] = {
 | 
					 | 
				
			||||||
	{ "ncp15wb473", TYPE_NCPXXWB473 },
 | 
					 | 
				
			||||||
	{ "ncp18wb473", TYPE_NCPXXWB473 },
 | 
					 | 
				
			||||||
	{ "ncp21wb473", TYPE_NCPXXWB473 },
 | 
					 | 
				
			||||||
	{ "ncp03wb473", TYPE_NCPXXWB473 },
 | 
					 | 
				
			||||||
	{ "ncp15wl333", TYPE_NCPXXWL333 },
 | 
					 | 
				
			||||||
	{ },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct platform_driver ntc_thermistor_driver = {
 | 
					static struct platform_driver ntc_thermistor_driver = {
 | 
				
			||||||
	.driver = {
 | 
						.driver = {
 | 
				
			||||||
		.name = "ntc-thermistor",
 | 
							.name = "ntc-thermistor",
 | 
				
			||||||
		.owner = THIS_MODULE,
 | 
							.owner = THIS_MODULE,
 | 
				
			||||||
 | 
							.of_match_table = of_match_ptr(ntc_match),
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	.probe = ntc_thermistor_probe,
 | 
						.probe = ntc_thermistor_probe,
 | 
				
			||||||
	.remove = ntc_thermistor_remove,
 | 
						.remove = ntc_thermistor_remove,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1190,8 +1190,7 @@ static int __init pc87360_find(int sioaddr, u8 *devid,
 | 
				
			||||||
				confreg[3] = superio_inb(sioaddr, 0x25);
 | 
									confreg[3] = superio_inb(sioaddr, 0x25);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (confreg[2] & 0x40) {
 | 
									if (confreg[2] & 0x40) {
 | 
				
			||||||
					pr_info("Using thermistors for "
 | 
										pr_info("Using thermistors for temperature monitoring\n");
 | 
				
			||||||
						"temperature monitoring\n");
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if (confreg[3] & 0xE0) {
 | 
									if (confreg[3] & 0xE0) {
 | 
				
			||||||
					pr_info("VID inputs routed (mode %u)\n",
 | 
										pr_info("VID inputs routed (mode %u)\n",
 | 
				
			||||||
| 
						 | 
					@ -1271,9 +1270,9 @@ static int pc87360_probe(struct platform_device *pdev)
 | 
				
			||||||
		if (data->address[i]
 | 
							if (data->address[i]
 | 
				
			||||||
		 && !devm_request_region(dev, extra_isa[i], PC87360_EXTENT,
 | 
							 && !devm_request_region(dev, extra_isa[i], PC87360_EXTENT,
 | 
				
			||||||
					 pc87360_driver.driver.name)) {
 | 
										 pc87360_driver.driver.name)) {
 | 
				
			||||||
			dev_err(dev, "Region 0x%x-0x%x already "
 | 
								dev_err(dev,
 | 
				
			||||||
				"in use!\n", extra_isa[i],
 | 
									"Region 0x%x-0x%x already in use!\n",
 | 
				
			||||||
				extra_isa[i]+PC87360_EXTENT-1);
 | 
									extra_isa[i], extra_isa[i]+PC87360_EXTENT-1);
 | 
				
			||||||
			return -EBUSY;
 | 
								return -EBUSY;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1435,8 +1434,8 @@ static void pc87360_init_device(struct platform_device *pdev,
 | 
				
			||||||
	if (init >= 2 && data->innr) {
 | 
						if (init >= 2 && data->innr) {
 | 
				
			||||||
		reg = pc87360_read_value(data, LD_IN, NO_BANK,
 | 
							reg = pc87360_read_value(data, LD_IN, NO_BANK,
 | 
				
			||||||
					 PC87365_REG_IN_CONVRATE);
 | 
										 PC87365_REG_IN_CONVRATE);
 | 
				
			||||||
		dev_info(&pdev->dev, "VLM conversion set to "
 | 
							dev_info(&pdev->dev,
 | 
				
			||||||
			 "1s period, 160us delay\n");
 | 
								 "VLM conversion set to 1s period, 160us delay\n");
 | 
				
			||||||
		pc87360_write_value(data, LD_IN, NO_BANK,
 | 
							pc87360_write_value(data, LD_IN, NO_BANK,
 | 
				
			||||||
				    PC87365_REG_IN_CONVRATE,
 | 
									    PC87365_REG_IN_CONVRATE,
 | 
				
			||||||
				    (reg & 0xC0) | 0x11);
 | 
									    (reg & 0xC0) | 0x11);
 | 
				
			||||||
| 
						 | 
					@ -1450,8 +1449,8 @@ static void pc87360_init_device(struct platform_device *pdev,
 | 
				
			||||||
		if (init >= init_in[i]) {
 | 
							if (init >= init_in[i]) {
 | 
				
			||||||
			/* Forcibly enable voltage channel */
 | 
								/* Forcibly enable voltage channel */
 | 
				
			||||||
			if (!(reg & CHAN_ENA)) {
 | 
								if (!(reg & CHAN_ENA)) {
 | 
				
			||||||
				dev_dbg(&pdev->dev, "Forcibly "
 | 
									dev_dbg(&pdev->dev, "Forcibly enabling in%d\n",
 | 
				
			||||||
					"enabling in%d\n", i);
 | 
										i);
 | 
				
			||||||
				pc87360_write_value(data, LD_IN, i,
 | 
									pc87360_write_value(data, LD_IN, i,
 | 
				
			||||||
						    PC87365_REG_IN_STATUS,
 | 
											    PC87365_REG_IN_STATUS,
 | 
				
			||||||
						    (reg & 0x68) | 0x87);
 | 
											    (reg & 0x68) | 0x87);
 | 
				
			||||||
| 
						 | 
					@ -1575,8 +1574,8 @@ static void pc87360_autodiv(struct device *dev, int nr)
 | 
				
			||||||
			data->fan_status[nr] += 0x20;
 | 
								data->fan_status[nr] += 0x20;
 | 
				
			||||||
			data->fan_min[nr] >>= 1;
 | 
								data->fan_min[nr] >>= 1;
 | 
				
			||||||
			data->fan[nr] >>= 1;
 | 
								data->fan[nr] >>= 1;
 | 
				
			||||||
			dev_dbg(dev, "Increasing "
 | 
								dev_dbg(dev,
 | 
				
			||||||
				"clock divider to %d for fan %d\n",
 | 
									"Increasing clock divider to %d for fan %d\n",
 | 
				
			||||||
				FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1);
 | 
									FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -1587,8 +1586,8 @@ static void pc87360_autodiv(struct device *dev, int nr)
 | 
				
			||||||
			data->fan_status[nr] -= 0x20;
 | 
								data->fan_status[nr] -= 0x20;
 | 
				
			||||||
			data->fan_min[nr] <<= 1;
 | 
								data->fan_min[nr] <<= 1;
 | 
				
			||||||
			data->fan[nr] <<= 1;
 | 
								data->fan[nr] <<= 1;
 | 
				
			||||||
			dev_dbg(dev, "Decreasing "
 | 
								dev_dbg(dev,
 | 
				
			||||||
				"clock divider to %d for fan %d\n",
 | 
									"Decreasing clock divider to %d for fan %d\n",
 | 
				
			||||||
				FAN_DIV_FROM_REG(data->fan_status[nr]),
 | 
									FAN_DIV_FROM_REG(data->fan_status[nr]),
 | 
				
			||||||
				nr + 1);
 | 
									nr + 1);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -627,8 +627,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute
 | 
				
			||||||
	pc87427_readall_pwm(data, nr);
 | 
						pc87427_readall_pwm(data, nr);
 | 
				
			||||||
	mode = data->pwm_enable[nr] & PWM_ENABLE_MODE_MASK;
 | 
						mode = data->pwm_enable[nr] & PWM_ENABLE_MODE_MASK;
 | 
				
			||||||
	if (mode != PWM_MODE_MANUAL && mode != PWM_MODE_OFF) {
 | 
						if (mode != PWM_MODE_MANUAL && mode != PWM_MODE_OFF) {
 | 
				
			||||||
		dev_notice(dev, "Can't set PWM%d duty cycle while not in "
 | 
							dev_notice(dev,
 | 
				
			||||||
			   "manual mode\n", nr + 1);
 | 
								   "Can't set PWM%d duty cycle while not in manual mode\n",
 | 
				
			||||||
 | 
								   nr + 1);
 | 
				
			||||||
		mutex_unlock(&data->lock);
 | 
							mutex_unlock(&data->lock);
 | 
				
			||||||
		return -EPERM;
 | 
							return -EPERM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1245,16 +1246,16 @@ static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		val = superio_inb(sioaddr, SIOREG_MAP);
 | 
							val = superio_inb(sioaddr, SIOREG_MAP);
 | 
				
			||||||
		if (val & 0x01) {
 | 
							if (val & 0x01) {
 | 
				
			||||||
			pr_warn("Logical device 0x%02x is memory-mapped, "
 | 
								pr_warn("Logical device 0x%02x is memory-mapped, can't use\n",
 | 
				
			||||||
				"can't use\n", logdev[i]);
 | 
									logdev[i]);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)
 | 
							val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)
 | 
				
			||||||
		    | superio_inb(sioaddr, SIOREG_IOBASE + 1);
 | 
							    | superio_inb(sioaddr, SIOREG_IOBASE + 1);
 | 
				
			||||||
		if (!val) {
 | 
							if (!val) {
 | 
				
			||||||
			pr_info("I/O base address not set for logical device "
 | 
								pr_info("I/O base address not set for logical device 0x%02x\n",
 | 
				
			||||||
				"0x%02x\n", logdev[i]);
 | 
									logdev[i]);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		sio_data->address[i] = val;
 | 
							sio_data->address[i] = val;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,17 +42,17 @@ config SENSORS_LM25066
 | 
				
			||||||
	default n
 | 
						default n
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  If you say yes here you get hardware monitoring support for National
 | 
						  If you say yes here you get hardware monitoring support for National
 | 
				
			||||||
	  Semiconductor LM25066, LM5064, and LM5066.
 | 
						  Semiconductor LM25056, LM25066, LM5064, and LM5066.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  This driver can also be built as a module. If so, the module will
 | 
						  This driver can also be built as a module. If so, the module will
 | 
				
			||||||
	  be called lm25066.
 | 
						  be called lm25066.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config SENSORS_LTC2978
 | 
					config SENSORS_LTC2978
 | 
				
			||||||
	tristate "Linear Technologies LTC2978 and LTC3880"
 | 
						tristate "Linear Technologies LTC2974, LTC2978, LTC3880, and LTC3883"
 | 
				
			||||||
	default n
 | 
						default n
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  If you say yes here you get hardware monitoring support for Linear
 | 
						  If you say yes here you get hardware monitoring support for Linear
 | 
				
			||||||
	  Technology LTC2978 and LTC3880.
 | 
						  Technology LTC2974, LTC2978, LTC3880, and LTC3883.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  This driver can also be built as a module. If so, the module will
 | 
						  This driver can also be built as a module. If so, the module will
 | 
				
			||||||
	  be called ltc2978.
 | 
						  be called ltc2978.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Hardware monitoring driver for LM25066 / LM5064 / LM5066
 | 
					 * Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (c) 2011 Ericsson AB.
 | 
					 * Copyright (c) 2011 Ericsson AB.
 | 
				
			||||||
 | 
					 * Copyright (c) 2013 Guenter Roeck
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 * it under the terms of the GNU General Public License as published by
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
| 
						 | 
					@ -26,7 +27,7 @@
 | 
				
			||||||
#include <linux/i2c.h>
 | 
					#include <linux/i2c.h>
 | 
				
			||||||
#include "pmbus.h"
 | 
					#include "pmbus.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum chips { lm25066, lm5064, lm5066 };
 | 
					enum chips { lm25056, lm25066, lm5064, lm5066 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LM25066_READ_VAUX		0xd0
 | 
					#define LM25066_READ_VAUX		0xd0
 | 
				
			||||||
#define LM25066_MFR_READ_IIN		0xd1
 | 
					#define LM25066_MFR_READ_IIN		0xd1
 | 
				
			||||||
| 
						 | 
					@ -43,6 +44,138 @@ enum chips { lm25066, lm5064, lm5066 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LM25066_DEV_SETUP_CL		(1 << 4)	/* Current limit */
 | 
					#define LM25066_DEV_SETUP_CL		(1 << 4)	/* Current limit */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* LM25056 only */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LM25056_VAUX_OV_WARN_LIMIT	0xe3
 | 
				
			||||||
 | 
					#define LM25056_VAUX_UV_WARN_LIMIT	0xe4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LM25056_MFR_STS_VAUX_OV_WARN	(1 << 1)
 | 
				
			||||||
 | 
					#define LM25056_MFR_STS_VAUX_UV_WARN	(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct __coeff {
 | 
				
			||||||
 | 
						short m, b, R;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PSC_CURRENT_IN_L	(PSC_NUM_CLASSES)
 | 
				
			||||||
 | 
					#define PSC_POWER_L		(PSC_NUM_CLASSES + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = {
 | 
				
			||||||
 | 
						[lm25056] = {
 | 
				
			||||||
 | 
							[PSC_VOLTAGE_IN] = {
 | 
				
			||||||
 | 
								.m = 16296,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_CURRENT_IN] = {
 | 
				
			||||||
 | 
								.m = 13797,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_CURRENT_IN_L] = {
 | 
				
			||||||
 | 
								.m = 6726,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_POWER] = {
 | 
				
			||||||
 | 
								.m = 5501,
 | 
				
			||||||
 | 
								.R = -3,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_POWER_L] = {
 | 
				
			||||||
 | 
								.m = 26882,
 | 
				
			||||||
 | 
								.R = -4,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_TEMPERATURE] = {
 | 
				
			||||||
 | 
								.m = 1580,
 | 
				
			||||||
 | 
								.b = -14500,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[lm25066] = {
 | 
				
			||||||
 | 
							[PSC_VOLTAGE_IN] = {
 | 
				
			||||||
 | 
								.m = 22070,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_VOLTAGE_OUT] = {
 | 
				
			||||||
 | 
								.m = 22070,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_CURRENT_IN] = {
 | 
				
			||||||
 | 
								.m = 13661,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_CURRENT_IN_L] = {
 | 
				
			||||||
 | 
								.m = 6852,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_POWER] = {
 | 
				
			||||||
 | 
								.m = 736,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_POWER_L] = {
 | 
				
			||||||
 | 
								.m = 369,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_TEMPERATURE] = {
 | 
				
			||||||
 | 
								.m = 16,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[lm5064] = {
 | 
				
			||||||
 | 
							[PSC_VOLTAGE_IN] = {
 | 
				
			||||||
 | 
								.m = 4611,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_VOLTAGE_OUT] = {
 | 
				
			||||||
 | 
								.m = 4621,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_CURRENT_IN] = {
 | 
				
			||||||
 | 
								.m = 10742,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_CURRENT_IN_L] = {
 | 
				
			||||||
 | 
								.m = 5456,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_POWER] = {
 | 
				
			||||||
 | 
								.m = 1204,
 | 
				
			||||||
 | 
								.R = -3,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_POWER_L] = {
 | 
				
			||||||
 | 
								.m = 612,
 | 
				
			||||||
 | 
								.R = -3,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_TEMPERATURE] = {
 | 
				
			||||||
 | 
								.m = 16,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[lm5066] = {
 | 
				
			||||||
 | 
							[PSC_VOLTAGE_IN] = {
 | 
				
			||||||
 | 
								.m = 4587,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_VOLTAGE_OUT] = {
 | 
				
			||||||
 | 
								.m = 4587,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_CURRENT_IN] = {
 | 
				
			||||||
 | 
								.m = 10753,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_CURRENT_IN_L] = {
 | 
				
			||||||
 | 
								.m = 5405,
 | 
				
			||||||
 | 
								.R = -2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_POWER] = {
 | 
				
			||||||
 | 
								.m = 1204,
 | 
				
			||||||
 | 
								.R = -3,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_POWER_L] = {
 | 
				
			||||||
 | 
								.m = 605,
 | 
				
			||||||
 | 
								.R = -3,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[PSC_TEMPERATURE] = {
 | 
				
			||||||
 | 
								.m = 16,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct lm25066_data {
 | 
					struct lm25066_data {
 | 
				
			||||||
	int id;
 | 
						int id;
 | 
				
			||||||
	struct pmbus_driver_info info;
 | 
						struct pmbus_driver_info info;
 | 
				
			||||||
| 
						 | 
					@ -56,42 +189,31 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
	const struct lm25066_data *data = to_lm25066_data(info);
 | 
						const struct lm25066_data *data = to_lm25066_data(info);
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (page > 1)
 | 
						switch (reg) {
 | 
				
			||||||
		return -ENXIO;
 | 
						case PMBUS_VIRT_READ_VMON:
 | 
				
			||||||
 | 
							ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
 | 
				
			||||||
	/* Map READ_VAUX into READ_VOUT register on page 1 */
 | 
							if (ret < 0)
 | 
				
			||||||
	if (page == 1) {
 | 
					 | 
				
			||||||
		switch (reg) {
 | 
					 | 
				
			||||||
		case PMBUS_READ_VOUT:
 | 
					 | 
				
			||||||
			ret = pmbus_read_word_data(client, 0,
 | 
					 | 
				
			||||||
						   LM25066_READ_VAUX);
 | 
					 | 
				
			||||||
			if (ret < 0)
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			/* Adjust returned value to match VOUT coefficients */
 | 
					 | 
				
			||||||
			switch (data->id) {
 | 
					 | 
				
			||||||
			case lm25066:
 | 
					 | 
				
			||||||
				/* VOUT: 4.54 mV VAUX: 283.2 uV LSB */
 | 
					 | 
				
			||||||
				ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			case lm5064:
 | 
					 | 
				
			||||||
				/* VOUT: 4.53 mV VAUX: 700 uV LSB */
 | 
					 | 
				
			||||||
				ret = DIV_ROUND_CLOSEST(ret * 70, 453);
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			case lm5066:
 | 
					 | 
				
			||||||
				/* VOUT: 2.18 mV VAUX: 725 uV LSB */
 | 
					 | 
				
			||||||
				ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							/* Adjust returned value to match VIN coefficients */
 | 
				
			||||||
			/* No other valid registers on page 1 */
 | 
							switch (data->id) {
 | 
				
			||||||
			ret = -ENXIO;
 | 
							case lm25056:
 | 
				
			||||||
 | 
								/* VIN: 6.14 mV VAUX: 293 uV LSB */
 | 
				
			||||||
 | 
								ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case lm25066:
 | 
				
			||||||
 | 
								/* VIN: 4.54 mV VAUX: 283.2 uV LSB */
 | 
				
			||||||
 | 
								ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case lm5064:
 | 
				
			||||||
 | 
								/* VIN: 4.53 mV VAUX: 700 uV LSB */
 | 
				
			||||||
 | 
								ret = DIV_ROUND_CLOSEST(ret * 70, 453);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case lm5066:
 | 
				
			||||||
 | 
								/* VIN: 2.18 mV VAUX: 725 uV LSB */
 | 
				
			||||||
 | 
								ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		goto done;
 | 
							break;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (reg) {
 | 
					 | 
				
			||||||
	case PMBUS_READ_IIN:
 | 
						case PMBUS_READ_IIN:
 | 
				
			||||||
		ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
 | 
							ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -128,7 +250,58 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
		ret = -ENODATA;
 | 
							ret = -ENODATA;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
done:
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (reg) {
 | 
				
			||||||
 | 
						case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
 | 
				
			||||||
 | 
							ret = pmbus_read_word_data(client, 0,
 | 
				
			||||||
 | 
										   LM25056_VAUX_UV_WARN_LIMIT);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							/* Adjust returned value to match VIN coefficients */
 | 
				
			||||||
 | 
							ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
 | 
				
			||||||
 | 
							ret = pmbus_read_word_data(client, 0,
 | 
				
			||||||
 | 
										   LM25056_VAUX_OV_WARN_LIMIT);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							/* Adjust returned value to match VIN coefficients */
 | 
				
			||||||
 | 
							ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ret = lm25066_read_word_data(client, page, reg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lm25056_read_byte_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret, s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (reg) {
 | 
				
			||||||
 | 
						case PMBUS_VIRT_STATUS_VMON:
 | 
				
			||||||
 | 
							ret = pmbus_read_byte_data(client, 0,
 | 
				
			||||||
 | 
										   PMBUS_STATUS_MFR_SPECIFIC);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							s = 0;
 | 
				
			||||||
 | 
							if (ret & LM25056_MFR_STS_VAUX_UV_WARN)
 | 
				
			||||||
 | 
								s |= PB_VOLTAGE_UV_WARNING;
 | 
				
			||||||
 | 
							if (ret & LM25056_MFR_STS_VAUX_OV_WARN)
 | 
				
			||||||
 | 
								s |= PB_VOLTAGE_OV_WARNING;
 | 
				
			||||||
 | 
							ret = s;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ret = -ENODATA;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -137,19 +310,45 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (page > 1)
 | 
					 | 
				
			||||||
		return -ENXIO;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (reg) {
 | 
						switch (reg) {
 | 
				
			||||||
 | 
						case PMBUS_VOUT_UV_WARN_LIMIT:
 | 
				
			||||||
 | 
						case PMBUS_OT_FAULT_LIMIT:
 | 
				
			||||||
 | 
						case PMBUS_OT_WARN_LIMIT:
 | 
				
			||||||
 | 
						case PMBUS_VIN_UV_WARN_LIMIT:
 | 
				
			||||||
 | 
						case PMBUS_VIN_OV_WARN_LIMIT:
 | 
				
			||||||
 | 
							word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 | 
				
			||||||
 | 
							ret = pmbus_write_word_data(client, 0, reg, word);
 | 
				
			||||||
 | 
							pmbus_clear_cache(client);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	case PMBUS_IIN_OC_WARN_LIMIT:
 | 
						case PMBUS_IIN_OC_WARN_LIMIT:
 | 
				
			||||||
 | 
							word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 | 
				
			||||||
		ret = pmbus_write_word_data(client, 0,
 | 
							ret = pmbus_write_word_data(client, 0,
 | 
				
			||||||
					    LM25066_MFR_IIN_OC_WARN_LIMIT,
 | 
										    LM25066_MFR_IIN_OC_WARN_LIMIT,
 | 
				
			||||||
					    word);
 | 
										    word);
 | 
				
			||||||
 | 
							pmbus_clear_cache(client);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PMBUS_PIN_OP_WARN_LIMIT:
 | 
						case PMBUS_PIN_OP_WARN_LIMIT:
 | 
				
			||||||
 | 
							word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 | 
				
			||||||
		ret = pmbus_write_word_data(client, 0,
 | 
							ret = pmbus_write_word_data(client, 0,
 | 
				
			||||||
					    LM25066_MFR_PIN_OP_WARN_LIMIT,
 | 
										    LM25066_MFR_PIN_OP_WARN_LIMIT,
 | 
				
			||||||
					    word);
 | 
										    word);
 | 
				
			||||||
 | 
							pmbus_clear_cache(client);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
 | 
				
			||||||
 | 
							/* Adjust from VIN coefficients (for LM25056) */
 | 
				
			||||||
 | 
							word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
 | 
				
			||||||
 | 
							word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 | 
				
			||||||
 | 
							ret = pmbus_write_word_data(client, 0,
 | 
				
			||||||
 | 
										    LM25056_VAUX_UV_WARN_LIMIT, word);
 | 
				
			||||||
 | 
							pmbus_clear_cache(client);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
 | 
				
			||||||
 | 
							/* Adjust from VIN coefficients (for LM25056) */
 | 
				
			||||||
 | 
							word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
 | 
				
			||||||
 | 
							word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 | 
				
			||||||
 | 
							ret = pmbus_write_word_data(client, 0,
 | 
				
			||||||
 | 
										    LM25056_VAUX_OV_WARN_LIMIT, word);
 | 
				
			||||||
 | 
							pmbus_clear_cache(client);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PMBUS_VIRT_RESET_PIN_HISTORY:
 | 
						case PMBUS_VIRT_RESET_PIN_HISTORY:
 | 
				
			||||||
		ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
 | 
							ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
 | 
				
			||||||
| 
						 | 
					@ -161,23 +360,13 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int lm25066_write_byte(struct i2c_client *client, int page, u8 value)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (page > 1)
 | 
					 | 
				
			||||||
		return -ENXIO;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (page <= 0)
 | 
					 | 
				
			||||||
		return pmbus_write_byte(client, page, value);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int lm25066_probe(struct i2c_client *client,
 | 
					static int lm25066_probe(struct i2c_client *client,
 | 
				
			||||||
			  const struct i2c_device_id *id)
 | 
								  const struct i2c_device_id *id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int config;
 | 
						int config;
 | 
				
			||||||
	struct lm25066_data *data;
 | 
						struct lm25066_data *data;
 | 
				
			||||||
	struct pmbus_driver_info *info;
 | 
						struct pmbus_driver_info *info;
 | 
				
			||||||
 | 
						struct __coeff *coeff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!i2c_check_functionality(client->adapter,
 | 
						if (!i2c_check_functionality(client->adapter,
 | 
				
			||||||
				     I2C_FUNC_SMBUS_READ_BYTE_DATA))
 | 
									     I2C_FUNC_SMBUS_READ_BYTE_DATA))
 | 
				
			||||||
| 
						 | 
					@ -195,107 +384,54 @@ static int lm25066_probe(struct i2c_client *client,
 | 
				
			||||||
	data->id = id->driver_data;
 | 
						data->id = id->driver_data;
 | 
				
			||||||
	info = &data->info;
 | 
						info = &data->info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	info->pages = 2;
 | 
						info->pages = 1;
 | 
				
			||||||
	info->format[PSC_VOLTAGE_IN] = direct;
 | 
						info->format[PSC_VOLTAGE_IN] = direct;
 | 
				
			||||||
	info->format[PSC_VOLTAGE_OUT] = direct;
 | 
						info->format[PSC_VOLTAGE_OUT] = direct;
 | 
				
			||||||
	info->format[PSC_CURRENT_IN] = direct;
 | 
						info->format[PSC_CURRENT_IN] = direct;
 | 
				
			||||||
	info->format[PSC_TEMPERATURE] = direct;
 | 
						info->format[PSC_TEMPERATURE] = direct;
 | 
				
			||||||
	info->format[PSC_POWER] = direct;
 | 
						info->format[PSC_POWER] = direct;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	info->m[PSC_TEMPERATURE] = 16;
 | 
						info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON
 | 
				
			||||||
	info->b[PSC_TEMPERATURE] = 0;
 | 
						  | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT
 | 
				
			||||||
	info->R[PSC_TEMPERATURE] = 0;
 | 
						  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT
 | 
						if (data->id == lm25056) {
 | 
				
			||||||
	  | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN
 | 
							info->func[0] |= PMBUS_HAVE_STATUS_VMON;
 | 
				
			||||||
	  | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 | 
							info->read_word_data = lm25056_read_word_data;
 | 
				
			||||||
	info->func[1] = PMBUS_HAVE_VOUT;
 | 
							info->read_byte_data = lm25056_read_byte_data;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
	info->read_word_data = lm25066_read_word_data;
 | 
							info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
 | 
				
			||||||
 | 
							info->read_word_data = lm25066_read_word_data;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	info->write_word_data = lm25066_write_word_data;
 | 
						info->write_word_data = lm25066_write_word_data;
 | 
				
			||||||
	info->write_byte = lm25066_write_byte;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (id->driver_data) {
 | 
						coeff = &lm25066_coeff[data->id][0];
 | 
				
			||||||
	case lm25066:
 | 
						info->m[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].m;
 | 
				
			||||||
		info->m[PSC_VOLTAGE_IN] = 22070;
 | 
						info->b[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].b;
 | 
				
			||||||
		info->b[PSC_VOLTAGE_IN] = 0;
 | 
						info->R[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].R;
 | 
				
			||||||
		info->R[PSC_VOLTAGE_IN] = -2;
 | 
						info->m[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].m;
 | 
				
			||||||
		info->m[PSC_VOLTAGE_OUT] = 22070;
 | 
						info->b[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].b;
 | 
				
			||||||
		info->b[PSC_VOLTAGE_OUT] = 0;
 | 
						info->R[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].R;
 | 
				
			||||||
		info->R[PSC_VOLTAGE_OUT] = -2;
 | 
						info->m[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].m;
 | 
				
			||||||
 | 
						info->b[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].b;
 | 
				
			||||||
		if (config & LM25066_DEV_SETUP_CL) {
 | 
						info->R[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].R;
 | 
				
			||||||
			info->m[PSC_CURRENT_IN] = 6852;
 | 
						info->b[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].b;
 | 
				
			||||||
			info->b[PSC_CURRENT_IN] = 0;
 | 
						info->R[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].R;
 | 
				
			||||||
			info->R[PSC_CURRENT_IN] = -2;
 | 
						info->b[PSC_POWER] = coeff[PSC_POWER].b;
 | 
				
			||||||
			info->m[PSC_POWER] = 369;
 | 
						info->R[PSC_POWER] = coeff[PSC_POWER].R;
 | 
				
			||||||
			info->b[PSC_POWER] = 0;
 | 
						if (config & LM25066_DEV_SETUP_CL) {
 | 
				
			||||||
			info->R[PSC_POWER] = -2;
 | 
							info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN_L].m;
 | 
				
			||||||
		} else {
 | 
							info->m[PSC_POWER] = coeff[PSC_POWER_L].m;
 | 
				
			||||||
			info->m[PSC_CURRENT_IN] = 13661;
 | 
						} else {
 | 
				
			||||||
			info->b[PSC_CURRENT_IN] = 0;
 | 
							info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].m;
 | 
				
			||||||
			info->R[PSC_CURRENT_IN] = -2;
 | 
							info->m[PSC_POWER] = coeff[PSC_POWER].m;
 | 
				
			||||||
			info->m[PSC_POWER] = 736;
 | 
					 | 
				
			||||||
			info->b[PSC_POWER] = 0;
 | 
					 | 
				
			||||||
			info->R[PSC_POWER] = -2;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case lm5064:
 | 
					 | 
				
			||||||
		info->m[PSC_VOLTAGE_IN] = 22075;
 | 
					 | 
				
			||||||
		info->b[PSC_VOLTAGE_IN] = 0;
 | 
					 | 
				
			||||||
		info->R[PSC_VOLTAGE_IN] = -2;
 | 
					 | 
				
			||||||
		info->m[PSC_VOLTAGE_OUT] = 22075;
 | 
					 | 
				
			||||||
		info->b[PSC_VOLTAGE_OUT] = 0;
 | 
					 | 
				
			||||||
		info->R[PSC_VOLTAGE_OUT] = -2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (config & LM25066_DEV_SETUP_CL) {
 | 
					 | 
				
			||||||
			info->m[PSC_CURRENT_IN] = 6713;
 | 
					 | 
				
			||||||
			info->b[PSC_CURRENT_IN] = 0;
 | 
					 | 
				
			||||||
			info->R[PSC_CURRENT_IN] = -2;
 | 
					 | 
				
			||||||
			info->m[PSC_POWER] = 3619;
 | 
					 | 
				
			||||||
			info->b[PSC_POWER] = 0;
 | 
					 | 
				
			||||||
			info->R[PSC_POWER] = -3;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			info->m[PSC_CURRENT_IN] = 13426;
 | 
					 | 
				
			||||||
			info->b[PSC_CURRENT_IN] = 0;
 | 
					 | 
				
			||||||
			info->R[PSC_CURRENT_IN] = -2;
 | 
					 | 
				
			||||||
			info->m[PSC_POWER] = 7238;
 | 
					 | 
				
			||||||
			info->b[PSC_POWER] = 0;
 | 
					 | 
				
			||||||
			info->R[PSC_POWER] = -3;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case lm5066:
 | 
					 | 
				
			||||||
		info->m[PSC_VOLTAGE_IN] = 4587;
 | 
					 | 
				
			||||||
		info->b[PSC_VOLTAGE_IN] = 0;
 | 
					 | 
				
			||||||
		info->R[PSC_VOLTAGE_IN] = -2;
 | 
					 | 
				
			||||||
		info->m[PSC_VOLTAGE_OUT] = 4587;
 | 
					 | 
				
			||||||
		info->b[PSC_VOLTAGE_OUT] = 0;
 | 
					 | 
				
			||||||
		info->R[PSC_VOLTAGE_OUT] = -2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (config & LM25066_DEV_SETUP_CL) {
 | 
					 | 
				
			||||||
			info->m[PSC_CURRENT_IN] = 10753;
 | 
					 | 
				
			||||||
			info->b[PSC_CURRENT_IN] = 0;
 | 
					 | 
				
			||||||
			info->R[PSC_CURRENT_IN] = -2;
 | 
					 | 
				
			||||||
			info->m[PSC_POWER] = 1204;
 | 
					 | 
				
			||||||
			info->b[PSC_POWER] = 0;
 | 
					 | 
				
			||||||
			info->R[PSC_POWER] = -3;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			info->m[PSC_CURRENT_IN] = 5405;
 | 
					 | 
				
			||||||
			info->b[PSC_CURRENT_IN] = 0;
 | 
					 | 
				
			||||||
			info->R[PSC_CURRENT_IN] = -2;
 | 
					 | 
				
			||||||
			info->m[PSC_POWER] = 605;
 | 
					 | 
				
			||||||
			info->b[PSC_POWER] = 0;
 | 
					 | 
				
			||||||
			info->R[PSC_POWER] = -3;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return -ENODEV;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pmbus_do_probe(client, id, info);
 | 
						return pmbus_do_probe(client, id, info);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct i2c_device_id lm25066_id[] = {
 | 
					static const struct i2c_device_id lm25066_id[] = {
 | 
				
			||||||
 | 
						{"lm25056", lm25056},
 | 
				
			||||||
	{"lm25066", lm25066},
 | 
						{"lm25066", lm25066},
 | 
				
			||||||
	{"lm5064", lm5064},
 | 
						{"lm5064", lm5064},
 | 
				
			||||||
	{"lm5066", lm5066},
 | 
						{"lm5066", lm5066},
 | 
				
			||||||
| 
						 | 
					@ -317,5 +453,5 @@ static struct i2c_driver lm25066_driver = {
 | 
				
			||||||
module_i2c_driver(lm25066_driver);
 | 
					module_i2c_driver(lm25066_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_AUTHOR("Guenter Roeck");
 | 
					MODULE_AUTHOR("Guenter Roeck");
 | 
				
			||||||
MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066");
 | 
					MODULE_DESCRIPTION("PMBus driver for LM25056/LM25066/LM5064/LM5066");
 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Hardware monitoring driver for LTC2978 and LTC3880
 | 
					 * Hardware monitoring driver for LTC2974, LTC2978, LTC3880, and LTC3883
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (c) 2011 Ericsson AB.
 | 
					 * Copyright (c) 2011 Ericsson AB.
 | 
				
			||||||
 | 
					 * Copyright (c) 2013 Guenter Roeck
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 * it under the terms of the GNU General Public License as published by
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
| 
						 | 
					@ -26,28 +27,43 @@
 | 
				
			||||||
#include <linux/i2c.h>
 | 
					#include <linux/i2c.h>
 | 
				
			||||||
#include "pmbus.h"
 | 
					#include "pmbus.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum chips { ltc2978, ltc3880 };
 | 
					enum chips { ltc2974, ltc2978, ltc3880, ltc3883 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* LTC2978 and LTC3880 */
 | 
					/* Common for all chips */
 | 
				
			||||||
#define LTC2978_MFR_VOUT_PEAK		0xdd
 | 
					#define LTC2978_MFR_VOUT_PEAK		0xdd
 | 
				
			||||||
#define LTC2978_MFR_VIN_PEAK		0xde
 | 
					#define LTC2978_MFR_VIN_PEAK		0xde
 | 
				
			||||||
#define LTC2978_MFR_TEMPERATURE_PEAK	0xdf
 | 
					#define LTC2978_MFR_TEMPERATURE_PEAK	0xdf
 | 
				
			||||||
#define LTC2978_MFR_SPECIAL_ID		0xe7
 | 
					#define LTC2978_MFR_SPECIAL_ID		0xe7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* LTC2978 only */
 | 
					/* LTC2974 and LTC2978 */
 | 
				
			||||||
#define LTC2978_MFR_VOUT_MIN		0xfb
 | 
					#define LTC2978_MFR_VOUT_MIN		0xfb
 | 
				
			||||||
#define LTC2978_MFR_VIN_MIN		0xfc
 | 
					#define LTC2978_MFR_VIN_MIN		0xfc
 | 
				
			||||||
#define LTC2978_MFR_TEMPERATURE_MIN	0xfd
 | 
					#define LTC2978_MFR_TEMPERATURE_MIN	0xfd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* LTC3880 only */
 | 
					/* LTC2974 only */
 | 
				
			||||||
 | 
					#define LTC2974_MFR_IOUT_PEAK		0xd7
 | 
				
			||||||
 | 
					#define LTC2974_MFR_IOUT_MIN		0xd8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* LTC3880 and LTC3883 */
 | 
				
			||||||
#define LTC3880_MFR_IOUT_PEAK		0xd7
 | 
					#define LTC3880_MFR_IOUT_PEAK		0xd7
 | 
				
			||||||
#define LTC3880_MFR_CLEAR_PEAKS		0xe3
 | 
					#define LTC3880_MFR_CLEAR_PEAKS		0xe3
 | 
				
			||||||
#define LTC3880_MFR_TEMPERATURE2_PEAK	0xf4
 | 
					#define LTC3880_MFR_TEMPERATURE2_PEAK	0xf4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* LTC3883 only */
 | 
				
			||||||
 | 
					#define LTC3883_MFR_IIN_PEAK		0xe1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LTC2974_ID			0x0212
 | 
				
			||||||
#define LTC2978_ID_REV1			0x0121
 | 
					#define LTC2978_ID_REV1			0x0121
 | 
				
			||||||
#define LTC2978_ID_REV2			0x0122
 | 
					#define LTC2978_ID_REV2			0x0122
 | 
				
			||||||
#define LTC3880_ID			0x4000
 | 
					#define LTC3880_ID			0x4000
 | 
				
			||||||
#define LTC3880_ID_MASK			0xff00
 | 
					#define LTC3880_ID_MASK			0xff00
 | 
				
			||||||
 | 
					#define LTC3883_ID			0x4300
 | 
				
			||||||
 | 
					#define LTC3883_ID_MASK			0xff00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LTC2974_NUM_PAGES		4
 | 
				
			||||||
 | 
					#define LTC2978_NUM_PAGES		8
 | 
				
			||||||
 | 
					#define LTC3880_NUM_PAGES		2
 | 
				
			||||||
 | 
					#define LTC3883_NUM_PAGES		1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
 | 
					 * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
 | 
				
			||||||
| 
						 | 
					@ -56,13 +72,15 @@ enum chips { ltc2978, ltc3880 };
 | 
				
			||||||
 * internal cache of measured peak data, which is only cleared if an explicit
 | 
					 * internal cache of measured peak data, which is only cleared if an explicit
 | 
				
			||||||
 * "clear peak" command is executed for the sensor in question.
 | 
					 * "clear peak" command is executed for the sensor in question.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ltc2978_data {
 | 
					struct ltc2978_data {
 | 
				
			||||||
	enum chips id;
 | 
						enum chips id;
 | 
				
			||||||
	int vin_min, vin_max;
 | 
						u16 vin_min, vin_max;
 | 
				
			||||||
	int temp_min, temp_max[2];
 | 
						u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES];
 | 
				
			||||||
	int vout_min[8], vout_max[8];
 | 
						u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES];
 | 
				
			||||||
	int iout_max[2];
 | 
						u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES];
 | 
				
			||||||
	int temp2_max;
 | 
						u16 iin_max;
 | 
				
			||||||
 | 
						u16 temp2_max;
 | 
				
			||||||
	struct pmbus_driver_info info;
 | 
						struct pmbus_driver_info info;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -167,9 +185,9 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
					   LTC2978_MFR_TEMPERATURE_MIN);
 | 
										   LTC2978_MFR_TEMPERATURE_MIN);
 | 
				
			||||||
		if (ret >= 0) {
 | 
							if (ret >= 0) {
 | 
				
			||||||
			if (lin11_to_val(ret)
 | 
								if (lin11_to_val(ret)
 | 
				
			||||||
			    < lin11_to_val(data->temp_min))
 | 
								    < lin11_to_val(data->temp_min[page]))
 | 
				
			||||||
				data->temp_min = ret;
 | 
									data->temp_min[page] = ret;
 | 
				
			||||||
			ret = data->temp_min;
 | 
								ret = data->temp_min[page];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PMBUS_VIRT_READ_IOUT_MAX:
 | 
						case PMBUS_VIRT_READ_IOUT_MAX:
 | 
				
			||||||
| 
						 | 
					@ -185,6 +203,41 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 | 
				
			||||||
 | 
						struct ltc2978_data *data = to_ltc2978_data(info);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (reg) {
 | 
				
			||||||
 | 
						case PMBUS_VIRT_READ_IOUT_MAX:
 | 
				
			||||||
 | 
							ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_PEAK);
 | 
				
			||||||
 | 
							if (ret >= 0) {
 | 
				
			||||||
 | 
								if (lin11_to_val(ret)
 | 
				
			||||||
 | 
								    > lin11_to_val(data->iout_max[page]))
 | 
				
			||||||
 | 
									data->iout_max[page] = ret;
 | 
				
			||||||
 | 
								ret = data->iout_max[page];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PMBUS_VIRT_READ_IOUT_MIN:
 | 
				
			||||||
 | 
							ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_MIN);
 | 
				
			||||||
 | 
							if (ret >= 0) {
 | 
				
			||||||
 | 
								if (lin11_to_val(ret)
 | 
				
			||||||
 | 
								    < lin11_to_val(data->iout_min[page]))
 | 
				
			||||||
 | 
									data->iout_min[page] = ret;
 | 
				
			||||||
 | 
								ret = data->iout_min[page];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PMBUS_VIRT_RESET_IOUT_HISTORY:
 | 
				
			||||||
 | 
							ret = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ret = ltc2978_read_word_data(client, page, reg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
 | 
					static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 | 
						const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 | 
				
			||||||
| 
						 | 
					@ -226,15 +279,41 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 | 
				
			||||||
 | 
						struct ltc2978_data *data = to_ltc2978_data(info);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (reg) {
 | 
				
			||||||
 | 
						case PMBUS_VIRT_READ_IIN_MAX:
 | 
				
			||||||
 | 
							ret = pmbus_read_word_data(client, page, LTC3883_MFR_IIN_PEAK);
 | 
				
			||||||
 | 
							if (ret >= 0) {
 | 
				
			||||||
 | 
								if (lin11_to_val(ret)
 | 
				
			||||||
 | 
								    > lin11_to_val(data->iin_max))
 | 
				
			||||||
 | 
									data->iin_max = ret;
 | 
				
			||||||
 | 
								ret = data->iin_max;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PMBUS_VIRT_RESET_IIN_HISTORY:
 | 
				
			||||||
 | 
							ret = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ret = ltc3880_read_word_data(client, page, reg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ltc2978_clear_peaks(struct i2c_client *client, int page,
 | 
					static int ltc2978_clear_peaks(struct i2c_client *client, int page,
 | 
				
			||||||
			       enum chips id)
 | 
								       enum chips id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (id == ltc2978)
 | 
						if (id == ltc3880 || id == ltc3883)
 | 
				
			||||||
		ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
 | 
							ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -247,8 +326,13 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (reg) {
 | 
						switch (reg) {
 | 
				
			||||||
 | 
						case PMBUS_VIRT_RESET_IIN_HISTORY:
 | 
				
			||||||
 | 
							data->iin_max = 0x7c00;
 | 
				
			||||||
 | 
							ret = ltc2978_clear_peaks(client, page, data->id);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	case PMBUS_VIRT_RESET_IOUT_HISTORY:
 | 
						case PMBUS_VIRT_RESET_IOUT_HISTORY:
 | 
				
			||||||
		data->iout_max[page] = 0x7c00;
 | 
							data->iout_max[page] = 0x7c00;
 | 
				
			||||||
 | 
							data->iout_min[page] = 0xfbff;
 | 
				
			||||||
		ret = ltc2978_clear_peaks(client, page, data->id);
 | 
							ret = ltc2978_clear_peaks(client, page, data->id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
 | 
						case PMBUS_VIRT_RESET_TEMP2_HISTORY:
 | 
				
			||||||
| 
						 | 
					@ -266,7 +350,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
 | 
				
			||||||
		ret = ltc2978_clear_peaks(client, page, data->id);
 | 
							ret = ltc2978_clear_peaks(client, page, data->id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PMBUS_VIRT_RESET_TEMP_HISTORY:
 | 
						case PMBUS_VIRT_RESET_TEMP_HISTORY:
 | 
				
			||||||
		data->temp_min = 0x7bff;
 | 
							data->temp_min[page] = 0x7bff;
 | 
				
			||||||
		data->temp_max[page] = 0x7c00;
 | 
							data->temp_max[page] = 0x7c00;
 | 
				
			||||||
		ret = ltc2978_clear_peaks(client, page, data->id);
 | 
							ret = ltc2978_clear_peaks(client, page, data->id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -278,8 +362,10 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct i2c_device_id ltc2978_id[] = {
 | 
					static const struct i2c_device_id ltc2978_id[] = {
 | 
				
			||||||
 | 
						{"ltc2974", ltc2974},
 | 
				
			||||||
	{"ltc2978", ltc2978},
 | 
						{"ltc2978", ltc2978},
 | 
				
			||||||
	{"ltc3880", ltc3880},
 | 
						{"ltc3880", ltc3880},
 | 
				
			||||||
 | 
						{"ltc3883", ltc3883},
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
 | 
					MODULE_DEVICE_TABLE(i2c, ltc2978_id);
 | 
				
			||||||
| 
						 | 
					@ -304,10 +390,14 @@ static int ltc2978_probe(struct i2c_client *client,
 | 
				
			||||||
	if (chip_id < 0)
 | 
						if (chip_id < 0)
 | 
				
			||||||
		return chip_id;
 | 
							return chip_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
 | 
						if (chip_id == LTC2974_ID) {
 | 
				
			||||||
 | 
							data->id = ltc2974;
 | 
				
			||||||
 | 
						} else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
 | 
				
			||||||
		data->id = ltc2978;
 | 
							data->id = ltc2978;
 | 
				
			||||||
	} else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
 | 
						} else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
 | 
				
			||||||
		data->id = ltc3880;
 | 
							data->id = ltc3880;
 | 
				
			||||||
 | 
						} else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
 | 
				
			||||||
 | 
							data->id = ltc3883;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
 | 
							dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
| 
						 | 
					@ -323,26 +413,45 @@ static int ltc2978_probe(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->vin_min = 0x7bff;
 | 
						data->vin_min = 0x7bff;
 | 
				
			||||||
	data->vin_max = 0x7c00;
 | 
						data->vin_max = 0x7c00;
 | 
				
			||||||
	data->temp_min = 0x7bff;
 | 
						for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
 | 
				
			||||||
 | 
							data->vout_min[i] = 0xffff;
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(data->iout_min); i++)
 | 
				
			||||||
 | 
							data->iout_min[i] = 0xfbff;
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(data->iout_max); i++)
 | 
				
			||||||
 | 
							data->iout_max[i] = 0x7c00;
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(data->temp_min); i++)
 | 
				
			||||||
 | 
							data->temp_min[i] = 0x7bff;
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
 | 
						for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
 | 
				
			||||||
		data->temp_max[i] = 0x7c00;
 | 
							data->temp_max[i] = 0x7c00;
 | 
				
			||||||
	data->temp2_max = 0x7c00;
 | 
						data->temp2_max = 0x7c00;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (data->id) {
 | 
						switch (data->id) {
 | 
				
			||||||
 | 
						case ltc2974:
 | 
				
			||||||
 | 
							info->read_word_data = ltc2974_read_word_data;
 | 
				
			||||||
 | 
							info->pages = LTC2974_NUM_PAGES;
 | 
				
			||||||
 | 
							info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
 | 
				
			||||||
 | 
							  | PMBUS_HAVE_TEMP2;
 | 
				
			||||||
 | 
							for (i = 0; i < info->pages; i++) {
 | 
				
			||||||
 | 
								info->func[i] |= PMBUS_HAVE_VOUT
 | 
				
			||||||
 | 
								  | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
 | 
				
			||||||
 | 
								  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
 | 
				
			||||||
 | 
								  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	case ltc2978:
 | 
						case ltc2978:
 | 
				
			||||||
		info->read_word_data = ltc2978_read_word_data;
 | 
							info->read_word_data = ltc2978_read_word_data;
 | 
				
			||||||
		info->pages = 8;
 | 
							info->pages = LTC2978_NUM_PAGES;
 | 
				
			||||||
		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
 | 
							info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
 | 
				
			||||||
		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
 | 
							  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
 | 
				
			||||||
		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 | 
							  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 | 
				
			||||||
		for (i = 1; i < 8; i++) {
 | 
							for (i = 1; i < LTC2978_NUM_PAGES; i++) {
 | 
				
			||||||
			info->func[i] = PMBUS_HAVE_VOUT
 | 
								info->func[i] = PMBUS_HAVE_VOUT
 | 
				
			||||||
			  | PMBUS_HAVE_STATUS_VOUT;
 | 
								  | PMBUS_HAVE_STATUS_VOUT;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case ltc3880:
 | 
						case ltc3880:
 | 
				
			||||||
		info->read_word_data = ltc3880_read_word_data;
 | 
							info->read_word_data = ltc3880_read_word_data;
 | 
				
			||||||
		info->pages = 2;
 | 
							info->pages = LTC3880_NUM_PAGES;
 | 
				
			||||||
		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
 | 
							info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
 | 
				
			||||||
		  | PMBUS_HAVE_STATUS_INPUT
 | 
							  | PMBUS_HAVE_STATUS_INPUT
 | 
				
			||||||
		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
 | 
							  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
 | 
				
			||||||
| 
						 | 
					@ -353,15 +462,20 @@ static int ltc2978_probe(struct i2c_client *client,
 | 
				
			||||||
		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
 | 
							  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
 | 
				
			||||||
		  | PMBUS_HAVE_POUT
 | 
							  | PMBUS_HAVE_POUT
 | 
				
			||||||
		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 | 
							  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 | 
				
			||||||
		data->iout_max[0] = 0x7c00;
 | 
							break;
 | 
				
			||||||
		data->iout_max[1] = 0x7c00;
 | 
						case ltc3883:
 | 
				
			||||||
 | 
							info->read_word_data = ltc3883_read_word_data;
 | 
				
			||||||
 | 
							info->pages = LTC3883_NUM_PAGES;
 | 
				
			||||||
 | 
							info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
 | 
				
			||||||
 | 
							  | PMBUS_HAVE_STATUS_INPUT
 | 
				
			||||||
 | 
							  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
 | 
				
			||||||
 | 
							  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
 | 
				
			||||||
 | 
							  | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
 | 
				
			||||||
 | 
							  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (i = 0; i < info->pages; i++)
 | 
					 | 
				
			||||||
		data->vout_min[i] = 0xffff;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return pmbus_do_probe(client, id, info);
 | 
						return pmbus_do_probe(client, id, info);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -378,5 +492,5 @@ static struct i2c_driver ltc2978_driver = {
 | 
				
			||||||
module_i2c_driver(ltc2978_driver);
 | 
					module_i2c_driver(ltc2978_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_AUTHOR("Guenter Roeck");
 | 
					MODULE_AUTHOR("Guenter Roeck");
 | 
				
			||||||
MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880");
 | 
					MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883");
 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,17 +107,14 @@ static ssize_t s3c_hwmon_show_raw(struct device *dev,
 | 
				
			||||||
	return  (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret);
 | 
						return  (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DEF_ADC_ATTR(x)	\
 | 
					static SENSOR_DEVICE_ATTR(adc0_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 0);
 | 
				
			||||||
	static SENSOR_DEVICE_ATTR(adc##x##_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, x)
 | 
					static SENSOR_DEVICE_ATTR(adc1_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(adc2_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 2);
 | 
				
			||||||
DEF_ADC_ATTR(0);
 | 
					static SENSOR_DEVICE_ATTR(adc3_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 3);
 | 
				
			||||||
DEF_ADC_ATTR(1);
 | 
					static SENSOR_DEVICE_ATTR(adc4_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 4);
 | 
				
			||||||
DEF_ADC_ATTR(2);
 | 
					static SENSOR_DEVICE_ATTR(adc5_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 5);
 | 
				
			||||||
DEF_ADC_ATTR(3);
 | 
					static SENSOR_DEVICE_ATTR(adc6_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 6);
 | 
				
			||||||
DEF_ADC_ATTR(4);
 | 
					static SENSOR_DEVICE_ATTR(adc7_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 7);
 | 
				
			||||||
DEF_ADC_ATTR(5);
 | 
					 | 
				
			||||||
DEF_ADC_ATTR(6);
 | 
					 | 
				
			||||||
DEF_ADC_ATTR(7);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct attribute *s3c_hwmon_attrs[9] = {
 | 
					static struct attribute *s3c_hwmon_attrs[9] = {
 | 
				
			||||||
	&sensor_dev_attr_adc0_raw.dev_attr.attr,
 | 
						&sensor_dev_attr_adc0_raw.dev_attr.attr,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,8 +161,8 @@ static int sch56xx_send_cmd(u16 addr, u8 cmd, u16 reg, u8 v)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (i == max_busy_polls + max_lazy_polls) {
 | 
						if (i == max_busy_polls + max_lazy_polls) {
 | 
				
			||||||
		pr_err("Max retries exceeded reading virtual "
 | 
							pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
 | 
				
			||||||
		       "register 0x%04hx (%d)\n", reg, 1);
 | 
							       reg, 1);
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -178,12 +178,12 @@ static int sch56xx_send_cmd(u16 addr, u8 cmd, u16 reg, u8 v)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (i == 0)
 | 
							if (i == 0)
 | 
				
			||||||
			pr_warn("EC reports: 0x%02x reading virtual register "
 | 
								pr_warn("EC reports: 0x%02x reading virtual register 0x%04hx\n",
 | 
				
			||||||
				"0x%04hx\n", (unsigned int)val, reg);
 | 
									(unsigned int)val, reg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (i == max_busy_polls) {
 | 
						if (i == max_busy_polls) {
 | 
				
			||||||
		pr_err("Max retries exceeded reading virtual "
 | 
							pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
 | 
				
			||||||
		       "register 0x%04hx (%d)\n", reg, 2);
 | 
							       reg, 2);
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -456,8 +456,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
 | 
				
			||||||
		data->fan_div[nr] = 3;
 | 
							data->fan_div[nr] = 3;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		dev_err(dev, "fan_div value %ld not "
 | 
							dev_err(dev,
 | 
				
			||||||
			"supported. Choose one of 1, 2, 4 or 8!\n", val);
 | 
								"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
 | 
				
			||||||
 | 
								val);
 | 
				
			||||||
		mutex_unlock(&data->update_lock);
 | 
							mutex_unlock(&data->update_lock);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,8 +41,8 @@ enum chips { thmc50, adm1022 };
 | 
				
			||||||
static unsigned short adm1022_temp3[16];
 | 
					static unsigned short adm1022_temp3[16];
 | 
				
			||||||
static unsigned int adm1022_temp3_num;
 | 
					static unsigned int adm1022_temp3_num;
 | 
				
			||||||
module_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0);
 | 
					module_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0);
 | 
				
			||||||
MODULE_PARM_DESC(adm1022_temp3, "List of adapter,address pairs "
 | 
					MODULE_PARM_DESC(adm1022_temp3,
 | 
				
			||||||
			"to enable 3rd temperature (ADM1022 only)");
 | 
							 "List of adapter,address pairs to enable 3rd temperature (ADM1022 only)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Many THMC50 constants specified below */
 | 
					/* Many THMC50 constants specified below */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -312,8 +312,7 @@ static int thmc50_detect(struct i2c_client *client,
 | 
				
			||||||
	const char *type_name;
 | 
						const char *type_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 | 
						if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 | 
				
			||||||
		pr_debug("thmc50: detect failed, "
 | 
							pr_debug("thmc50: detect failed, smbus byte data not supported!\n");
 | 
				
			||||||
			 "smbus byte data not supported!\n");
 | 
					 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -155,8 +155,8 @@ static int tmp102_probe(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!i2c_check_functionality(client->adapter,
 | 
						if (!i2c_check_functionality(client->adapter,
 | 
				
			||||||
				     I2C_FUNC_SMBUS_WORD_DATA)) {
 | 
									     I2C_FUNC_SMBUS_WORD_DATA)) {
 | 
				
			||||||
		dev_err(&client->dev, "adapter doesn't support SMBus word "
 | 
							dev_err(&client->dev,
 | 
				
			||||||
			"transactions\n");
 | 
								"adapter doesn't support SMBus word transactions\n");
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,9 @@
 | 
				
			||||||
 * Gabriel Konat, Sander Leget, Wouter Willems
 | 
					 * Gabriel Konat, Sander Leget, Wouter Willems
 | 
				
			||||||
 * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
 | 
					 * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * Cleanup and support for TMP431 and TMP432 by Guenter Roeck
 | 
				
			||||||
 | 
					 * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 * it under the terms of the GNU General Public License as published by
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
| 
						 | 
					@ -30,6 +33,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/init.h>
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/bitops.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/jiffies.h>
 | 
					#include <linux/jiffies.h>
 | 
				
			||||||
#include <linux/i2c.h>
 | 
					#include <linux/i2c.h>
 | 
				
			||||||
| 
						 | 
					@ -40,9 +44,9 @@
 | 
				
			||||||
#include <linux/sysfs.h>
 | 
					#include <linux/sysfs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Addresses to scan */
 | 
					/* Addresses to scan */
 | 
				
			||||||
static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
 | 
					static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum chips { tmp401, tmp411 };
 | 
					enum chips { tmp401, tmp411, tmp431, tmp432 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The TMP401 registers, note some registers have different addresses for
 | 
					 * The TMP401 registers, note some registers have different addresses for
 | 
				
			||||||
| 
						 | 
					@ -54,42 +58,84 @@ enum chips { tmp401, tmp411 };
 | 
				
			||||||
#define TMP401_CONVERSION_RATE_READ		0x04
 | 
					#define TMP401_CONVERSION_RATE_READ		0x04
 | 
				
			||||||
#define TMP401_CONVERSION_RATE_WRITE		0x0A
 | 
					#define TMP401_CONVERSION_RATE_WRITE		0x0A
 | 
				
			||||||
#define TMP401_TEMP_CRIT_HYST			0x21
 | 
					#define TMP401_TEMP_CRIT_HYST			0x21
 | 
				
			||||||
#define TMP401_CONSECUTIVE_ALERT		0x22
 | 
					 | 
				
			||||||
#define TMP401_MANUFACTURER_ID_REG		0xFE
 | 
					#define TMP401_MANUFACTURER_ID_REG		0xFE
 | 
				
			||||||
#define TMP401_DEVICE_ID_REG			0xFF
 | 
					#define TMP401_DEVICE_ID_REG			0xFF
 | 
				
			||||||
#define TMP411_N_FACTOR_REG			0x18
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const u8 TMP401_TEMP_MSB[2]			= { 0x00, 0x01 };
 | 
					static const u8 TMP401_TEMP_MSB_READ[6][2] = {
 | 
				
			||||||
static const u8 TMP401_TEMP_LSB[2]			= { 0x15, 0x10 };
 | 
						{ 0x00, 0x01 },	/* temp */
 | 
				
			||||||
static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2]	= { 0x06, 0x08 };
 | 
						{ 0x06, 0x08 },	/* low limit */
 | 
				
			||||||
static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2]	= { 0x0C, 0x0E };
 | 
						{ 0x05, 0x07 },	/* high limit */
 | 
				
			||||||
static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2]		= { 0x17, 0x14 };
 | 
						{ 0x20, 0x19 },	/* therm (crit) limit */
 | 
				
			||||||
static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2]	= { 0x05, 0x07 };
 | 
						{ 0x30, 0x34 },	/* lowest */
 | 
				
			||||||
static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2]	= { 0x0B, 0x0D };
 | 
						{ 0x32, 0x36 },	/* highest */
 | 
				
			||||||
static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2]		= { 0x16, 0x13 };
 | 
					};
 | 
				
			||||||
/* These are called the THERM limit / hysteresis / mask in the datasheet */
 | 
					 | 
				
			||||||
static const u8 TMP401_TEMP_CRIT_LIMIT[2]		= { 0x20, 0x19 };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const u8 TMP411_TEMP_LOWEST_MSB[2]		= { 0x30, 0x34 };
 | 
					static const u8 TMP401_TEMP_MSB_WRITE[6][2] = {
 | 
				
			||||||
static const u8 TMP411_TEMP_LOWEST_LSB[2]		= { 0x31, 0x35 };
 | 
						{ 0, 0 },	/* temp (unused) */
 | 
				
			||||||
static const u8 TMP411_TEMP_HIGHEST_MSB[2]		= { 0x32, 0x36 };
 | 
						{ 0x0C, 0x0E },	/* low limit */
 | 
				
			||||||
static const u8 TMP411_TEMP_HIGHEST_LSB[2]		= { 0x33, 0x37 };
 | 
						{ 0x0B, 0x0D },	/* high limit */
 | 
				
			||||||
 | 
						{ 0x20, 0x19 },	/* therm (crit) limit */
 | 
				
			||||||
 | 
						{ 0x30, 0x34 },	/* lowest */
 | 
				
			||||||
 | 
						{ 0x32, 0x36 },	/* highest */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const u8 TMP401_TEMP_LSB[6][2] = {
 | 
				
			||||||
 | 
						{ 0x15, 0x10 },	/* temp */
 | 
				
			||||||
 | 
						{ 0x17, 0x14 },	/* low limit */
 | 
				
			||||||
 | 
						{ 0x16, 0x13 },	/* high limit */
 | 
				
			||||||
 | 
						{ 0, 0 },	/* therm (crit) limit (unused) */
 | 
				
			||||||
 | 
						{ 0x31, 0x35 },	/* lowest */
 | 
				
			||||||
 | 
						{ 0x33, 0x37 },	/* highest */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const u8 TMP432_TEMP_MSB_READ[4][3] = {
 | 
				
			||||||
 | 
						{ 0x00, 0x01, 0x23 },	/* temp */
 | 
				
			||||||
 | 
						{ 0x06, 0x08, 0x16 },	/* low limit */
 | 
				
			||||||
 | 
						{ 0x05, 0x07, 0x15 },	/* high limit */
 | 
				
			||||||
 | 
						{ 0x20, 0x19, 0x1A },	/* therm (crit) limit */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const u8 TMP432_TEMP_MSB_WRITE[4][3] = {
 | 
				
			||||||
 | 
						{ 0, 0, 0 },		/* temp  - unused */
 | 
				
			||||||
 | 
						{ 0x0C, 0x0E, 0x16 },	/* low limit */
 | 
				
			||||||
 | 
						{ 0x0B, 0x0D, 0x15 },	/* high limit */
 | 
				
			||||||
 | 
						{ 0x20, 0x19, 0x1A },	/* therm (crit) limit */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const u8 TMP432_TEMP_LSB[3][3] = {
 | 
				
			||||||
 | 
						{ 0x29, 0x10, 0x24 },	/* temp */
 | 
				
			||||||
 | 
						{ 0x3E, 0x14, 0x18 },	/* low limit */
 | 
				
			||||||
 | 
						{ 0x3D, 0x13, 0x17 },	/* high limit */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */
 | 
				
			||||||
 | 
					static const u8 TMP432_STATUS_REG[] = {
 | 
				
			||||||
 | 
						0x1b, 0x36, 0x35, 0x37 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Flags */
 | 
					/* Flags */
 | 
				
			||||||
#define TMP401_CONFIG_RANGE		0x04
 | 
					#define TMP401_CONFIG_RANGE			BIT(2)
 | 
				
			||||||
#define TMP401_CONFIG_SHUTDOWN		0x40
 | 
					#define TMP401_CONFIG_SHUTDOWN			BIT(6)
 | 
				
			||||||
#define TMP401_STATUS_LOCAL_CRIT		0x01
 | 
					#define TMP401_STATUS_LOCAL_CRIT		BIT(0)
 | 
				
			||||||
#define TMP401_STATUS_REMOTE_CRIT		0x02
 | 
					#define TMP401_STATUS_REMOTE_CRIT		BIT(1)
 | 
				
			||||||
#define TMP401_STATUS_REMOTE_OPEN		0x04
 | 
					#define TMP401_STATUS_REMOTE_OPEN		BIT(2)
 | 
				
			||||||
#define TMP401_STATUS_REMOTE_LOW		0x08
 | 
					#define TMP401_STATUS_REMOTE_LOW		BIT(3)
 | 
				
			||||||
#define TMP401_STATUS_REMOTE_HIGH		0x10
 | 
					#define TMP401_STATUS_REMOTE_HIGH		BIT(4)
 | 
				
			||||||
#define TMP401_STATUS_LOCAL_LOW		0x20
 | 
					#define TMP401_STATUS_LOCAL_LOW			BIT(5)
 | 
				
			||||||
#define TMP401_STATUS_LOCAL_HIGH		0x40
 | 
					#define TMP401_STATUS_LOCAL_HIGH		BIT(6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* On TMP432, each status has its own register */
 | 
				
			||||||
 | 
					#define TMP432_STATUS_LOCAL			BIT(0)
 | 
				
			||||||
 | 
					#define TMP432_STATUS_REMOTE1			BIT(1)
 | 
				
			||||||
 | 
					#define TMP432_STATUS_REMOTE2			BIT(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Manufacturer / Device ID's */
 | 
					/* Manufacturer / Device ID's */
 | 
				
			||||||
#define TMP401_MANUFACTURER_ID			0x55
 | 
					#define TMP401_MANUFACTURER_ID			0x55
 | 
				
			||||||
#define TMP401_DEVICE_ID			0x11
 | 
					#define TMP401_DEVICE_ID			0x11
 | 
				
			||||||
#define TMP411_DEVICE_ID			0x12
 | 
					#define TMP411A_DEVICE_ID			0x12
 | 
				
			||||||
 | 
					#define TMP411B_DEVICE_ID			0x13
 | 
				
			||||||
 | 
					#define TMP411C_DEVICE_ID			0x10
 | 
				
			||||||
 | 
					#define TMP431_DEVICE_ID			0x31
 | 
				
			||||||
 | 
					#define TMP432_DEVICE_ID			0x32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Driver data (common to all clients)
 | 
					 * Driver data (common to all clients)
 | 
				
			||||||
| 
						 | 
					@ -98,6 +144,8 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2]		= { 0x33, 0x37 };
 | 
				
			||||||
static const struct i2c_device_id tmp401_id[] = {
 | 
					static const struct i2c_device_id tmp401_id[] = {
 | 
				
			||||||
	{ "tmp401", tmp401 },
 | 
						{ "tmp401", tmp401 },
 | 
				
			||||||
	{ "tmp411", tmp411 },
 | 
						{ "tmp411", tmp411 },
 | 
				
			||||||
 | 
						{ "tmp431", tmp431 },
 | 
				
			||||||
 | 
						{ "tmp432", tmp432 },
 | 
				
			||||||
	{ }
 | 
						{ }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MODULE_DEVICE_TABLE(i2c, tmp401_id);
 | 
					MODULE_DEVICE_TABLE(i2c, tmp401_id);
 | 
				
			||||||
| 
						 | 
					@ -113,16 +161,13 @@ struct tmp401_data {
 | 
				
			||||||
	unsigned long last_updated; /* in jiffies */
 | 
						unsigned long last_updated; /* in jiffies */
 | 
				
			||||||
	enum chips kind;
 | 
						enum chips kind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned int update_interval;	/* in milliseconds */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* register values */
 | 
						/* register values */
 | 
				
			||||||
	u8 status;
 | 
						u8 status[4];
 | 
				
			||||||
	u8 config;
 | 
						u8 config;
 | 
				
			||||||
	u16 temp[2];
 | 
						u16 temp[6][3];
 | 
				
			||||||
	u16 temp_low[2];
 | 
					 | 
				
			||||||
	u16 temp_high[2];
 | 
					 | 
				
			||||||
	u8 temp_crit[2];
 | 
					 | 
				
			||||||
	u8 temp_crit_hyst;
 | 
						u8 temp_crit_hyst;
 | 
				
			||||||
	u16 temp_lowest[2];
 | 
					 | 
				
			||||||
	u16 temp_highest[2];
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -136,10 +181,10 @@ static int tmp401_register_to_temp(u16 reg, u8 config)
 | 
				
			||||||
	if (config & TMP401_CONFIG_RANGE)
 | 
						if (config & TMP401_CONFIG_RANGE)
 | 
				
			||||||
		temp -= 64 * 256;
 | 
							temp -= 64 * 256;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (temp * 625 + 80) / 160;
 | 
						return DIV_ROUND_CLOSEST(temp * 125, 32);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u16 tmp401_temp_to_register(long temp, u8 config)
 | 
					static u16 tmp401_temp_to_register(long temp, u8 config, int zbits)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (config & TMP401_CONFIG_RANGE) {
 | 
						if (config & TMP401_CONFIG_RANGE) {
 | 
				
			||||||
		temp = clamp_val(temp, -64000, 191000);
 | 
							temp = clamp_val(temp, -64000, 191000);
 | 
				
			||||||
| 
						 | 
					@ -147,134 +192,127 @@ static u16 tmp401_temp_to_register(long temp, u8 config)
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		temp = clamp_val(temp, 0, 127000);
 | 
							temp = clamp_val(temp, 0, 127000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (temp * 160 + 312) / 625;
 | 
						return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tmp401_crit_register_to_temp(u8 reg, u8 config)
 | 
					static int tmp401_update_device_reg16(struct i2c_client *client,
 | 
				
			||||||
 | 
									      struct tmp401_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int temp = reg;
 | 
						int i, j, val;
 | 
				
			||||||
 | 
						int num_regs = data->kind == tmp411 ? 6 : 4;
 | 
				
			||||||
 | 
						int num_sensors = data->kind == tmp432 ? 3 : 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (config & TMP401_CONFIG_RANGE)
 | 
						for (i = 0; i < num_sensors; i++) {		/* local / r1 / r2 */
 | 
				
			||||||
		temp -= 64;
 | 
							for (j = 0; j < num_regs; j++) {	/* temp / low / ... */
 | 
				
			||||||
 | 
								u8 regaddr;
 | 
				
			||||||
	return temp * 1000;
 | 
								/*
 | 
				
			||||||
}
 | 
								 * High byte must be read first immediately followed
 | 
				
			||||||
 | 
								 * by the low byte
 | 
				
			||||||
static u8 tmp401_crit_temp_to_register(long temp, u8 config)
 | 
								 */
 | 
				
			||||||
{
 | 
								regaddr = data->kind == tmp432 ?
 | 
				
			||||||
	if (config & TMP401_CONFIG_RANGE) {
 | 
											TMP432_TEMP_MSB_READ[j][i] :
 | 
				
			||||||
		temp = clamp_val(temp, -64000, 191000);
 | 
											TMP401_TEMP_MSB_READ[j][i];
 | 
				
			||||||
		temp += 64000;
 | 
								val = i2c_smbus_read_byte_data(client, regaddr);
 | 
				
			||||||
	} else
 | 
								if (val < 0)
 | 
				
			||||||
		temp = clamp_val(temp, 0, 127000);
 | 
									return val;
 | 
				
			||||||
 | 
								data->temp[j][i] = val << 8;
 | 
				
			||||||
	return (temp + 500) / 1000;
 | 
								if (j == 3)		/* crit is msb only */
 | 
				
			||||||
}
 | 
									continue;
 | 
				
			||||||
 | 
								regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i]
 | 
				
			||||||
static struct tmp401_data *tmp401_update_device_reg16(
 | 
											       : TMP401_TEMP_LSB[j][i];
 | 
				
			||||||
	struct i2c_client *client, struct tmp401_data *data)
 | 
								val = i2c_smbus_read_byte_data(client, regaddr);
 | 
				
			||||||
{
 | 
								if (val < 0)
 | 
				
			||||||
	int i;
 | 
									return val;
 | 
				
			||||||
 | 
								data->temp[j][i] |= val;
 | 
				
			||||||
	for (i = 0; i < 2; i++) {
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * High byte must be read first immediately followed
 | 
					 | 
				
			||||||
		 * by the low byte
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		data->temp[i] = i2c_smbus_read_byte_data(client,
 | 
					 | 
				
			||||||
			TMP401_TEMP_MSB[i]) << 8;
 | 
					 | 
				
			||||||
		data->temp[i] |= i2c_smbus_read_byte_data(client,
 | 
					 | 
				
			||||||
			TMP401_TEMP_LSB[i]);
 | 
					 | 
				
			||||||
		data->temp_low[i] = i2c_smbus_read_byte_data(client,
 | 
					 | 
				
			||||||
			TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
 | 
					 | 
				
			||||||
		data->temp_low[i] |= i2c_smbus_read_byte_data(client,
 | 
					 | 
				
			||||||
			TMP401_TEMP_LOW_LIMIT_LSB[i]);
 | 
					 | 
				
			||||||
		data->temp_high[i] = i2c_smbus_read_byte_data(client,
 | 
					 | 
				
			||||||
			TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
 | 
					 | 
				
			||||||
		data->temp_high[i] |= i2c_smbus_read_byte_data(client,
 | 
					 | 
				
			||||||
			TMP401_TEMP_HIGH_LIMIT_LSB[i]);
 | 
					 | 
				
			||||||
		data->temp_crit[i] = i2c_smbus_read_byte_data(client,
 | 
					 | 
				
			||||||
			TMP401_TEMP_CRIT_LIMIT[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (data->kind == tmp411) {
 | 
					 | 
				
			||||||
			data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
 | 
					 | 
				
			||||||
				TMP411_TEMP_LOWEST_MSB[i]) << 8;
 | 
					 | 
				
			||||||
			data->temp_lowest[i] |= i2c_smbus_read_byte_data(
 | 
					 | 
				
			||||||
				client, TMP411_TEMP_LOWEST_LSB[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			data->temp_highest[i] = i2c_smbus_read_byte_data(
 | 
					 | 
				
			||||||
				client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
 | 
					 | 
				
			||||||
			data->temp_highest[i] |= i2c_smbus_read_byte_data(
 | 
					 | 
				
			||||||
				client, TMP411_TEMP_HIGHEST_LSB[i]);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return data;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct tmp401_data *tmp401_update_device(struct device *dev)
 | 
					static struct tmp401_data *tmp401_update_device(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(dev);
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
	struct tmp401_data *data = i2c_get_clientdata(client);
 | 
						struct tmp401_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						struct tmp401_data *ret = data;
 | 
				
			||||||
 | 
						int i, val;
 | 
				
			||||||
 | 
						unsigned long next_update;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 | 
						next_update = data->last_updated +
 | 
				
			||||||
		data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
 | 
							      msecs_to_jiffies(data->update_interval) + 1;
 | 
				
			||||||
		data->config = i2c_smbus_read_byte_data(client,
 | 
						if (time_after(jiffies, next_update) || !data->valid) {
 | 
				
			||||||
						TMP401_CONFIG_READ);
 | 
							if (data->kind != tmp432) {
 | 
				
			||||||
		tmp401_update_device_reg16(client, data);
 | 
								/*
 | 
				
			||||||
 | 
								 * The driver uses the TMP432 status format internally.
 | 
				
			||||||
 | 
								 * Convert status to TMP432 format for other chips.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								val = i2c_smbus_read_byte_data(client, TMP401_STATUS);
 | 
				
			||||||
 | 
								if (val < 0) {
 | 
				
			||||||
 | 
									ret = ERR_PTR(val);
 | 
				
			||||||
 | 
									goto abort;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								data->status[0] =
 | 
				
			||||||
 | 
								  (val & TMP401_STATUS_REMOTE_OPEN) >> 1;
 | 
				
			||||||
 | 
								data->status[1] =
 | 
				
			||||||
 | 
								  ((val & TMP401_STATUS_REMOTE_LOW) >> 2) |
 | 
				
			||||||
 | 
								  ((val & TMP401_STATUS_LOCAL_LOW) >> 5);
 | 
				
			||||||
 | 
								data->status[2] =
 | 
				
			||||||
 | 
								  ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) |
 | 
				
			||||||
 | 
								  ((val & TMP401_STATUS_LOCAL_HIGH) >> 6);
 | 
				
			||||||
 | 
								data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT
 | 
				
			||||||
 | 
											| TMP401_STATUS_REMOTE_CRIT);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								for (i = 0; i < ARRAY_SIZE(data->status); i++) {
 | 
				
			||||||
 | 
									val = i2c_smbus_read_byte_data(client,
 | 
				
			||||||
 | 
												TMP432_STATUS_REG[i]);
 | 
				
			||||||
 | 
									if (val < 0) {
 | 
				
			||||||
 | 
										ret = ERR_PTR(val);
 | 
				
			||||||
 | 
										goto abort;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									data->status[i] = val;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
 | 
							val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
 | 
				
			||||||
						TMP401_TEMP_CRIT_HYST);
 | 
							if (val < 0) {
 | 
				
			||||||
 | 
								ret = ERR_PTR(val);
 | 
				
			||||||
 | 
								goto abort;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							data->config = val;
 | 
				
			||||||
 | 
							val = tmp401_update_device_reg16(client, data);
 | 
				
			||||||
 | 
							if (val < 0) {
 | 
				
			||||||
 | 
								ret = ERR_PTR(val);
 | 
				
			||||||
 | 
								goto abort;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST);
 | 
				
			||||||
 | 
							if (val < 0) {
 | 
				
			||||||
 | 
								ret = ERR_PTR(val);
 | 
				
			||||||
 | 
								goto abort;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							data->temp_crit_hyst = val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		data->last_updated = jiffies;
 | 
							data->last_updated = jiffies;
 | 
				
			||||||
		data->valid = 1;
 | 
							data->valid = 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abort:
 | 
				
			||||||
	mutex_unlock(&data->update_lock);
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
	return data;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t show_temp_value(struct device *dev,
 | 
					static ssize_t show_temp(struct device *dev,
 | 
				
			||||||
	struct device_attribute *devattr, char *buf)
 | 
								 struct device_attribute *devattr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int index = to_sensor_dev_attr(devattr)->index;
 | 
						int nr = to_sensor_dev_attr_2(devattr)->nr;
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr_2(devattr)->index;
 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
						struct tmp401_data *data = tmp401_update_device(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%d\n",
 | 
						if (IS_ERR(data))
 | 
				
			||||||
		tmp401_register_to_temp(data->temp[index], data->config));
 | 
							return PTR_ERR(data);
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t show_temp_min(struct device *dev,
 | 
					 | 
				
			||||||
	struct device_attribute *devattr, char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int index = to_sensor_dev_attr(devattr)->index;
 | 
					 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%d\n",
 | 
						return sprintf(buf, "%d\n",
 | 
				
			||||||
		tmp401_register_to_temp(data->temp_low[index], data->config));
 | 
							tmp401_register_to_temp(data->temp[nr][index], data->config));
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t show_temp_max(struct device *dev,
 | 
					 | 
				
			||||||
	struct device_attribute *devattr, char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int index = to_sensor_dev_attr(devattr)->index;
 | 
					 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sprintf(buf, "%d\n",
 | 
					 | 
				
			||||||
		tmp401_register_to_temp(data->temp_high[index], data->config));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t show_temp_crit(struct device *dev,
 | 
					 | 
				
			||||||
	struct device_attribute *devattr, char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int index = to_sensor_dev_attr(devattr)->index;
 | 
					 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sprintf(buf, "%d\n",
 | 
					 | 
				
			||||||
			tmp401_crit_register_to_temp(data->temp_crit[index],
 | 
					 | 
				
			||||||
							data->config));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t show_temp_crit_hyst(struct device *dev,
 | 
					static ssize_t show_temp_crit_hyst(struct device *dev,
 | 
				
			||||||
| 
						 | 
					@ -283,122 +321,60 @@ static ssize_t show_temp_crit_hyst(struct device *dev,
 | 
				
			||||||
	int temp, index = to_sensor_dev_attr(devattr)->index;
 | 
						int temp, index = to_sensor_dev_attr(devattr)->index;
 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
						struct tmp401_data *data = tmp401_update_device(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(data))
 | 
				
			||||||
 | 
							return PTR_ERR(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
	temp = tmp401_crit_register_to_temp(data->temp_crit[index],
 | 
						temp = tmp401_register_to_temp(data->temp[3][index], data->config);
 | 
				
			||||||
						data->config);
 | 
					 | 
				
			||||||
	temp -= data->temp_crit_hyst * 1000;
 | 
						temp -= data->temp_crit_hyst * 1000;
 | 
				
			||||||
	mutex_unlock(&data->update_lock);
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sprintf(buf, "%d\n", temp);
 | 
						return sprintf(buf, "%d\n", temp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t show_temp_lowest(struct device *dev,
 | 
					 | 
				
			||||||
	struct device_attribute *devattr, char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int index = to_sensor_dev_attr(devattr)->index;
 | 
					 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sprintf(buf, "%d\n",
 | 
					 | 
				
			||||||
		tmp401_register_to_temp(data->temp_lowest[index],
 | 
					 | 
				
			||||||
					data->config));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t show_temp_highest(struct device *dev,
 | 
					 | 
				
			||||||
	struct device_attribute *devattr, char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int index = to_sensor_dev_attr(devattr)->index;
 | 
					 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sprintf(buf, "%d\n",
 | 
					 | 
				
			||||||
		tmp401_register_to_temp(data->temp_highest[index],
 | 
					 | 
				
			||||||
					data->config));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t show_status(struct device *dev,
 | 
					static ssize_t show_status(struct device *dev,
 | 
				
			||||||
	struct device_attribute *devattr, char *buf)
 | 
						struct device_attribute *devattr, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int mask = to_sensor_dev_attr(devattr)->index;
 | 
						int nr = to_sensor_dev_attr_2(devattr)->nr;
 | 
				
			||||||
 | 
						int mask = to_sensor_dev_attr_2(devattr)->index;
 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
						struct tmp401_data *data = tmp401_update_device(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data->status & mask)
 | 
						if (IS_ERR(data))
 | 
				
			||||||
		return sprintf(buf, "1\n");
 | 
							return PTR_ERR(data);
 | 
				
			||||||
	else
 | 
					
 | 
				
			||||||
		return sprintf(buf, "0\n");
 | 
						return sprintf(buf, "%d\n", !!(data->status[nr] & mask));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t store_temp_min(struct device *dev, struct device_attribute
 | 
					static ssize_t store_temp(struct device *dev, struct device_attribute *devattr,
 | 
				
			||||||
	*devattr, const char *buf, size_t count)
 | 
								  const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int index = to_sensor_dev_attr(devattr)->index;
 | 
						int nr = to_sensor_dev_attr_2(devattr)->nr;
 | 
				
			||||||
 | 
						int index = to_sensor_dev_attr_2(devattr)->index;
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
						struct tmp401_data *data = tmp401_update_device(dev);
 | 
				
			||||||
	long val;
 | 
						long val;
 | 
				
			||||||
	u16 reg;
 | 
						u16 reg;
 | 
				
			||||||
 | 
						u8 regaddr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(data))
 | 
				
			||||||
 | 
							return PTR_ERR(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (kstrtol(buf, 10, &val))
 | 
						if (kstrtol(buf, 10, &val))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reg = tmp401_temp_to_register(val, data->config);
 | 
						reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i2c_smbus_write_byte_data(to_i2c_client(dev),
 | 
						regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index]
 | 
				
			||||||
		TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8);
 | 
									       : TMP401_TEMP_MSB_WRITE[nr][index];
 | 
				
			||||||
	i2c_smbus_write_byte_data(to_i2c_client(dev),
 | 
						i2c_smbus_write_byte_data(client, regaddr, reg >> 8);
 | 
				
			||||||
		TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF);
 | 
						if (nr != 3) {
 | 
				
			||||||
 | 
							regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index]
 | 
				
			||||||
	data->temp_low[index] = reg;
 | 
										       : TMP401_TEMP_LSB[nr][index];
 | 
				
			||||||
 | 
							i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF);
 | 
				
			||||||
	mutex_unlock(&data->update_lock);
 | 
						}
 | 
				
			||||||
 | 
						data->temp[nr][index] = reg;
 | 
				
			||||||
	return count;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t store_temp_max(struct device *dev, struct device_attribute
 | 
					 | 
				
			||||||
	*devattr, const char *buf, size_t count)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int index = to_sensor_dev_attr(devattr)->index;
 | 
					 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
					 | 
				
			||||||
	long val;
 | 
					 | 
				
			||||||
	u16 reg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (kstrtol(buf, 10, &val))
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	reg = tmp401_temp_to_register(val, data->config);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	i2c_smbus_write_byte_data(to_i2c_client(dev),
 | 
					 | 
				
			||||||
		TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8);
 | 
					 | 
				
			||||||
	i2c_smbus_write_byte_data(to_i2c_client(dev),
 | 
					 | 
				
			||||||
		TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	data->temp_high[index] = reg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_unlock(&data->update_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return count;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t store_temp_crit(struct device *dev, struct device_attribute
 | 
					 | 
				
			||||||
	*devattr, const char *buf, size_t count)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int index = to_sensor_dev_attr(devattr)->index;
 | 
					 | 
				
			||||||
	struct tmp401_data *data = tmp401_update_device(dev);
 | 
					 | 
				
			||||||
	long val;
 | 
					 | 
				
			||||||
	u8 reg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (kstrtol(buf, 10, &val))
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	reg = tmp401_crit_temp_to_register(val, data->config);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	i2c_smbus_write_byte_data(to_i2c_client(dev),
 | 
					 | 
				
			||||||
		TMP401_TEMP_CRIT_LIMIT[index], reg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	data->temp_crit[index] = reg;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&data->update_lock);
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -413,6 +389,9 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
 | 
				
			||||||
	long val;
 | 
						long val;
 | 
				
			||||||
	u8 reg;
 | 
						u8 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(data))
 | 
				
			||||||
 | 
							return PTR_ERR(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (kstrtol(buf, 10, &val))
 | 
						if (kstrtol(buf, 10, &val))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -422,13 +401,12 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
 | 
				
			||||||
		val = clamp_val(val, 0, 127000);
 | 
							val = clamp_val(val, 0, 127000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&data->update_lock);
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
	temp = tmp401_crit_register_to_temp(data->temp_crit[index],
 | 
						temp = tmp401_register_to_temp(data->temp[3][index], data->config);
 | 
				
			||||||
						data->config);
 | 
					 | 
				
			||||||
	val = clamp_val(val, temp - 255000, temp);
 | 
						val = clamp_val(val, temp - 255000, temp);
 | 
				
			||||||
	reg = ((temp - val) + 500) / 1000;
 | 
						reg = ((temp - val) + 500) / 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i2c_smbus_write_byte_data(to_i2c_client(dev),
 | 
						i2c_smbus_write_byte_data(to_i2c_client(dev), TMP401_TEMP_CRIT_HYST,
 | 
				
			||||||
		TMP401_TEMP_CRIT_HYST, reg);
 | 
									  reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->temp_crit_hyst = reg;
 | 
						data->temp_crit_hyst = reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -445,54 +423,130 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
 | 
				
			||||||
static ssize_t reset_temp_history(struct device *dev,
 | 
					static ssize_t reset_temp_history(struct device *dev,
 | 
				
			||||||
	struct device_attribute	*devattr, const char *buf, size_t count)
 | 
						struct device_attribute	*devattr, const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
						struct tmp401_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
	long val;
 | 
						long val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (kstrtol(buf, 10, &val))
 | 
						if (kstrtol(buf, 10, &val))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (val != 1) {
 | 
						if (val != 1) {
 | 
				
			||||||
		dev_err(dev, "temp_reset_history value %ld not"
 | 
							dev_err(dev,
 | 
				
			||||||
			" supported. Use 1 to reset the history!\n", val);
 | 
								"temp_reset_history value %ld not supported. Use 1 to reset the history!\n",
 | 
				
			||||||
 | 
								val);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	i2c_smbus_write_byte_data(to_i2c_client(dev),
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
		TMP411_TEMP_LOWEST_MSB[0], val);
 | 
						i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val);
 | 
				
			||||||
 | 
						data->valid = 0;
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return count;
 | 
						return count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct sensor_device_attribute tmp401_attr[] = {
 | 
					static ssize_t show_update_interval(struct device *dev,
 | 
				
			||||||
	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
 | 
									    struct device_attribute *attr, char *buf)
 | 
				
			||||||
	SENSOR_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
 | 
					{
 | 
				
			||||||
		    store_temp_min, 0),
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
	SENSOR_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
 | 
						struct tmp401_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
		    store_temp_max, 0),
 | 
					
 | 
				
			||||||
	SENSOR_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit,
 | 
						return sprintf(buf, "%u\n", data->update_interval);
 | 
				
			||||||
		    store_temp_crit, 0),
 | 
					}
 | 
				
			||||||
	SENSOR_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_crit_hyst,
 | 
					
 | 
				
			||||||
		    store_temp_crit_hyst, 0),
 | 
					static ssize_t set_update_interval(struct device *dev,
 | 
				
			||||||
	SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_status, NULL,
 | 
									   struct device_attribute *attr,
 | 
				
			||||||
		    TMP401_STATUS_LOCAL_LOW),
 | 
									   const char *buf, size_t count)
 | 
				
			||||||
	SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_status, NULL,
 | 
					{
 | 
				
			||||||
		    TMP401_STATUS_LOCAL_HIGH),
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
	SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
 | 
						struct tmp401_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
		    TMP401_STATUS_LOCAL_CRIT),
 | 
						unsigned long val;
 | 
				
			||||||
	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
 | 
						int err, rate;
 | 
				
			||||||
	SENSOR_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
 | 
					
 | 
				
			||||||
		    store_temp_min, 1),
 | 
						err = kstrtoul(buf, 10, &val);
 | 
				
			||||||
	SENSOR_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
 | 
						if (err)
 | 
				
			||||||
		    store_temp_max, 1),
 | 
							return err;
 | 
				
			||||||
	SENSOR_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit,
 | 
					
 | 
				
			||||||
		    store_temp_crit, 1),
 | 
						/*
 | 
				
			||||||
	SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
 | 
						 * For valid rates, interval can be calculated as
 | 
				
			||||||
	SENSOR_ATTR(temp2_fault, S_IRUGO, show_status, NULL,
 | 
						 *	interval = (1 << (7 - rate)) * 125;
 | 
				
			||||||
		    TMP401_STATUS_REMOTE_OPEN),
 | 
						 * Rounded rate is therefore
 | 
				
			||||||
	SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_status, NULL,
 | 
						 *	rate = 7 - __fls(interval * 4 / (125 * 3));
 | 
				
			||||||
		    TMP401_STATUS_REMOTE_LOW),
 | 
						 * Use clamp_val() to avoid overflows, and to ensure valid input
 | 
				
			||||||
	SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_status, NULL,
 | 
						 * for __fls.
 | 
				
			||||||
		    TMP401_STATUS_REMOTE_HIGH),
 | 
						 */
 | 
				
			||||||
	SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
 | 
						val = clamp_val(val, 125, 16000);
 | 
				
			||||||
		    TMP401_STATUS_REMOTE_CRIT),
 | 
						rate = 7 - __fls(val * 4 / (125 * 3));
 | 
				
			||||||
 | 
						mutex_lock(&data->update_lock);
 | 
				
			||||||
 | 
						i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate);
 | 
				
			||||||
 | 
						data->update_interval = (1 << (7 - rate)) * 125;
 | 
				
			||||||
 | 
						mutex_unlock(&data->update_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp,
 | 
				
			||||||
 | 
								    store_temp, 1, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp,
 | 
				
			||||||
 | 
								    store_temp, 2, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp,
 | 
				
			||||||
 | 
								    store_temp, 3, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
 | 
				
			||||||
 | 
								  show_temp_crit_hyst, store_temp_crit_hyst, 0);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    1, TMP432_STATUS_LOCAL);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    2, TMP432_STATUS_LOCAL);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    3, TMP432_STATUS_LOCAL);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp,
 | 
				
			||||||
 | 
								    store_temp, 1, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp,
 | 
				
			||||||
 | 
								    store_temp, 2, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp,
 | 
				
			||||||
 | 
								    store_temp, 3, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst,
 | 
				
			||||||
 | 
								  NULL, 1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    0, TMP432_STATUS_REMOTE1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    1, TMP432_STATUS_REMOTE1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    2, TMP432_STATUS_REMOTE1);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    3, TMP432_STATUS_REMOTE1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
 | 
				
			||||||
 | 
							   set_update_interval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct attribute *tmp401_attributes[] = {
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_min.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_crit.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_min.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_crit.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_fault.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						&dev_attr_update_interval.attr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NULL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct attribute_group tmp401_group = {
 | 
				
			||||||
 | 
						.attrs = tmp401_attributes,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -502,12 +556,60 @@ static struct sensor_device_attribute tmp401_attr[] = {
 | 
				
			||||||
 * minimum and maximum register reset for both the local
 | 
					 * minimum and maximum register reset for both the local
 | 
				
			||||||
 * and remote channels.
 | 
					 * and remote channels.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct sensor_device_attribute tmp411_attr[] = {
 | 
					static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0);
 | 
				
			||||||
	SENSOR_ATTR(temp1_highest, S_IRUGO, show_temp_highest, NULL, 0),
 | 
					static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0);
 | 
				
			||||||
	SENSOR_ATTR(temp1_lowest, S_IRUGO, show_temp_lowest, NULL, 0),
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1);
 | 
				
			||||||
	SENSOR_ATTR(temp2_highest, S_IRUGO, show_temp_highest, NULL, 1),
 | 
					static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1);
 | 
				
			||||||
	SENSOR_ATTR(temp2_lowest, S_IRUGO, show_temp_lowest, NULL, 1),
 | 
					static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history,
 | 
				
			||||||
	SENSOR_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, 0),
 | 
								  0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct attribute *tmp411_attributes[] = {
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_highest.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp1_lowest.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_highest.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp2_lowest.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp_reset_history.dev_attr.attr,
 | 
				
			||||||
 | 
						NULL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct attribute_group tmp411_group = {
 | 
				
			||||||
 | 
						.attrs = tmp411_attributes,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp,
 | 
				
			||||||
 | 
								    store_temp, 1, 2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp,
 | 
				
			||||||
 | 
								    store_temp, 2, 2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
 | 
				
			||||||
 | 
								    store_temp, 3, 2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst,
 | 
				
			||||||
 | 
								  NULL, 2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    0, TMP432_STATUS_REMOTE2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    1, TMP432_STATUS_REMOTE2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    2, TMP432_STATUS_REMOTE2);
 | 
				
			||||||
 | 
					static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL,
 | 
				
			||||||
 | 
								    3, TMP432_STATUS_REMOTE2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct attribute *tmp432_attributes[] = {
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_input.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_min.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_max.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_crit.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_fault.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
						&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NULL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct attribute_group tmp432_group = {
 | 
				
			||||||
 | 
						.attrs = tmp432_attributes,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -517,9 +619,11 @@ static struct sensor_device_attribute tmp411_attr[] = {
 | 
				
			||||||
static void tmp401_init_client(struct i2c_client *client)
 | 
					static void tmp401_init_client(struct i2c_client *client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int config, config_orig;
 | 
						int config, config_orig;
 | 
				
			||||||
 | 
						struct tmp401_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set the conversion rate to 2 Hz */
 | 
						/* Set the conversion rate to 2 Hz */
 | 
				
			||||||
	i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
 | 
						i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
 | 
				
			||||||
 | 
						data->update_interval = 500;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Start conversions (disable shutdown if necessary) */
 | 
						/* Start conversions (disable shutdown if necessary) */
 | 
				
			||||||
	config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
 | 
						config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
 | 
				
			||||||
| 
						 | 
					@ -554,11 +658,35 @@ static int tmp401_detect(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (reg) {
 | 
						switch (reg) {
 | 
				
			||||||
	case TMP401_DEVICE_ID:
 | 
						case TMP401_DEVICE_ID:
 | 
				
			||||||
 | 
							if (client->addr != 0x4c)
 | 
				
			||||||
 | 
								return -ENODEV;
 | 
				
			||||||
		kind = tmp401;
 | 
							kind = tmp401;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case TMP411_DEVICE_ID:
 | 
						case TMP411A_DEVICE_ID:
 | 
				
			||||||
 | 
							if (client->addr != 0x4c)
 | 
				
			||||||
 | 
								return -ENODEV;
 | 
				
			||||||
		kind = tmp411;
 | 
							kind = tmp411;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case TMP411B_DEVICE_ID:
 | 
				
			||||||
 | 
							if (client->addr != 0x4d)
 | 
				
			||||||
 | 
								return -ENODEV;
 | 
				
			||||||
 | 
							kind = tmp411;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TMP411C_DEVICE_ID:
 | 
				
			||||||
 | 
							if (client->addr != 0x4e)
 | 
				
			||||||
 | 
								return -ENODEV;
 | 
				
			||||||
 | 
							kind = tmp411;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TMP431_DEVICE_ID:
 | 
				
			||||||
 | 
							if (client->addr == 0x4e)
 | 
				
			||||||
 | 
								return -ENODEV;
 | 
				
			||||||
 | 
							kind = tmp431;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TMP432_DEVICE_ID:
 | 
				
			||||||
 | 
							if (client->addr == 0x4e)
 | 
				
			||||||
 | 
								return -ENODEV;
 | 
				
			||||||
 | 
							kind = tmp432;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -579,20 +707,19 @@ static int tmp401_detect(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tmp401_remove(struct i2c_client *client)
 | 
					static int tmp401_remove(struct i2c_client *client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct device *dev = &client->dev;
 | 
				
			||||||
	struct tmp401_data *data = i2c_get_clientdata(client);
 | 
						struct tmp401_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data->hwmon_dev)
 | 
						if (data->hwmon_dev)
 | 
				
			||||||
		hwmon_device_unregister(data->hwmon_dev);
 | 
							hwmon_device_unregister(data->hwmon_dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
 | 
						sysfs_remove_group(&dev->kobj, &tmp401_group);
 | 
				
			||||||
		device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data->kind == tmp411) {
 | 
						if (data->kind == tmp411)
 | 
				
			||||||
		for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
 | 
							sysfs_remove_group(&dev->kobj, &tmp411_group);
 | 
				
			||||||
			device_remove_file(&client->dev,
 | 
					
 | 
				
			||||||
					   &tmp411_attr[i].dev_attr);
 | 
						if (data->kind == tmp432)
 | 
				
			||||||
	}
 | 
							sysfs_remove_group(&dev->kobj, &tmp432_group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -600,12 +727,12 @@ static int tmp401_remove(struct i2c_client *client)
 | 
				
			||||||
static int tmp401_probe(struct i2c_client *client,
 | 
					static int tmp401_probe(struct i2c_client *client,
 | 
				
			||||||
			const struct i2c_device_id *id)
 | 
								const struct i2c_device_id *id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i, err = 0;
 | 
						struct device *dev = &client->dev;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
	struct tmp401_data *data;
 | 
						struct tmp401_data *data;
 | 
				
			||||||
	const char *names[] = { "TMP401", "TMP411" };
 | 
						const char *names[] = { "TMP401", "TMP411", "TMP431", "TMP432" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data = devm_kzalloc(&client->dev, sizeof(struct tmp401_data),
 | 
						data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL);
 | 
				
			||||||
			    GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!data)
 | 
						if (!data)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -617,31 +744,32 @@ static int tmp401_probe(struct i2c_client *client,
 | 
				
			||||||
	tmp401_init_client(client);
 | 
						tmp401_init_client(client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Register sysfs hooks */
 | 
						/* Register sysfs hooks */
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) {
 | 
						err = sysfs_create_group(&dev->kobj, &tmp401_group);
 | 
				
			||||||
		err = device_create_file(&client->dev,
 | 
						if (err)
 | 
				
			||||||
					 &tmp401_attr[i].dev_attr);
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Register additional tmp411 sysfs hooks */
 | 
				
			||||||
 | 
						if (data->kind == tmp411) {
 | 
				
			||||||
 | 
							err = sysfs_create_group(&dev->kobj, &tmp411_group);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto exit_remove;
 | 
								goto exit_remove;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Register additional tmp411 sysfs hooks */
 | 
						/* Register additional tmp432 sysfs hooks */
 | 
				
			||||||
	if (data->kind == tmp411) {
 | 
						if (data->kind == tmp432) {
 | 
				
			||||||
		for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) {
 | 
							err = sysfs_create_group(&dev->kobj, &tmp432_group);
 | 
				
			||||||
			err = device_create_file(&client->dev,
 | 
							if (err)
 | 
				
			||||||
						 &tmp411_attr[i].dev_attr);
 | 
								goto exit_remove;
 | 
				
			||||||
			if (err)
 | 
					 | 
				
			||||||
				goto exit_remove;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->hwmon_dev = hwmon_device_register(&client->dev);
 | 
						data->hwmon_dev = hwmon_device_register(dev);
 | 
				
			||||||
	if (IS_ERR(data->hwmon_dev)) {
 | 
						if (IS_ERR(data->hwmon_dev)) {
 | 
				
			||||||
		err = PTR_ERR(data->hwmon_dev);
 | 
							err = PTR_ERR(data->hwmon_dev);
 | 
				
			||||||
		data->hwmon_dev = NULL;
 | 
							data->hwmon_dev = NULL;
 | 
				
			||||||
		goto exit_remove;
 | 
							goto exit_remove;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_info(&client->dev, "Detected TI %s chip\n", names[data->kind]);
 | 
						dev_info(dev, "Detected TI %s chip\n", names[data->kind]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,8 +208,8 @@ static int tmp421_init_client(struct i2c_client *client)
 | 
				
			||||||
	/* Start conversions (disable shutdown if necessary) */
 | 
						/* Start conversions (disable shutdown if necessary) */
 | 
				
			||||||
	config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
 | 
						config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
 | 
				
			||||||
	if (config < 0) {
 | 
						if (config < 0) {
 | 
				
			||||||
		dev_err(&client->dev, "Could not read configuration"
 | 
							dev_err(&client->dev,
 | 
				
			||||||
			 " register (%d)\n", config);
 | 
								"Could not read configuration register (%d)\n", config);
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -322,6 +322,5 @@ static struct i2c_driver tmp421_driver = {
 | 
				
			||||||
module_i2c_driver(tmp421_driver);
 | 
					module_i2c_driver(tmp421_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>");
 | 
					MODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>");
 | 
				
			||||||
MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor"
 | 
					MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor driver");
 | 
				
			||||||
		   " driver");
 | 
					 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,7 +125,7 @@ static const u8 VIA686A_REG_TEMP_HYST[]	= { 0x3a, 0x3e, 0x1e };
 | 
				
			||||||
 * (These conversions were contributed by Jonathan Teh Soon Yew
 | 
					 * (These conversions were contributed by Jonathan Teh Soon Yew
 | 
				
			||||||
 * <j.teh@iname.com>)
 | 
					 * <j.teh@iname.com>)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static inline u8 IN_TO_REG(long val, int inNum)
 | 
					static inline u8 IN_TO_REG(long val, int in_num)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
 | 
						 * To avoid floating point, we multiply constants by 10 (100 for +12V).
 | 
				
			||||||
| 
						 | 
					@ -134,29 +134,29 @@ static inline u8 IN_TO_REG(long val, int inNum)
 | 
				
			||||||
	 * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
 | 
						 * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
 | 
				
			||||||
	 * for the constants.
 | 
						 * for the constants.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (inNum <= 1)
 | 
						if (in_num <= 1)
 | 
				
			||||||
		return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
 | 
							return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
 | 
				
			||||||
	else if (inNum == 2)
 | 
						else if (in_num == 2)
 | 
				
			||||||
		return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
 | 
							return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
 | 
				
			||||||
	else if (inNum == 3)
 | 
						else if (in_num == 3)
 | 
				
			||||||
		return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
 | 
							return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
 | 
							return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
 | 
				
			||||||
				      255);
 | 
									      255);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline long IN_FROM_REG(u8 val, int inNum)
 | 
					static inline long IN_FROM_REG(u8 val, int in_num)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * To avoid floating point, we multiply constants by 10 (100 for +12V).
 | 
						 * To avoid floating point, we multiply constants by 10 (100 for +12V).
 | 
				
			||||||
	 * We also multiply them by 1000 because we want 0.001V/bit for the
 | 
						 * We also multiply them by 1000 because we want 0.001V/bit for the
 | 
				
			||||||
	 * output value. Rounding is done.
 | 
						 * output value. Rounding is done.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (inNum <= 1)
 | 
						if (in_num <= 1)
 | 
				
			||||||
		return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
 | 
							return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
 | 
				
			||||||
	else if (inNum == 2)
 | 
						else if (in_num == 2)
 | 
				
			||||||
		return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
 | 
							return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
 | 
				
			||||||
	else if (inNum == 3)
 | 
						else if (in_num == 3)
 | 
				
			||||||
		return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
 | 
							return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
 | 
							return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
 | 
				
			||||||
| 
						 | 
					@ -210,10 +210,10 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 | 
				
			||||||
 * VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
 | 
					 * VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
 | 
				
			||||||
 * precision.  (I could have done all 1024 values for our 10-bit readings,
 | 
					 * precision.  (I could have done all 1024 values for our 10-bit readings,
 | 
				
			||||||
 * but the function is very linear in the useful range (0-80 deg C), so
 | 
					 * but the function is very linear in the useful range (0-80 deg C), so
 | 
				
			||||||
 * we'll just use linear interpolation for 10-bit readings.)  So, tempLUT
 | 
					 * we'll just use linear interpolation for 10-bit readings.)  So, temp_lut
 | 
				
			||||||
 * is the temp at via register values 0-255:
 | 
					 * is the temp at via register values 0-255:
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static const s16 tempLUT[] = {
 | 
					static const s16 temp_lut[] = {
 | 
				
			||||||
	-709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
 | 
						-709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
 | 
				
			||||||
	-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
 | 
						-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
 | 
				
			||||||
	-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
 | 
						-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
 | 
				
			||||||
| 
						 | 
					@ -261,7 +261,7 @@ static const s16 tempLUT[] = {
 | 
				
			||||||
 * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
 | 
					 * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
 | 
				
			||||||
 * Note that n=161:
 | 
					 * Note that n=161:
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static const u8 viaLUT[] = {
 | 
					static const u8 via_lut[] = {
 | 
				
			||||||
	12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
 | 
						12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
 | 
				
			||||||
	23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
 | 
						23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
 | 
				
			||||||
	41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
 | 
						41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
 | 
				
			||||||
| 
						 | 
					@ -284,26 +284,26 @@ static const u8 viaLUT[] = {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static inline u8 TEMP_TO_REG(long val)
 | 
					static inline u8 TEMP_TO_REG(long val)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
 | 
						return via_lut[val <= -50000 ? 0 : val >= 110000 ? 160 :
 | 
				
			||||||
		      (val < 0 ? val - 500 : val + 500) / 1000 + 50];
 | 
							      (val < 0 ? val - 500 : val + 500) / 1000 + 50];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* for 8-bit temperature hyst and over registers */
 | 
					/* for 8-bit temperature hyst and over registers */
 | 
				
			||||||
#define TEMP_FROM_REG(val)	((long)tempLUT[val] * 100)
 | 
					#define TEMP_FROM_REG(val)	((long)temp_lut[val] * 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* for 10-bit temperature readings */
 | 
					/* for 10-bit temperature readings */
 | 
				
			||||||
static inline long TEMP_FROM_REG10(u16 val)
 | 
					static inline long TEMP_FROM_REG10(u16 val)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u16 eightBits = val >> 2;
 | 
						u16 eight_bits = val >> 2;
 | 
				
			||||||
	u16 twoBits = val & 3;
 | 
						u16 two_bits = val & 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* no interpolation for these */
 | 
						/* no interpolation for these */
 | 
				
			||||||
	if (twoBits == 0 || eightBits == 255)
 | 
						if (two_bits == 0 || eight_bits == 255)
 | 
				
			||||||
		return TEMP_FROM_REG(eightBits);
 | 
							return TEMP_FROM_REG(eight_bits);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* do some linear interpolation */
 | 
						/* do some linear interpolation */
 | 
				
			||||||
	return (tempLUT[eightBits] * (4 - twoBits) +
 | 
						return (temp_lut[eight_bits] * (4 - two_bits) +
 | 
				
			||||||
		tempLUT[eightBits + 1] * twoBits) * 25;
 | 
							temp_lut[eight_bits + 1] * two_bits) * 25;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DIV_FROM_REG(val) (1 << (val))
 | 
					#define DIV_FROM_REG(val) (1 << (val))
 | 
				
			||||||
| 
						 | 
					@ -889,8 +889,8 @@ static int via686a_pci_probe(struct pci_dev *dev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	address = val & ~(VIA686A_EXTENT - 1);
 | 
						address = val & ~(VIA686A_EXTENT - 1);
 | 
				
			||||||
	if (address == 0) {
 | 
						if (address == 0) {
 | 
				
			||||||
		dev_err(&dev->dev, "base address not set - upgrade BIOS "
 | 
							dev_err(&dev->dev,
 | 
				
			||||||
			"or use force_addr=0xaddr\n");
 | 
								"base address not set - upgrade BIOS or use force_addr=0xaddr\n");
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -899,8 +899,9 @@ static int via686a_pci_probe(struct pci_dev *dev,
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	if (!(val & 0x0001)) {
 | 
						if (!(val & 0x0001)) {
 | 
				
			||||||
		if (!force_addr) {
 | 
							if (!force_addr) {
 | 
				
			||||||
			dev_warn(&dev->dev, "Sensors disabled, enable "
 | 
								dev_warn(&dev->dev,
 | 
				
			||||||
				 "with force_addr=0x%x\n", address);
 | 
									 "Sensors disabled, enable with force_addr=0x%x\n",
 | 
				
			||||||
 | 
									 address);
 | 
				
			||||||
			return -ENODEV;
 | 
								return -ENODEV;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -571,8 +571,9 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			count = -EINVAL;
 | 
								count = -EINVAL;
 | 
				
			||||||
			dev_warn(dev, "fan div value %ld not supported. "
 | 
								dev_warn(dev,
 | 
				
			||||||
				 "Choose one of 1, 2, 4, or 8.\n", val);
 | 
									 "fan div value %ld not supported. Choose one of 1, 2, 4, or 8.\n",
 | 
				
			||||||
 | 
									 val);
 | 
				
			||||||
			goto EXIT;
 | 
								goto EXIT;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		vt1211_write8(data, VT1211_REG_FAN_DIV,
 | 
							vt1211_write8(data, VT1211_REG_FAN_DIV,
 | 
				
			||||||
| 
						 | 
					@ -674,8 +675,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			count = -EINVAL;
 | 
								count = -EINVAL;
 | 
				
			||||||
			dev_warn(dev, "pwm mode %ld not supported. "
 | 
								dev_warn(dev,
 | 
				
			||||||
				 "Choose one of 0 or 2.\n", val);
 | 
									 "pwm mode %ld not supported. Choose one of 0 or 2.\n",
 | 
				
			||||||
 | 
									 val);
 | 
				
			||||||
			goto EXIT;
 | 
								goto EXIT;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		vt1211_write8(data, VT1211_REG_PWM_CTL,
 | 
							vt1211_write8(data, VT1211_REG_PWM_CTL,
 | 
				
			||||||
| 
						 | 
					@ -700,8 +702,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
	case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
 | 
						case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
 | 
				
			||||||
		if (val < 1 || val > 7) {
 | 
							if (val < 1 || val > 7) {
 | 
				
			||||||
			count = -EINVAL;
 | 
								count = -EINVAL;
 | 
				
			||||||
			dev_warn(dev, "temp channel %ld not supported. "
 | 
								dev_warn(dev,
 | 
				
			||||||
				 "Choose a value between 1 and 7.\n", val);
 | 
									 "temp channel %ld not supported. Choose a value between 1 and 7.\n",
 | 
				
			||||||
 | 
									 val);
 | 
				
			||||||
			goto EXIT;
 | 
								goto EXIT;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (!ISTEMP(val - 1, data->uch_config)) {
 | 
							if (!ISTEMP(val - 1, data->uch_config)) {
 | 
				
			||||||
| 
						 | 
					@ -1325,15 +1328,15 @@ static int __init vt1211_init(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((uch_config < -1) || (uch_config > 31)) {
 | 
						if ((uch_config < -1) || (uch_config > 31)) {
 | 
				
			||||||
		err = -EINVAL;
 | 
							err = -EINVAL;
 | 
				
			||||||
		pr_warn("Invalid UCH configuration %d. "
 | 
							pr_warn("Invalid UCH configuration %d. Choose a value between 0 and 31.\n",
 | 
				
			||||||
			"Choose a value between 0 and 31.\n", uch_config);
 | 
								uch_config);
 | 
				
			||||||
		goto EXIT;
 | 
							goto EXIT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((int_mode < -1) || (int_mode > 0)) {
 | 
						if ((int_mode < -1) || (int_mode > 0)) {
 | 
				
			||||||
		err = -EINVAL;
 | 
							err = -EINVAL;
 | 
				
			||||||
		pr_warn("Invalid interrupt mode %d. "
 | 
							pr_warn("Invalid interrupt mode %d. Only mode 0 is supported.\n",
 | 
				
			||||||
			"Only mode 0 is supported.\n", int_mode);
 | 
								int_mode);
 | 
				
			||||||
		goto EXIT;
 | 
							goto EXIT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -573,8 +573,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
		data->fan_div[nr] = 3;
 | 
							data->fan_div[nr] = 3;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		dev_err(dev, "fan_div value %ld not supported. "
 | 
							dev_err(dev,
 | 
				
			||||||
			"Choose one of 1, 2, 4 or 8!\n", val);
 | 
								"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
 | 
				
			||||||
 | 
								val);
 | 
				
			||||||
		mutex_unlock(&data->update_lock);
 | 
							mutex_unlock(&data->update_lock);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -840,8 +840,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 | 
				
			||||||
			    && (reg >= 0xff || (sio_data->kind == nct6775
 | 
								    && (reg >= 0xff || (sio_data->kind == nct6775
 | 
				
			||||||
						&& reg == 0x00))
 | 
											&& reg == 0x00))
 | 
				
			||||||
			    && data->fan_div[i] < 0x07) {
 | 
								    && data->fan_div[i] < 0x07) {
 | 
				
			||||||
				dev_dbg(dev, "Increasing fan%d "
 | 
									dev_dbg(dev,
 | 
				
			||||||
					"clock divider from %u to %u\n",
 | 
										"Increasing fan%d clock divider from %u to %u\n",
 | 
				
			||||||
					i + 1, div_from_reg(data->fan_div[i]),
 | 
										i + 1, div_from_reg(data->fan_div[i]),
 | 
				
			||||||
					div_from_reg(data->fan_div[i] + 1));
 | 
										div_from_reg(data->fan_div[i] + 1));
 | 
				
			||||||
				data->fan_div[i]++;
 | 
									data->fan_div[i]++;
 | 
				
			||||||
| 
						 | 
					@ -1110,9 +1110,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		data->fan_min[nr] = 254;
 | 
							data->fan_min[nr] = 254;
 | 
				
			||||||
		new_div = 7; /* 128 == (1 << 7) */
 | 
							new_div = 7; /* 128 == (1 << 7) */
 | 
				
			||||||
		dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
 | 
							dev_warn(dev,
 | 
				
			||||||
			 "minimum\n", nr + 1, val,
 | 
								 "fan%u low limit %lu below minimum %u, set to minimum\n",
 | 
				
			||||||
			 data->fan_from_reg_min(254, 7));
 | 
								 nr + 1, val, data->fan_from_reg_min(254, 7));
 | 
				
			||||||
	} else if (!reg) {
 | 
						} else if (!reg) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Speed above this value cannot possibly be represented,
 | 
							 * Speed above this value cannot possibly be represented,
 | 
				
			||||||
| 
						 | 
					@ -1120,9 +1120,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		data->fan_min[nr] = 1;
 | 
							data->fan_min[nr] = 1;
 | 
				
			||||||
		new_div = 0; /* 1 == (1 << 0) */
 | 
							new_div = 0; /* 1 == (1 << 0) */
 | 
				
			||||||
		dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
 | 
							dev_warn(dev,
 | 
				
			||||||
			 "maximum\n", nr + 1, val,
 | 
								 "fan%u low limit %lu above maximum %u, set to maximum\n",
 | 
				
			||||||
			 data->fan_from_reg_min(1, 0));
 | 
								 nr + 1, val, data->fan_from_reg_min(1, 0));
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Automatically pick the best divider, i.e. the one such
 | 
							 * Automatically pick the best divider, i.e. the one such
 | 
				
			||||||
| 
						 | 
					@ -2396,15 +2396,15 @@ static int w83627ehf_probe(struct platform_device *pdev)
 | 
				
			||||||
				en_vrm10 = superio_inb(sio_data->sioreg,
 | 
									en_vrm10 = superio_inb(sio_data->sioreg,
 | 
				
			||||||
						       SIO_REG_EN_VRM10);
 | 
											       SIO_REG_EN_VRM10);
 | 
				
			||||||
				if ((en_vrm10 & 0x08) && data->vrm == 90) {
 | 
									if ((en_vrm10 & 0x08) && data->vrm == 90) {
 | 
				
			||||||
					dev_warn(dev, "Setting VID input "
 | 
										dev_warn(dev,
 | 
				
			||||||
						 "voltage to TTL\n");
 | 
											 "Setting VID input voltage to TTL\n");
 | 
				
			||||||
					superio_outb(sio_data->sioreg,
 | 
										superio_outb(sio_data->sioreg,
 | 
				
			||||||
						     SIO_REG_EN_VRM10,
 | 
											     SIO_REG_EN_VRM10,
 | 
				
			||||||
						     en_vrm10 & ~0x08);
 | 
											     en_vrm10 & ~0x08);
 | 
				
			||||||
				} else if (!(en_vrm10 & 0x08)
 | 
									} else if (!(en_vrm10 & 0x08)
 | 
				
			||||||
					   && data->vrm == 100) {
 | 
										   && data->vrm == 100) {
 | 
				
			||||||
					dev_warn(dev, "Setting VID input "
 | 
										dev_warn(dev,
 | 
				
			||||||
						 "voltage to VRM10\n");
 | 
											 "Setting VID input voltage to VRM10\n");
 | 
				
			||||||
					superio_outb(sio_data->sioreg,
 | 
										superio_outb(sio_data->sioreg,
 | 
				
			||||||
						     SIO_REG_EN_VRM10,
 | 
											     SIO_REG_EN_VRM10,
 | 
				
			||||||
						     en_vrm10 | 0x08);
 | 
											     en_vrm10 | 0x08);
 | 
				
			||||||
| 
						 | 
					@ -2420,8 +2420,8 @@ static int w83627ehf_probe(struct platform_device *pdev)
 | 
				
			||||||
			if (err)
 | 
								if (err)
 | 
				
			||||||
				goto exit_release;
 | 
									goto exit_release;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			dev_info(dev, "VID pins in output mode, CPU VID not "
 | 
								dev_info(dev,
 | 
				
			||||||
				 "available\n");
 | 
									 "VID pins in output mode, CPU VID not available\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2795,8 +2795,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
 | 
				
			||||||
	/* Activate logical device if needed */
 | 
						/* Activate logical device if needed */
 | 
				
			||||||
	val = superio_inb(sioaddr, SIO_REG_ENABLE);
 | 
						val = superio_inb(sioaddr, SIO_REG_ENABLE);
 | 
				
			||||||
	if (!(val & 0x01)) {
 | 
						if (!(val & 0x01)) {
 | 
				
			||||||
		pr_warn("Forcibly enabling Super-I/O. "
 | 
							pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
 | 
				
			||||||
			"Sensor is probably unusable.\n");
 | 
					 | 
				
			||||||
		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
 | 
							superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,8 +64,8 @@ enum chips { w83781d, w83782d, w83783s, as99127f };
 | 
				
			||||||
/* Insmod parameters */
 | 
					/* Insmod parameters */
 | 
				
			||||||
static unsigned short force_subclients[4];
 | 
					static unsigned short force_subclients[4];
 | 
				
			||||||
module_param_array(force_subclients, short, NULL, 0);
 | 
					module_param_array(force_subclients, short, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
 | 
					MODULE_PARM_DESC(force_subclients,
 | 
				
			||||||
		    "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
							 "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool reset;
 | 
					static bool reset;
 | 
				
			||||||
module_param(reset, bool, 0);
 | 
					module_param(reset, bool, 0);
 | 
				
			||||||
| 
						 | 
					@ -826,8 +826,9 @@ store_sensor(struct device *dev, struct device_attribute *da,
 | 
				
			||||||
		data->sens[nr] = val;
 | 
							data->sens[nr] = val;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case W83781D_DEFAULT_BETA:
 | 
						case W83781D_DEFAULT_BETA:
 | 
				
			||||||
		dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
 | 
							dev_warn(dev,
 | 
				
			||||||
			 "instead\n", W83781D_DEFAULT_BETA);
 | 
								 "Sensor type %d is deprecated, please use 4 instead\n",
 | 
				
			||||||
 | 
								 W83781D_DEFAULT_BETA);
 | 
				
			||||||
		/* fall through */
 | 
							/* fall through */
 | 
				
			||||||
	case 4:		/* thermistor */
 | 
						case 4:		/* thermistor */
 | 
				
			||||||
		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
 | 
							tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
 | 
				
			||||||
| 
						 | 
					@ -874,8 +875,8 @@ w83781d_detect_subclients(struct i2c_client *new_client)
 | 
				
			||||||
		for (i = 2; i <= 3; i++) {
 | 
							for (i = 2; i <= 3; i++) {
 | 
				
			||||||
			if (force_subclients[i] < 0x48 ||
 | 
								if (force_subclients[i] < 0x48 ||
 | 
				
			||||||
			    force_subclients[i] > 0x4f) {
 | 
								    force_subclients[i] > 0x4f) {
 | 
				
			||||||
				dev_err(&new_client->dev, "Invalid subclient "
 | 
									dev_err(&new_client->dev,
 | 
				
			||||||
					"address %d; must be 0x48-0x4f\n",
 | 
										"Invalid subclient address %d; must be 0x48-0x4f\n",
 | 
				
			||||||
					force_subclients[i]);
 | 
										force_subclients[i]);
 | 
				
			||||||
				err = -EINVAL;
 | 
									err = -EINVAL;
 | 
				
			||||||
				goto ERROR_SC_1;
 | 
									goto ERROR_SC_1;
 | 
				
			||||||
| 
						 | 
					@ -910,9 +911,9 @@ w83781d_detect_subclients(struct i2c_client *new_client)
 | 
				
			||||||
	for (i = 0; i < num_sc; i++) {
 | 
						for (i = 0; i < num_sc; i++) {
 | 
				
			||||||
		data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
 | 
							data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
 | 
				
			||||||
		if (!data->lm75[i]) {
 | 
							if (!data->lm75[i]) {
 | 
				
			||||||
			dev_err(&new_client->dev, "Subclient %d "
 | 
								dev_err(&new_client->dev,
 | 
				
			||||||
				"registration at address 0x%x "
 | 
									"Subclient %d registration at address 0x%x failed.\n",
 | 
				
			||||||
				"failed.\n", i, sc_addr[i]);
 | 
									i, sc_addr[i]);
 | 
				
			||||||
			err = -ENOMEM;
 | 
								err = -ENOMEM;
 | 
				
			||||||
			if (i == 1)
 | 
								if (i == 1)
 | 
				
			||||||
				goto ERROR_SC_3;
 | 
									goto ERROR_SC_3;
 | 
				
			||||||
| 
						 | 
					@ -1176,8 +1177,9 @@ w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
 | 
				
			||||||
		goto err_nodev;
 | 
							goto err_nodev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
 | 
						if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
 | 
				
			||||||
		dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
 | 
							dev_dbg(&adapter->dev,
 | 
				
			||||||
			"be the same as ISA device\n", address);
 | 
								"Device at 0x%02x appears to be the same as ISA device\n",
 | 
				
			||||||
 | 
								address);
 | 
				
			||||||
		goto err_nodev;
 | 
							goto err_nodev;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1367,8 +1369,8 @@ w83781d_init_device(struct device *dev)
 | 
				
			||||||
		 * as I see very little reason why this would be needed at
 | 
							 * as I see very little reason why this would be needed at
 | 
				
			||||||
		 * all.
 | 
							 * all.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		dev_info(dev, "If reset=1 solved a problem you were "
 | 
							dev_info(dev,
 | 
				
			||||||
			 "having, please report!\n");
 | 
								 "If reset=1 solved a problem you were having, please report!\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* save these registers */
 | 
							/* save these registers */
 | 
				
			||||||
		i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
 | 
							i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
 | 
				
			||||||
| 
						 | 
					@ -1425,8 +1427,8 @@ w83781d_init_device(struct device *dev)
 | 
				
			||||||
		/* Enable temp2 */
 | 
							/* Enable temp2 */
 | 
				
			||||||
		tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
 | 
							tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
 | 
				
			||||||
		if (tmp & 0x01) {
 | 
							if (tmp & 0x01) {
 | 
				
			||||||
			dev_warn(dev, "Enabling temp2, readings "
 | 
								dev_warn(dev,
 | 
				
			||||||
				 "might not make sense\n");
 | 
									 "Enabling temp2, readings might not make sense\n");
 | 
				
			||||||
			w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
 | 
								w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
 | 
				
			||||||
				tmp & 0xfe);
 | 
									tmp & 0xfe);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1436,8 +1438,8 @@ w83781d_init_device(struct device *dev)
 | 
				
			||||||
			tmp = w83781d_read_value(data,
 | 
								tmp = w83781d_read_value(data,
 | 
				
			||||||
				W83781D_REG_TEMP3_CONFIG);
 | 
									W83781D_REG_TEMP3_CONFIG);
 | 
				
			||||||
			if (tmp & 0x01) {
 | 
								if (tmp & 0x01) {
 | 
				
			||||||
				dev_warn(dev, "Enabling temp3, "
 | 
									dev_warn(dev,
 | 
				
			||||||
					 "readings might not make sense\n");
 | 
										 "Enabling temp3, readings might not make sense\n");
 | 
				
			||||||
				w83781d_write_value(data,
 | 
									w83781d_write_value(data,
 | 
				
			||||||
					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
 | 
										W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,8 +56,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned short force_subclients[4];
 | 
					static unsigned short force_subclients[4];
 | 
				
			||||||
module_param_array(force_subclients, short, NULL, 0);
 | 
					module_param_array(force_subclients, short, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
 | 
					MODULE_PARM_DESC(force_subclients,
 | 
				
			||||||
			"{bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
							 "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool reset;
 | 
					static bool reset;
 | 
				
			||||||
module_param(reset, bool, 0);
 | 
					module_param(reset, bool, 0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,8 +54,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned short force_subclients[4];
 | 
					static unsigned short force_subclients[4];
 | 
				
			||||||
module_param_array(force_subclients, short, NULL, 0);
 | 
					module_param_array(force_subclients, short, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
 | 
					MODULE_PARM_DESC(force_subclients,
 | 
				
			||||||
			"{bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
							 "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool init;
 | 
					static bool init;
 | 
				
			||||||
module_param(init, bool, 0);
 | 
					module_param(init, bool, 0);
 | 
				
			||||||
| 
						 | 
					@ -951,8 +951,8 @@ w83792d_detect_subclients(struct i2c_client *new_client)
 | 
				
			||||||
		for (i = 2; i <= 3; i++) {
 | 
							for (i = 2; i <= 3; i++) {
 | 
				
			||||||
			if (force_subclients[i] < 0x48 ||
 | 
								if (force_subclients[i] < 0x48 ||
 | 
				
			||||||
			    force_subclients[i] > 0x4f) {
 | 
								    force_subclients[i] > 0x4f) {
 | 
				
			||||||
				dev_err(&new_client->dev, "invalid subclient "
 | 
									dev_err(&new_client->dev,
 | 
				
			||||||
					"address %d; must be 0x48-0x4f\n",
 | 
										"invalid subclient address %d; must be 0x48-0x4f\n",
 | 
				
			||||||
					force_subclients[i]);
 | 
										force_subclients[i]);
 | 
				
			||||||
				err = -ENODEV;
 | 
									err = -ENODEV;
 | 
				
			||||||
				goto ERROR_SC_0;
 | 
									goto ERROR_SC_0;
 | 
				
			||||||
| 
						 | 
					@ -969,8 +969,9 @@ w83792d_detect_subclients(struct i2c_client *new_client)
 | 
				
			||||||
	if (!(val & 0x80)) {
 | 
						if (!(val & 0x80)) {
 | 
				
			||||||
		if ((data->lm75[0] != NULL) &&
 | 
							if ((data->lm75[0] != NULL) &&
 | 
				
			||||||
			((val & 0x7) == ((val >> 4) & 0x7))) {
 | 
								((val & 0x7) == ((val >> 4) & 0x7))) {
 | 
				
			||||||
			dev_err(&new_client->dev, "duplicate addresses 0x%x, "
 | 
								dev_err(&new_client->dev,
 | 
				
			||||||
				"use force_subclient\n", data->lm75[0]->addr);
 | 
									"duplicate addresses 0x%x, use force_subclient\n",
 | 
				
			||||||
 | 
									data->lm75[0]->addr);
 | 
				
			||||||
			err = -ENODEV;
 | 
								err = -ENODEV;
 | 
				
			||||||
			goto ERROR_SC_1;
 | 
								goto ERROR_SC_1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,8 +59,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned short force_subclients[4];
 | 
					static unsigned short force_subclients[4];
 | 
				
			||||||
module_param_array(force_subclients, short, NULL, 0);
 | 
					module_param_array(force_subclients, short, NULL, 0);
 | 
				
			||||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
 | 
					MODULE_PARM_DESC(force_subclients,
 | 
				
			||||||
		       "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
							 "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool reset;
 | 
					static bool reset;
 | 
				
			||||||
module_param(reset, bool, 0);
 | 
					module_param(reset, bool, 0);
 | 
				
			||||||
| 
						 | 
					@ -1921,8 +1921,8 @@ static int w83793_probe(struct i2c_client *client,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (i == ARRAY_SIZE(watchdog_minors)) {
 | 
						if (i == ARRAY_SIZE(watchdog_minors)) {
 | 
				
			||||||
		data->watchdog_miscdev.minor = 0;
 | 
							data->watchdog_miscdev.minor = 0;
 | 
				
			||||||
		dev_warn(&client->dev, "Couldn't register watchdog chardev "
 | 
							dev_warn(&client->dev,
 | 
				
			||||||
			"(due to no free minor)\n");
 | 
								 "Couldn't register watchdog chardev (due to no free minor)\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&watchdog_data_mutex);
 | 
						mutex_unlock(&watchdog_data_mutex);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2120,11 +2120,12 @@ static void w83795_check_dynamic_in_limits(struct i2c_client *client)
 | 
				
			||||||
					   &w83795_in[i][3].dev_attr.attr,
 | 
										   &w83795_in[i][3].dev_attr.attr,
 | 
				
			||||||
					   S_IRUGO);
 | 
										   S_IRUGO);
 | 
				
			||||||
		if (err_max || err_min)
 | 
							if (err_max || err_min)
 | 
				
			||||||
			dev_warn(&client->dev, "Failed to set in%d limits "
 | 
								dev_warn(&client->dev,
 | 
				
			||||||
				 "read-only (%d, %d)\n", i, err_max, err_min);
 | 
									 "Failed to set in%d limits read-only (%d, %d)\n",
 | 
				
			||||||
 | 
									 i, err_max, err_min);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			dev_info(&client->dev, "in%d limits set dynamically "
 | 
								dev_info(&client->dev,
 | 
				
			||||||
				 "from VID\n", i);
 | 
									 "in%d limits set dynamically from VID\n", i);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,8 @@
 | 
				
			||||||
#ifndef _LINUX_NTC_H
 | 
					#ifndef _LINUX_NTC_H
 | 
				
			||||||
#define _LINUX_NTC_H
 | 
					#define _LINUX_NTC_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct iio_channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum ntc_thermistor_type {
 | 
					enum ntc_thermistor_type {
 | 
				
			||||||
	TYPE_NCPXXWB473,
 | 
						TYPE_NCPXXWB473,
 | 
				
			||||||
	TYPE_NCPXXWL333,
 | 
						TYPE_NCPXXWL333,
 | 
				
			||||||
| 
						 | 
					@ -39,13 +41,17 @@ struct ntc_thermistor_platform_data {
 | 
				
			||||||
	 * described at Documentation/hwmon/ntc_thermistor
 | 
						 * described at Documentation/hwmon/ntc_thermistor
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * pullup/down_ohm: 0 for infinite / not-connected
 | 
						 * pullup/down_ohm: 0 for infinite / not-connected
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * chan: iio_channel pointer to communicate with the ADC which the
 | 
				
			||||||
 | 
						 * thermistor is using for conversion of the analog values.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	int (*read_uV)(void);
 | 
						int (*read_uv)(struct ntc_thermistor_platform_data *);
 | 
				
			||||||
	unsigned int pullup_uV;
 | 
						unsigned int pullup_uv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int pullup_ohm;
 | 
						unsigned int pullup_ohm;
 | 
				
			||||||
	unsigned int pulldown_ohm;
 | 
						unsigned int pulldown_ohm;
 | 
				
			||||||
	enum { NTC_CONNECTED_POSITIVE, NTC_CONNECTED_GROUND } connect;
 | 
						enum { NTC_CONNECTED_POSITIVE, NTC_CONNECTED_GROUND } connect;
 | 
				
			||||||
 | 
						struct iio_channel *chan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int (*read_ohm)(void);
 | 
						int (*read_ohm)(void);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue