mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 17:23:55 +08:00
New drivers for ADC128D818, LTC2945, LTC4260, and LTC4222.
Added support for LTM4676 to ltc2978 driver. Converted several drivers to use devm_hwmon_device_register_with_groups. Various cleanup in several drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJTOKi6AAoJEMsfJm/On5mBxTUP/R8v33fuvpvToBkDB2U7Cv6w IOZenshpBpyk40IHLX+yxHKfmeS91VcuwBmQIgcmGgaBqi8fvaa3o4vFwjDFhEXB +RkrxPiV4t5O3xKyqiYYZwGAznt2IIpewUtM6DTyXlewbTBmishGur2e2UX6UNIf zQNhV3vzSjlxSlQq1aMe4RGne7FX1CJL7HMOs6rWGdNdPDdU+nryujHs+ADHVhL2 naYNiTv1f55znzp0sw+o4Gg+s9IeQxUmM6YHb7XFol9tXR7T9nJnOf9oXxpKNI2G fiu08YDPeV9RyIYDqgcCc/zTDVauoWXSOdU3b7EbYHCBXTn5HX/6QS8HpBKd9NTE Zl7iOTTHYgWDcBcqoyf3I1x+3+xYJvdEVtj+iDQYBsiOg4NMyGhT2cS9OvKTDmEG zitqifWDX1YNKT6dCLS49jXu3rVhsV0z0kJNX3MxXKuFyNcqHMbbhZVRa0I86Ae5 OYPjrsmRSFEC89Ip3ePSs8gc0NXImfM3KCJdtU+CUcoIsR1spGBPAqcgMbuSWZAV 40UNN59LI9fTQ4PFV7ibljp/slQn0OSChPjT4jAjvfN9WMw8yBn3vqtylOfNkkEE tef66LbcpMn88EcJEc6LBsHco7hEjZc2PEP6b6NHvOm4tAFqj0GP+5kJzXlAqEGF 0vwTI2GihBzUNp/1T0AA =U7ih -----END PGP SIGNATURE----- Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hwmon updates from Guenter Roeck: - New drivers for ADC128D818, LTC2945, LTC4260, and LTC4222 - Added support for LTM4676 to ltc2978 driver - Converted several drivers to use devm_hwmon_device_register_with_groups - Various cleanup in several drivers * tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (36 commits) hwmon: (pmbus/ltc2978) Add support for LTM4676 hwmon: (pmbus/ltc2978) Add new chip ID for LTC2974 hwmon: Do not accept invalid name attributes hwmon: (max6639) Use SIMPLE_DEV_PM_OPS macro hwmon: (lm95245) Make temp2_crit_hyst read-only hwmon: (lm95245) Convert to use devm_hwmon_device_register_with_groups hwmon: (lm95245) Drop useless debug message hwmon: (lm95245) Fix hysteresis temperatures hwmon: (max6639) Convert to use devm_hwmon_device_register_with_groups hwmon: (max6639) Introduce local dev variable, and reduce noisiness hwmon: (max6650) Introduce local 'dev' variable hwmon: (max6650) Drop error message after memory allocation failures hwmon: (max6650) Convert to use devm_hwmon_device_register_with_groups hwmon: (max6650) Rearrange code to no longer require forward declarations hwmon: (ltc4215) Convert to devm_hwmon_device_register_with_groups hwmon: (coretemp) Convert to use devm_hwmon_device_register_with_groups hwmon: (coretemp) Allocate platform data with devm_kzalloc hwmon: (coretemp) Use sysfs_create_group to create sysfs attributes hwmon: (ltc4245) Remove devicetree conditionals hwmon: (ltc4245) Drop debug messages ...
This commit is contained in:
commit
26f31fb936
47
Documentation/hwmon/adc128d818
Normal file
47
Documentation/hwmon/adc128d818
Normal file
@ -0,0 +1,47 @@
|
||||
Kernel driver adc128d818
|
||||
========================
|
||||
|
||||
Supported chips:
|
||||
* Texas Instruments ADC818D818
|
||||
Prefix: 'adc818d818'
|
||||
Addresses scanned: I2C 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f
|
||||
Datasheet: Publicly available at the TI website
|
||||
http://www.ti.com/
|
||||
|
||||
Author: Guenter Roeck
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Texas Instruments ADC128D818.
|
||||
It is described as 'ADC System Monitor with Temperature Sensor'.
|
||||
|
||||
The ADC128D818 implements one temperature sensor and seven voltage sensors.
|
||||
|
||||
Temperatures are measured in degrees Celsius. There is one set of limits.
|
||||
When the HOT Temperature Limit is crossed, this will cause an alarm that will
|
||||
be reasserted until the temperature drops below the HOT Hysteresis.
|
||||
Measurements are guaranteed between -55 and +125 degrees. The temperature
|
||||
measurement has a resolution of 0.5 degrees; the limits have a resolution
|
||||
of 1 degree.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in volts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit. Note that minimum in this case always means 'closest to
|
||||
zero'; this is important for negative voltage measurements. All voltage
|
||||
inputs can measure voltages between 0 and 2.55 volts, with a resolution
|
||||
of 0.625 mV.
|
||||
|
||||
If an alarm triggers, it will remain triggered until the hardware register
|
||||
is read at least once. This means that the cause for the alarm may
|
||||
already have disappeared by the time the alarm is read. The driver
|
||||
caches the alarm status for each sensor until it is at least reported
|
||||
once, to ensure that alarms are reported to user space.
|
||||
|
||||
The ADC128D818 only updates its values approximately once per second;
|
||||
reading it more often will do no harm, but will return 'old' values.
|
||||
|
||||
In addition to the scanned address list, the chip can also be configured for
|
||||
addresses 0x35 to 0x37. Those addresses are not scanned. You have to instantiate
|
||||
the driver explicitly if the chip is configured for any of those addresses in
|
||||
your system.
|
@ -24,8 +24,12 @@ is given within a range of -127 to +127.875 degrees. Remote temperatures are
|
||||
given within a range of -127 to +255 degrees. Resolution depends on
|
||||
temperature input and range.
|
||||
|
||||
Each sensor has its own critical limit, but the hysteresis is common to all
|
||||
two channels.
|
||||
Each sensor has its own critical limit. Additionally, there is a relative
|
||||
hysteresis value common to both critical limits. To make life easier to
|
||||
user-space applications, two absolute values are exported, one for each
|
||||
channel, but these values are of course linked. Only the local hysteresis
|
||||
can be set from user-space, and the same delta applies to the remote
|
||||
hysteresis.
|
||||
|
||||
The lm95245 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
|
||||
|
84
Documentation/hwmon/ltc2945
Normal file
84
Documentation/hwmon/ltc2945
Normal file
@ -0,0 +1,84 @@
|
||||
Kernel driver ltc2945
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Linear Technology LTC2945
|
||||
Prefix: 'ltc2945'
|
||||
Addresses scanned: -
|
||||
Datasheet:
|
||||
http://cds.linear.com/docs/en/datasheet/2945fa.pdf
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The LTC2945 is a rail-to-rail system monitor that measures current, voltage,
|
||||
and power consumption.
|
||||
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
||||
This driver does not probe for LTC2945 devices, since there is no register
|
||||
which can be safely used to identify the chip. You will have to instantiate
|
||||
the devices explicitly.
|
||||
|
||||
Example: the following will load the driver for an LTC2945 at address 0x10
|
||||
on I2C bus #1:
|
||||
$ modprobe ltc2945
|
||||
$ echo ltc2945 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
|
||||
|
||||
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
Voltage readings provided by this driver are reported as obtained from the ADC
|
||||
registers. If a set of voltage divider resistors is installed, calculate the
|
||||
real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
|
||||
value of the divider resistor against the measured voltage and R2 is the value
|
||||
of the divider resistor against Ground.
|
||||
|
||||
Current reading provided by this driver is reported as obtained from the ADC
|
||||
Current Sense register. The reported value assumes that a 1 mOhm sense resistor
|
||||
is installed. If a different sense resistor is installed, calculate the real
|
||||
current by dividing the reported value by the sense resistor value in mOhm.
|
||||
|
||||
in1_input VIN voltage (mV). Voltage is measured either at
|
||||
SENSE+ or VDD pin depending on chip configuration.
|
||||
in1_min Undervoltage threshold
|
||||
in1_max Overvoltage threshold
|
||||
in1_lowest Lowest measured voltage
|
||||
in1_highest Highest measured voltage
|
||||
in1_reset_history Write 1 to reset in1 history
|
||||
in1_min_alarm Undervoltage alarm
|
||||
in1_max_alarm Overvoltage alarm
|
||||
|
||||
in2_input ADIN voltage (mV)
|
||||
in2_min Undervoltage threshold
|
||||
in2_max Overvoltage threshold
|
||||
in2_lowest Lowest measured voltage
|
||||
in2_highest Highest measured voltage
|
||||
in2_reset_history Write 1 to reset in2 history
|
||||
in2_min_alarm Undervoltage alarm
|
||||
in2_max_alarm Overvoltage alarm
|
||||
|
||||
curr1_input SENSE current (mA)
|
||||
curr1_min Undercurrent threshold
|
||||
curr1_max Overcurrent threshold
|
||||
curr1_lowest Lowest measured current
|
||||
curr1_highest Highest measured current
|
||||
curr1_reset_history Write 1 to reset curr1 history
|
||||
curr1_min_alarm Undercurrent alarm
|
||||
curr1_max_alarm Overcurrent alarm
|
||||
|
||||
power1_input Power (in uW). Power is calculated based on SENSE+/VDD
|
||||
voltage or ADIN voltage depending on chip configuration.
|
||||
power1_min Low lower threshold
|
||||
power1_max High power threshold
|
||||
power1_input_lowest Historical minimum power use
|
||||
power1_input_highest Historical maximum power use
|
||||
power1_reset_history Write 1 to reset power1 history
|
||||
power1_min_alarm Low power alarm
|
||||
power1_max_alarm High power alarm
|
@ -23,6 +23,10 @@ Supported chips:
|
||||
Prefix: 'ltc3883'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://www.linear.com/product/ltc3883
|
||||
* Linear Technology LTM4676
|
||||
Prefix: 'ltm4676'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://www.linear.com/product/ltm4676
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
@ -33,7 +37,8 @@ Description
|
||||
LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply
|
||||
monitor. LTC2977 is a pin compatible replacement for LTC2978. LTC3880 is a dual
|
||||
output poly-phase step-down DC/DC controller. LTC3883 is a single phase
|
||||
step-down DC/DC controller.
|
||||
step-down DC/DC controller. LTM4676 is a dual 13A or single 26A uModule
|
||||
regulator.
|
||||
|
||||
|
||||
Usage Notes
|
||||
@ -75,7 +80,7 @@ in[N]_label "vout[1-8]".
|
||||
LTC2974: N=2-5
|
||||
LTC2977: N=2-9
|
||||
LTC2978: N=2-9
|
||||
LTC3880: N=2-3
|
||||
LTC3880, LTM4676: N=2-3
|
||||
LTC3883: N=2
|
||||
in[N]_input Measured output voltage.
|
||||
in[N]_min Minimum output voltage.
|
||||
@ -95,7 +100,7 @@ temp[N]_input Measured temperature.
|
||||
and temp5 reports the chip temperature.
|
||||
On LTC2977 and LTC2978, only one temperature measurement
|
||||
is supported and reports the chip temperature.
|
||||
On LTC3880, temp1 and temp2 report external
|
||||
On LTC3880 and LTM4676, temp1 and temp2 report external
|
||||
temperatures, and temp3 reports the chip temperature.
|
||||
On LTC3883, temp1 reports an external temperature,
|
||||
and temp2 reports the chip temperature.
|
||||
@ -123,11 +128,11 @@ power[N]_label "pout[1-4]".
|
||||
LTC2974: N=1-4
|
||||
LTC2977: Not supported
|
||||
LTC2978: Not supported
|
||||
LTC3880: N=1-2
|
||||
LTC3880, LTM4676: N=1-2
|
||||
LTC3883: N=2
|
||||
power[N]_input Measured output power.
|
||||
|
||||
curr1_label "iin". LTC3880 and LTC3883 only.
|
||||
curr1_label "iin". LTC3880, LTC3883, and LTM4676 only.
|
||||
curr1_input Measured input current.
|
||||
curr1_max Maximum input current.
|
||||
curr1_max_alarm Input current high alarm.
|
||||
@ -138,7 +143,7 @@ curr[N]_label "iout[1-4]".
|
||||
LTC2974: N=1-4
|
||||
LTC2977: not supported
|
||||
LTC2978: not supported
|
||||
LTC3880: N=2-3
|
||||
LTC3880, LTM4676: N=2-3
|
||||
LTC3883: N=2
|
||||
curr[N]_input Measured output current.
|
||||
curr[N]_max Maximum output current.
|
||||
|
56
Documentation/hwmon/ltc4260
Normal file
56
Documentation/hwmon/ltc4260
Normal file
@ -0,0 +1,56 @@
|
||||
Kernel driver ltc4260
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Linear Technology LTC4260
|
||||
Prefix: 'ltc4260'
|
||||
Addresses scanned: -
|
||||
Datasheet:
|
||||
http://cds.linear.com/docs/en/datasheet/4260fc.pdf
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The LTC4260 Hot Swap controller allows a board to be safely inserted
|
||||
and removed from a live backplane.
|
||||
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
||||
This driver does not probe for LTC4260 devices, since there is no register
|
||||
which can be safely used to identify the chip. You will have to instantiate
|
||||
the devices explicitly.
|
||||
|
||||
Example: the following will load the driver for an LTC4260 at address 0x10
|
||||
on I2C bus #1:
|
||||
$ modprobe ltc4260
|
||||
$ echo ltc4260 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
|
||||
|
||||
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
Voltage readings provided by this driver are reported as obtained from the ADC
|
||||
registers. If a set of voltage divider resistors is installed, calculate the
|
||||
real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
|
||||
value of the divider resistor against the measured voltage and R2 is the value
|
||||
of the divider resistor against Ground.
|
||||
|
||||
Current reading provided by this driver is reported as obtained from the ADC
|
||||
Current Sense register. The reported value assumes that a 1 mOhm sense resistor
|
||||
is installed. If a different sense resistor is installed, calculate the real
|
||||
current by dividing the reported value by the sense resistor value in mOhm.
|
||||
|
||||
in1_input SOURCE voltage (mV)
|
||||
in1_min_alarm Undervoltage alarm
|
||||
in1_max_alarm Overvoltage alarm
|
||||
|
||||
in2_input ADIN voltage (mV)
|
||||
in2_alarm Power bad alarm
|
||||
|
||||
curr1_input SENSE current (mA)
|
||||
curr1_alarm SENSE overcurrent alarm
|
@ -111,22 +111,6 @@ config SENSORS_AD7418
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ad7418.
|
||||
|
||||
config SENSORS_ADCXX
|
||||
tristate "National Semiconductor ADCxxxSxxx"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
If you say yes here you get support for the National Semiconductor
|
||||
ADC<bb><c>S<sss> chip family, where
|
||||
* bb is the resolution in number of bits (8, 10, 12)
|
||||
* c is the number of channels (1, 2, 4, 8)
|
||||
* sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500
|
||||
kSPS and 101 for 1 MSPS)
|
||||
|
||||
Examples : ADC081S101, ADC124S501, ...
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adcxx.
|
||||
|
||||
config SENSORS_ADM1021
|
||||
tristate "Analog Devices ADM1021 and compatibles"
|
||||
depends on I2C
|
||||
@ -312,6 +296,31 @@ config SENSORS_FAM15H_POWER
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called fam15h_power.
|
||||
|
||||
config SENSORS_APPLESMC
|
||||
tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
|
||||
depends on INPUT && X86
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
select INPUT_POLLDEV
|
||||
default n
|
||||
help
|
||||
This driver provides support for the Apple System Management
|
||||
Controller, which provides an accelerometer (Apple Sudden Motion
|
||||
Sensor), light sensors, temperature sensors, keyboard backlight
|
||||
control and fan control.
|
||||
|
||||
Only Intel-based Apple's computers are supported (MacBook Pro,
|
||||
MacBook, MacMini).
|
||||
|
||||
Data from the different sensors, keyboard backlight control and fan
|
||||
control are accessible via sysfs.
|
||||
|
||||
This driver also provides an absolute input class device, allowing
|
||||
the laptop to act as a pinball machine-esque joystick.
|
||||
|
||||
Say Y here if you have an applicable laptop and want to experience
|
||||
the awesome power of applesmc.
|
||||
|
||||
config SENSORS_ASB100
|
||||
tristate "Asus ASB100 Bach"
|
||||
depends on X86 && I2C
|
||||
@ -435,6 +444,12 @@ config SENSORS_F75375S
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called f75375s.
|
||||
|
||||
config SENSORS_MC13783_ADC
|
||||
tristate "Freescale MC13783/MC13892 ADC"
|
||||
depends on MFD_MC13XXX
|
||||
help
|
||||
Support for the A/D converter on MC13783 and MC13892 PMIC.
|
||||
|
||||
config SENSORS_FSCHMD
|
||||
tristate "Fujitsu Siemens Computers sensor chips"
|
||||
depends on X86 && I2C
|
||||
@ -451,26 +466,6 @@ config SENSORS_FSCHMD
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called fschmd.
|
||||
|
||||
config SENSORS_G760A
|
||||
tristate "GMT G760A"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Global Mixed-mode
|
||||
Technology Inc G760A fan speed PWM controller chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called g760a.
|
||||
|
||||
config SENSORS_G762
|
||||
tristate "GMT G762 and G763"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Global Mixed-mode
|
||||
Technology Inc G762 and G763 fan speed PWM controller chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called g762.
|
||||
|
||||
config SENSORS_GL518SM
|
||||
tristate "Genesys Logic GL518SM"
|
||||
depends on I2C
|
||||
@ -492,6 +487,26 @@ config SENSORS_GL520SM
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called gl520sm.
|
||||
|
||||
config SENSORS_G760A
|
||||
tristate "GMT G760A"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Global Mixed-mode
|
||||
Technology Inc G760A fan speed PWM controller chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called g760a.
|
||||
|
||||
config SENSORS_G762
|
||||
tristate "GMT G762 and G763"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Global Mixed-mode
|
||||
Technology Inc G762 and G763 fan speed PWM controller chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called g762.
|
||||
|
||||
config SENSORS_GPIO_FAN
|
||||
tristate "GPIO fan"
|
||||
depends on GPIOLIB
|
||||
@ -511,24 +526,6 @@ config SENSORS_HIH6130
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called hih6130.
|
||||
|
||||
config SENSORS_HTU21
|
||||
tristate "Measurement Specialties HTU21D humidity/temperature sensors"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Measurement Specialties
|
||||
HTU21D humidity and temperature sensors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called htu21.
|
||||
|
||||
config SENSORS_CORETEMP
|
||||
tristate "Intel Core/Core2/Atom temperature sensor"
|
||||
depends on X86
|
||||
help
|
||||
If you say yes here you get support for the temperature
|
||||
sensor inside your CPU. Most of the family 6 CPUs
|
||||
are supported. Check Documentation/hwmon/coretemp for details.
|
||||
|
||||
config SENSORS_IBMAEM
|
||||
tristate "IBM Active Energy Manager temperature/power sensors and control"
|
||||
select IPMI_SI
|
||||
@ -566,6 +563,14 @@ config SENSORS_IIO_HWMON
|
||||
for those channels specified in the map. This map can be provided
|
||||
either via platform data or the device tree bindings.
|
||||
|
||||
config SENSORS_CORETEMP
|
||||
tristate "Intel Core/Core2/Atom temperature sensor"
|
||||
depends on X86
|
||||
help
|
||||
If you say yes here you get support for the temperature
|
||||
sensor inside your CPU. Most of the family 6 CPUs
|
||||
are supported. Check Documentation/hwmon/coretemp for details.
|
||||
|
||||
config SENSORS_IT87
|
||||
tristate "ITE IT87xx and compatibles"
|
||||
depends on !PPC
|
||||
@ -614,6 +619,219 @@ config SENSORS_LINEAGE
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lineage-pem.
|
||||
|
||||
config SENSORS_LTC2945
|
||||
tristate "Linear Technology LTC2945"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC2945
|
||||
I2C System Monitor.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc2945.
|
||||
|
||||
config SENSORS_LTC4151
|
||||
tristate "Linear Technology LTC4151"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4151
|
||||
High Voltage I2C Current and Voltage Monitor interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4151.
|
||||
|
||||
config SENSORS_LTC4215
|
||||
tristate "Linear Technology LTC4215"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4215
|
||||
Hot Swap Controller I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4215.
|
||||
|
||||
config SENSORS_LTC4222
|
||||
tristate "Linear Technology LTC4222"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4222
|
||||
Dual Hot Swap Controller I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4222.
|
||||
|
||||
config SENSORS_LTC4245
|
||||
tristate "Linear Technology LTC4245"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4245
|
||||
Multiple Supply Hot Swap Controller I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4245.
|
||||
|
||||
config SENSORS_LTC4260
|
||||
tristate "Linear Technology LTC4260"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4260
|
||||
Positive Voltage Hot Swap Controller I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4260.
|
||||
|
||||
config SENSORS_LTC4261
|
||||
tristate "Linear Technology LTC4261"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4261
|
||||
Negative Voltage Hot Swap Controller I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4261.
|
||||
|
||||
config SENSORS_MAX1111
|
||||
tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
|
||||
ADC chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max1111.
|
||||
|
||||
config SENSORS_MAX16065
|
||||
tristate "Maxim MAX16065 System Manager and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for hardware monitoring
|
||||
capabilities of the following Maxim System Manager chips.
|
||||
MAX16065
|
||||
MAX16066
|
||||
MAX16067
|
||||
MAX16068
|
||||
MAX16070
|
||||
MAX16071
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max16065.
|
||||
|
||||
config SENSORS_MAX1619
|
||||
tristate "Maxim MAX1619 sensor chip"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MAX1619 sensor chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max1619.
|
||||
|
||||
config SENSORS_MAX1668
|
||||
tristate "Maxim MAX1668 and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MAX1668, MAX1989 and
|
||||
MAX1805 chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max1668.
|
||||
|
||||
config SENSORS_MAX197
|
||||
tristate "Maxim MAX197 and compatibles"
|
||||
help
|
||||
Support for the Maxim MAX197 A/D converter.
|
||||
Support will include, but not be limited to, MAX197, and MAX199.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max197.
|
||||
|
||||
config SENSORS_MAX6639
|
||||
tristate "Maxim MAX6639 sensor chip"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the MAX6639
|
||||
sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6639.
|
||||
|
||||
config SENSORS_MAX6642
|
||||
tristate "Maxim MAX6642 sensor chip"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MAX6642 sensor chip.
|
||||
MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
|
||||
with Overtemperature Alarm from Maxim.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6642.
|
||||
|
||||
config SENSORS_MAX6650
|
||||
tristate "Maxim MAX6650 sensor chip"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the MAX6650 / MAX6651
|
||||
sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6650.
|
||||
|
||||
config SENSORS_MAX6697
|
||||
tristate "Maxim MAX6697 and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MAX6581, MAX6602, MAX6622,
|
||||
MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
|
||||
temperature sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6697.
|
||||
|
||||
config SENSORS_HTU21
|
||||
tristate "Measurement Specialties HTU21D humidity/temperature sensors"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Measurement Specialties
|
||||
HTU21D humidity and temperature sensors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called htu21.
|
||||
|
||||
config SENSORS_MCP3021
|
||||
tristate "Microchip MCP3021 and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MCP3021 and MCP3221.
|
||||
The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
|
||||
with 12-bit resolution.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called mcp3021.
|
||||
|
||||
config SENSORS_ADCXX
|
||||
tristate "National Semiconductor ADCxxxSxxx"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
If you say yes here you get support for the National Semiconductor
|
||||
ADC<bb><c>S<sss> chip family, where
|
||||
* bb is the resolution in number of bits (8, 10, 12)
|
||||
* c is the number of channels (1, 2, 4, 8)
|
||||
* sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500
|
||||
kSPS and 101 for 1 MSPS)
|
||||
|
||||
Examples : ADC081S101, ADC124S501, ...
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adcxx.
|
||||
|
||||
config SENSORS_LM63
|
||||
tristate "National Semiconductor LM63 and compatibles"
|
||||
depends on I2C
|
||||
@ -776,50 +994,6 @@ config SENSORS_LM93
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm93.
|
||||
|
||||
config SENSORS_LTC4151
|
||||
tristate "Linear Technology LTC4151"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4151
|
||||
High Voltage I2C Current and Voltage Monitor interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4151.
|
||||
|
||||
config SENSORS_LTC4215
|
||||
tristate "Linear Technology LTC4215"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4215
|
||||
Hot Swap Controller I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4215.
|
||||
|
||||
config SENSORS_LTC4245
|
||||
tristate "Linear Technology LTC4245"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4245
|
||||
Multiple Supply Hot Swap Controller I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4245.
|
||||
|
||||
config SENSORS_LTC4261
|
||||
tristate "Linear Technology LTC4261"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for Linear Technology LTC4261
|
||||
Negative Voltage Hot Swap Controller I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4261.
|
||||
|
||||
config SENSORS_LM95234
|
||||
tristate "National Semiconductor LM95234"
|
||||
depends on I2C
|
||||
@ -849,140 +1023,6 @@ config SENSORS_LM95245
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm95245.
|
||||
|
||||
config SENSORS_MAX1111
|
||||
tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
|
||||
ADC chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max1111.
|
||||
|
||||
config SENSORS_MAX16065
|
||||
tristate "Maxim MAX16065 System Manager and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for hardware monitoring
|
||||
capabilities of the following Maxim System Manager chips.
|
||||
MAX16065
|
||||
MAX16066
|
||||
MAX16067
|
||||
MAX16068
|
||||
MAX16070
|
||||
MAX16071
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max16065.
|
||||
|
||||
config SENSORS_MAX1619
|
||||
tristate "Maxim MAX1619 sensor chip"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MAX1619 sensor chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max1619.
|
||||
|
||||
config SENSORS_MAX1668
|
||||
tristate "Maxim MAX1668 and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MAX1668, MAX1989 and
|
||||
MAX1805 chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max1668.
|
||||
|
||||
config SENSORS_MAX197
|
||||
tristate "Maxim MAX197 and compatibles"
|
||||
help
|
||||
Support for the Maxim MAX197 A/D converter.
|
||||
Support will include, but not be limited to, MAX197, and MAX199.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max197.
|
||||
|
||||
config SENSORS_MAX6639
|
||||
tristate "Maxim MAX6639 sensor chip"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the MAX6639
|
||||
sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6639.
|
||||
|
||||
config SENSORS_MAX6642
|
||||
tristate "Maxim MAX6642 sensor chip"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MAX6642 sensor chip.
|
||||
MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
|
||||
with Overtemperature Alarm from Maxim.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6642.
|
||||
|
||||
config SENSORS_MAX6650
|
||||
tristate "Maxim MAX6650 sensor chip"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the MAX6650 / MAX6651
|
||||
sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6650.
|
||||
|
||||
config SENSORS_MAX6697
|
||||
tristate "Maxim MAX6697 and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MAX6581, MAX6602, MAX6622,
|
||||
MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
|
||||
temperature sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6697.
|
||||
|
||||
config SENSORS_MCP3021
|
||||
tristate "Microchip MCP3021 and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for MCP3021 and MCP3221.
|
||||
The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
|
||||
with 12-bit resolution.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
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
|
||||
tristate "NTC thermistor support"
|
||||
depends on (!OF && !IIO) || (OF && IIO)
|
||||
help
|
||||
This driver supports NTC thermistors sensor reading and its
|
||||
interpretation. The driver can also monitor the temperature and
|
||||
send notifications about the temperature.
|
||||
|
||||
Currently, this driver supports
|
||||
NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ntc-thermistor.
|
||||
|
||||
config SENSORS_PC87360
|
||||
tristate "National Semiconductor PC87360 family"
|
||||
depends on !PPC
|
||||
@ -1011,6 +1051,33 @@ config SENSORS_PC87427
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pc87427.
|
||||
|
||||
config SENSORS_NTC_THERMISTOR
|
||||
tristate "NTC thermistor support"
|
||||
depends on (!OF && !IIO) || (OF && IIO)
|
||||
help
|
||||
This driver supports NTC thermistors sensor reading and its
|
||||
interpretation. The driver can also monitor the temperature and
|
||||
send notifications about the temperature.
|
||||
|
||||
Currently, this driver supports
|
||||
NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ntc-thermistor.
|
||||
|
||||
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_PCF8591
|
||||
tristate "Philips PCF8591 ADC/DAC"
|
||||
depends on I2C
|
||||
@ -1074,21 +1141,6 @@ config SENSORS_SIS5595
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sis5595.
|
||||
|
||||
config SENSORS_SMM665
|
||||
tristate "Summit Microelectronics SMM665"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for the hardware monitoring
|
||||
features of the Summit Microelectronics SMM665/SMM665B Six-Channel
|
||||
Active DC Output Controller / Monitor.
|
||||
|
||||
Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
|
||||
Support for those chips is untested.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called smm665.
|
||||
|
||||
config SENSORS_DME1737
|
||||
tristate "SMSC DME1737, SCH311x and compatibles"
|
||||
depends on I2C && !PPC
|
||||
@ -1210,6 +1262,31 @@ config SENSORS_SCH5636
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sch5636.
|
||||
|
||||
config SENSORS_SMM665
|
||||
tristate "Summit Microelectronics SMM665"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support for the hardware monitoring
|
||||
features of the Summit Microelectronics SMM665/SMM665B Six-Channel
|
||||
Active DC Output Controller / Monitor.
|
||||
|
||||
Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
|
||||
Support for those chips is untested.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called smm665.
|
||||
|
||||
config SENSORS_ADC128D818
|
||||
tristate "Texas Instruments ADC128D818"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Texas Instruments
|
||||
ADC128D818 System Monitor with Temperature Sensor chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adc128d818.
|
||||
|
||||
config SENSORS_ADS1015
|
||||
tristate "Texas Instruments ADS1015"
|
||||
depends on I2C
|
||||
@ -1525,37 +1602,6 @@ config SENSORS_ULTRA45
|
||||
This driver provides support for the Ultra45 workstation environmental
|
||||
sensors.
|
||||
|
||||
config SENSORS_APPLESMC
|
||||
tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
|
||||
depends on INPUT && X86
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
select INPUT_POLLDEV
|
||||
default n
|
||||
help
|
||||
This driver provides support for the Apple System Management
|
||||
Controller, which provides an accelerometer (Apple Sudden Motion
|
||||
Sensor), light sensors, temperature sensors, keyboard backlight
|
||||
control and fan control.
|
||||
|
||||
Only Intel-based Apple's computers are supported (MacBook Pro,
|
||||
MacBook, MacMini).
|
||||
|
||||
Data from the different sensors, keyboard backlight control and fan
|
||||
control are accessible via sysfs.
|
||||
|
||||
This driver also provides an absolute input class device, allowing
|
||||
the laptop to act as a pinball machine-esque joystick.
|
||||
|
||||
Say Y here if you have an applicable laptop and want to experience
|
||||
the awesome power of applesmc.
|
||||
|
||||
config SENSORS_MC13783_ADC
|
||||
tristate "Freescale MC13783/MC13892 ADC"
|
||||
depends on MFD_MC13XXX
|
||||
help
|
||||
Support for the A/D converter on MC13783 and MC13892 PMIC.
|
||||
|
||||
if ACPI
|
||||
|
||||
comment "ACPI drivers"
|
||||
|
@ -25,6 +25,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
|
||||
obj-$(CONFIG_SENSORS_AD7314) += ad7314.o
|
||||
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
|
||||
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
|
||||
obj-$(CONFIG_SENSORS_ADC128D818) += adc128d818.o
|
||||
obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o
|
||||
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
|
||||
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
|
||||
@ -95,9 +96,12 @@ obj-$(CONFIG_SENSORS_LM93) += lm93.o
|
||||
obj-$(CONFIG_SENSORS_LM95234) += lm95234.o
|
||||
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
|
||||
obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
|
||||
obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o
|
||||
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
|
||||
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
|
||||
obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o
|
||||
obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
|
||||
obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o
|
||||
obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
|
||||
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
|
||||
obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
|
||||
|
491
drivers/hwmon/adc128d818.c
Normal file
491
drivers/hwmon/adc128d818.c
Normal file
@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Driver for TI ADC128D818 System Monitor with Temperature Sensor
|
||||
*
|
||||
* Copyright (c) 2014 Guenter Roeck
|
||||
*
|
||||
* Derived from lm80.c
|
||||
* Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
* and Philip Edelbrock <phil@netroedge.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/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/regulator/consumer.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
/* Addresses to scan
|
||||
* The chip also supports addresses 0x35..0x37. Don't scan those addresses
|
||||
* since they are also used by some EEPROMs, which may result in false
|
||||
* positives.
|
||||
*/
|
||||
static const unsigned short normal_i2c[] = {
|
||||
0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
|
||||
|
||||
/* registers */
|
||||
#define ADC128_REG_IN_MAX(nr) (0x2a + (nr) * 2)
|
||||
#define ADC128_REG_IN_MIN(nr) (0x2b + (nr) * 2)
|
||||
#define ADC128_REG_IN(nr) (0x20 + (nr))
|
||||
|
||||
#define ADC128_REG_TEMP 0x27
|
||||
#define ADC128_REG_TEMP_MAX 0x38
|
||||
#define ADC128_REG_TEMP_HYST 0x39
|
||||
|
||||
#define ADC128_REG_CONFIG 0x00
|
||||
#define ADC128_REG_ALARM 0x01
|
||||
#define ADC128_REG_MASK 0x03
|
||||
#define ADC128_REG_CONV_RATE 0x07
|
||||
#define ADC128_REG_ONESHOT 0x09
|
||||
#define ADC128_REG_SHUTDOWN 0x0a
|
||||
#define ADC128_REG_CONFIG_ADV 0x0b
|
||||
#define ADC128_REG_BUSY_STATUS 0x0c
|
||||
|
||||
#define ADC128_REG_MAN_ID 0x3e
|
||||
#define ADC128_REG_DEV_ID 0x3f
|
||||
|
||||
struct adc128_data {
|
||||
struct i2c_client *client;
|
||||
struct regulator *regulator;
|
||||
int vref; /* Reference voltage in mV */
|
||||
struct mutex update_lock;
|
||||
bool valid; /* true if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
u16 in[3][7]; /* Register value, normalized to 12 bit
|
||||
* 0: input voltage
|
||||
* 1: min limit
|
||||
* 2: max limit
|
||||
*/
|
||||
s16 temp[3]; /* Register value, normalized to 9 bit
|
||||
* 0: sensor 1: limit 2: hyst
|
||||
*/
|
||||
u8 alarms; /* alarm register value */
|
||||
};
|
||||
|
||||
static struct adc128_data *adc128_update_device(struct device *dev)
|
||||
{
|
||||
struct adc128_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
struct adc128_data *ret = data;
|
||||
int i, rv;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
for (i = 0; i < 7; i++) {
|
||||
rv = i2c_smbus_read_word_swapped(client,
|
||||
ADC128_REG_IN(i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->in[0][i] = rv >> 4;
|
||||
|
||||
rv = i2c_smbus_read_byte_data(client,
|
||||
ADC128_REG_IN_MIN(i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->in[1][i] = rv << 4;
|
||||
|
||||
rv = i2c_smbus_read_byte_data(client,
|
||||
ADC128_REG_IN_MAX(i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->in[2][i] = rv << 4;
|
||||
}
|
||||
|
||||
rv = i2c_smbus_read_word_swapped(client, ADC128_REG_TEMP);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->temp[0] = rv >> 7;
|
||||
|
||||
rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_MAX);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->temp[1] = rv << 1;
|
||||
|
||||
rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_HYST);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->temp[2] = rv << 1;
|
||||
|
||||
rv = i2c_smbus_read_byte_data(client, ADC128_REG_ALARM);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->alarms |= rv;
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
}
|
||||
goto done;
|
||||
|
||||
abort:
|
||||
ret = ERR_PTR(rv);
|
||||
data->valid = false;
|
||||
done:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t adc128_show_in(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adc128_data *data = adc128_update_device(dev);
|
||||
int index = to_sensor_dev_attr_2(attr)->index;
|
||||
int nr = to_sensor_dev_attr_2(attr)->nr;
|
||||
int val;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
val = DIV_ROUND_CLOSEST(data->in[index][nr] * data->vref, 4095);
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
static ssize_t adc128_set_in(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adc128_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr_2(attr)->index;
|
||||
int nr = to_sensor_dev_attr_2(attr)->nr;
|
||||
u8 reg, regval;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/* 10 mV LSB on limit registers */
|
||||
regval = clamp_val(DIV_ROUND_CLOSEST(val, 10), 0, 255);
|
||||
data->in[index][nr] = regval << 4;
|
||||
reg = index == 1 ? ADC128_REG_IN_MIN(nr) : ADC128_REG_IN_MAX(nr);
|
||||
i2c_smbus_write_byte_data(data->client, reg, regval);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t adc128_show_temp(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adc128_data *data = adc128_update_device(dev);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
int temp;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
temp = (data->temp[index] << 7) >> 7; /* sign extend */
|
||||
return sprintf(buf, "%d\n", temp * 500);/* 0.5 degrees C resolution */
|
||||
}
|
||||
|
||||
static ssize_t adc128_set_temp(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adc128_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int err;
|
||||
s8 regval;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
regval = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
|
||||
data->temp[index] = regval << 1;
|
||||
i2c_smbus_write_byte_data(data->client,
|
||||
index == 1 ? ADC128_REG_TEMP_MAX
|
||||
: ADC128_REG_TEMP_HYST,
|
||||
regval);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t adc128_show_alarm(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adc128_data *data = adc128_update_device(dev);
|
||||
int mask = 1 << to_sensor_dev_attr(attr)->index;
|
||||
u8 alarms;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
/*
|
||||
* Clear an alarm after reporting it to user space. If it is still
|
||||
* active, the next update sequence will set the alarm bit again.
|
||||
*/
|
||||
alarms = data->alarms;
|
||||
data->alarms &= ~mask;
|
||||
|
||||
return sprintf(buf, "%u\n", !!(alarms & mask));
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(in0_input, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 0, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 0, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 0, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(in1_input, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 1, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 1, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 1, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(in2_input, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 2, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 2, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 2, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(in3_input, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 3, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 3, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 3, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(in4_input, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 4, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 4, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 4, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(in5_input, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 5, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 5, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 5, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(in6_input, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 6, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 6, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO,
|
||||
adc128_show_in, adc128_set_in, 6, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adc128_show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
|
||||
adc128_show_temp, adc128_set_temp, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
|
||||
adc128_show_temp, adc128_set_temp, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, adc128_show_alarm, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, adc128_show_alarm, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, adc128_show_alarm, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, adc128_show_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, adc128_show_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, adc128_show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, adc128_show_alarm, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adc128_show_alarm, NULL, 7);
|
||||
|
||||
static struct attribute *adc128_attrs[] = {
|
||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(adc128);
|
||||
|
||||
static int adc128_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||
{
|
||||
int man_id, dev_id;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
man_id = i2c_smbus_read_byte_data(client, ADC128_REG_MAN_ID);
|
||||
dev_id = i2c_smbus_read_byte_data(client, ADC128_REG_DEV_ID);
|
||||
if (man_id != 0x01 || dev_id != 0x09)
|
||||
return -ENODEV;
|
||||
|
||||
/* Check unused bits for confirmation */
|
||||
if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG) & 0xf4)
|
||||
return -ENODEV;
|
||||
if (i2c_smbus_read_byte_data(client, ADC128_REG_CONV_RATE) & 0xfe)
|
||||
return -ENODEV;
|
||||
if (i2c_smbus_read_byte_data(client, ADC128_REG_ONESHOT) & 0xfe)
|
||||
return -ENODEV;
|
||||
if (i2c_smbus_read_byte_data(client, ADC128_REG_SHUTDOWN) & 0xfe)
|
||||
return -ENODEV;
|
||||
if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG_ADV) & 0xf8)
|
||||
return -ENODEV;
|
||||
if (i2c_smbus_read_byte_data(client, ADC128_REG_BUSY_STATUS) & 0xfc)
|
||||
return -ENODEV;
|
||||
|
||||
strlcpy(info->type, "adc128d818", I2C_NAME_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adc128_init_client(struct adc128_data *data)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Reset chip to defaults.
|
||||
* This makes most other initializations unnecessary.
|
||||
*/
|
||||
err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x80);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Start monitoring */
|
||||
err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x01);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* If external vref is selected, configure the chip to use it */
|
||||
if (data->regulator) {
|
||||
err = i2c_smbus_write_byte_data(client,
|
||||
ADC128_REG_CONFIG_ADV, 0x01);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adc128_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct regulator *regulator;
|
||||
struct device *hwmon_dev;
|
||||
struct adc128_data *data;
|
||||
int err, vref;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(struct adc128_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* vref is optional. If specified, is used as chip reference voltage */
|
||||
regulator = devm_regulator_get_optional(dev, "vref");
|
||||
if (!IS_ERR(regulator)) {
|
||||
data->regulator = regulator;
|
||||
err = regulator_enable(regulator);
|
||||
if (err < 0)
|
||||
return err;
|
||||
vref = regulator_get_voltage(regulator);
|
||||
if (vref < 0) {
|
||||
err = vref;
|
||||
goto error;
|
||||
}
|
||||
data->vref = DIV_ROUND_CLOSEST(vref, 1000);
|
||||
} else {
|
||||
data->vref = 2560; /* 2.56V, in mV */
|
||||
}
|
||||
|
||||
data->client = client;
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the chip */
|
||||
err = adc128_init_client(data);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, adc128_groups);
|
||||
if (IS_ERR(hwmon_dev)) {
|
||||
err = PTR_ERR(hwmon_dev);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (data->regulator)
|
||||
regulator_disable(data->regulator);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adc128_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adc128_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (data->regulator)
|
||||
regulator_disable(data->regulator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adc128_id[] = {
|
||||
{ "adc128d818", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adc128_id);
|
||||
|
||||
static struct i2c_driver adc128_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adc128d818",
|
||||
},
|
||||
.probe = adc128_probe,
|
||||
.remove = adc128_remove,
|
||||
.id_table = adc128_id,
|
||||
.detect = adc128_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adc128_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("Driver for ADC128D818");
|
||||
MODULE_LICENSE("GPL");
|
@ -94,6 +94,8 @@ struct temp_data {
|
||||
bool valid;
|
||||
struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
|
||||
char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
|
||||
struct attribute *attrs[TOTAL_ATTRS + 1];
|
||||
struct attribute_group attr_group;
|
||||
struct mutex update_lock;
|
||||
};
|
||||
|
||||
@ -114,12 +116,6 @@ struct pdev_entry {
|
||||
static LIST_HEAD(pdev_list);
|
||||
static DEFINE_MUTEX(pdev_list_mutex);
|
||||
|
||||
static ssize_t show_name(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", DRVNAME);
|
||||
}
|
||||
|
||||
static ssize_t show_label(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
@ -393,20 +389,10 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
|
||||
return adjust_tjmax(c, id, dev);
|
||||
}
|
||||
|
||||
static int create_name_attr(struct platform_data *pdata,
|
||||
struct device *dev)
|
||||
{
|
||||
sysfs_attr_init(&pdata->name_attr.attr);
|
||||
pdata->name_attr.attr.name = "name";
|
||||
pdata->name_attr.attr.mode = S_IRUGO;
|
||||
pdata->name_attr.show = show_name;
|
||||
return device_create_file(dev, &pdata->name_attr);
|
||||
}
|
||||
|
||||
static int create_core_attrs(struct temp_data *tdata, struct device *dev,
|
||||
int attr_no)
|
||||
{
|
||||
int err, i;
|
||||
int i;
|
||||
static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
|
||||
struct device_attribute *devattr, char *buf) = {
|
||||
show_label, show_crit_alarm, show_temp, show_tjmax,
|
||||
@ -424,16 +410,10 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
|
||||
tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
|
||||
tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
|
||||
tdata->sd_attrs[i].index = attr_no;
|
||||
err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;
|
||||
}
|
||||
return 0;
|
||||
|
||||
exit_free:
|
||||
while (--i >= 0)
|
||||
device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
|
||||
return err;
|
||||
tdata->attr_group.attrs = tdata->attrs;
|
||||
return sysfs_create_group(&dev->kobj, &tdata->attr_group);
|
||||
}
|
||||
|
||||
|
||||
@ -548,7 +528,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
|
||||
pdata->core_data[attr_no] = tdata;
|
||||
|
||||
/* Create sysfs interfaces */
|
||||
err = create_core_attrs(tdata, &pdev->dev, attr_no);
|
||||
err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
@ -573,14 +553,12 @@ static void coretemp_add_core(unsigned int cpu, int pkg_flag)
|
||||
}
|
||||
|
||||
static void coretemp_remove_core(struct platform_data *pdata,
|
||||
struct device *dev, int indx)
|
||||
int indx)
|
||||
{
|
||||
int i;
|
||||
struct temp_data *tdata = pdata->core_data[indx];
|
||||
|
||||
/* Remove the sysfs attributes */
|
||||
for (i = 0; i < tdata->attr_size; i++)
|
||||
device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
|
||||
sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);
|
||||
|
||||
kfree(pdata->core_data[indx]);
|
||||
pdata->core_data[indx] = NULL;
|
||||
@ -588,34 +566,20 @@ static void coretemp_remove_core(struct platform_data *pdata,
|
||||
|
||||
static int coretemp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct platform_data *pdata;
|
||||
int err;
|
||||
|
||||
/* Initialize the per-package data structures */
|
||||
pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
|
||||
pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
err = create_name_attr(pdata, &pdev->dev);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
pdata->phys_proc_id = pdev->id;
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(pdata->hwmon_dev)) {
|
||||
err = PTR_ERR(pdata->hwmon_dev);
|
||||
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
|
||||
goto exit_name;
|
||||
}
|
||||
return 0;
|
||||
|
||||
exit_name:
|
||||
device_remove_file(&pdev->dev, &pdata->name_attr);
|
||||
exit_free:
|
||||
kfree(pdata);
|
||||
return err;
|
||||
pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
|
||||
pdata, NULL);
|
||||
return PTR_ERR_OR_ZERO(pdata->hwmon_dev);
|
||||
}
|
||||
|
||||
static int coretemp_remove(struct platform_device *pdev)
|
||||
@ -625,11 +589,8 @@ static int coretemp_remove(struct platform_device *pdev)
|
||||
|
||||
for (i = MAX_CORE_DATA - 1; i >= 0; --i)
|
||||
if (pdata->core_data[i])
|
||||
coretemp_remove_core(pdata, &pdev->dev, i);
|
||||
coretemp_remove_core(pdata, i);
|
||||
|
||||
device_remove_file(&pdev->dev, &pdata->name_attr);
|
||||
hwmon_device_unregister(pdata->hwmon_dev);
|
||||
kfree(pdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -777,7 +738,7 @@ static void put_core_offline(unsigned int cpu)
|
||||
return;
|
||||
|
||||
if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu)
|
||||
coretemp_remove_core(pdata, &pdev->dev, indx);
|
||||
coretemp_remove_core(pdata, indx);
|
||||
|
||||
/*
|
||||
* If a HT sibling of a core is taken offline, but another HT sibling
|
||||
|
@ -349,7 +349,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
|
||||
dev_dbg(&client->dev, "reg 0x%02x, err %d\n",
|
||||
REG_FAN_CONF1, status);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return -EIO;
|
||||
return status;
|
||||
}
|
||||
status &= 0x9F;
|
||||
status |= (new_range_bits << 5);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#define HWMON_ID_PREFIX "hwmon"
|
||||
#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
|
||||
@ -99,6 +100,10 @@ hwmon_device_register_with_groups(struct device *dev, const char *name,
|
||||
struct hwmon_device *hwdev;
|
||||
int err, id;
|
||||
|
||||
/* Do not accept invalid characters in hwmon name attribute */
|
||||
if (name && (!strlen(name) || strpbrk(name, "-* \t\n")))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL);
|
||||
if (id < 0)
|
||||
return ERR_PTR(id);
|
||||
|
@ -31,6 +31,7 @@ struct iio_hwmon_state {
|
||||
int num_channels;
|
||||
struct device *hwmon_dev;
|
||||
struct attribute_group attr_group;
|
||||
const struct attribute_group *groups[2];
|
||||
struct attribute **attrs;
|
||||
};
|
||||
|
||||
@ -56,19 +57,6 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
|
||||
return sprintf(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
const char *name = "iio_hwmon";
|
||||
|
||||
if (dev->of_node && dev->of_node->name)
|
||||
name = dev->of_node->name;
|
||||
|
||||
return sprintf(buf, "%s\n", name);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
static int iio_hwmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -78,6 +66,10 @@ static int iio_hwmon_probe(struct platform_device *pdev)
|
||||
int in_i = 1, temp_i = 1, curr_i = 1;
|
||||
enum iio_chan_type type;
|
||||
struct iio_channel *channels;
|
||||
const char *name = "iio_hwmon";
|
||||
|
||||
if (dev->of_node && dev->of_node->name)
|
||||
name = dev->of_node->name;
|
||||
|
||||
channels = iio_channel_get_all(dev);
|
||||
if (IS_ERR(channels))
|
||||
@ -96,7 +88,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
|
||||
st->num_channels++;
|
||||
|
||||
st->attrs = devm_kzalloc(dev,
|
||||
sizeof(*st->attrs) * (st->num_channels + 2),
|
||||
sizeof(*st->attrs) * (st->num_channels + 1),
|
||||
GFP_KERNEL);
|
||||
if (st->attrs == NULL) {
|
||||
ret = -ENOMEM;
|
||||
@ -144,22 +136,18 @@ static int iio_hwmon_probe(struct platform_device *pdev)
|
||||
a->index = i;
|
||||
st->attrs[i] = &a->dev_attr.attr;
|
||||
}
|
||||
st->attrs[st->num_channels] = &dev_attr_name.attr;
|
||||
st->attr_group.attrs = st->attrs;
|
||||
platform_set_drvdata(pdev, st);
|
||||
ret = sysfs_create_group(&dev->kobj, &st->attr_group);
|
||||
if (ret < 0)
|
||||
goto error_release_channels;
|
||||
|
||||
st->hwmon_dev = hwmon_device_register(dev);
|
||||
st->attr_group.attrs = st->attrs;
|
||||
st->groups[0] = &st->attr_group;
|
||||
st->hwmon_dev = hwmon_device_register_with_groups(dev, name, st,
|
||||
st->groups);
|
||||
if (IS_ERR(st->hwmon_dev)) {
|
||||
ret = PTR_ERR(st->hwmon_dev);
|
||||
goto error_remove_group;
|
||||
goto error_release_channels;
|
||||
}
|
||||
platform_set_drvdata(pdev, st);
|
||||
return 0;
|
||||
|
||||
error_remove_group:
|
||||
sysfs_remove_group(&dev->kobj, &st->attr_group);
|
||||
error_release_channels:
|
||||
iio_channel_release_all(channels);
|
||||
return ret;
|
||||
@ -170,7 +158,6 @@ static int iio_hwmon_remove(struct platform_device *pdev)
|
||||
struct iio_hwmon_state *st = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(st->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &st->attr_group);
|
||||
iio_channel_release_all(st->channels);
|
||||
|
||||
return 0;
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <linux/hwmon.h>
|
||||
|
||||
struct jz4740_hwmon {
|
||||
struct resource *mem;
|
||||
void __iomem *base;
|
||||
|
||||
int irq;
|
||||
@ -106,6 +105,7 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct jz4740_hwmon *hwmon;
|
||||
struct resource *mem;
|
||||
|
||||
hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
|
||||
if (!hwmon)
|
||||
@ -120,25 +120,10 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
|
||||
return hwmon->irq;
|
||||
}
|
||||
|
||||
hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!hwmon->mem) {
|
||||
dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
hwmon->mem = devm_request_mem_region(&pdev->dev, hwmon->mem->start,
|
||||
resource_size(hwmon->mem), pdev->name);
|
||||
if (!hwmon->mem) {
|
||||
dev_err(&pdev->dev, "Failed to request mmio memory region\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
hwmon->base = devm_ioremap_nocache(&pdev->dev, hwmon->mem->start,
|
||||
resource_size(hwmon->mem));
|
||||
if (!hwmon->base) {
|
||||
dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
hwmon->base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(hwmon->base))
|
||||
return PTR_ERR(hwmon->base);
|
||||
|
||||
init_completion(&hwmon->read_completion);
|
||||
mutex_init(&hwmon->lock);
|
||||
|
@ -89,7 +89,7 @@ static const u8 lm95241_reg_address[] = {
|
||||
|
||||
/* Client data (each client gets its own) */
|
||||
struct lm95241_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
unsigned long last_updated, interval; /* in jiffies */
|
||||
char valid; /* zero until following fields are valid */
|
||||
@ -113,8 +113,8 @@ static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
|
||||
|
||||
static struct lm95241_data *lm95241_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95241_data *data = i2c_get_clientdata(client);
|
||||
struct lm95241_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@ -122,7 +122,7 @@ static struct lm95241_data *lm95241_update_device(struct device *dev)
|
||||
!data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(&client->dev, "Updating lm95241 data.\n");
|
||||
dev_dbg(dev, "Updating lm95241 data.\n");
|
||||
for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++)
|
||||
data->temp[i]
|
||||
= i2c_smbus_read_byte_data(client,
|
||||
@ -153,8 +153,7 @@ static ssize_t show_input(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t show_type(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95241_data *data = i2c_get_clientdata(client);
|
||||
struct lm95241_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1,
|
||||
data->model & to_sensor_dev_attr(attr)->index ? "1\n" : "2\n");
|
||||
@ -163,8 +162,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr,
|
||||
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 lm95241_data *data = i2c_get_clientdata(client);
|
||||
struct lm95241_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int shift;
|
||||
u8 mask = to_sensor_dev_attr(attr)->index;
|
||||
@ -201,8 +200,7 @@ static ssize_t set_type(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t show_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95241_data *data = i2c_get_clientdata(client);
|
||||
struct lm95241_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1,
|
||||
data->config & to_sensor_dev_attr(attr)->index ?
|
||||
@ -212,8 +210,7 @@ static ssize_t show_min(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t set_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95241_data *data = i2c_get_clientdata(client);
|
||||
struct lm95241_data *data = dev_get_drvdata(dev);
|
||||
long val;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
@ -229,7 +226,8 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr,
|
||||
data->config &= ~to_sensor_dev_attr(attr)->index;
|
||||
data->valid = 0;
|
||||
|
||||
i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
|
||||
i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
|
||||
data->config);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
@ -239,8 +237,7 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t show_max(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95241_data *data = i2c_get_clientdata(client);
|
||||
struct lm95241_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1,
|
||||
data->config & to_sensor_dev_attr(attr)->index ?
|
||||
@ -250,8 +247,7 @@ static ssize_t show_max(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t set_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95241_data *data = i2c_get_clientdata(client);
|
||||
struct lm95241_data *data = dev_get_drvdata(dev);
|
||||
long val;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
@ -267,7 +263,8 @@ static ssize_t set_max(struct device *dev, struct device_attribute *attr,
|
||||
data->config &= ~to_sensor_dev_attr(attr)->index;
|
||||
data->valid = 0;
|
||||
|
||||
i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
|
||||
i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
|
||||
data->config);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
@ -286,8 +283,7 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
|
||||
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 lm95241_data *data = i2c_get_clientdata(client);
|
||||
struct lm95241_data *data = dev_get_drvdata(dev);
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0)
|
||||
@ -316,7 +312,7 @@ static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max,
|
||||
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
|
||||
set_interval);
|
||||
|
||||
static struct attribute *lm95241_attributes[] = {
|
||||
static struct attribute *lm95241_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
@ -329,10 +325,7 @@ static struct attribute *lm95241_attributes[] = {
|
||||
&dev_attr_update_interval.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm95241_group = {
|
||||
.attrs = lm95241_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(lm95241);
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int lm95241_detect(struct i2c_client *new_client,
|
||||
@ -366,14 +359,11 @@ static int lm95241_detect(struct i2c_client *new_client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lm95241_init_client(struct i2c_client *client)
|
||||
static void lm95241_init_client(struct i2c_client *client,
|
||||
struct lm95241_data *data)
|
||||
{
|
||||
struct lm95241_data *data = i2c_get_clientdata(client);
|
||||
|
||||
data->interval = HZ; /* 1 sec default */
|
||||
data->valid = 0;
|
||||
data->config = CFG_CR0076;
|
||||
data->model = 0;
|
||||
data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
|
||||
|
||||
i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
|
||||
@ -385,49 +375,27 @@ static void lm95241_init_client(struct i2c_client *client)
|
||||
data->model);
|
||||
}
|
||||
|
||||
static int lm95241_probe(struct i2c_client *new_client,
|
||||
static int lm95241_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct lm95241_data *data;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
data = devm_kzalloc(&new_client->dev, sizeof(struct lm95241_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct lm95241_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(new_client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the LM95241 chip */
|
||||
lm95241_init_client(new_client);
|
||||
lm95241_init_client(client, data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->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(&new_client->dev.kobj, &lm95241_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lm95241_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lm95241_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm95241_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
lm95241_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
/* Driver data (common to all clients) */
|
||||
@ -444,7 +412,6 @@ static struct i2c_driver lm95241_driver = {
|
||||
.name = DEVNAME,
|
||||
},
|
||||
.probe = lm95241_probe,
|
||||
.remove = lm95241_remove,
|
||||
.id_table = lm95241_id,
|
||||
.detect = lm95241_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
@ -115,7 +115,7 @@ static const u8 lm95245_reg_address[] = {
|
||||
|
||||
/* Client data (each client gets its own) */
|
||||
struct lm95245_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
unsigned long interval; /* in msecs */
|
||||
@ -140,8 +140,8 @@ static int temp_from_reg_signed(u8 val_h, u8 val_l)
|
||||
|
||||
static struct lm95245_data *lm95245_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95245_data *data = i2c_get_clientdata(client);
|
||||
struct lm95245_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@ -149,7 +149,6 @@ static struct lm95245_data *lm95245_update_device(struct device *dev)
|
||||
+ msecs_to_jiffies(data->interval)) || !data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(&client->dev, "Updating lm95245 data.\n");
|
||||
for (i = 0; i < ARRAY_SIZE(lm95245_reg_address); i++)
|
||||
data->regs[i]
|
||||
= i2c_smbus_read_byte_data(client,
|
||||
@ -249,9 +248,9 @@ static ssize_t show_limit(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95245_data *data = i2c_get_clientdata(client);
|
||||
struct lm95245_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0)
|
||||
@ -272,27 +271,38 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_crit_hyst(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lm95245_data *data = lm95245_update_device(dev);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
int hyst = data->regs[index] - data->regs[8];
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1, "%d\n", hyst * 1000);
|
||||
}
|
||||
|
||||
static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95245_data *data = i2c_get_clientdata(client);
|
||||
struct lm95245_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int hyst, limit;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
val /= 1000;
|
||||
|
||||
val = clamp_val(val, 0, 31);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
data->valid = 0;
|
||||
limit = i2c_smbus_read_byte_data(client, lm95245_reg_address[index]);
|
||||
hyst = limit - val / 1000;
|
||||
hyst = clamp_val(hyst, 0, 31);
|
||||
data->regs[8] = hyst;
|
||||
|
||||
/* shared crit hysteresis */
|
||||
i2c_smbus_write_byte_data(client, LM95245_REG_RW_COMMON_HYSTERESIS,
|
||||
val);
|
||||
hyst);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
@ -302,8 +312,7 @@ static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t show_type(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95245_data *data = i2c_get_clientdata(client);
|
||||
struct lm95245_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1,
|
||||
data->config2 & CFG2_REMOTE_TT ? "1\n" : "2\n");
|
||||
@ -312,8 +321,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr,
|
||||
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 lm95245_data *data = i2c_get_clientdata(client);
|
||||
struct lm95245_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0)
|
||||
@ -359,8 +368,8 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
|
||||
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 lm95245_data *data = i2c_get_clientdata(client);
|
||||
struct lm95245_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0)
|
||||
@ -378,16 +387,15 @@ static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit,
|
||||
set_limit, 6);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
|
||||
set_crit_hyst, 8);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_crit_hyst,
|
||||
set_crit_hyst, 6);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
|
||||
STATUS1_LOC);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit,
|
||||
set_limit, 7);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
|
||||
set_crit_hyst, 8);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_crit_hyst, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
|
||||
STATUS1_RTCRIT);
|
||||
static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type,
|
||||
@ -398,7 +406,7 @@ static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
|
||||
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
|
||||
set_interval);
|
||||
|
||||
static struct attribute *lm95245_attributes[] = {
|
||||
static struct attribute *lm95245_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
|
||||
@ -412,10 +420,7 @@ static struct attribute *lm95245_attributes[] = {
|
||||
&dev_attr_update_interval.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm95245_group = {
|
||||
.attrs = lm95245_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(lm95245);
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int lm95245_detect(struct i2c_client *new_client,
|
||||
@ -436,11 +441,9 @@ static int lm95245_detect(struct i2c_client *new_client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lm95245_init_client(struct i2c_client *client)
|
||||
static void lm95245_init_client(struct i2c_client *client,
|
||||
struct lm95245_data *data)
|
||||
{
|
||||
struct lm95245_data *data = i2c_get_clientdata(client);
|
||||
|
||||
data->valid = 0;
|
||||
data->interval = lm95245_read_conversion_rate(client);
|
||||
|
||||
data->config1 = i2c_smbus_read_byte_data(client,
|
||||
@ -456,49 +459,27 @@ static void lm95245_init_client(struct i2c_client *client)
|
||||
}
|
||||
}
|
||||
|
||||
static int lm95245_probe(struct i2c_client *new_client,
|
||||
static int lm95245_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct lm95245_data *data;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
data = devm_kzalloc(&new_client->dev, sizeof(struct lm95245_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct lm95245_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(new_client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the LM95245 chip */
|
||||
lm95245_init_client(new_client);
|
||||
lm95245_init_client(client, data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->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(&new_client->dev.kobj, &lm95245_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lm95245_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lm95245_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm95245_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
lm95245_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
/* Driver data (common to all clients) */
|
||||
@ -514,7 +495,6 @@ static struct i2c_driver lm95245_driver = {
|
||||
.name = DEVNAME,
|
||||
},
|
||||
.probe = lm95245_probe,
|
||||
.remove = lm95245_remove,
|
||||
.id_table = lm95245_id,
|
||||
.detect = lm95245_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
519
drivers/hwmon/ltc2945.c
Normal file
519
drivers/hwmon/ltc2945.c
Normal file
@ -0,0 +1,519 @@
|
||||
/*
|
||||
* Driver for Linear Technology LTC2945 I2C Power Monitor
|
||||
*
|
||||
* Copyright (c) 2014 Guenter Roeck
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* chip registers */
|
||||
#define LTC2945_CONTROL 0x00
|
||||
#define LTC2945_ALERT 0x01
|
||||
#define LTC2945_STATUS 0x02
|
||||
#define LTC2945_FAULT 0x03
|
||||
#define LTC2945_POWER_H 0x05
|
||||
#define LTC2945_MAX_POWER_H 0x08
|
||||
#define LTC2945_MIN_POWER_H 0x0b
|
||||
#define LTC2945_MAX_POWER_THRES_H 0x0e
|
||||
#define LTC2945_MIN_POWER_THRES_H 0x11
|
||||
#define LTC2945_SENSE_H 0x14
|
||||
#define LTC2945_MAX_SENSE_H 0x16
|
||||
#define LTC2945_MIN_SENSE_H 0x18
|
||||
#define LTC2945_MAX_SENSE_THRES_H 0x1a
|
||||
#define LTC2945_MIN_SENSE_THRES_H 0x1c
|
||||
#define LTC2945_VIN_H 0x1e
|
||||
#define LTC2945_MAX_VIN_H 0x20
|
||||
#define LTC2945_MIN_VIN_H 0x22
|
||||
#define LTC2945_MAX_VIN_THRES_H 0x24
|
||||
#define LTC2945_MIN_VIN_THRES_H 0x26
|
||||
#define LTC2945_ADIN_H 0x28
|
||||
#define LTC2945_MAX_ADIN_H 0x2a
|
||||
#define LTC2945_MIN_ADIN_H 0x2c
|
||||
#define LTC2945_MAX_ADIN_THRES_H 0x2e
|
||||
#define LTC2945_MIN_ADIN_THRES_H 0x30
|
||||
#define LTC2945_MIN_ADIN_THRES_L 0x31
|
||||
|
||||
/* Fault register bits */
|
||||
|
||||
#define FAULT_ADIN_UV (1 << 0)
|
||||
#define FAULT_ADIN_OV (1 << 1)
|
||||
#define FAULT_VIN_UV (1 << 2)
|
||||
#define FAULT_VIN_OV (1 << 3)
|
||||
#define FAULT_SENSE_UV (1 << 4)
|
||||
#define FAULT_SENSE_OV (1 << 5)
|
||||
#define FAULT_POWER_UV (1 << 6)
|
||||
#define FAULT_POWER_OV (1 << 7)
|
||||
|
||||
/* Control register bits */
|
||||
|
||||
#define CONTROL_MULT_SELECT (1 << 0)
|
||||
#define CONTROL_TEST_MODE (1 << 4)
|
||||
|
||||
static inline bool is_power_reg(u8 reg)
|
||||
{
|
||||
return reg < LTC2945_SENSE_H;
|
||||
}
|
||||
|
||||
/* Return the value from the given register in uW, mV, or mA */
|
||||
static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
|
||||
{
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
unsigned int control;
|
||||
u8 buf[3];
|
||||
long long val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(regmap, reg, buf,
|
||||
is_power_reg(reg) ? 3 : 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (is_power_reg(reg)) {
|
||||
/* power */
|
||||
val = (buf[0] << 16) + (buf[1] << 8) + buf[2];
|
||||
} else {
|
||||
/* current, voltage */
|
||||
val = (buf[0] << 4) + (buf[1] >> 4);
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case LTC2945_POWER_H:
|
||||
case LTC2945_MAX_POWER_H:
|
||||
case LTC2945_MIN_POWER_H:
|
||||
case LTC2945_MAX_POWER_THRES_H:
|
||||
case LTC2945_MIN_POWER_THRES_H:
|
||||
/*
|
||||
* Convert to uW by assuming current is measured with
|
||||
* an 1mOhm sense resistor, similar to current
|
||||
* measurements.
|
||||
* Control register bit 0 selects if voltage at SENSE+/VDD
|
||||
* or voltage at ADIN is used to measure power.
|
||||
*/
|
||||
ret = regmap_read(regmap, LTC2945_CONTROL, &control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (control & CONTROL_MULT_SELECT) {
|
||||
/* 25 mV * 25 uV = 0.625 uV resolution. */
|
||||
val *= 625LL;
|
||||
} else {
|
||||
/* 0.5 mV * 25 uV = 0.0125 uV resolution. */
|
||||
val = (val * 25LL) >> 1;
|
||||
}
|
||||
break;
|
||||
case LTC2945_VIN_H:
|
||||
case LTC2945_MAX_VIN_H:
|
||||
case LTC2945_MIN_VIN_H:
|
||||
case LTC2945_MAX_VIN_THRES_H:
|
||||
case LTC2945_MIN_VIN_THRES_H:
|
||||
/* 25 mV resolution. Convert to mV. */
|
||||
val *= 25;
|
||||
break;
|
||||
case LTC2945_ADIN_H:
|
||||
case LTC2945_MAX_ADIN_H:
|
||||
case LTC2945_MIN_ADIN_THRES_H:
|
||||
case LTC2945_MAX_ADIN_THRES_H:
|
||||
case LTC2945_MIN_ADIN_H:
|
||||
/* 0.5mV resolution. Convert to mV. */
|
||||
val = val >> 1;
|
||||
break;
|
||||
case LTC2945_SENSE_H:
|
||||
case LTC2945_MAX_SENSE_H:
|
||||
case LTC2945_MIN_SENSE_H:
|
||||
case LTC2945_MAX_SENSE_THRES_H:
|
||||
case LTC2945_MIN_SENSE_THRES_H:
|
||||
/*
|
||||
* 25 uV resolution. Convert to current as measured with
|
||||
* an 1 mOhm sense resistor, in mA. If a different sense
|
||||
* resistor is installed, calculate the actual current by
|
||||
* dividing the reported current by the sense resistor value
|
||||
* in mOhm.
|
||||
*/
|
||||
val *= 25;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static int ltc2945_val_to_reg(struct device *dev, u8 reg,
|
||||
unsigned long val)
|
||||
{
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
unsigned int control;
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case LTC2945_POWER_H:
|
||||
case LTC2945_MAX_POWER_H:
|
||||
case LTC2945_MIN_POWER_H:
|
||||
case LTC2945_MAX_POWER_THRES_H:
|
||||
case LTC2945_MIN_POWER_THRES_H:
|
||||
/*
|
||||
* Convert to register value by assuming current is measured
|
||||
* with an 1mOhm sense resistor, similar to current
|
||||
* measurements.
|
||||
* Control register bit 0 selects if voltage at SENSE+/VDD
|
||||
* or voltage at ADIN is used to measure power, which in turn
|
||||
* determines register calculations.
|
||||
*/
|
||||
ret = regmap_read(regmap, LTC2945_CONTROL, &control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (control & CONTROL_MULT_SELECT) {
|
||||
/* 25 mV * 25 uV = 0.625 uV resolution. */
|
||||
val = DIV_ROUND_CLOSEST(val, 625);
|
||||
} else {
|
||||
/*
|
||||
* 0.5 mV * 25 uV = 0.0125 uV resolution.
|
||||
* Divide first to avoid overflow;
|
||||
* accept loss of accuracy.
|
||||
*/
|
||||
val = DIV_ROUND_CLOSEST(val, 25) * 2;
|
||||
}
|
||||
break;
|
||||
case LTC2945_VIN_H:
|
||||
case LTC2945_MAX_VIN_H:
|
||||
case LTC2945_MIN_VIN_H:
|
||||
case LTC2945_MAX_VIN_THRES_H:
|
||||
case LTC2945_MIN_VIN_THRES_H:
|
||||
/* 25 mV resolution. */
|
||||
val /= 25;
|
||||
break;
|
||||
case LTC2945_ADIN_H:
|
||||
case LTC2945_MAX_ADIN_H:
|
||||
case LTC2945_MIN_ADIN_THRES_H:
|
||||
case LTC2945_MAX_ADIN_THRES_H:
|
||||
case LTC2945_MIN_ADIN_H:
|
||||
/* 0.5mV resolution. */
|
||||
val *= 2;
|
||||
break;
|
||||
case LTC2945_SENSE_H:
|
||||
case LTC2945_MAX_SENSE_H:
|
||||
case LTC2945_MIN_SENSE_H:
|
||||
case LTC2945_MAX_SENSE_THRES_H:
|
||||
case LTC2945_MIN_SENSE_THRES_H:
|
||||
/*
|
||||
* 25 uV resolution. Convert to current as measured with
|
||||
* an 1 mOhm sense resistor, in mA. If a different sense
|
||||
* resistor is installed, calculate the actual current by
|
||||
* dividing the reported current by the sense resistor value
|
||||
* in mOhm.
|
||||
*/
|
||||
val = DIV_ROUND_CLOSEST(val, 25);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static ssize_t ltc2945_show_value(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
long long value;
|
||||
|
||||
value = ltc2945_reg_to_val(dev, attr->index);
|
||||
if (value < 0)
|
||||
return value;
|
||||
return snprintf(buf, PAGE_SIZE, "%lld\n", value);
|
||||
}
|
||||
|
||||
static ssize_t ltc2945_set_value(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
u8 reg = attr->index;
|
||||
unsigned long val;
|
||||
u8 regbuf[3];
|
||||
int num_regs;
|
||||
int regval;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* convert to register value, then clamp and write result */
|
||||
regval = ltc2945_val_to_reg(dev, reg, val);
|
||||
if (is_power_reg(reg)) {
|
||||
regval = clamp_val(regval, 0, 0xffffff);
|
||||
regbuf[0] = regval >> 16;
|
||||
regbuf[1] = (regval >> 8) & 0xff;
|
||||
regbuf[2] = regval;
|
||||
num_regs = 3;
|
||||
} else {
|
||||
regval = clamp_val(regval, 0, 0xfff) << 4;
|
||||
regbuf[0] = regval >> 8;
|
||||
regbuf[1] = regval & 0xff;
|
||||
num_regs = 2;
|
||||
}
|
||||
ret = regmap_bulk_write(regmap, reg, regbuf, num_regs);
|
||||
return ret < 0 ? ret : count;
|
||||
}
|
||||
|
||||
static ssize_t ltc2945_reset_history(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
u8 reg = attr->index;
|
||||
int num_regs = is_power_reg(reg) ? 3 : 2;
|
||||
u8 buf_min[3] = { 0xff, 0xff, 0xff };
|
||||
u8 buf_max[3] = { 0, 0, 0 };
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (val != 1)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE,
|
||||
CONTROL_TEST_MODE);
|
||||
|
||||
/* Reset minimum */
|
||||
ret = regmap_bulk_write(regmap, reg, buf_min, num_regs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (reg) {
|
||||
case LTC2945_MIN_POWER_H:
|
||||
reg = LTC2945_MAX_POWER_H;
|
||||
break;
|
||||
case LTC2945_MIN_SENSE_H:
|
||||
reg = LTC2945_MAX_SENSE_H;
|
||||
break;
|
||||
case LTC2945_MIN_VIN_H:
|
||||
reg = LTC2945_MAX_VIN_H;
|
||||
break;
|
||||
case LTC2945_MIN_ADIN_H:
|
||||
reg = LTC2945_MAX_ADIN_H;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
/* Reset maximum */
|
||||
ret = regmap_bulk_write(regmap, reg, buf_max, num_regs);
|
||||
|
||||
/* Try resetting test mode even if there was an error */
|
||||
regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE, 0);
|
||||
|
||||
return ret ? : count;
|
||||
}
|
||||
|
||||
static ssize_t ltc2945_show_bool(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
unsigned int fault;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, LTC2945_FAULT, &fault);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fault &= attr->index;
|
||||
if (fault) /* Clear reported faults in chip register */
|
||||
regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
|
||||
}
|
||||
|
||||
/* Input voltages */
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_VIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
|
||||
ltc2945_set_value, LTC2945_MIN_VIN_THRES_H);
|
||||
static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
|
||||
ltc2945_set_value, LTC2945_MAX_VIN_THRES_H);
|
||||
static SENSOR_DEVICE_ATTR(in1_lowest, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_MIN_VIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in1_highest, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_MAX_VIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
|
||||
ltc2945_reset_history, LTC2945_MIN_VIN_H);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_ADIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
|
||||
ltc2945_set_value, LTC2945_MIN_ADIN_THRES_H);
|
||||
static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
|
||||
ltc2945_set_value, LTC2945_MAX_ADIN_THRES_H);
|
||||
static SENSOR_DEVICE_ATTR(in2_lowest, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_MIN_ADIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in2_highest, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_MAX_ADIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in2_reset_history, S_IWUSR, NULL,
|
||||
ltc2945_reset_history, LTC2945_MIN_ADIN_H);
|
||||
|
||||
/* Voltage alarms */
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
|
||||
FAULT_VIN_UV);
|
||||
static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
|
||||
FAULT_VIN_OV);
|
||||
static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
|
||||
FAULT_ADIN_UV);
|
||||
static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
|
||||
FAULT_ADIN_OV);
|
||||
|
||||
/* Currents (via sense resistor) */
|
||||
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_SENSE_H);
|
||||
static SENSOR_DEVICE_ATTR(curr1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
|
||||
ltc2945_set_value, LTC2945_MIN_SENSE_THRES_H);
|
||||
static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
|
||||
ltc2945_set_value, LTC2945_MAX_SENSE_THRES_H);
|
||||
static SENSOR_DEVICE_ATTR(curr1_lowest, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_MIN_SENSE_H);
|
||||
static SENSOR_DEVICE_ATTR(curr1_highest, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_MAX_SENSE_H);
|
||||
static SENSOR_DEVICE_ATTR(curr1_reset_history, S_IWUSR, NULL,
|
||||
ltc2945_reset_history, LTC2945_MIN_SENSE_H);
|
||||
|
||||
/* Current alarms */
|
||||
|
||||
static SENSOR_DEVICE_ATTR(curr1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
|
||||
FAULT_SENSE_UV);
|
||||
static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
|
||||
FAULT_SENSE_OV);
|
||||
|
||||
/* Power */
|
||||
|
||||
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc2945_show_value, NULL,
|
||||
LTC2945_POWER_H);
|
||||
static SENSOR_DEVICE_ATTR(power1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
|
||||
ltc2945_set_value, LTC2945_MIN_POWER_THRES_H);
|
||||
static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
|
||||
ltc2945_set_value, LTC2945_MAX_POWER_THRES_H);
|
||||
static SENSOR_DEVICE_ATTR(power1_input_lowest, S_IRUGO, ltc2945_show_value,
|
||||
NULL, LTC2945_MIN_POWER_H);
|
||||
static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ltc2945_show_value,
|
||||
NULL, LTC2945_MAX_POWER_H);
|
||||
static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
|
||||
ltc2945_reset_history, LTC2945_MIN_POWER_H);
|
||||
|
||||
/* Power alarms */
|
||||
|
||||
static SENSOR_DEVICE_ATTR(power1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
|
||||
FAULT_POWER_UV);
|
||||
static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
|
||||
FAULT_POWER_OV);
|
||||
|
||||
static struct attribute *ltc2945_attrs[] = {
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_lowest.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_reset_history.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_lowest.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_reset_history.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_curr1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_lowest.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_reset_history.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_power1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_power1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_power1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_power1_input_lowest.dev_attr.attr,
|
||||
&sensor_dev_attr_power1_input_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_power1_reset_history.dev_attr.attr,
|
||||
&sensor_dev_attr_power1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_power1_max_alarm.dev_attr.attr,
|
||||
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ltc2945);
|
||||
|
||||
static struct regmap_config ltc2945_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = LTC2945_MIN_ADIN_THRES_L,
|
||||
};
|
||||
|
||||
static int ltc2945_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, <c2945_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "failed to allocate register map\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
/* Clear faults */
|
||||
regmap_write(regmap, LTC2945_FAULT, 0x00);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
regmap,
|
||||
ltc2945_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ltc2945_id[] = {
|
||||
{"ltc2945", 0},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ltc2945_id);
|
||||
|
||||
static struct i2c_driver ltc2945_driver = {
|
||||
.driver = {
|
||||
.name = "ltc2945",
|
||||
},
|
||||
.probe = ltc2945_probe,
|
||||
.id_table = ltc2945_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ltc2945_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
|
||||
MODULE_DESCRIPTION("LTC2945 driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -33,7 +33,7 @@ enum ltc4215_cmd {
|
||||
};
|
||||
|
||||
struct ltc4215_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
|
||||
struct mutex update_lock;
|
||||
bool valid;
|
||||
@ -45,8 +45,8 @@ struct ltc4215_data {
|
||||
|
||||
static struct ltc4215_data *ltc4215_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ltc4215_data *data = i2c_get_clientdata(client);
|
||||
struct ltc4215_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
s32 val;
|
||||
int i;
|
||||
|
||||
@ -214,7 +214,7 @@ static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
|
||||
* Finally, construct an array of pointers to members of the above objects,
|
||||
* as required for sysfs_create_group()
|
||||
*/
|
||||
static struct attribute *ltc4215_attributes[] = {
|
||||
static struct attribute *ltc4215_attrs[] = {
|
||||
&sensor_dev_attr_curr1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
|
||||
|
||||
@ -229,57 +229,33 @@ static struct attribute *ltc4215_attributes[] = {
|
||||
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ltc4215_group = {
|
||||
.attrs = ltc4215_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ltc4215);
|
||||
|
||||
static int ltc4215_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct device *dev = &client->dev;
|
||||
struct ltc4215_data *data;
|
||||
int ret;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the LTC4215 chip */
|
||||
i2c_smbus_write_byte_data(client, LTC4215_FAULT, 0x00);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
ret = sysfs_create_group(&client->dev.kobj, <c4215_group);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
ret = PTR_ERR(data->hwmon_dev);
|
||||
goto out_hwmon_device_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_hwmon_device_register:
|
||||
sysfs_remove_group(&client->dev.kobj, <c4215_group);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc4215_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ltc4215_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, <c4215_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
ltc4215_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ltc4215_id[] = {
|
||||
@ -294,7 +270,6 @@ static struct i2c_driver ltc4215_driver = {
|
||||
.name = "ltc4215",
|
||||
},
|
||||
.probe = ltc4215_probe,
|
||||
.remove = ltc4215_remove,
|
||||
.id_table = ltc4215_id,
|
||||
};
|
||||
|
||||
|
237
drivers/hwmon/ltc4222.c
Normal file
237
drivers/hwmon/ltc4222.c
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Driver for Linear Technology LTC4222 Dual Hot Swap controller
|
||||
*
|
||||
* Copyright (c) 2014 Guenter Roeck
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* chip registers */
|
||||
|
||||
#define LTC4222_CONTROL1 0xd0
|
||||
#define LTC4222_ALERT1 0xd1
|
||||
#define LTC4222_STATUS1 0xd2
|
||||
#define LTC4222_FAULT1 0xd3
|
||||
#define LTC4222_CONTROL2 0xd4
|
||||
#define LTC4222_ALERT2 0xd5
|
||||
#define LTC4222_STATUS2 0xd6
|
||||
#define LTC4222_FAULT2 0xd7
|
||||
#define LTC4222_SOURCE1 0xd8
|
||||
#define LTC4222_SOURCE2 0xda
|
||||
#define LTC4222_ADIN1 0xdc
|
||||
#define LTC4222_ADIN2 0xde
|
||||
#define LTC4222_SENSE1 0xe0
|
||||
#define LTC4222_SENSE2 0xe2
|
||||
#define LTC4222_ADC_CONTROL 0xe4
|
||||
|
||||
/*
|
||||
* Fault register bits
|
||||
*/
|
||||
#define FAULT_OV BIT(0)
|
||||
#define FAULT_UV BIT(1)
|
||||
#define FAULT_OC BIT(2)
|
||||
#define FAULT_POWER_BAD BIT(3)
|
||||
#define FAULT_FET_BAD BIT(5)
|
||||
|
||||
/* Return the voltage from the given register in mV or mA */
|
||||
static int ltc4222_get_value(struct device *dev, u8 reg)
|
||||
{
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
unsigned int val;
|
||||
u8 buf[2];
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(regmap, reg, buf, 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = ((buf[0] << 8) + buf[1]) >> 6;
|
||||
|
||||
switch (reg) {
|
||||
case LTC4222_ADIN1:
|
||||
case LTC4222_ADIN2:
|
||||
/* 1.25 mV resolution. Convert to mV. */
|
||||
val = DIV_ROUND_CLOSEST(val * 5, 4);
|
||||
break;
|
||||
case LTC4222_SOURCE1:
|
||||
case LTC4222_SOURCE2:
|
||||
/* 31.25 mV resolution. Convert to mV. */
|
||||
val = DIV_ROUND_CLOSEST(val * 125, 4);
|
||||
break;
|
||||
case LTC4222_SENSE1:
|
||||
case LTC4222_SENSE2:
|
||||
/*
|
||||
* 62.5 uV resolution. Convert to current as measured with
|
||||
* an 1 mOhm sense resistor, in mA. If a different sense
|
||||
* resistor is installed, calculate the actual current by
|
||||
* dividing the reported current by the sense resistor value
|
||||
* in mOhm.
|
||||
*/
|
||||
val = DIV_ROUND_CLOSEST(val * 125, 2);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static ssize_t ltc4222_show_value(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
int value;
|
||||
|
||||
value = ltc4222_get_value(dev, attr->index);
|
||||
if (value < 0)
|
||||
return value;
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", value);
|
||||
}
|
||||
|
||||
static ssize_t ltc4222_show_bool(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
unsigned int fault;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, attr->nr, &fault);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
fault &= attr->index;
|
||||
if (fault) /* Clear reported faults in chip register */
|
||||
regmap_update_bits(regmap, attr->nr, attr->index, 0);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
|
||||
}
|
||||
|
||||
/* Voltages */
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4222_show_value, NULL,
|
||||
LTC4222_SOURCE1);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4222_show_value, NULL,
|
||||
LTC4222_ADIN1);
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4222_show_value, NULL,
|
||||
LTC4222_SOURCE2);
|
||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4222_show_value, NULL,
|
||||
LTC4222_ADIN2);
|
||||
|
||||
/*
|
||||
* Voltage alarms
|
||||
* UV/OV faults are associated with the input voltage, and power bad and fet
|
||||
* faults are associated with the output voltage.
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
|
||||
LTC4222_FAULT1, FAULT_UV);
|
||||
static SENSOR_DEVICE_ATTR_2(in1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
|
||||
LTC4222_FAULT1, FAULT_OV);
|
||||
static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, ltc4222_show_bool, NULL,
|
||||
LTC4222_FAULT1, FAULT_POWER_BAD | FAULT_FET_BAD);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
|
||||
LTC4222_FAULT2, FAULT_UV);
|
||||
static SENSOR_DEVICE_ATTR_2(in3_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
|
||||
LTC4222_FAULT2, FAULT_OV);
|
||||
static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, ltc4222_show_bool, NULL,
|
||||
LTC4222_FAULT2, FAULT_POWER_BAD | FAULT_FET_BAD);
|
||||
|
||||
/* Current (via sense resistor) */
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4222_show_value, NULL,
|
||||
LTC4222_SENSE1);
|
||||
static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4222_show_value, NULL,
|
||||
LTC4222_SENSE2);
|
||||
|
||||
/* Overcurrent alarm */
|
||||
static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
|
||||
LTC4222_FAULT1, FAULT_OC);
|
||||
static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
|
||||
LTC4222_FAULT2, FAULT_OC);
|
||||
|
||||
static struct attribute *ltc4222_attrs[] = {
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_curr1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_curr2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
|
||||
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ltc4222);
|
||||
|
||||
static struct regmap_config ltc4222_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = LTC4222_ADC_CONTROL,
|
||||
};
|
||||
|
||||
static int ltc4222_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, <c4222_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "failed to allocate register map\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
/* Clear faults */
|
||||
regmap_write(regmap, LTC4222_FAULT1, 0x00);
|
||||
regmap_write(regmap, LTC4222_FAULT2, 0x00);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
regmap,
|
||||
ltc4222_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ltc4222_id[] = {
|
||||
{"ltc4222", 0},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ltc4222_id);
|
||||
|
||||
static struct i2c_driver ltc4222_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4222",
|
||||
},
|
||||
.probe = ltc4222_probe,
|
||||
.id_table = ltc4222_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ltc4222_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
|
||||
MODULE_DESCRIPTION("LTC4222 driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -95,7 +95,6 @@ static void ltc4245_update_gpios(struct device *dev)
|
||||
* readings as stale by setting them to -EAGAIN
|
||||
*/
|
||||
if (time_after(jiffies, data->last_updated + 5 * HZ)) {
|
||||
dev_dbg(&client->dev, "Marking GPIOs invalid\n");
|
||||
for (i = 0; i < ARRAY_SIZE(data->gpios); i++)
|
||||
data->gpios[i] = -EAGAIN;
|
||||
}
|
||||
@ -141,8 +140,6 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
|
||||
dev_dbg(&client->dev, "Starting ltc4245 update\n");
|
||||
|
||||
/* Read control registers -- 0x00 to 0x07 */
|
||||
for (i = 0; i < ARRAY_SIZE(data->cregs); i++) {
|
||||
val = i2c_smbus_read_byte_data(client, i);
|
||||
@ -470,19 +467,15 @@ static void ltc4245_sysfs_add_groups(struct ltc4245_data *data)
|
||||
static bool ltc4245_use_extra_gpios(struct i2c_client *client)
|
||||
{
|
||||
struct ltc4245_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
#ifdef CONFIG_OF
|
||||
struct device_node *np = client->dev.of_node;
|
||||
#endif
|
||||
|
||||
/* prefer platform data */
|
||||
if (pdata)
|
||||
return pdata->use_extra_gpios;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/* fallback on OF */
|
||||
if (of_find_property(np, "ltc4245,use-extra-gpios", NULL))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -512,24 +505,10 @@ static int ltc4245_probe(struct i2c_client *client,
|
||||
/* Add sysfs hooks */
|
||||
ltc4245_sysfs_add_groups(data);
|
||||
|
||||
hwmon_dev = hwmon_device_register_with_groups(&client->dev,
|
||||
client->name, data,
|
||||
data->groups);
|
||||
if (IS_ERR(hwmon_dev))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
i2c_set_clientdata(client, hwmon_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltc4245_remove(struct i2c_client *client)
|
||||
{
|
||||
struct device *hwmon_dev = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(hwmon_dev);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
|
||||
client->name, data,
|
||||
data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ltc4245_id[] = {
|
||||
@ -544,7 +523,6 @@ static struct i2c_driver ltc4245_driver = {
|
||||
.name = "ltc4245",
|
||||
},
|
||||
.probe = ltc4245_probe,
|
||||
.remove = ltc4245_remove,
|
||||
.id_table = ltc4245_id,
|
||||
};
|
||||
|
||||
|
200
drivers/hwmon/ltc4260.c
Normal file
200
drivers/hwmon/ltc4260.c
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Driver for Linear Technology LTC4260 I2C Positive Voltage Hot Swap Controller
|
||||
*
|
||||
* Copyright (c) 2014 Guenter Roeck
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* chip registers */
|
||||
#define LTC4260_CONTROL 0x00
|
||||
#define LTC4260_ALERT 0x01
|
||||
#define LTC4260_STATUS 0x02
|
||||
#define LTC4260_FAULT 0x03
|
||||
#define LTC4260_SENSE 0x04
|
||||
#define LTC4260_SOURCE 0x05
|
||||
#define LTC4260_ADIN 0x06
|
||||
|
||||
/*
|
||||
* Fault register bits
|
||||
*/
|
||||
#define FAULT_OV (1 << 0)
|
||||
#define FAULT_UV (1 << 1)
|
||||
#define FAULT_OC (1 << 2)
|
||||
#define FAULT_POWER_BAD (1 << 3)
|
||||
#define FAULT_FET_SHORT (1 << 5)
|
||||
|
||||
/* Return the voltage from the given register in mV or mA */
|
||||
static int ltc4260_get_value(struct device *dev, u8 reg)
|
||||
{
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, reg, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (reg) {
|
||||
case LTC4260_ADIN:
|
||||
/* 10 mV resolution. Convert to mV. */
|
||||
val = val * 10;
|
||||
break;
|
||||
case LTC4260_SOURCE:
|
||||
/* 400 mV resolution. Convert to mV. */
|
||||
val = val * 400;
|
||||
break;
|
||||
case LTC4260_SENSE:
|
||||
/*
|
||||
* 300 uV resolution. Convert to current as measured with
|
||||
* an 1 mOhm sense resistor, in mA. If a different sense
|
||||
* resistor is installed, calculate the actual current by
|
||||
* dividing the reported current by the sense resistor value
|
||||
* in mOhm.
|
||||
*/
|
||||
val = val * 300;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static ssize_t ltc4260_show_value(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
int value;
|
||||
|
||||
value = ltc4260_get_value(dev, attr->index);
|
||||
if (value < 0)
|
||||
return value;
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", value);
|
||||
}
|
||||
|
||||
static ssize_t ltc4260_show_bool(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
unsigned int fault;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, LTC4260_FAULT, &fault);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fault &= attr->index;
|
||||
if (fault) /* Clear reported faults in chip register */
|
||||
regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
|
||||
}
|
||||
|
||||
/* Voltages */
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4260_show_value, NULL,
|
||||
LTC4260_SOURCE);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4260_show_value, NULL,
|
||||
LTC4260_ADIN);
|
||||
|
||||
/*
|
||||
* Voltage alarms
|
||||
* UV/OV faults are associated with the input voltage, and the POWER BAD and
|
||||
* FET SHORT faults are associated with the output voltage.
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4260_show_bool, NULL,
|
||||
FAULT_UV);
|
||||
static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
|
||||
FAULT_OV);
|
||||
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, ltc4260_show_bool, NULL,
|
||||
FAULT_POWER_BAD | FAULT_FET_SHORT);
|
||||
|
||||
/* Current (via sense resistor) */
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4260_show_value, NULL,
|
||||
LTC4260_SENSE);
|
||||
|
||||
/* Overcurrent alarm */
|
||||
static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
|
||||
FAULT_OC);
|
||||
|
||||
static struct attribute *ltc4260_attrs[] = {
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_curr1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
|
||||
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ltc4260);
|
||||
|
||||
static struct regmap_config ltc4260_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = LTC4260_ADIN,
|
||||
};
|
||||
|
||||
static int ltc4260_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, <c4260_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "failed to allocate register map\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
/* Clear faults */
|
||||
regmap_write(regmap, LTC4260_FAULT, 0x00);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
regmap,
|
||||
ltc4260_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ltc4260_id[] = {
|
||||
{"ltc4260", 0},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ltc4260_id);
|
||||
|
||||
static struct i2c_driver ltc4260_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4260",
|
||||
},
|
||||
.probe = ltc4260_probe,
|
||||
.id_table = ltc4260_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ltc4260_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
|
||||
MODULE_DESCRIPTION("LTC4260 driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -66,7 +66,8 @@ MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
|
||||
enum chips { max1668, max1805, max1989 };
|
||||
|
||||
struct max1668_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[3];
|
||||
enum chips type;
|
||||
|
||||
struct mutex update_lock;
|
||||
@ -82,8 +83,8 @@ struct max1668_data {
|
||||
|
||||
static struct max1668_data *max1668_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max1668_data *data = i2c_get_clientdata(client);
|
||||
struct max1668_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
struct max1668_data *ret = data;
|
||||
s32 val;
|
||||
int i;
|
||||
@ -205,8 +206,8 @@ static ssize_t set_temp_max(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max1668_data *data = i2c_get_clientdata(client);
|
||||
struct max1668_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
int ret;
|
||||
|
||||
@ -216,10 +217,11 @@ static ssize_t set_temp_max(struct device *dev,
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max[index] = clamp_val(temp/1000, -128, 127);
|
||||
if (i2c_smbus_write_byte_data(client,
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
MAX1668_REG_LIMH_WR(index),
|
||||
data->temp_max[index]))
|
||||
count = -EIO;
|
||||
data->temp_max[index]);
|
||||
if (ret < 0)
|
||||
count = ret;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
@ -230,8 +232,8 @@ static ssize_t set_temp_min(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max1668_data *data = i2c_get_clientdata(client);
|
||||
struct max1668_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
int ret;
|
||||
|
||||
@ -241,10 +243,11 @@ static ssize_t set_temp_min(struct device *dev,
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_min[index] = clamp_val(temp/1000, -128, 127);
|
||||
if (i2c_smbus_write_byte_data(client,
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
MAX1668_REG_LIML_WR(index),
|
||||
data->temp_min[index]))
|
||||
count = -EIO;
|
||||
data->temp_min[index]);
|
||||
if (ret < 0)
|
||||
count = ret;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
@ -405,60 +408,29 @@ static int max1668_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct max1668_data *data;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct max1668_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct max1668_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (data->type == max1668 || data->type == max1989) {
|
||||
err = sysfs_create_group(&client->dev.kobj,
|
||||
&max1668_group_unique);
|
||||
if (err)
|
||||
goto error_sysrem0;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error_sysrem1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_sysrem1:
|
||||
/* sysfs hooks */
|
||||
data->groups[0] = &max1668_group_common;
|
||||
if (data->type == max1668 || data->type == max1989)
|
||||
sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
|
||||
error_sysrem0:
|
||||
sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
|
||||
return err;
|
||||
}
|
||||
data->groups[1] = &max1668_group_unique;
|
||||
|
||||
static int max1668_remove(struct i2c_client *client)
|
||||
{
|
||||
struct max1668_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
if (data->type == max1668 || data->type == max1989)
|
||||
sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max1668_id[] = {
|
||||
@ -476,7 +448,6 @@ static struct i2c_driver max1668_driver = {
|
||||
.name = "max1668",
|
||||
},
|
||||
.probe = max1668_probe,
|
||||
.remove = max1668_remove,
|
||||
.id_table = max1668_id,
|
||||
.detect = max1668_detect,
|
||||
.address_list = max1668_addr_list,
|
||||
|
@ -80,7 +80,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
|
||||
* Client data (each client gets its own)
|
||||
*/
|
||||
struct max6639_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -104,8 +104,8 @@ struct max6639_data {
|
||||
|
||||
static struct max6639_data *max6639_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct max6639_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
struct max6639_data *ret = data;
|
||||
int i;
|
||||
int status_reg;
|
||||
@ -191,9 +191,8 @@ static ssize_t show_temp_fault(struct device *dev,
|
||||
static ssize_t show_temp_max(struct device *dev,
|
||||
struct device_attribute *dev_attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
struct max6639_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", (data->temp_therm[attr->index] * 1000));
|
||||
}
|
||||
@ -202,9 +201,9 @@ static ssize_t set_temp_max(struct device *dev,
|
||||
struct device_attribute *dev_attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
struct max6639_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int res;
|
||||
|
||||
@ -224,9 +223,8 @@ static ssize_t set_temp_max(struct device *dev,
|
||||
static ssize_t show_temp_crit(struct device *dev,
|
||||
struct device_attribute *dev_attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
struct max6639_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", (data->temp_alert[attr->index] * 1000));
|
||||
}
|
||||
@ -235,9 +233,9 @@ static ssize_t set_temp_crit(struct device *dev,
|
||||
struct device_attribute *dev_attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
struct max6639_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int res;
|
||||
|
||||
@ -258,9 +256,8 @@ static ssize_t show_temp_emergency(struct device *dev,
|
||||
struct device_attribute *dev_attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
struct max6639_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", (data->temp_ot[attr->index] * 1000));
|
||||
}
|
||||
@ -269,9 +266,9 @@ static ssize_t set_temp_emergency(struct device *dev,
|
||||
struct device_attribute *dev_attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
struct max6639_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int res;
|
||||
|
||||
@ -291,9 +288,8 @@ static ssize_t set_temp_emergency(struct device *dev,
|
||||
static ssize_t show_pwm(struct device *dev,
|
||||
struct device_attribute *dev_attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
struct max6639_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->pwm[attr->index] * 255 / 120);
|
||||
}
|
||||
@ -302,9 +298,9 @@ static ssize_t set_pwm(struct device *dev,
|
||||
struct device_attribute *dev_attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
struct max6639_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int res;
|
||||
|
||||
@ -378,7 +374,7 @@ static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
|
||||
|
||||
static struct attribute *max6639_attributes[] = {
|
||||
static struct attribute *max6639_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_fault.dev_attr.attr,
|
||||
@ -403,10 +399,7 @@ static struct attribute *max6639_attributes[] = {
|
||||
&sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group max6639_group = {
|
||||
.attrs = max6639_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(max6639);
|
||||
|
||||
/*
|
||||
* returns respective index in rpm_ranges table
|
||||
@ -424,9 +417,9 @@ static int rpm_range_to_reg(int range)
|
||||
return 1; /* default: 4000 RPM */
|
||||
}
|
||||
|
||||
static int max6639_init_client(struct i2c_client *client)
|
||||
static int max6639_init_client(struct i2c_client *client,
|
||||
struct max6639_data *data)
|
||||
{
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
struct max6639_platform_data *max6639_info =
|
||||
dev_get_platdata(&client->dev);
|
||||
int i;
|
||||
@ -545,50 +538,27 @@ static int max6639_detect(struct i2c_client *client,
|
||||
static int max6639_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct max6639_data *data;
|
||||
struct device *hwmon_dev;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct max6639_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the max6639 chip */
|
||||
err = max6639_init_client(client);
|
||||
err = max6639_init_client(client, data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &max6639_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error_remove;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "temperature sensor and fan control found\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &max6639_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int max6639_remove(struct i2c_client *client)
|
||||
{
|
||||
struct max6639_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &max6639_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
max6639_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -622,9 +592,7 @@ static const struct i2c_device_id max6639_id[] = {
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, max6639_id);
|
||||
|
||||
static const struct dev_pm_ops max6639_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(max6639_suspend, max6639_resume)
|
||||
};
|
||||
static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
|
||||
|
||||
static struct i2c_driver max6639_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
@ -633,7 +601,6 @@ static struct i2c_driver max6639_driver = {
|
||||
.pm = &max6639_pm_ops,
|
||||
},
|
||||
.probe = max6639_probe,
|
||||
.remove = max6639_remove,
|
||||
.id_table = max6639_id,
|
||||
.detect = max6639_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
@ -105,38 +105,13 @@ module_param(clock, int, S_IRUGO);
|
||||
|
||||
#define DIV_FROM_REG(reg) (1 << (reg & 7))
|
||||
|
||||
static int max6650_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int max6650_init_client(struct i2c_client *client);
|
||||
static int max6650_remove(struct i2c_client *client);
|
||||
static struct max6650_data *max6650_update_device(struct device *dev);
|
||||
|
||||
/*
|
||||
* Driver data (common to all clients)
|
||||
*/
|
||||
|
||||
static const struct i2c_device_id max6650_id[] = {
|
||||
{ "max6650", 1 },
|
||||
{ "max6651", 4 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max6650_id);
|
||||
|
||||
static struct i2c_driver max6650_driver = {
|
||||
.driver = {
|
||||
.name = "max6650",
|
||||
},
|
||||
.probe = max6650_probe,
|
||||
.remove = max6650_remove,
|
||||
.id_table = max6650_id,
|
||||
};
|
||||
|
||||
/*
|
||||
* Client data (each client gets its own)
|
||||
*/
|
||||
|
||||
struct max6650_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[3];
|
||||
struct mutex update_lock;
|
||||
int nr_fans;
|
||||
char valid; /* zero until following fields are valid */
|
||||
@ -151,6 +126,51 @@ struct max6650_data {
|
||||
u8 alarm;
|
||||
};
|
||||
|
||||
static const u8 tach_reg[] = {
|
||||
MAX6650_REG_TACH0,
|
||||
MAX6650_REG_TACH1,
|
||||
MAX6650_REG_TACH2,
|
||||
MAX6650_REG_TACH3,
|
||||
};
|
||||
|
||||
static struct max6650_data *max6650_update_device(struct device *dev)
|
||||
{
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
data->speed = i2c_smbus_read_byte_data(client,
|
||||
MAX6650_REG_SPEED);
|
||||
data->config = i2c_smbus_read_byte_data(client,
|
||||
MAX6650_REG_CONFIG);
|
||||
for (i = 0; i < data->nr_fans; i++) {
|
||||
data->tach[i] = i2c_smbus_read_byte_data(client,
|
||||
tach_reg[i]);
|
||||
}
|
||||
data->count = i2c_smbus_read_byte_data(client,
|
||||
MAX6650_REG_COUNT);
|
||||
data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
|
||||
|
||||
/*
|
||||
* Alarms are cleared on read in case the condition that
|
||||
* caused the alarm is removed. Keep the value latched here
|
||||
* for providing the register through different alarm files.
|
||||
*/
|
||||
data->alarm |= i2c_smbus_read_byte_data(client,
|
||||
MAX6650_REG_ALARM);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
@ -235,8 +255,8 @@ static ssize_t get_target(struct device *dev, struct device_attribute *devattr,
|
||||
static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int kscale, ktach;
|
||||
unsigned long rpm;
|
||||
int err;
|
||||
@ -304,8 +324,8 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long pwm;
|
||||
int err;
|
||||
|
||||
@ -350,8 +370,8 @@ static ssize_t get_enable(struct device *dev, struct device_attribute *devattr,
|
||||
static ssize_t set_enable(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int max6650_modes[3] = {0, 3, 2};
|
||||
unsigned long mode;
|
||||
int err;
|
||||
@ -400,8 +420,8 @@ static ssize_t get_div(struct device *dev, struct device_attribute *devattr,
|
||||
static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long div;
|
||||
int err;
|
||||
|
||||
@ -446,7 +466,7 @@ static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct max6650_data *data = max6650_update_device(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int alarm = 0;
|
||||
|
||||
if (data->alarm & attr->index) {
|
||||
@ -484,7 +504,8 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
|
||||
int n)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
|
||||
struct device_attribute *devattr;
|
||||
|
||||
@ -519,7 +540,7 @@ static struct attribute *max6650_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group max6650_attr_grp = {
|
||||
static const struct attribute_group max6650_group = {
|
||||
.attrs = max6650_attrs,
|
||||
.is_visible = max6650_attrs_visible,
|
||||
};
|
||||
@ -531,7 +552,7 @@ static struct attribute *max6651_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group max6651_attr_grp = {
|
||||
static const struct attribute_group max6651_group = {
|
||||
.attrs = max6651_attrs,
|
||||
};
|
||||
|
||||
@ -539,74 +560,17 @@ static const struct attribute_group max6651_attr_grp = {
|
||||
* Real code
|
||||
*/
|
||||
|
||||
static int max6650_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static int max6650_init_client(struct max6650_data *data,
|
||||
struct i2c_client *client)
|
||||
{
|
||||
struct max6650_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct max6650_data),
|
||||
GFP_KERNEL);
|
||||
if (!data) {
|
||||
dev_err(&client->dev, "out of memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
data->nr_fans = id->driver_data;
|
||||
|
||||
/*
|
||||
* Initialize the max6650 chip
|
||||
*/
|
||||
err = max6650_init_client(client);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
|
||||
if (err)
|
||||
return err;
|
||||
/* 3 additional fan inputs for the MAX6651 */
|
||||
if (data->nr_fans == 4) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp);
|
||||
if (err)
|
||||
goto err_remove;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (!IS_ERR(data->hwmon_dev))
|
||||
return 0;
|
||||
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
dev_err(&client->dev, "error registering hwmon device.\n");
|
||||
if (data->nr_fans == 4)
|
||||
sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
|
||||
err_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int max6650_remove(struct i2c_client *client)
|
||||
{
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
if (data->nr_fans == 4)
|
||||
sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
|
||||
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max6650_init_client(struct i2c_client *client)
|
||||
{
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
struct device *dev = &client->dev;
|
||||
int config;
|
||||
int err = -EIO;
|
||||
|
||||
config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
|
||||
|
||||
if (config < 0) {
|
||||
dev_err(&client->dev, "Error reading config, aborting.\n");
|
||||
dev_err(dev, "Error reading config, aborting.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -620,11 +584,11 @@ static int max6650_init_client(struct i2c_client *client)
|
||||
config |= MAX6650_CFG_V12;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev, "illegal value for fan_voltage (%d)\n",
|
||||
dev_err(dev, "illegal value for fan_voltage (%d)\n",
|
||||
fan_voltage);
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "Fan voltage is set to %dV.\n",
|
||||
dev_info(dev, "Fan voltage is set to %dV.\n",
|
||||
(config & MAX6650_CFG_V12) ? 12 : 5);
|
||||
|
||||
switch (prescaler) {
|
||||
@ -650,11 +614,10 @@ static int max6650_init_client(struct i2c_client *client)
|
||||
| MAX6650_CFG_PRESCALER_16;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev, "illegal value for prescaler (%d)\n",
|
||||
prescaler);
|
||||
dev_err(dev, "illegal value for prescaler (%d)\n", prescaler);
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "Prescaler is set to %d.\n",
|
||||
dev_info(dev, "Prescaler is set to %d.\n",
|
||||
1 << (config & MAX6650_CFG_PRESCALER_MASK));
|
||||
|
||||
/*
|
||||
@ -664,17 +627,17 @@ static int max6650_init_client(struct i2c_client *client)
|
||||
*/
|
||||
|
||||
if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) {
|
||||
dev_dbg(&client->dev, "Change mode to open loop, full off.\n");
|
||||
dev_dbg(dev, "Change mode to open loop, full off.\n");
|
||||
config = (config & ~MAX6650_CFG_MODE_MASK)
|
||||
| MAX6650_CFG_MODE_OPEN_LOOP;
|
||||
if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) {
|
||||
dev_err(&client->dev, "DAC write error, aborting.\n");
|
||||
dev_err(dev, "DAC write error, aborting.\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
|
||||
dev_err(&client->dev, "Config write error, aborting.\n");
|
||||
dev_err(dev, "Config write error, aborting.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -684,51 +647,55 @@ static int max6650_init_client(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const u8 tach_reg[] = {
|
||||
MAX6650_REG_TACH0,
|
||||
MAX6650_REG_TACH1,
|
||||
MAX6650_REG_TACH2,
|
||||
MAX6650_REG_TACH3,
|
||||
};
|
||||
|
||||
static struct max6650_data *max6650_update_device(struct device *dev)
|
||||
static int max6650_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
struct device *dev = &client->dev;
|
||||
struct max6650_data *data;
|
||||
struct device *hwmon_dev;
|
||||
int err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data = devm_kzalloc(dev, sizeof(struct max6650_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
data->speed = i2c_smbus_read_byte_data(client,
|
||||
MAX6650_REG_SPEED);
|
||||
data->config = i2c_smbus_read_byte_data(client,
|
||||
MAX6650_REG_CONFIG);
|
||||
for (i = 0; i < data->nr_fans; i++) {
|
||||
data->tach[i] = i2c_smbus_read_byte_data(client,
|
||||
tach_reg[i]);
|
||||
}
|
||||
data->count = i2c_smbus_read_byte_data(client,
|
||||
MAX6650_REG_COUNT);
|
||||
data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
data->nr_fans = id->driver_data;
|
||||
|
||||
/*
|
||||
* Alarms are cleared on read in case the condition that
|
||||
* caused the alarm is removed. Keep the value latched here
|
||||
* for providing the register through different alarm files.
|
||||
*/
|
||||
data->alarm |= i2c_smbus_read_byte_data(client,
|
||||
MAX6650_REG_ALARM);
|
||||
/*
|
||||
* Initialize the max6650 chip
|
||||
*/
|
||||
err = max6650_init_client(data, client);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
data->groups[0] = &max6650_group;
|
||||
/* 3 additional fan inputs for the MAX6651 */
|
||||
if (data->nr_fans == 4)
|
||||
data->groups[1] = &max6651_group;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
|
||||
client->name, data,
|
||||
data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max6650_id[] = {
|
||||
{ "max6650", 1 },
|
||||
{ "max6651", 4 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max6650_id);
|
||||
|
||||
static struct i2c_driver max6650_driver = {
|
||||
.driver = {
|
||||
.name = "max6650",
|
||||
},
|
||||
.probe = max6650_probe,
|
||||
.id_table = max6650_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(max6650_driver);
|
||||
|
||||
MODULE_AUTHOR("Hans J. Koch");
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880,
|
||||
* and LTC3883
|
||||
* LTC3883, and LTM4676
|
||||
*
|
||||
* Copyright (c) 2011 Ericsson AB.
|
||||
* Copyright (c) 2013 Guenter Roeck
|
||||
* Copyright (c) 2013, 2014 Guenter Roeck
|
||||
*
|
||||
* 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
|
||||
@ -14,10 +14,6 @@
|
||||
* 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/kernel.h>
|
||||
@ -28,7 +24,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
|
||||
enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 };
|
||||
|
||||
/* Common for all chips */
|
||||
#define LTC2978_MFR_VOUT_PEAK 0xdd
|
||||
@ -45,7 +41,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
|
||||
#define LTC2974_MFR_IOUT_PEAK 0xd7
|
||||
#define LTC2974_MFR_IOUT_MIN 0xd8
|
||||
|
||||
/* LTC3880 and LTC3883 */
|
||||
/* LTC3880, LTC3883, and LTM4676 */
|
||||
#define LTC3880_MFR_IOUT_PEAK 0xd7
|
||||
#define LTC3880_MFR_CLEAR_PEAKS 0xe3
|
||||
#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
|
||||
@ -53,7 +49,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
|
||||
/* LTC3883 only */
|
||||
#define LTC3883_MFR_IIN_PEAK 0xe1
|
||||
|
||||
#define LTC2974_ID 0x0212
|
||||
#define LTC2974_ID_REV1 0x0212
|
||||
#define LTC2974_ID_REV2 0x0213
|
||||
#define LTC2977_ID 0x0130
|
||||
#define LTC2978_ID_REV1 0x0121
|
||||
#define LTC2978_ID_REV2 0x0122
|
||||
@ -62,6 +59,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
|
||||
#define LTC3880_ID_MASK 0xff00
|
||||
#define LTC3883_ID 0x4300
|
||||
#define LTC3883_ID_MASK 0xff00
|
||||
#define LTM4676_ID 0x4480 /* datasheet claims 0x440X */
|
||||
#define LTM4676_ID_MASK 0xfff0
|
||||
|
||||
#define LTC2974_NUM_PAGES 4
|
||||
#define LTC2978_NUM_PAGES 8
|
||||
@ -370,6 +369,7 @@ static const struct i2c_device_id ltc2978_id[] = {
|
||||
{"ltc2978", ltc2978},
|
||||
{"ltc3880", ltc3880},
|
||||
{"ltc3883", ltc3883},
|
||||
{"ltm4676", ltm4676},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
|
||||
@ -394,7 +394,7 @@ static int ltc2978_probe(struct i2c_client *client,
|
||||
if (chip_id < 0)
|
||||
return chip_id;
|
||||
|
||||
if (chip_id == LTC2974_ID) {
|
||||
if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) {
|
||||
data->id = ltc2974;
|
||||
} else if (chip_id == LTC2977_ID) {
|
||||
data->id = ltc2977;
|
||||
@ -405,6 +405,8 @@ static int ltc2978_probe(struct i2c_client *client,
|
||||
data->id = ltc3880;
|
||||
} else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
|
||||
data->id = ltc3883;
|
||||
} else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) {
|
||||
data->id = ltm4676;
|
||||
} else {
|
||||
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
|
||||
return -ENODEV;
|
||||
@ -458,6 +460,7 @@ static int ltc2978_probe(struct i2c_client *client,
|
||||
}
|
||||
break;
|
||||
case ltc3880:
|
||||
case ltm4676:
|
||||
info->read_word_data = ltc3880_read_word_data;
|
||||
info->pages = LTC3880_NUM_PAGES;
|
||||
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
|
||||
@ -500,5 +503,5 @@ static struct i2c_driver ltc2978_driver = {
|
||||
module_i2c_driver(ltc2978_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883");
|
||||
MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -222,7 +222,7 @@ static int smm665_read_adc(struct smm665_data *data, int adc)
|
||||
rv = i2c_smbus_read_word_swapped(client, 0);
|
||||
if (rv < 0) {
|
||||
dev_dbg(&client->dev, "Failed to read ADC value: error %d", rv);
|
||||
return -1;
|
||||
return rv;
|
||||
}
|
||||
/*
|
||||
* Validate/verify readback adc channel (in bit 11..14).
|
||||
|
Loading…
Reference in New Issue
Block a user