mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 13:14:07 +08:00
hwmon changes for v3.4
Mostly cleanup. No new drivers this time around, but support for several chips added to existing drivers: TPS40400, TPS40422, MTD040, MAX34446, ZL9101M, ZL9117M, and LM96080. Also, added watchdog support for SCH56xx, and additional attributes for a couple of drivers.312869e
hwmon: (sch56xx) Add support for the integrated watchdog (v2)840e191
hwmon: (w83627ehf) Add support for temperature offset registers86dda17
hwmon: (jc42) Remove unnecessary device IDs3360a10
hwmon: (zl6100) Add support for ZL9101M and ZL9117M9271126
hwmon: (adm1275) Add support for ADM1075590defe
hwmon: (max34440) Add support for MAX3444660b873e
hwmon: (pmbus) Add more virtual registers2163340
hwmon: (pmbus) Add support for Lineage Power MDT040c5f35c9
hwmon: (pmbus) Add support for TI TPS40400 and TPS4042256aad5d
hwmon: (max34440) Add support for 'lowest' output voltage attributef15df57
hwmon: (jc42) Convert to use devm_kzalloc918ddef
hwmon: (max16065) Convert to use devm_kzallocb8a5a7c
hwmon: (smm665) Convert to use devm_kzalloc3683928
hwmon: (ltc4261) Convert to use devm_kzallocdd285ad
hwmon: (pmbus) Simplify remove functions8b313ca
hwmon: (pmbus) Convert pmbus drivers to use devm_kzalloc07404aa
hwmon: (lineage-pem) Convert to use devm_kzallocf352df6
hwmon: (hwmon-vid) Fix checkpatch issues3230f70
hwmon: (hwmon-vid) Add new entries to VRM model table9908ad4
hwmon: (lm80) Add detection of NatSemi/TI LM960800e190b7
hwmon: (lm87) Get rid of macro-generated functions8652a26
hwmon: (lm87) Reorganize the code0fc86ec
hwmon: (applesmc) Silence uninitialized warnings7599d32
hwmon: (lm70) Fix: do not use assignment in if conditione200c14
hwmon: (lm70) Register hwmon device after creating attribute files, and remove it first01d9def
hwmon: (w83l786ng) Fix multi-line comments130067d
hwmon: (w83l785ts) Fix multi-line comments7950133
hwmon: (w83781d) Fix: do not use assignment in if conditionaff6e00
hwmon: (w83781d) Fix multi-line comments2a52dd6
hwmon: (smsc47b397) Fix multi-line comments36564ef
hwmon: (pc87427) Fix multi-line commentsb6707b7
hwmon: (max1668) Fix multi-line comments1160631
hwmon: (lm80) Fix multi-line commentsbf0f3a0
hwmon: (emc2103) Fix multi-line commentsfbb6670
hwmon: (adm1031) Fix multi-line comments94b991d
hwmon: (adm1029) Fix multi-line comments27b9de3
hwmon: (w83627hf) Fix checkpatch issuesca3ccad
hwmon: (w83l786ng) Fix checkpatch issues47efe87
hwmon: (w83793) Fix checkpatch issuesd174368
hwmon: (w83792d) Fix checkpatch issues2185696
hwmon: (vt1211) Fix: do not use assignment in if conditionb162c03
hwmon: (vt1211) Fix checkpatch issues9004ac8
hwmon: (via686a) Fix checkpatch issuesbce2778
hwmon: (pc87360) Fix: do not use assignment in if condition449a7a0
hwmon: (pc87360) Fix checkpatch issues8958dfb
hwmon: (max1619): Fix checkpatch issues09770b2
hwmon: (lm85) Fix checkpatch issues9b03079
hwmon: (lm78) Fix checkpatch issues02fe2fd
hwmon: (lm77) Fix checkpatch issuesf445a9a
hwmon: (gl520sm) Fix: do not use assignment in if condition43da3d1
hwmon: (gl520sm) Fix checkpatch issues228f8e0
hwmon: (gl518sm) Fix checkpatch issuesc8de836
hwmon: (dme1737) Fix checkpatch issues8c10369
hwmon: (asb100): Fix checkpatch issuesc387e4e
hwmon: (adm9240) Fix checkpatch issues86aa3e2
hwmon: (adm1026) Fix checkpatch issues21d2a8f
hwmon: (adm1021) Fix checkpatch issues1bd385d
hwmon: (abituguru) Fix checkpatch issues8969e84
hwmon: (w83627ehf) Fix multi-line comments51683ee
hwmon: (max1111) Fix multi-line comments 1b05d22 hwmon: (ltc4151) Fix multi-line comments1b9c491
hwmon: (g760a) Fix multi-line comments20eaf72
hwmon: (f71882fg) Fix multi-line comments 4bebced hwmon: (emc1403) Fix multi-line commentsca3c7b6
hwmon: (amc6821) Fix multi-line comments10775d1
hwmon: (ads7871) Fix multi-line commentsd13d623
hwmon: (ads7828) Fix multi-line comments562fca2
hwmon: (abituguru3) Fix multi-line commentsec1c319
hwmon: (w83791d) Fix checkpatch issuesa80b10c
hwmon: (ultra45_env) Fix checkpatch issues4d387df
hwmon: (thmc50) Fix checkpatch issues85a0c0d
hwmon: (smsc47m1) Fix checkpatch issues 7e61268 hwmon: (smsc47m1) Fix: do not use assignment in if condition7cc3cb6
hwmon: (smsc47m192) Fix checkpatch issues8fda79e
hwmon: (sis5595) Fix checkpatch issues 5725608 hwmon: (pcf8591) Fix checkpatch issues 2804a4c hwmon: (lm93) Fix checkpatch issuesa318afd
hwmon: (lm92) Fix checkpatch issues073f1e6c
hwmon: (lm87) Fix: do not use assignment in if conditionc6370db
hwmon: (lm87) Fix checkpatch issues525ad37
hwmon: (fschmd) Fix checkpatch issuesf24d548
hwmon: (atxp1) Fix checkpatch issues724cc33
hwmon: (adt7462) Fix checkpatch issues790fa38
hwmon: (ltc4215) Fix multi-line comments430b4fc
hwmon: (ltc4245) Fix multi-line commentsa68abd3
hwmon: (wm8350-hwmon) Constify fixed string array85ebfd3
hwmon: (applesmc) Fix multi-line comments75bdc93
hwmon: (asus_atk0110) Fix multi-line comments3c4c497
hwmon: (it87) Constify fixed string arrays8deeac8
hwmon: (ad7414) Fix multi-line comments5d577db
hwmon: (jc42) Fix multi-line comments780affe
hwmon: (coretemp) Fix checkpatch error3af2861
hwmon: (pc87360) Fix multi-line comments07de3df
hwmon: (wm831x-hwmon) Fix multi-line comments3c22e23
hwmon: (smm665) Fix checkpatch error3c56b06
hwmon: (asc7621) Fix multi-line comments4a0d71c
hwmon: (it87) Fix multi-line comments86d566e
hwmon: (hwmon-vid) Fix multi-line comments5ed0488
hwmon: (hwmon) Fix multi-line comments19f2c05
hwmon: (ds1621) Fix checkpatch issues91efffe
hwmon: convert drivers/hwmon/* to use module_spi_driver()f0967ee
hwmon: convert drivers/hwmon/* to use module_i2c_driver()61ba031
hwmon: (vt8231) Fix multi-line comments9ed5bc2
hwmon: (adt7475) Fix multi-line comments2fff084
hwmon: (f71805f) Fix checkpatch issues703af96
hwmon: (max6650) Fix multi-line commentsc531eb3
hwmon: (w83781d) Fix checkpatch issues2b22de5
hwmon: (adm1025) Fix checkpatch issues7973841
hwmon: (abituguru3) Fix checkpatch issues65fe5c7
hwmon: (vt8231) Fix checkpatch issues bafda5d hwmon: (max6650) Fix checkpatch issues0117c3f
hwmon: (pmbus) Replace strict_strtol with kstrtolb3789a0
hwmon: (lm83) fix checkpatch issues93092a6
hwmon: (k8temp) fix checkpatch issues96585f1
hwmon: (lm80) reset device if error occurred6a9e7c4c
hwmon: (lm80) fix checkpatch warnings6b904b6
hwmon: (adt7470) fix checkpatch issuese6a83db
hwmon: (adt7411) fix checkpatch issues56c24af
hwmon: (lm70) fix checkpatch issues1dc3708
hwmon: (f71882fg) fix checkpatch issuesc6e8ac0
hwmon: (asus_atk0110) fix checkpatch issues99b8c83
hwmon: (adt7475) fix checkpatch issuesb2ae8f8
hwmon: (smm665) fix checkpatch issuesc9e1498
hwmon: (sht15) fix checkpatch issues0910b28
hwmon: (ibmaem) fix checkpatch issuesdcb7cb9
hwmon: (ad7414) fix checkpatch issues e91aef2 hwmon: (ad7418) fix checkpatch issues5996542
hwmon: (w83l785ts) fix checkpatch issuesa6100f6
hwmon: (wm831x-hwmon) fix checkpatch issues839a9ee
hwmon: fix checkpatch issues08f5090
hwmon: (adm1029) fix checkpatch issues4d7c5d4
hwmon: (g760a) fix checkpatch issues7b102ed
hwmon: (i5k_amb) fix checkpatch issues600151b
hwmon: use DEFINE_PCI_DEVICE_TABLE7fe83ad
hwmon: remove () used with returna6bee4a
hwmon: (amc6821) fix initialisation2faaa93
hwmon: (lm80) add error handling -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) iQIcBAABAgAGBQJPaJBFAAoJEMsfJm/On5mBhkMP/09vlmsG7J3TLHcSKYJBkvSx 6VNOOJgPqnvF71Az0dX47SU3zVXhG3I7dZufd/hqOK+0CNylSB7OSZMcWvBTduea 0hDLTYj++SyVDQfVXb3zCVLU/wAE3YuXB3umWPwAKit4s2wAYYRDVCjwK96B88rv llNvo6JryuJDBUq7xiEmr0vKWMO0mKwwjpMTGCD3NpzK02ZV49T0gM94xa4gi5nM QAhNeO1AzQTx0+mBSRlq+SBBLSiXQmHcNrhnxcRMPha1bEi1D+QESozsczr+9/lz 8vuTIULOIZxafM4XkBsZdknvlZnYrA6ukituDfVfiYQVcljO/cNu+seutFQDCMJe 1zTDoNGIAwwnw0sAWWmTQwUMi+GSvlaL20gmm8FhTlvQaj9hNETsPYxEvPEsBNY1 ICCixZcwpa1mZBXmryz2btf8az0OlX/sApzyHiq24B7lSE5Fv4tBDtwypLRu5N8m C4oNXC2dqDU0gtVxzO5Lavu6LHWV9lhyZvRPO75+zxYt4i5cnO04GTAYWh46aOzO DAZcs8M2Rj++dI5VW9Vl0k8hP9eWjxtPJFhNv/OWTx4YYQRICrde+j7QZcikIUWF 0bzYI/zeIcwOg059vhnglBFM3mr7Z92jm4mftcNaSj/zuUHbWf6AQLbIq86Zq7tF 3Eru3WuTZTwAkyNAVWd5 =cUoW -----END PGP SIGNATURE----- Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hwmon changes for v3.4 from Guenter Roeck: "Mostly cleanup. No new drivers this time around, but support for several chips added to existing drivers: TPS40400, TPS40422, MTD040, MAX34446, ZL9101M, ZL9117M, and LM96080. Also, added watchdog support for SCH56xx, and additional attributes for a couple of drivers." * tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (137 commits) hwmon: (sch56xx) Add support for the integrated watchdog (v2) hwmon: (w83627ehf) Add support for temperature offset registers hwmon: (jc42) Remove unnecessary device IDs hwmon: (zl6100) Add support for ZL9101M and ZL9117M hwmon: (adm1275) Add support for ADM1075 hwmon: (max34440) Add support for MAX34446 hwmon: (pmbus) Add more virtual registers hwmon: (pmbus) Add support for Lineage Power MDT040 hwmon: (pmbus) Add support for TI TPS40400 and TPS40422 hwmon: (max34440) Add support for 'lowest' output voltage attribute hwmon: (jc42) Convert to use devm_kzalloc hwmon: (max16065) Convert to use devm_kzalloc hwmon: (smm665) Convert to use devm_kzalloc hwmon: (ltc4261) Convert to use devm_kzalloc hwmon: (pmbus) Simplify remove functions hwmon: (pmbus) Convert pmbus drivers to use devm_kzalloc hwmon: (lineage-pem) Convert to use devm_kzalloc hwmon: (hwmon-vid) Fix checkpatch issues hwmon: (hwmon-vid) Add new entries to VRM model table hwmon: (lm80) Add detection of NatSemi/TI LM96080 ...
This commit is contained in:
commit
31f6765266
@ -2,6 +2,10 @@ Kernel driver adm1275
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Analog Devices ADM1075
|
||||
Prefix: 'adm1075'
|
||||
Addresses scanned: -
|
||||
Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1075.pdf
|
||||
* Analog Devices ADM1275
|
||||
Prefix: 'adm1275'
|
||||
Addresses scanned: -
|
||||
@ -17,13 +21,13 @@ Author: Guenter Roeck <guenter.roeck@ericsson.com>
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver supports hardware montoring for Analog Devices ADM1275 and ADM1276
|
||||
Hot-Swap Controller and Digital Power Monitor.
|
||||
This driver supports hardware montoring for Analog Devices ADM1075, ADM1275,
|
||||
and ADM1276 Hot-Swap Controller and Digital Power Monitor.
|
||||
|
||||
ADM1275 and ADM1276 are hot-swap controllers that allow a circuit board to be
|
||||
removed from or inserted into a live backplane. They also feature current and
|
||||
voltage readback via an integrated 12-bit analog-to-digital converter (ADC),
|
||||
accessed using a PMBus interface.
|
||||
ADM1075, ADM1275, and ADM1276 are hot-swap controllers that allow a circuit
|
||||
board to be removed from or inserted into a live backplane. They also feature
|
||||
current and voltage readback via an integrated 12-bit analog-to-digital
|
||||
converter (ADC), accessed using a PMBus interface.
|
||||
|
||||
The driver is a client driver to the core PMBus driver. Please see
|
||||
Documentation/hwmon/pmbus for details on PMBus client drivers.
|
||||
@ -36,6 +40,10 @@ This driver does not auto-detect devices. You will have to instantiate the
|
||||
devices explicitly. Please see Documentation/i2c/instantiating-devices for
|
||||
details.
|
||||
|
||||
The ADM1075, unlike many other PMBus devices, does not support internal voltage
|
||||
or current scaling. Reported voltages, currents, and power are raw measurements,
|
||||
and will typically have to be scaled.
|
||||
|
||||
|
||||
Platform data support
|
||||
---------------------
|
||||
@ -51,7 +59,8 @@ The following attributes are supported. Limits are read-write, history reset
|
||||
attributes are write-only, all other attributes are read-only.
|
||||
|
||||
in1_label "vin1" or "vout1" depending on chip variant and
|
||||
configuration.
|
||||
configuration. On ADM1075, vout1 reports the voltage on
|
||||
the VAUX pin.
|
||||
in1_input Measured voltage.
|
||||
in1_min Minimum Voltage.
|
||||
in1_max Maximum voltage.
|
||||
@ -74,3 +83,10 @@ curr1_crit Critical maximum current. Depending on the chip
|
||||
curr1_crit_alarm Critical current high alarm.
|
||||
curr1_highest Historical maximum current.
|
||||
curr1_reset_history Write any value to reset history.
|
||||
|
||||
power1_label "pin1"
|
||||
power1_input Input power.
|
||||
power1_reset_history Write any value to reset history.
|
||||
|
||||
Power attributes are supported on ADM1075 and ADM1276
|
||||
only.
|
||||
|
@ -3,71 +3,50 @@ Kernel driver jc42
|
||||
|
||||
Supported chips:
|
||||
* Analog Devices ADT7408
|
||||
Prefix: 'adt7408'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
Datasheets:
|
||||
http://www.analog.com/static/imported-files/data_sheets/ADT7408.pdf
|
||||
* Atmel AT30TS00
|
||||
Prefix: 'at30ts00'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
Datasheets:
|
||||
http://www.atmel.com/Images/doc8585.pdf
|
||||
* IDT TSE2002B3, TSE2002GB2, TS3000B3, TS3000GB2
|
||||
Prefix: 'tse2002', 'ts3000'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
Datasheets:
|
||||
http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf
|
||||
http://www.idt.com/sites/default/files/documents/IDT_TSE2002GB2A1_DST_20111107_120303145914.pdf
|
||||
http://www.idt.com/sites/default/files/documents/IDT_TS3000B3A_DST_20101129_120303152013.pdf
|
||||
http://www.idt.com/sites/default/files/documents/IDT_TS3000GB2A1_DST_20111104_120303151012.pdf
|
||||
* Maxim MAX6604
|
||||
Prefix: 'max6604'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
Datasheets:
|
||||
http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf
|
||||
* Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP9843
|
||||
Prefixes: 'mcp9804', 'mcp9805', 'mcp98242', 'mcp98243', 'mcp9843'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
Datasheets:
|
||||
http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf
|
||||
http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf
|
||||
http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf
|
||||
http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf
|
||||
* NXP Semiconductors SE97, SE97B
|
||||
Prefix: 'se97'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
* NXP Semiconductors SE97, SE97B, SE98, SE98A
|
||||
Datasheets:
|
||||
http://www.nxp.com/documents/data_sheet/SE97.pdf
|
||||
http://www.nxp.com/documents/data_sheet/SE97B.pdf
|
||||
* NXP Semiconductors SE98
|
||||
Prefix: 'se98'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
Datasheets:
|
||||
http://www.nxp.com/documents/data_sheet/SE98.pdf
|
||||
http://www.nxp.com/documents/data_sheet/SE98A.pdf
|
||||
* ON Semiconductor CAT34TS02, CAT6095
|
||||
Prefix: 'cat34ts02', 'cat6095'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
Datasheet:
|
||||
http://www.onsemi.com/pub_link/Collateral/CAT34TS02-D.PDF
|
||||
http://www.onsemi.com/pub/Collateral/CAT6095-D.PDF
|
||||
* ST Microelectronics STTS424, STTS424E02
|
||||
Prefix: 'stts424'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
Datasheets:
|
||||
http://www.st.com/stonline/products/literature/ds/13447/stts424.pdf
|
||||
http://www.st.com/stonline/products/literature/ds/13448/stts424e02.pdf
|
||||
* ST Microelectronics STTS2002, STTS3000
|
||||
Prefix: 'stts2002', 'stts3000'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
* ST Microelectronics STTS424, STTS424E02, STTS2002, STTS3000
|
||||
Datasheets:
|
||||
http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157556.pdf
|
||||
http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157558.pdf
|
||||
http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00225278.pdf
|
||||
http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/CD00270920.pdf
|
||||
* JEDEC JC 42.4 compliant temperature sensor chips
|
||||
Prefix: 'jc42'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
Datasheet:
|
||||
http://www.jedec.org/sites/default/files/docs/4_01_04R19.pdf
|
||||
|
||||
Common for all chips:
|
||||
Prefix: 'jc42'
|
||||
Addresses scanned: I2C 0x18 - 0x1f
|
||||
|
||||
Author:
|
||||
Guenter Roeck <guenter.roeck@ericsson.com>
|
||||
|
||||
|
@ -7,6 +7,11 @@ Supported chips:
|
||||
Addresses scanned: I2C 0x28 - 0x2f
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/
|
||||
* National Semiconductor LM96080
|
||||
Prefix: 'lm96080'
|
||||
Addresses scanned: I2C 0x28 - 0x2f
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
@ -17,7 +22,9 @@ Description
|
||||
|
||||
This driver implements support for the National Semiconductor LM80.
|
||||
It is described as a 'Serial Interface ACPI-Compatible Microprocessor
|
||||
System Hardware Monitor'.
|
||||
System Hardware Monitor'. The LM96080 is a more recent incarnation,
|
||||
it is pin and register compatible, with a few additional features not
|
||||
yet supported by the driver.
|
||||
|
||||
The LM80 implements one temperature sensor, two fan rotation speed sensors,
|
||||
seven voltage sensors, alarms, and some miscellaneous stuff.
|
||||
|
@ -11,6 +11,11 @@ Supported chips:
|
||||
Prefixes: 'max34441'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf
|
||||
* Maxim MAX34446
|
||||
PMBus Power-Supply Data Logger
|
||||
Prefixes: 'max34446'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34446.pdf
|
||||
|
||||
Author: Guenter Roeck <guenter.roeck@ericsson.com>
|
||||
|
||||
@ -19,8 +24,8 @@ Description
|
||||
-----------
|
||||
|
||||
This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel
|
||||
Power-Supply Manager and MAX34441 PMBus 5-Channel Power-Supply Manager
|
||||
and Intelligent Fan Controller.
|
||||
Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply Manager
|
||||
and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data Logger.
|
||||
|
||||
The driver is a client driver to the core PMBus driver. Please see
|
||||
Documentation/hwmon/pmbus for details on PMBus client drivers.
|
||||
@ -33,6 +38,13 @@ This driver does not auto-detect devices. You will have to instantiate the
|
||||
devices explicitly. Please see Documentation/i2c/instantiating-devices for
|
||||
details.
|
||||
|
||||
For MAX34446, the value of the currX_crit attribute determines if current or
|
||||
voltage measurement is enabled for a given channel. Voltage measurement is
|
||||
enabled if currX_crit is set to 0; current measurement is enabled if the
|
||||
attribute is set to a positive value. Power measurement is only enabled if
|
||||
channel 1 (3) is configured for voltage measurement, and channel 2 (4) is
|
||||
configured for current measurement.
|
||||
|
||||
|
||||
Platform data support
|
||||
---------------------
|
||||
@ -56,19 +68,31 @@ in[1-6]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status.
|
||||
in[1-6]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status.
|
||||
in[1-6]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
|
||||
in[1-6]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
|
||||
in[1-6]_lowest Historical minimum voltage.
|
||||
in[1-6]_highest Historical maximum voltage.
|
||||
in[1-6]_reset_history Write any value to reset history.
|
||||
|
||||
MAX34446 only supports in[1-4].
|
||||
|
||||
curr[1-6]_label "iout[1-6]".
|
||||
curr[1-6]_input Measured current. From READ_IOUT register.
|
||||
curr[1-6]_max Maximum current. From IOUT_OC_WARN_LIMIT register.
|
||||
curr[1-6]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
|
||||
curr[1-6]_max_alarm Current high alarm. From IOUT_OC_WARNING status.
|
||||
curr[1-6]_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status.
|
||||
curr[1-4]_average Historical average current (MAX34446 only).
|
||||
curr[1-6]_highest Historical maximum current.
|
||||
curr[1-6]_reset_history Write any value to reset history.
|
||||
|
||||
in6 and curr6 attributes only exist for MAX34440.
|
||||
MAX34446 only supports curr[1-4].
|
||||
|
||||
power[1,3]_label "pout[1,3]"
|
||||
power[1,3]_input Measured power.
|
||||
power[1,3]_average Historical average power.
|
||||
power[1,3]_highest Historical maximum power.
|
||||
|
||||
Power attributes only exist for MAX34446.
|
||||
|
||||
temp[1-8]_input Measured temperatures. From READ_TEMPERATURE_1 register.
|
||||
temp1 is the chip's internal temperature. temp2..temp5
|
||||
@ -79,7 +103,9 @@ temp[1-8]_max Maximum temperature. From OT_WARN_LIMIT register.
|
||||
temp[1-8]_crit Critical high temperature. From OT_FAULT_LIMIT register.
|
||||
temp[1-8]_max_alarm Temperature high alarm.
|
||||
temp[1-8]_crit_alarm Temperature critical high alarm.
|
||||
temp[1-8]_average Historical average temperature (MAX34446 only).
|
||||
temp[1-8]_highest Historical maximum temperature.
|
||||
temp[1-8]_reset_history Write any value to reset history.
|
||||
|
||||
temp7 and temp8 attributes only exist for MAX34440.
|
||||
MAX34446 only supports temp[1-3].
|
||||
|
@ -15,13 +15,20 @@ Supported chips:
|
||||
http://www.onsemi.com/pub_link/Collateral/NCP4200-D.PDF
|
||||
http://www.onsemi.com/pub_link/Collateral/JUNE%202009-%20REV.%200.PDF
|
||||
* Lineage Power
|
||||
Prefixes: 'pdt003', 'pdt006', 'pdt012', 'udt020'
|
||||
Prefixes: 'mdt040', 'pdt003', 'pdt006', 'pdt012', 'udt020'
|
||||
Addresses scanned: -
|
||||
Datasheets:
|
||||
http://www.lineagepower.com/oem/pdf/PDT003A0X.pdf
|
||||
http://www.lineagepower.com/oem/pdf/PDT006A0X.pdf
|
||||
http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf
|
||||
http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf
|
||||
http://www.lineagepower.com/oem/pdf/MDT040A0X.pdf
|
||||
* Texas Instruments TPS40400, TPS40422
|
||||
Prefixes: 'tps40400', 'tps40422'
|
||||
Addresses scanned: -
|
||||
Datasheets:
|
||||
http://www.ti.com/lit/gpn/tps40400
|
||||
http://www.ti.com/lit/gpn/tps40422
|
||||
* Generic PMBus devices
|
||||
Prefix: 'pmbus'
|
||||
Addresses scanned: -
|
||||
|
@ -16,6 +16,11 @@ Description
|
||||
SMSC SCH5627 Super I/O chips include complete hardware monitoring
|
||||
capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures.
|
||||
|
||||
The SMSC SCH5627 hardware monitoring part also contains an integrated
|
||||
watchdog. In order for this watchdog to function some motherboard specific
|
||||
initialization most be done by the BIOS, so if the watchdog is not enabled
|
||||
by the BIOS the sch5627 driver will not register a watchdog device.
|
||||
|
||||
The hardware monitoring part of the SMSC SCH5627 is accessed by talking
|
||||
through an embedded microcontroller. An application note describing the
|
||||
protocol for communicating with the microcontroller is available upon
|
||||
|
@ -26,6 +26,9 @@ temperatures. Note that the driver detects how many fan headers /
|
||||
temperature sensors are actually implemented on the motherboard, so you will
|
||||
likely see fewer temperature and fan inputs.
|
||||
|
||||
The Fujitsu Theseus hwmon solution also contains an integrated watchdog.
|
||||
This watchdog is fully supported by the sch5636 driver.
|
||||
|
||||
An application note describing the Theseus' registers, as well as an
|
||||
application note describing the protocol for communicating with the
|
||||
microcontroller is available upon request. Please mail me if you want a copy.
|
||||
|
@ -34,6 +34,14 @@ Supported chips:
|
||||
Prefix: 'zl6105'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://www.intersil.com/data/fn/fn6906.pdf
|
||||
* Intersil / Zilker Labs ZL9101M
|
||||
Prefix: 'zl9101'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://www.intersil.com/data/fn/fn7669.pdf
|
||||
* Intersil / Zilker Labs ZL9117M
|
||||
Prefix: 'zl9117'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://www.intersil.com/data/fn/fn7914.pdf
|
||||
* Ericsson BMR450, BMR451
|
||||
Prefix: 'bmr450', 'bmr451'
|
||||
Addresses scanned: -
|
||||
|
@ -598,11 +598,11 @@ config SENSORS_LM78
|
||||
will be called lm78.
|
||||
|
||||
config SENSORS_LM80
|
||||
tristate "National Semiconductor LM80"
|
||||
tristate "National Semiconductor LM80 and LM96080"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor
|
||||
LM80 sensor chips.
|
||||
LM80 and LM96080 sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm80.
|
||||
@ -1028,7 +1028,8 @@ config SENSORS_SCH5627
|
||||
select SENSORS_SCH56XX_COMMON
|
||||
help
|
||||
If you say yes here you get support for the hardware monitoring
|
||||
features of the SMSC SCH5627 Super-I/O chip.
|
||||
features of the SMSC SCH5627 Super-I/O chip including support for
|
||||
the integrated watchdog.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sch5627.
|
||||
@ -1044,7 +1045,8 @@ config SENSORS_SCH5636
|
||||
|
||||
Currently this driver only supports the Fujitsu Theseus SCH5636 based
|
||||
hwmon solution. Say yes here if you want support for the Fujitsu
|
||||
Theseus' hardware monitoring features.
|
||||
Theseus' hardware monitoring features including support for the
|
||||
integrated watchdog.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sch5636.
|
||||
|
@ -1,24 +1,24 @@
|
||||
/*
|
||||
abituguru.c Copyright (c) 2005-2006 Hans de Goede <hdegoede@redhat.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* abituguru.c Copyright (c) 2005-2006 Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
This driver supports the sensor part of the first and second revision of
|
||||
the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because
|
||||
of lack of specs the CPU/RAM voltage & frequency control is not supported!
|
||||
* This driver supports the sensor part of the first and second revision of
|
||||
* the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because
|
||||
* of lack of specs the CPU/RAM voltage & frequency control is not supported!
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -44,8 +44,10 @@
|
||||
#define ABIT_UGURU_SENSOR_BANK2 0x26 /* fans */
|
||||
/* max nr of sensors in bank1, a bank1 sensor can be in, temp or nc */
|
||||
#define ABIT_UGURU_MAX_BANK1_SENSORS 16
|
||||
/* Warning if you increase one of the 2 MAX defines below to 10 or higher you
|
||||
should adjust the belonging _NAMES_LENGTH macro for the 2 digit number! */
|
||||
/*
|
||||
* Warning if you increase one of the 2 MAX defines below to 10 or higher you
|
||||
* should adjust the belonging _NAMES_LENGTH macro for the 2 digit number!
|
||||
*/
|
||||
/* max nr of sensors in bank2, currently mb's with max 6 fans are known */
|
||||
#define ABIT_UGURU_MAX_BANK2_SENSORS 6
|
||||
/* max nr of pwm outputs, currently mb's with max 5 pwm outputs are known */
|
||||
@ -70,16 +72,22 @@
|
||||
#define ABIT_UGURU_IN_SENSOR 0
|
||||
#define ABIT_UGURU_TEMP_SENSOR 1
|
||||
#define ABIT_UGURU_NC 2
|
||||
/* In many cases we need to wait for the uGuru to reach a certain status, most
|
||||
of the time it will reach this status within 30 - 90 ISA reads, and thus we
|
||||
can best busy wait. This define gives the total amount of reads to try. */
|
||||
/*
|
||||
* In many cases we need to wait for the uGuru to reach a certain status, most
|
||||
* of the time it will reach this status within 30 - 90 ISA reads, and thus we
|
||||
* can best busy wait. This define gives the total amount of reads to try.
|
||||
*/
|
||||
#define ABIT_UGURU_WAIT_TIMEOUT 125
|
||||
/* However sometimes older versions of the uGuru seem to be distracted and they
|
||||
do not respond for a long time. To handle this we sleep before each of the
|
||||
last ABIT_UGURU_WAIT_TIMEOUT_SLEEP tries. */
|
||||
/*
|
||||
* However sometimes older versions of the uGuru seem to be distracted and they
|
||||
* do not respond for a long time. To handle this we sleep before each of the
|
||||
* last ABIT_UGURU_WAIT_TIMEOUT_SLEEP tries.
|
||||
*/
|
||||
#define ABIT_UGURU_WAIT_TIMEOUT_SLEEP 5
|
||||
/* Normally all expected status in abituguru_ready, are reported after the
|
||||
first read, but sometimes not and we need to poll. */
|
||||
/*
|
||||
* Normally all expected status in abituguru_ready, are reported after the
|
||||
* first read, but sometimes not and we need to poll.
|
||||
*/
|
||||
#define ABIT_UGURU_READY_TIMEOUT 5
|
||||
/* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */
|
||||
#define ABIT_UGURU_MAX_RETRIES 3
|
||||
@ -92,17 +100,25 @@
|
||||
if (level <= verbose) \
|
||||
printk(KERN_DEBUG ABIT_UGURU_NAME ": " format , ## arg)
|
||||
/* Macros to help calculate the sysfs_names array length */
|
||||
/* sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
|
||||
in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0 */
|
||||
/*
|
||||
* sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
|
||||
* in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0
|
||||
*/
|
||||
#define ABITUGURU_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14)
|
||||
/* sum of strlen of: temp??_input\0, temp??_max\0, temp??_crit\0,
|
||||
temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0 */
|
||||
/*
|
||||
* sum of strlen of: temp??_input\0, temp??_max\0, temp??_crit\0,
|
||||
* temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0
|
||||
*/
|
||||
#define ABITUGURU_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16)
|
||||
/* sum of strlen of: fan?_input\0, fan?_min\0, fan?_alarm\0,
|
||||
fan?_alarm_enable\0, fan?_beep\0, fan?_shutdown\0 */
|
||||
/*
|
||||
* sum of strlen of: fan?_input\0, fan?_min\0, fan?_alarm\0,
|
||||
* fan?_alarm_enable\0, fan?_beep\0, fan?_shutdown\0
|
||||
*/
|
||||
#define ABITUGURU_FAN_NAMES_LENGTH (11 + 9 + 11 + 18 + 10 + 14)
|
||||
/* sum of strlen of: pwm?_enable\0, pwm?_auto_channels_temp\0,
|
||||
pwm?_auto_point{1,2}_pwm\0, pwm?_auto_point{1,2}_temp\0 */
|
||||
/*
|
||||
* sum of strlen of: pwm?_enable\0, pwm?_auto_channels_temp\0,
|
||||
* pwm?_auto_point{1,2}_pwm\0, pwm?_auto_point{1,2}_temp\0
|
||||
*/
|
||||
#define ABITUGURU_PWM_NAMES_LENGTH (12 + 24 + 2 * 21 + 2 * 22)
|
||||
/* IN_NAMES_LENGTH > TEMP_NAMES_LENGTH so assume all bank1 sensors are in */
|
||||
#define ABITUGURU_SYSFS_NAMES_LENGTH ( \
|
||||
@ -110,10 +126,12 @@
|
||||
ABIT_UGURU_MAX_BANK2_SENSORS * ABITUGURU_FAN_NAMES_LENGTH + \
|
||||
ABIT_UGURU_MAX_PWMS * ABITUGURU_PWM_NAMES_LENGTH)
|
||||
|
||||
/* All the macros below are named identical to the oguru and oguru2 programs
|
||||
reverse engineered by Olle Sandberg, hence the names might not be 100%
|
||||
logical. I could come up with better names, but I prefer keeping the names
|
||||
identical so that this driver can be compared with his work more easily. */
|
||||
/*
|
||||
* All the macros below are named identical to the oguru and oguru2 programs
|
||||
* reverse engineered by Olle Sandberg, hence the names might not be 100%
|
||||
* logical. I could come up with better names, but I prefer keeping the names
|
||||
* identical so that this driver can be compared with his work more easily.
|
||||
*/
|
||||
/* Two i/o-ports are used by uGuru */
|
||||
#define ABIT_UGURU_BASE 0x00E0
|
||||
/* Used to tell uGuru what to read and to read the actual data */
|
||||
@ -130,16 +148,22 @@
|
||||
/* Constants */
|
||||
/* in (Volt) sensors go up to 3494 mV, temp to 255000 millidegrees Celsius */
|
||||
static const int abituguru_bank1_max_value[2] = { 3494, 255000 };
|
||||
/* Min / Max allowed values for sensor2 (fan) alarm threshold, these values
|
||||
correspond to 300-3000 RPM */
|
||||
/*
|
||||
* Min / Max allowed values for sensor2 (fan) alarm threshold, these values
|
||||
* correspond to 300-3000 RPM
|
||||
*/
|
||||
static const u8 abituguru_bank2_min_threshold = 5;
|
||||
static const u8 abituguru_bank2_max_threshold = 50;
|
||||
/* Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4
|
||||
are temperature trip points. */
|
||||
/*
|
||||
* Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4
|
||||
* are temperature trip points.
|
||||
*/
|
||||
static const int abituguru_pwm_settings_multiplier[5] = { 0, 1, 1, 1000, 1000 };
|
||||
/* Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a
|
||||
special case the minium allowed pwm% setting for this is 30% (77) on
|
||||
some MB's this special case is handled in the code! */
|
||||
/*
|
||||
* Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a
|
||||
* special case the minium allowed pwm% setting for this is 30% (77) on
|
||||
* some MB's this special case is handled in the code!
|
||||
*/
|
||||
static const u8 abituguru_pwm_min[5] = { 0, 170, 170, 25, 25 };
|
||||
static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 };
|
||||
|
||||
@ -175,23 +199,29 @@ MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n"
|
||||
" 3 + retryable error reporting");
|
||||
|
||||
|
||||
/* For the Abit uGuru, we need to keep some data in memory.
|
||||
The structure is dynamically allocated, at the same time when a new
|
||||
abituguru device is allocated. */
|
||||
/*
|
||||
* For the Abit uGuru, we need to keep some data in memory.
|
||||
* The structure is dynamically allocated, at the same time when a new
|
||||
* abituguru device is allocated.
|
||||
*/
|
||||
struct abituguru_data {
|
||||
struct device *hwmon_dev; /* hwmon registered device */
|
||||
struct mutex update_lock; /* protect access to data and uGuru */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
unsigned short addr; /* uguru base address */
|
||||
char uguru_ready; /* is the uguru in ready state? */
|
||||
unsigned char update_timeouts; /* number of update timeouts since last
|
||||
successful update */
|
||||
unsigned char update_timeouts; /*
|
||||
* number of update timeouts since last
|
||||
* successful update
|
||||
*/
|
||||
|
||||
/* The sysfs attr and their names are generated automatically, for bank1
|
||||
we cannot use a predefined array because we don't know beforehand
|
||||
of a sensor is a volt or a temp sensor, for bank2 and the pwms its
|
||||
easier todo things the same way. For in sensors we have 9 (temp 7)
|
||||
sysfs entries per sensor, for bank2 and pwms 6. */
|
||||
/*
|
||||
* The sysfs attr and their names are generated automatically, for bank1
|
||||
* we cannot use a predefined array because we don't know beforehand
|
||||
* of a sensor is a volt or a temp sensor, for bank2 and the pwms its
|
||||
* easier todo things the same way. For in sensors we have 9 (temp 7)
|
||||
* sysfs entries per sensor, for bank2 and pwms 6.
|
||||
*/
|
||||
struct sensor_device_attribute_2 sysfs_attr[
|
||||
ABIT_UGURU_MAX_BANK1_SENSORS * 9 +
|
||||
ABIT_UGURU_MAX_BANK2_SENSORS * 6 + ABIT_UGURU_MAX_PWMS * 6];
|
||||
@ -203,11 +233,15 @@ struct abituguru_data {
|
||||
u8 bank1_sensors[2];
|
||||
u8 bank1_address[2][ABIT_UGURU_MAX_BANK1_SENSORS];
|
||||
u8 bank1_value[ABIT_UGURU_MAX_BANK1_SENSORS];
|
||||
/* This array holds 3 entries per sensor for the bank 1 sensor settings
|
||||
(flags, min, max for voltage / flags, warn, shutdown for temp). */
|
||||
/*
|
||||
* This array holds 3 entries per sensor for the bank 1 sensor settings
|
||||
* (flags, min, max for voltage / flags, warn, shutdown for temp).
|
||||
*/
|
||||
u8 bank1_settings[ABIT_UGURU_MAX_BANK1_SENSORS][3];
|
||||
/* Maximum value for each sensor used for scaling in mV/millidegrees
|
||||
Celsius. */
|
||||
/*
|
||||
* Maximum value for each sensor used for scaling in mV/millidegrees
|
||||
* Celsius.
|
||||
*/
|
||||
int bank1_max_value[ABIT_UGURU_MAX_BANK1_SENSORS];
|
||||
|
||||
/* Bank 2 data, ABIT_UGURU_MAX_BANK2_SENSORS entries for bank2 */
|
||||
@ -236,8 +270,10 @@ static int abituguru_wait(struct abituguru_data *data, u8 state)
|
||||
timeout--;
|
||||
if (timeout == 0)
|
||||
return -EBUSY;
|
||||
/* sleep a bit before our last few tries, see the comment on
|
||||
this where ABIT_UGURU_WAIT_TIMEOUT_SLEEP is defined. */
|
||||
/*
|
||||
* sleep a bit before our last few tries, see the comment on
|
||||
* this where ABIT_UGURU_WAIT_TIMEOUT_SLEEP is defined.
|
||||
*/
|
||||
if (timeout <= ABIT_UGURU_WAIT_TIMEOUT_SLEEP)
|
||||
msleep(0);
|
||||
}
|
||||
@ -273,8 +309,10 @@ static int abituguru_ready(struct abituguru_data *data)
|
||||
msleep(0);
|
||||
}
|
||||
|
||||
/* After this the ABIT_UGURU_DATA port should contain
|
||||
ABIT_UGURU_STATUS_INPUT */
|
||||
/*
|
||||
* After this the ABIT_UGURU_DATA port should contain
|
||||
* ABIT_UGURU_STATUS_INPUT
|
||||
*/
|
||||
timeout = ABIT_UGURU_READY_TIMEOUT;
|
||||
while (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) {
|
||||
timeout--;
|
||||
@ -290,27 +328,35 @@ static int abituguru_ready(struct abituguru_data *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send the bank and then sensor address to the uGuru for the next read/write
|
||||
cycle. This function gets called as the first part of a read/write by
|
||||
abituguru_read and abituguru_write. This function should never be
|
||||
called by any other function. */
|
||||
/*
|
||||
* Send the bank and then sensor address to the uGuru for the next read/write
|
||||
* cycle. This function gets called as the first part of a read/write by
|
||||
* abituguru_read and abituguru_write. This function should never be
|
||||
* called by any other function.
|
||||
*/
|
||||
static int abituguru_send_address(struct abituguru_data *data,
|
||||
u8 bank_addr, u8 sensor_addr, int retries)
|
||||
{
|
||||
/* assume the caller does error handling itself if it has not requested
|
||||
any retries, and thus be quiet. */
|
||||
/*
|
||||
* assume the caller does error handling itself if it has not requested
|
||||
* any retries, and thus be quiet.
|
||||
*/
|
||||
int report_errors = retries;
|
||||
|
||||
for (;;) {
|
||||
/* Make sure the uguru is ready and then send the bank address,
|
||||
after this the uguru is no longer "ready". */
|
||||
/*
|
||||
* Make sure the uguru is ready and then send the bank address,
|
||||
* after this the uguru is no longer "ready".
|
||||
*/
|
||||
if (abituguru_ready(data) != 0)
|
||||
return -EIO;
|
||||
outb(bank_addr, data->addr + ABIT_UGURU_DATA);
|
||||
data->uguru_ready = 0;
|
||||
|
||||
/* Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again
|
||||
and send the sensor addr */
|
||||
/*
|
||||
* Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again
|
||||
* and send the sensor addr
|
||||
*/
|
||||
if (abituguru_wait(data, ABIT_UGURU_STATUS_INPUT)) {
|
||||
if (retries) {
|
||||
ABIT_UGURU_DEBUG(3, "timeout exceeded "
|
||||
@ -332,8 +378,10 @@ static int abituguru_send_address(struct abituguru_data *data,
|
||||
}
|
||||
}
|
||||
|
||||
/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
|
||||
result in buf, retry the send address part of the read retries times. */
|
||||
/*
|
||||
* Read count bytes from sensor sensor_addr in bank bank_addr and store the
|
||||
* result in buf, retry the send address part of the read retries times.
|
||||
*/
|
||||
static int abituguru_read(struct abituguru_data *data,
|
||||
u8 bank_addr, u8 sensor_addr, u8 *buf, int count, int retries)
|
||||
{
|
||||
@ -362,13 +410,17 @@ static int abituguru_read(struct abituguru_data *data,
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send
|
||||
address part of the write is always retried ABIT_UGURU_MAX_RETRIES times. */
|
||||
/*
|
||||
* Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send
|
||||
* address part of the write is always retried ABIT_UGURU_MAX_RETRIES times.
|
||||
*/
|
||||
static int abituguru_write(struct abituguru_data *data,
|
||||
u8 bank_addr, u8 sensor_addr, u8 *buf, int count)
|
||||
{
|
||||
/* We use the ready timeout as we have to wait for 0xAC just like the
|
||||
ready function */
|
||||
/*
|
||||
* We use the ready timeout as we have to wait for 0xAC just like the
|
||||
* ready function
|
||||
*/
|
||||
int i, timeout = ABIT_UGURU_READY_TIMEOUT;
|
||||
|
||||
/* Send the address */
|
||||
@ -388,9 +440,11 @@ static int abituguru_write(struct abituguru_data *data,
|
||||
outb(buf[i], data->addr + ABIT_UGURU_CMD);
|
||||
}
|
||||
|
||||
/* Now we need to wait till the chip is ready to be read again,
|
||||
so that we can read 0xAC as confirmation that our write has
|
||||
succeeded. */
|
||||
/*
|
||||
* Now we need to wait till the chip is ready to be read again,
|
||||
* so that we can read 0xAC as confirmation that our write has
|
||||
* succeeded.
|
||||
*/
|
||||
if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
|
||||
ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state "
|
||||
"after write (bank: %d, sensor: %d)\n", (int)bank_addr,
|
||||
@ -416,12 +470,14 @@ static int abituguru_write(struct abituguru_data *data,
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Detect sensor type. Temp and Volt sensors are enabled with
|
||||
different masks and will ignore enable masks not meant for them.
|
||||
This enables us to test what kind of sensor we're dealing with.
|
||||
By setting the alarm thresholds so that we will always get an
|
||||
alarm for sensor type X and then enabling the sensor as sensor type
|
||||
X, if we then get an alarm it is a sensor of type X. */
|
||||
/*
|
||||
* Detect sensor type. Temp and Volt sensors are enabled with
|
||||
* different masks and will ignore enable masks not meant for them.
|
||||
* This enables us to test what kind of sensor we're dealing with.
|
||||
* By setting the alarm thresholds so that we will always get an
|
||||
* alarm for sensor type X and then enabling the sensor as sensor type
|
||||
* X, if we then get an alarm it is a sensor of type X.
|
||||
*/
|
||||
static int __devinit
|
||||
abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
|
||||
u8 sensor_addr)
|
||||
@ -448,16 +504,20 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
|
||||
pr_warn("bank1-sensor: %d reading (%d) too close to limits, "
|
||||
"unable to determine sensor type, skipping sensor\n",
|
||||
(int)sensor_addr, (int)val);
|
||||
/* assume no sensor is there for sensors for which we can't
|
||||
determine the sensor type because their reading is too close
|
||||
to their limits, this usually means no sensor is there. */
|
||||
/*
|
||||
* assume no sensor is there for sensors for which we can't
|
||||
* determine the sensor type because their reading is too close
|
||||
* to their limits, this usually means no sensor is there.
|
||||
*/
|
||||
return ABIT_UGURU_NC;
|
||||
}
|
||||
|
||||
ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
|
||||
/* Volt sensor test, enable volt low alarm, set min value ridicously
|
||||
high, or vica versa if the reading is very high. If its a volt
|
||||
sensor this should always give us an alarm. */
|
||||
/*
|
||||
* Volt sensor test, enable volt low alarm, set min value ridicously
|
||||
* high, or vica versa if the reading is very high. If its a volt
|
||||
* sensor this should always give us an alarm.
|
||||
*/
|
||||
if (val <= 240u) {
|
||||
buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
|
||||
buf[1] = 245;
|
||||
@ -473,8 +533,10 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
|
||||
if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
|
||||
buf, 3) != 3)
|
||||
goto abituguru_detect_bank1_sensor_type_exit;
|
||||
/* Now we need 20 ms to give the uguru time to read the sensors
|
||||
and raise a voltage alarm */
|
||||
/*
|
||||
* Now we need 20 ms to give the uguru time to read the sensors
|
||||
* and raise a voltage alarm
|
||||
*/
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_timeout(HZ/50);
|
||||
/* Check for alarm and check the alarm is a volt low alarm. */
|
||||
@ -497,17 +559,21 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
|
||||
ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor "
|
||||
"test\n");
|
||||
|
||||
/* Temp sensor test, enable sensor as a temp sensor, set beep value
|
||||
ridicously low (but not too low, otherwise uguru ignores it).
|
||||
If its a temp sensor this should always give us an alarm. */
|
||||
/*
|
||||
* Temp sensor test, enable sensor as a temp sensor, set beep value
|
||||
* ridicously low (but not too low, otherwise uguru ignores it).
|
||||
* If its a temp sensor this should always give us an alarm.
|
||||
*/
|
||||
buf[0] = ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE;
|
||||
buf[1] = 5;
|
||||
buf[2] = 10;
|
||||
if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
|
||||
buf, 3) != 3)
|
||||
goto abituguru_detect_bank1_sensor_type_exit;
|
||||
/* Now we need 50 ms to give the uguru time to read the sensors
|
||||
and raise a temp alarm */
|
||||
/*
|
||||
* Now we need 50 ms to give the uguru time to read the sensors
|
||||
* and raise a temp alarm
|
||||
*/
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_timeout(HZ/20);
|
||||
/* Check for alarm and check the alarm is a temp high alarm. */
|
||||
@ -532,9 +598,11 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
|
||||
|
||||
ret = ABIT_UGURU_NC;
|
||||
abituguru_detect_bank1_sensor_type_exit:
|
||||
/* Restore original settings, failing here is really BAD, it has been
|
||||
reported that some BIOS-es hang when entering the uGuru menu with
|
||||
invalid settings present in the uGuru, so we try this 3 times. */
|
||||
/*
|
||||
* Restore original settings, failing here is really BAD, it has been
|
||||
* reported that some BIOS-es hang when entering the uGuru menu with
|
||||
* invalid settings present in the uGuru, so we try this 3 times.
|
||||
*/
|
||||
for (i = 0; i < 3; i++)
|
||||
if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
|
||||
sensor_addr, data->bank1_settings[sensor_addr],
|
||||
@ -548,23 +616,25 @@ abituguru_detect_bank1_sensor_type_exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* These functions try to find out how many sensors there are in bank2 and how
|
||||
many pwms there are. The purpose of this is to make sure that we don't give
|
||||
the user the possibility to change settings for non-existent sensors / pwm.
|
||||
The uGuru will happily read / write whatever memory happens to be after the
|
||||
memory storing the PWM settings when reading/writing to a PWM which is not
|
||||
there. Notice even if we detect a PWM which doesn't exist we normally won't
|
||||
write to it, unless the user tries to change the settings.
|
||||
|
||||
Although the uGuru allows reading (settings) from non existing bank2
|
||||
sensors, my version of the uGuru does seem to stop writing to them, the
|
||||
write function above aborts in this case with:
|
||||
"CMD reg does not hold 0xAC after write"
|
||||
|
||||
Notice these 2 tests are non destructive iow read-only tests, otherwise
|
||||
they would defeat their purpose. Although for the bank2_sensors detection a
|
||||
read/write test would be feasible because of the reaction above, I've
|
||||
however opted to stay on the safe side. */
|
||||
/*
|
||||
* These functions try to find out how many sensors there are in bank2 and how
|
||||
* many pwms there are. The purpose of this is to make sure that we don't give
|
||||
* the user the possibility to change settings for non-existent sensors / pwm.
|
||||
* The uGuru will happily read / write whatever memory happens to be after the
|
||||
* memory storing the PWM settings when reading/writing to a PWM which is not
|
||||
* there. Notice even if we detect a PWM which doesn't exist we normally won't
|
||||
* write to it, unless the user tries to change the settings.
|
||||
*
|
||||
* Although the uGuru allows reading (settings) from non existing bank2
|
||||
* sensors, my version of the uGuru does seem to stop writing to them, the
|
||||
* write function above aborts in this case with:
|
||||
* "CMD reg does not hold 0xAC after write"
|
||||
*
|
||||
* Notice these 2 tests are non destructive iow read-only tests, otherwise
|
||||
* they would defeat their purpose. Although for the bank2_sensors detection a
|
||||
* read/write test would be feasible because of the reaction above, I've
|
||||
* however opted to stay on the safe side.
|
||||
*/
|
||||
static void __devinit
|
||||
abituguru_detect_no_bank2_sensors(struct abituguru_data *data)
|
||||
{
|
||||
@ -580,12 +650,14 @@ abituguru_detect_no_bank2_sensors(struct abituguru_data *data)
|
||||
|
||||
ABIT_UGURU_DEBUG(2, "detecting number of fan sensors\n");
|
||||
for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
|
||||
/* 0x89 are the known used bits:
|
||||
-0x80 enable shutdown
|
||||
-0x08 enable beep
|
||||
-0x01 enable alarm
|
||||
All other bits should be 0, but on some motherboards
|
||||
0x40 (bit 6) is also high for some of the fans?? */
|
||||
/*
|
||||
* 0x89 are the known used bits:
|
||||
* -0x80 enable shutdown
|
||||
* -0x08 enable beep
|
||||
* -0x01 enable alarm
|
||||
* All other bits should be 0, but on some motherboards
|
||||
* 0x40 (bit 6) is also high for some of the fans??
|
||||
*/
|
||||
if (data->bank2_settings[i][0] & ~0xC9) {
|
||||
ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem "
|
||||
"to be a fan sensor: settings[0] = %02X\n",
|
||||
@ -633,9 +705,11 @@ abituguru_detect_no_pwms(struct abituguru_data *data)
|
||||
|
||||
ABIT_UGURU_DEBUG(2, "detecting number of PWM outputs\n");
|
||||
for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
|
||||
/* 0x80 is the enable bit and the low
|
||||
nibble is which temp sensor to use,
|
||||
the other bits should be 0 */
|
||||
/*
|
||||
* 0x80 is the enable bit and the low
|
||||
* nibble is which temp sensor to use,
|
||||
* the other bits should be 0
|
||||
*/
|
||||
if (data->pwm_settings[i][0] & ~0x8F) {
|
||||
ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem "
|
||||
"to be a pwm channel: settings[0] = %02X\n",
|
||||
@ -643,8 +717,10 @@ abituguru_detect_no_pwms(struct abituguru_data *data)
|
||||
break;
|
||||
}
|
||||
|
||||
/* the low nibble must correspond to one of the temp sensors
|
||||
we've found */
|
||||
/*
|
||||
* the low nibble must correspond to one of the temp sensors
|
||||
* we've found
|
||||
*/
|
||||
for (j = 0; j < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR];
|
||||
j++) {
|
||||
if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][j] ==
|
||||
@ -711,9 +787,11 @@ abituguru_detect_no_pwms_exit:
|
||||
ABIT_UGURU_DEBUG(2, " found: %d PWM outputs\n", (int)data->pwms);
|
||||
}
|
||||
|
||||
/* Following are the sysfs callback functions. These functions expect:
|
||||
sensor_device_attribute_2->index: sensor address/offset in the bank
|
||||
sensor_device_attribute_2->nr: register offset, bitmask or NA. */
|
||||
/*
|
||||
* Following are the sysfs callback functions. These functions expect:
|
||||
* sensor_device_attribute_2->index: sensor address/offset in the bank
|
||||
* sensor_device_attribute_2->nr: register offset, bitmask or NA.
|
||||
*/
|
||||
static struct abituguru_data *abituguru_update_device(struct device *dev);
|
||||
|
||||
static ssize_t show_bank1_value(struct device *dev,
|
||||
@ -763,10 +841,18 @@ static ssize_t store_bank1_setting(struct device *dev, struct device_attribute
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct abituguru_data *data = dev_get_drvdata(dev);
|
||||
u8 val = (simple_strtoul(buf, NULL, 10) * 255 +
|
||||
data->bank1_max_value[attr->index]/2) /
|
||||
unsigned long val;
|
||||
ssize_t ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = count;
|
||||
val = (val * 255 + data->bank1_max_value[attr->index] / 2) /
|
||||
data->bank1_max_value[attr->index];
|
||||
ssize_t ret = count;
|
||||
if (val > 255)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (data->bank1_settings[attr->index][attr->nr] != val) {
|
||||
@ -788,13 +874,19 @@ static ssize_t store_bank2_setting(struct device *dev, struct device_attribute
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct abituguru_data *data = dev_get_drvdata(dev);
|
||||
u8 val = (simple_strtoul(buf, NULL, 10)*255 + ABIT_UGURU_FAN_MAX/2) /
|
||||
ABIT_UGURU_FAN_MAX;
|
||||
ssize_t ret = count;
|
||||
unsigned long val;
|
||||
ssize_t ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = count;
|
||||
val = (val * 255 + ABIT_UGURU_FAN_MAX / 2) / ABIT_UGURU_FAN_MAX;
|
||||
|
||||
/* this check can be done before taking the lock */
|
||||
if ((val < abituguru_bank2_min_threshold) ||
|
||||
(val > abituguru_bank2_max_threshold))
|
||||
if (val < abituguru_bank2_min_threshold ||
|
||||
val > abituguru_bank2_max_threshold)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -819,11 +911,13 @@ static ssize_t show_bank1_alarm(struct device *dev,
|
||||
struct abituguru_data *data = abituguru_update_device(dev);
|
||||
if (!data)
|
||||
return -EIO;
|
||||
/* See if the alarm bit for this sensor is set, and if the
|
||||
alarm matches the type of alarm we're looking for (for volt
|
||||
it can be either low or high). The type is stored in a few
|
||||
readonly bits in the settings part of the relevant sensor.
|
||||
The bitmask of the type is passed to us in attr->nr. */
|
||||
/*
|
||||
* See if the alarm bit for this sensor is set, and if the
|
||||
* alarm matches the type of alarm we're looking for (for volt
|
||||
* it can be either low or high). The type is stored in a few
|
||||
* readonly bits in the settings part of the relevant sensor.
|
||||
* The bitmask of the type is passed to us in attr->nr.
|
||||
*/
|
||||
if ((data->alarms[attr->index / 8] & (0x01 << (attr->index % 8))) &&
|
||||
(data->bank1_settings[attr->index][0] & attr->nr))
|
||||
return sprintf(buf, "1\n");
|
||||
@ -871,10 +965,15 @@ static ssize_t store_bank1_mask(struct device *dev,
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct abituguru_data *data = dev_get_drvdata(dev);
|
||||
int mask = simple_strtoul(buf, NULL, 10);
|
||||
ssize_t ret = count;
|
||||
ssize_t ret;
|
||||
u8 orig_val;
|
||||
unsigned long mask;
|
||||
|
||||
ret = kstrtoul(buf, 10, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = count;
|
||||
mutex_lock(&data->update_lock);
|
||||
orig_val = data->bank1_settings[attr->index][0];
|
||||
|
||||
@ -899,10 +998,15 @@ static ssize_t store_bank2_mask(struct device *dev,
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct abituguru_data *data = dev_get_drvdata(dev);
|
||||
int mask = simple_strtoul(buf, NULL, 10);
|
||||
ssize_t ret = count;
|
||||
ssize_t ret;
|
||||
u8 orig_val;
|
||||
unsigned long mask;
|
||||
|
||||
ret = kstrtoul(buf, 10, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = count;
|
||||
mutex_lock(&data->update_lock);
|
||||
orig_val = data->bank2_settings[attr->index][0];
|
||||
|
||||
@ -937,10 +1041,17 @@ static ssize_t store_pwm_setting(struct device *dev, struct device_attribute
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct abituguru_data *data = dev_get_drvdata(dev);
|
||||
u8 min, val = (simple_strtoul(buf, NULL, 10) +
|
||||
abituguru_pwm_settings_multiplier[attr->nr]/2) /
|
||||
u8 min;
|
||||
unsigned long val;
|
||||
ssize_t ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = count;
|
||||
val = (val + abituguru_pwm_settings_multiplier[attr->nr] / 2) /
|
||||
abituguru_pwm_settings_multiplier[attr->nr];
|
||||
ssize_t ret = count;
|
||||
|
||||
/* special case pwm1 min pwm% */
|
||||
if ((attr->index == 0) && ((attr->nr == 1) || (attr->nr == 2)))
|
||||
@ -949,7 +1060,7 @@ static ssize_t store_pwm_setting(struct device *dev, struct device_attribute
|
||||
min = abituguru_pwm_min[attr->nr];
|
||||
|
||||
/* this check can be done before taking the lock */
|
||||
if ((val < min) || (val > abituguru_pwm_max[attr->nr]))
|
||||
if (val < min || val > abituguru_pwm_max[attr->nr])
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -981,8 +1092,10 @@ static ssize_t show_pwm_sensor(struct device *dev,
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct abituguru_data *data = dev_get_drvdata(dev);
|
||||
int i;
|
||||
/* We need to walk to the temp sensor addresses to find what
|
||||
the userspace id of the configured temp sensor is. */
|
||||
/*
|
||||
* We need to walk to the temp sensor addresses to find what
|
||||
* the userspace id of the configured temp sensor is.
|
||||
*/
|
||||
for (i = 0; i < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; i++)
|
||||
if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][i] ==
|
||||
(data->pwm_settings[attr->index][0] & 0x0F))
|
||||
@ -996,27 +1109,32 @@ static ssize_t store_pwm_sensor(struct device *dev, struct device_attribute
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct abituguru_data *data = dev_get_drvdata(dev);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10) - 1;
|
||||
ssize_t ret = count;
|
||||
ssize_t ret;
|
||||
unsigned long val;
|
||||
u8 orig_val;
|
||||
u8 address;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val == 0 || val > data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR])
|
||||
return -EINVAL;
|
||||
|
||||
val -= 1;
|
||||
ret = count;
|
||||
mutex_lock(&data->update_lock);
|
||||
if (val < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) {
|
||||
u8 orig_val = data->pwm_settings[attr->index][0];
|
||||
u8 address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val];
|
||||
orig_val = data->pwm_settings[attr->index][0];
|
||||
address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val];
|
||||
data->pwm_settings[attr->index][0] &= 0xF0;
|
||||
data->pwm_settings[attr->index][0] |= address;
|
||||
if (data->pwm_settings[attr->index][0] != orig_val) {
|
||||
if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
|
||||
attr->index,
|
||||
data->pwm_settings[attr->index],
|
||||
5) < 1) {
|
||||
if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, attr->index,
|
||||
data->pwm_settings[attr->index], 5) < 1) {
|
||||
data->pwm_settings[attr->index][0] = orig_val;
|
||||
ret = -EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ret = -EINVAL;
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
@ -1037,9 +1155,15 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct abituguru_data *data = dev_get_drvdata(dev);
|
||||
u8 orig_val, user_val = simple_strtoul(buf, NULL, 10);
|
||||
ssize_t ret = count;
|
||||
u8 orig_val;
|
||||
ssize_t ret;
|
||||
unsigned long user_val;
|
||||
|
||||
ret = kstrtoul(buf, 10, &user_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = count;
|
||||
mutex_lock(&data->update_lock);
|
||||
orig_val = data->pwm_settings[attr->index][0];
|
||||
switch (user_val) {
|
||||
@ -1048,8 +1172,7 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
|
||||
~ABIT_UGURU_FAN_PWM_ENABLE;
|
||||
break;
|
||||
case 2:
|
||||
data->pwm_settings[attr->index][0] |=
|
||||
ABIT_UGURU_FAN_PWM_ENABLE;
|
||||
data->pwm_settings[attr->index][0] |= ABIT_UGURU_FAN_PWM_ENABLE;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
@ -1147,13 +1270,16 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
|
||||
int i, j, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
|
||||
char *sysfs_filename;
|
||||
|
||||
/* El weirdo probe order, to keep the sysfs order identical to the
|
||||
BIOS and window-appliction listing order. */
|
||||
/*
|
||||
* El weirdo probe order, to keep the sysfs order identical to the
|
||||
* BIOS and window-appliction listing order.
|
||||
*/
|
||||
const u8 probe_order[ABIT_UGURU_MAX_BANK1_SENSORS] = {
|
||||
0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02,
|
||||
0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL)))
|
||||
data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
|
||||
@ -1164,9 +1290,11 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
|
||||
if (inb_p(data->addr + ABIT_UGURU_DATA) == ABIT_UGURU_STATUS_INPUT)
|
||||
data->uguru_ready = 1;
|
||||
|
||||
/* Completely read the uGuru this has 2 purposes:
|
||||
- testread / see if one really is there.
|
||||
- make an in memory copy of all the uguru settings for future use. */
|
||||
/*
|
||||
* Completely read the uGuru this has 2 purposes:
|
||||
* - testread / see if one really is there.
|
||||
* - make an in memory copy of all the uguru settings for future use.
|
||||
*/
|
||||
if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
|
||||
data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3)
|
||||
goto abituguru_probe_error;
|
||||
@ -1181,11 +1309,13 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
|
||||
ABIT_UGURU_MAX_RETRIES) != 3)
|
||||
goto abituguru_probe_error;
|
||||
}
|
||||
/* Note: We don't know how many bank2 sensors / pwms there really are,
|
||||
but in order to "detect" this we need to read the maximum amount
|
||||
anyways. If we read sensors/pwms not there we'll just read crap
|
||||
this can't hurt. We need the detection because we don't want
|
||||
unwanted writes, which will hurt! */
|
||||
/*
|
||||
* Note: We don't know how many bank2 sensors / pwms there really are,
|
||||
* but in order to "detect" this we need to read the maximum amount
|
||||
* anyways. If we read sensors/pwms not there we'll just read crap
|
||||
* this can't hurt. We need the detection because we don't want
|
||||
* unwanted writes, which will hurt!
|
||||
*/
|
||||
for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
|
||||
if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i,
|
||||
&data->bank2_value[i], 1,
|
||||
@ -1332,24 +1462,26 @@ static struct abituguru_data *abituguru_update_device(struct device *dev)
|
||||
mutex_lock(&data->update_lock);
|
||||
if (time_after(jiffies, data->last_updated + HZ)) {
|
||||
success = 0;
|
||||
if ((err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
|
||||
data->alarms, 3, 0)) != 3)
|
||||
err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
|
||||
data->alarms, 3, 0);
|
||||
if (err != 3)
|
||||
goto LEAVE_UPDATE;
|
||||
for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
|
||||
if ((err = abituguru_read(data,
|
||||
ABIT_UGURU_SENSOR_BANK1, i,
|
||||
&data->bank1_value[i], 1, 0)) != 1)
|
||||
err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK1,
|
||||
i, &data->bank1_value[i], 1, 0);
|
||||
if (err != 1)
|
||||
goto LEAVE_UPDATE;
|
||||
if ((err = abituguru_read(data,
|
||||
ABIT_UGURU_SENSOR_BANK1 + 1, i,
|
||||
data->bank1_settings[i], 3, 0)) != 3)
|
||||
err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
|
||||
i, data->bank1_settings[i], 3, 0);
|
||||
if (err != 3)
|
||||
goto LEAVE_UPDATE;
|
||||
}
|
||||
for (i = 0; i < data->bank2_sensors; i++)
|
||||
if ((err = abituguru_read(data,
|
||||
ABIT_UGURU_SENSOR_BANK2, i,
|
||||
&data->bank2_value[i], 1, 0)) != 1)
|
||||
for (i = 0; i < data->bank2_sensors; i++) {
|
||||
err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i,
|
||||
&data->bank2_value[i], 1, 0);
|
||||
if (err != 1)
|
||||
goto LEAVE_UPDATE;
|
||||
}
|
||||
/* success! */
|
||||
success = 1;
|
||||
data->update_timeouts = 0;
|
||||
@ -1385,8 +1517,10 @@ LEAVE_UPDATE:
|
||||
static int abituguru_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct abituguru_data *data = platform_get_drvdata(pdev);
|
||||
/* make sure all communications with the uguru are done and no new
|
||||
ones are started */
|
||||
/*
|
||||
* make sure all communications with the uguru are done and no new
|
||||
* ones are started
|
||||
*/
|
||||
mutex_lock(&data->update_lock);
|
||||
return 0;
|
||||
}
|
||||
@ -1418,12 +1552,14 @@ static struct platform_driver abituguru_driver = {
|
||||
|
||||
static int __init abituguru_detect(void)
|
||||
{
|
||||
/* See if there is an uguru there. After a reboot uGuru will hold 0x00
|
||||
at DATA and 0xAC, when this driver has already been loaded once
|
||||
DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either
|
||||
scenario but some will hold 0x00.
|
||||
Some uGuru's initially hold 0x09 at DATA and will only hold 0x08
|
||||
after reading CMD first, so CMD must be read first! */
|
||||
/*
|
||||
* See if there is an uguru there. After a reboot uGuru will hold 0x00
|
||||
* at DATA and 0xAC, when this driver has already been loaded once
|
||||
* DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either
|
||||
* scenario but some will hold 0x00.
|
||||
* Some uGuru's initially hold 0x09 at DATA and will only hold 0x08
|
||||
* after reading CMD first, so CMD must be read first!
|
||||
*/
|
||||
u8 cmd_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_CMD);
|
||||
u8 data_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_DATA);
|
||||
if (((data_val == 0x00) || (data_val == 0x08)) &&
|
||||
|
@ -1,27 +1,27 @@
|
||||
/*
|
||||
abituguru3.c
|
||||
|
||||
Copyright (c) 2006-2008 Hans de Goede <hdegoede@redhat.com>
|
||||
Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* abituguru3.c
|
||||
*
|
||||
* Copyright (c) 2006-2008 Hans de Goede <hdegoede@redhat.com>
|
||||
* Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
This driver supports the sensor part of revision 3 of the custom Abit uGuru
|
||||
chip found on newer Abit uGuru motherboards. Note: because of lack of specs
|
||||
only reading the sensors and their settings is supported.
|
||||
* This driver supports the sensor part of revision 3 of the custom Abit uGuru
|
||||
* chip found on newer Abit uGuru motherboards. Note: because of lack of specs
|
||||
* only reading the sensors and their settings is supported.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -62,13 +62,17 @@
|
||||
#define ABIT_UGURU3_TEMP_SENSOR 1
|
||||
#define ABIT_UGURU3_FAN_SENSOR 2
|
||||
|
||||
/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
|
||||
convert them to params. Determined by trial and error. I assume this is
|
||||
cpu-speed independent, since the ISA-bus and not the CPU should be the
|
||||
bottleneck. */
|
||||
/*
|
||||
* Timeouts / Retries, if these turn out to need a lot of fiddling we could
|
||||
* convert them to params. Determined by trial and error. I assume this is
|
||||
* cpu-speed independent, since the ISA-bus and not the CPU should be the
|
||||
* bottleneck.
|
||||
*/
|
||||
#define ABIT_UGURU3_WAIT_TIMEOUT 250
|
||||
/* Normally the 0xAC at the end of synchronize() is reported after the
|
||||
first read, but sometimes not and we need to poll */
|
||||
/*
|
||||
* Normally the 0xAC at the end of synchronize() is reported after the
|
||||
* first read, but sometimes not and we need to poll
|
||||
*/
|
||||
#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT 5
|
||||
/* utility macros */
|
||||
#define ABIT_UGURU3_NAME "abituguru3"
|
||||
@ -78,32 +82,45 @@
|
||||
|
||||
/* Macros to help calculate the sysfs_names array length */
|
||||
#define ABIT_UGURU3_MAX_NO_SENSORS 26
|
||||
/* sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
|
||||
in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0 */
|
||||
#define ABIT_UGURU3_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11)
|
||||
/* sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0,
|
||||
temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0,
|
||||
temp??_label\0 */
|
||||
/*
|
||||
* sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
|
||||
* in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0
|
||||
*/
|
||||
#define ABIT_UGURU3_IN_NAMES_LENGTH \
|
||||
(11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11)
|
||||
/*
|
||||
* sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0,
|
||||
* temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0,
|
||||
* temp??_label\0
|
||||
*/
|
||||
#define ABIT_UGURU3_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16 + 13)
|
||||
/* sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0,
|
||||
fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0 */
|
||||
/*
|
||||
* sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0,
|
||||
* fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0
|
||||
*/
|
||||
#define ABIT_UGURU3_FAN_NAMES_LENGTH (12 + 10 + 12 + 19 + 11 + 15 + 12)
|
||||
/* Worst case scenario 16 in sensors (longest names_length) and the rest
|
||||
temp sensors (second longest names_length). */
|
||||
/*
|
||||
* Worst case scenario 16 in sensors (longest names_length) and the rest
|
||||
* temp sensors (second longest names_length).
|
||||
*/
|
||||
#define ABIT_UGURU3_SYSFS_NAMES_LENGTH (16 * ABIT_UGURU3_IN_NAMES_LENGTH + \
|
||||
(ABIT_UGURU3_MAX_NO_SENSORS - 16) * ABIT_UGURU3_TEMP_NAMES_LENGTH)
|
||||
|
||||
/* All the macros below are named identical to the openguru2 program
|
||||
reverse engineered by Louis Kruger, hence the names might not be 100%
|
||||
logical. I could come up with better names, but I prefer keeping the names
|
||||
identical so that this driver can be compared with his work more easily. */
|
||||
/*
|
||||
* All the macros below are named identical to the openguru2 program
|
||||
* reverse engineered by Louis Kruger, hence the names might not be 100%
|
||||
* logical. I could come up with better names, but I prefer keeping the names
|
||||
* identical so that this driver can be compared with his work more easily.
|
||||
*/
|
||||
/* Two i/o-ports are used by uGuru */
|
||||
#define ABIT_UGURU3_BASE 0x00E0
|
||||
#define ABIT_UGURU3_CMD 0x00
|
||||
#define ABIT_UGURU3_DATA 0x04
|
||||
#define ABIT_UGURU3_REGION_LENGTH 5
|
||||
/* The wait_xxx functions return this on success and the last contents
|
||||
of the DATA register (0-255) on failure. */
|
||||
/*
|
||||
* The wait_xxx functions return this on success and the last contents
|
||||
* of the DATA register (0-255) on failure.
|
||||
*/
|
||||
#define ABIT_UGURU3_SUCCESS -1
|
||||
/* uGuru status flags */
|
||||
#define ABIT_UGURU3_STATUS_READY_FOR_READ 0x01
|
||||
@ -130,9 +147,11 @@ struct abituguru3_motherboard_info {
|
||||
struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1];
|
||||
};
|
||||
|
||||
/* For the Abit uGuru, we need to keep some data in memory.
|
||||
The structure is dynamically allocated, at the same time when a new
|
||||
abituguru3 device is allocated. */
|
||||
/*
|
||||
* For the Abit uGuru, we need to keep some data in memory.
|
||||
* The structure is dynamically allocated, at the same time when a new
|
||||
* abituguru3 device is allocated.
|
||||
*/
|
||||
struct abituguru3_data {
|
||||
struct device *hwmon_dev; /* hwmon registered device */
|
||||
struct mutex update_lock; /* protect access to data and uGuru */
|
||||
@ -140,8 +159,10 @@ struct abituguru3_data {
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
/* For convenience the sysfs attr and their names are generated
|
||||
automatically. We have max 10 entries per sensor (for in sensors) */
|
||||
/*
|
||||
* For convenience the sysfs attr and their names are generated
|
||||
* automatically. We have max 10 entries per sensor (for in sensors)
|
||||
*/
|
||||
struct sensor_device_attribute_2 sysfs_attr[ABIT_UGURU3_MAX_NO_SENSORS
|
||||
* 10];
|
||||
|
||||
@ -151,9 +172,11 @@ struct abituguru3_data {
|
||||
/* Pointer to the sensors info for the detected motherboard */
|
||||
const struct abituguru3_sensor_info *sensors;
|
||||
|
||||
/* The abituguru3 supports up to 48 sensors, and thus has registers
|
||||
sets for 48 sensors, for convienence reasons / simplicity of the
|
||||
code we always read and store all registers for all 48 sensors */
|
||||
/*
|
||||
* The abituguru3 supports up to 48 sensors, and thus has registers
|
||||
* sets for 48 sensors, for convienence reasons / simplicity of the
|
||||
* code we always read and store all registers for all 48 sensors
|
||||
*/
|
||||
|
||||
/* Alarms for all 48 sensors (1 bit per sensor) */
|
||||
u8 alarms[48/8];
|
||||
@ -161,9 +184,11 @@ struct abituguru3_data {
|
||||
/* Value of all 48 sensors */
|
||||
u8 value[48];
|
||||
|
||||
/* Settings of all 48 sensors, note in and temp sensors (the first 32
|
||||
sensors) have 3 bytes of settings, while fans only have 2 bytes,
|
||||
for convenience we use 3 bytes for all sensors */
|
||||
/*
|
||||
* Settings of all 48 sensors, note in and temp sensors (the first 32
|
||||
* sensors) have 3 bytes of settings, while fans only have 2 bytes,
|
||||
* for convenience we use 3 bytes for all sensors
|
||||
*/
|
||||
u8 settings[48][3];
|
||||
};
|
||||
|
||||
@ -626,8 +651,10 @@ static int abituguru3_wait_while_busy(struct abituguru3_data *data)
|
||||
timeout--;
|
||||
if (timeout == 0)
|
||||
return x;
|
||||
/* sleep a bit before our last try, to give the uGuru3 one
|
||||
last chance to respond. */
|
||||
/*
|
||||
* sleep a bit before our last try, to give the uGuru3 one
|
||||
* last chance to respond.
|
||||
*/
|
||||
if (timeout == 1)
|
||||
msleep(1);
|
||||
}
|
||||
@ -645,48 +672,57 @@ static int abituguru3_wait_for_read(struct abituguru3_data *data)
|
||||
timeout--;
|
||||
if (timeout == 0)
|
||||
return x;
|
||||
/* sleep a bit before our last try, to give the uGuru3 one
|
||||
last chance to respond. */
|
||||
/*
|
||||
* sleep a bit before our last try, to give the uGuru3 one
|
||||
* last chance to respond.
|
||||
*/
|
||||
if (timeout == 1)
|
||||
msleep(1);
|
||||
}
|
||||
return ABIT_UGURU3_SUCCESS;
|
||||
}
|
||||
|
||||
/* This synchronizes us with the uGuru3's protocol state machine, this
|
||||
must be done before each command. */
|
||||
/*
|
||||
* This synchronizes us with the uGuru3's protocol state machine, this
|
||||
* must be done before each command.
|
||||
*/
|
||||
static int abituguru3_synchronize(struct abituguru3_data *data)
|
||||
{
|
||||
int x, timeout = ABIT_UGURU3_SYNCHRONIZE_TIMEOUT;
|
||||
|
||||
if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_while_busy(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("synchronize timeout during initial busy "
|
||||
"wait, status: 0x%02x\n", x);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
outb(0x20, data->addr + ABIT_UGURU3_DATA);
|
||||
if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_while_busy(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x20, "
|
||||
"status: 0x%02x\n", x);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
outb(0x10, data->addr + ABIT_UGURU3_CMD);
|
||||
if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_while_busy(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x10, "
|
||||
"status: 0x%02x\n", x);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
outb(0x00, data->addr + ABIT_UGURU3_CMD);
|
||||
if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_while_busy(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x00, "
|
||||
"status: 0x%02x\n", x);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if ((x = abituguru3_wait_for_read(data)) != ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_for_read(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("synchronize timeout waiting for read, "
|
||||
"status: 0x%02x\n", x);
|
||||
return -EIO;
|
||||
@ -705,18 +741,22 @@ static int abituguru3_synchronize(struct abituguru3_data *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
|
||||
result in buf */
|
||||
/*
|
||||
* Read count bytes from sensor sensor_addr in bank bank_addr and store the
|
||||
* result in buf
|
||||
*/
|
||||
static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
|
||||
u8 count, u8 *buf)
|
||||
{
|
||||
int i, x;
|
||||
|
||||
if ((x = abituguru3_synchronize(data)))
|
||||
x = abituguru3_synchronize(data);
|
||||
if (x)
|
||||
return x;
|
||||
|
||||
outb(0x1A, data->addr + ABIT_UGURU3_DATA);
|
||||
if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_while_busy(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
|
||||
"sending 0x1A, status: 0x%02x\n", (unsigned int)bank,
|
||||
(unsigned int)offset, x);
|
||||
@ -724,7 +764,8 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
|
||||
}
|
||||
|
||||
outb(bank, data->addr + ABIT_UGURU3_CMD);
|
||||
if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_while_busy(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
|
||||
"sending the bank, status: 0x%02x\n",
|
||||
(unsigned int)bank, (unsigned int)offset, x);
|
||||
@ -732,7 +773,8 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
|
||||
}
|
||||
|
||||
outb(offset, data->addr + ABIT_UGURU3_CMD);
|
||||
if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_while_busy(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
|
||||
"sending the offset, status: 0x%02x\n",
|
||||
(unsigned int)bank, (unsigned int)offset, x);
|
||||
@ -740,7 +782,8 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
|
||||
}
|
||||
|
||||
outb(count, data->addr + ABIT_UGURU3_CMD);
|
||||
if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_while_busy(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
|
||||
"sending the count, status: 0x%02x\n",
|
||||
(unsigned int)bank, (unsigned int)offset, x);
|
||||
@ -748,8 +791,8 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((x = abituguru3_wait_for_read(data)) !=
|
||||
ABIT_UGURU3_SUCCESS) {
|
||||
x = abituguru3_wait_for_read(data);
|
||||
if (x != ABIT_UGURU3_SUCCESS) {
|
||||
ABIT_UGURU3_DEBUG("timeout reading byte %d from "
|
||||
"0x%02x:0x%02x, status: 0x%02x\n", i,
|
||||
(unsigned int)bank, (unsigned int)offset, x);
|
||||
@ -760,28 +803,34 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Sensor settings are stored 1 byte per offset with the bytes
|
||||
placed add consecutive offsets. */
|
||||
/*
|
||||
* Sensor settings are stored 1 byte per offset with the bytes
|
||||
* placed add consecutive offsets.
|
||||
*/
|
||||
static int abituguru3_read_increment_offset(struct abituguru3_data *data,
|
||||
u8 bank, u8 offset, u8 count,
|
||||
u8 *buf, int offset_count)
|
||||
{
|
||||
int i, x;
|
||||
|
||||
for (i = 0; i < offset_count; i++)
|
||||
if ((x = abituguru3_read(data, bank, offset + i, count,
|
||||
buf + i * count)) != count) {
|
||||
for (i = 0; i < offset_count; i++) {
|
||||
x = abituguru3_read(data, bank, offset + i, count,
|
||||
buf + i * count);
|
||||
if (x != count) {
|
||||
if (x < 0)
|
||||
return x;
|
||||
return i * count + x;
|
||||
}
|
||||
}
|
||||
|
||||
return i * count;
|
||||
}
|
||||
|
||||
/* Following are the sysfs callback functions. These functions expect:
|
||||
sensor_device_attribute_2->index: index into the data->sensors array
|
||||
sensor_device_attribute_2->nr: register offset, bitmask or NA. */
|
||||
/*
|
||||
* Following are the sysfs callback functions. These functions expect:
|
||||
* sensor_device_attribute_2->index: index into the data->sensors array
|
||||
* sensor_device_attribute_2->nr: register offset, bitmask or NA.
|
||||
*/
|
||||
static struct abituguru3_data *abituguru3_update_device(struct device *dev);
|
||||
|
||||
static ssize_t show_value(struct device *dev,
|
||||
@ -807,8 +856,10 @@ static ssize_t show_value(struct device *dev,
|
||||
value = (value * sensor->multiplier) / sensor->divisor +
|
||||
sensor->offset;
|
||||
|
||||
/* alternatively we could update the sensors settings struct for this,
|
||||
but then its contents would differ from the windows sw ini files */
|
||||
/*
|
||||
* alternatively we could update the sensors settings struct for this,
|
||||
* but then its contents would differ from the windows sw ini files
|
||||
*/
|
||||
if (sensor->type == ABIT_UGURU3_TEMP_SENSOR)
|
||||
value *= 1000;
|
||||
|
||||
@ -827,10 +878,12 @@ static ssize_t show_alarm(struct device *dev,
|
||||
|
||||
port = data->sensors[attr->index].port;
|
||||
|
||||
/* See if the alarm bit for this sensor is set and if a bitmask is
|
||||
given in attr->nr also check if the alarm matches the type of alarm
|
||||
we're looking for (for volt it can be either low or high). The type
|
||||
is stored in a few readonly bits in the settings of the sensor. */
|
||||
/*
|
||||
* See if the alarm bit for this sensor is set and if a bitmask is
|
||||
* given in attr->nr also check if the alarm matches the type of alarm
|
||||
* we're looking for (for volt it can be either low or high). The type
|
||||
* is stored in a few readonly bits in the settings of the sensor.
|
||||
*/
|
||||
if ((data->alarms[port / 8] & (0x01 << (port % 8))) &&
|
||||
(!attr->nr || (data->settings[port][0] & attr->nr)))
|
||||
return sprintf(buf, "1\n");
|
||||
@ -923,7 +976,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
|
||||
u8 buf[2];
|
||||
u16 id;
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL)))
|
||||
data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
|
||||
@ -931,10 +985,10 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
/* Read the motherboard ID */
|
||||
if ((i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK,
|
||||
ABIT_UGURU3_BOARD_ID, 2, buf)) != 2) {
|
||||
i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK, ABIT_UGURU3_BOARD_ID,
|
||||
2, buf);
|
||||
if (i != 2)
|
||||
goto abituguru3_probe_error;
|
||||
}
|
||||
|
||||
/* Completely read the uGuru to see if one really is there */
|
||||
if (!abituguru3_update_device(&pdev->dev))
|
||||
@ -1091,8 +1145,10 @@ LEAVE_UPDATE:
|
||||
static int abituguru3_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct abituguru3_data *data = platform_get_drvdata(pdev);
|
||||
/* make sure all communications with the uguru3 are done and no new
|
||||
ones are started */
|
||||
/*
|
||||
* make sure all communications with the uguru3 are done and no new
|
||||
* ones are started
|
||||
*/
|
||||
mutex_lock(&data->update_lock);
|
||||
return 0;
|
||||
}
|
||||
@ -1134,7 +1190,8 @@ static int __init abituguru3_dmi_detect(void)
|
||||
if (!board_name)
|
||||
return err;
|
||||
|
||||
/* At the moment, we don't care about the part of the vendor
|
||||
/*
|
||||
* At the moment, we don't care about the part of the vendor
|
||||
* DMI string contained in brackets. Truncate the string at
|
||||
* the first occurrence of a bracket. Trim any trailing space
|
||||
* from the substring.
|
||||
@ -1157,15 +1214,18 @@ static int __init abituguru3_dmi_detect(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: Manual detection should die eventually; we need to collect stable
|
||||
/*
|
||||
* FIXME: Manual detection should die eventually; we need to collect stable
|
||||
* DMI model names first before we can rely entirely on CONFIG_DMI.
|
||||
*/
|
||||
|
||||
static int __init abituguru3_detect(void)
|
||||
{
|
||||
/* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
|
||||
0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
|
||||
or 0x55 at CMD instead, why is unknown. */
|
||||
/*
|
||||
* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
|
||||
* 0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
|
||||
* or 0x55 at CMD instead, why is unknown.
|
||||
*/
|
||||
u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
|
||||
u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
|
||||
if (((data_val == 0x00) || (data_val == 0x08)) &&
|
||||
@ -1197,7 +1257,8 @@ static int __init abituguru3_init(void)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Fall back to manual detection if there was no exact
|
||||
/*
|
||||
* Fall back to manual detection if there was no exact
|
||||
* board name match, or force was specified.
|
||||
*/
|
||||
if (err > 0) {
|
||||
|
@ -167,17 +167,7 @@ static struct spi_driver ad7314_driver = {
|
||||
.id_table = ad7314_id,
|
||||
};
|
||||
|
||||
static __init int ad7314_init(void)
|
||||
{
|
||||
return spi_register_driver(&ad7314_driver);
|
||||
}
|
||||
module_init(ad7314_init);
|
||||
|
||||
static __exit void ad7314_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&ad7314_driver);
|
||||
}
|
||||
module_exit(ad7314_exit);
|
||||
module_spi_driver(ad7314_driver);
|
||||
|
||||
MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
|
||||
|
@ -50,7 +50,8 @@ struct ad7414_data {
|
||||
/* REG: (0.25C/bit, two's complement) << 6 */
|
||||
static inline int ad7414_temp_from_reg(s16 reg)
|
||||
{
|
||||
/* use integer division instead of equivalent right shift to
|
||||
/*
|
||||
* use integer division instead of equivalent right shift to
|
||||
* guarantee arithmetic shift and preserve the sign
|
||||
*/
|
||||
return ((int)reg / 64) * 250;
|
||||
@ -130,7 +131,11 @@ static ssize_t set_max_min(struct device *dev,
|
||||
struct ad7414_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
u8 reg = AD7414_REG_LIMIT[index];
|
||||
long temp = simple_strtol(buf, NULL, 10);
|
||||
long temp;
|
||||
int ret = kstrtol(buf, 10, &temp);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
temp = SENSORS_LIMIT(temp, -40000, 85000);
|
||||
temp = (temp + (temp < 0 ? -500 : 500)) / 1000;
|
||||
@ -252,17 +257,7 @@ static struct i2c_driver ad7414_driver = {
|
||||
.id_table = ad7414_id,
|
||||
};
|
||||
|
||||
static int __init ad7414_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ad7414_driver);
|
||||
}
|
||||
module_init(ad7414_init);
|
||||
|
||||
static void __exit ad7414_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ad7414_driver);
|
||||
}
|
||||
module_exit(ad7414_exit);
|
||||
module_i2c_driver(ad7414_driver);
|
||||
|
||||
MODULE_AUTHOR("Stefan Roese <sr at denx.de>, "
|
||||
"Frank Edelhaeuser <frank.edelhaeuser at spansion.com>");
|
||||
|
@ -167,7 +167,11 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ad7418_data *data = i2c_get_clientdata(client);
|
||||
long temp = simple_strtol(buf, NULL, 10);
|
||||
long temp;
|
||||
int ret = kstrtol(buf, 10, &temp);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
data->temp[attr->index] = LM75_TEMP_TO_REG(temp);
|
||||
@ -228,7 +232,8 @@ static int ad7418_probe(struct i2c_client *client,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL))) {
|
||||
data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
@ -261,7 +266,8 @@ static int ad7418_probe(struct i2c_client *client,
|
||||
ad7418_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
@ -289,20 +295,9 @@ static int ad7418_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init ad7418_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ad7418_driver);
|
||||
}
|
||||
|
||||
static void __exit ad7418_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ad7418_driver);
|
||||
}
|
||||
module_i2c_driver(ad7418_driver);
|
||||
|
||||
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
||||
MODULE_DESCRIPTION("AD7416/17/18 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
module_init(ad7418_init);
|
||||
module_exit(ad7418_exit);
|
||||
|
@ -248,18 +248,7 @@ static struct spi_driver adcxx_driver = {
|
||||
.remove = __devexit_p(adcxx_remove),
|
||||
};
|
||||
|
||||
static int __init init_adcxx(void)
|
||||
{
|
||||
return spi_register_driver(&adcxx_driver);
|
||||
}
|
||||
|
||||
static void __exit exit_adcxx(void)
|
||||
{
|
||||
spi_unregister_driver(&adcxx_driver);
|
||||
}
|
||||
|
||||
module_init(init_adcxx);
|
||||
module_exit(exit_adcxx);
|
||||
module_spi_driver(adcxx_driver);
|
||||
|
||||
MODULE_AUTHOR("Marc Pignat");
|
||||
MODULE_DESCRIPTION("National Semiconductor adcxx8sxxx Linux driver");
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
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.
|
||||
|
||||
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.
|
||||
* adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -70,10 +70,12 @@ enum chips {
|
||||
|
||||
/* Initial values */
|
||||
|
||||
/* Note: Even though I left the low and high limits named os and hyst,
|
||||
they don't quite work like a thermostat the way the LM75 does. I.e.,
|
||||
a lower temp than THYST actually triggers an alarm instead of
|
||||
clearing it. Weird, ey? --Phil */
|
||||
/*
|
||||
* Note: Even though I left the low and high limits named os and hyst,
|
||||
* they don't quite work like a thermostat the way the LM75 does. I.e.,
|
||||
* a lower temp than THYST actually triggers an alarm instead of
|
||||
* clearing it. Weird, ey? --Phil
|
||||
*/
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct adm1021_data {
|
||||
@ -182,7 +184,13 @@ static ssize_t set_temp_max(struct device *dev,
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1021_data *data = i2c_get_clientdata(client);
|
||||
long temp = simple_strtol(buf, NULL, 10) / 1000;
|
||||
long temp;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &temp);
|
||||
if (err)
|
||||
return err;
|
||||
temp /= 1000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127);
|
||||
@ -201,7 +209,13 @@ static ssize_t set_temp_min(struct device *dev,
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1021_data *data = i2c_get_clientdata(client);
|
||||
long temp = simple_strtol(buf, NULL, 10) / 1000;
|
||||
long temp;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &temp);
|
||||
if (err)
|
||||
return err;
|
||||
temp /= 1000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127);
|
||||
@ -226,7 +240,14 @@ static ssize_t set_low_power(struct device *dev,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1021_data *data = i2c_get_clientdata(client);
|
||||
int low_power = simple_strtol(buf, NULL, 10) != 0;
|
||||
char low_power;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
low_power = val != 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (low_power != data->low_power) {
|
||||
@ -361,7 +382,8 @@ static int adm1021_probe(struct i2c_client *client,
|
||||
adm1021_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1021_group);
|
||||
if (err)
|
||||
goto error1;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
@ -427,8 +449,10 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_STATUS) & 0x7c;
|
||||
if (data->type == adm1023) {
|
||||
/* The ADM1023 provides 3 extra bits of precision for
|
||||
* the remote sensor in extra registers. */
|
||||
/*
|
||||
* The ADM1023 provides 3 extra bits of precision for
|
||||
* the remote sensor in extra registers.
|
||||
*/
|
||||
data->temp[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_TEMP_PREC) >> 5);
|
||||
data->temp_max[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
@ -451,15 +475,7 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_adm1021_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adm1021_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_adm1021_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adm1021_driver);
|
||||
}
|
||||
module_i2c_driver(adm1021_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
|
||||
"Philip Edelbrock <phil@netroedge.com>");
|
||||
@ -468,6 +484,3 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
module_param(read_only, bool, 0);
|
||||
MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
|
||||
|
||||
module_init(sensors_adm1021_init)
|
||||
module_exit(sensors_adm1021_exit)
|
||||
|
@ -99,7 +99,8 @@ static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 };
|
||||
#define TEMP_FROM_REG(reg) ((reg) * 1000)
|
||||
#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \
|
||||
(val) >= 126500 ? 127 : \
|
||||
(((val) < 0 ? (val)-500 : (val)+500) / 1000))
|
||||
(((val) < 0 ? (val) - 500 : \
|
||||
(val) + 500) / 1000))
|
||||
|
||||
/*
|
||||
* Functions declaration
|
||||
@ -218,7 +219,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_min[index] = IN_TO_REG(val, in_scale[index]);
|
||||
@ -234,7 +240,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_max[index] = IN_TO_REG(val, in_scale[index]);
|
||||
@ -264,7 +275,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_min[index] = TEMP_TO_REG(val);
|
||||
@ -280,7 +296,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max[index] = TEMP_TO_REG(val);
|
||||
@ -343,7 +364,14 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adm1025_data *data = dev_get_drvdata(dev);
|
||||
data->vrm = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->vrm = val;
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
|
||||
@ -462,14 +490,15 @@ static int adm1025_probe(struct i2c_client *client,
|
||||
adm1025_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1025_group)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1025_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
/* Pin 11 is either in4 (+12V) or VID4 */
|
||||
config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
|
||||
if (!(config & 0x20)) {
|
||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||
&adm1025_group_in4)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1025_group_in4);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -589,19 +618,8 @@ static struct adm1025_data *adm1025_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_adm1025_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adm1025_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_adm1025_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adm1025_driver);
|
||||
}
|
||||
module_i2c_driver(adm1025_driver);
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("ADM1025 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_adm1025_init);
|
||||
module_exit(sensors_adm1025_exit);
|
||||
|
@ -1,26 +1,26 @@
|
||||
/*
|
||||
adm1026.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (C) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
|
||||
Copyright (C) 2004 Justin Thiessen <jthiessen@penguincomputing.com>
|
||||
|
||||
Chip details at:
|
||||
|
||||
<http://www.onsemi.com/PowerSolutions/product.do?id=ADM1026>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* adm1026.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (C) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
|
||||
* Copyright (C) 2004 Justin Thiessen <jthiessen@penguincomputing.com>
|
||||
*
|
||||
* Chip details at:
|
||||
*
|
||||
* <http://www.onsemi.com/PowerSolutions/product.do?id=ADM1026>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -90,7 +90,8 @@ MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs");
|
||||
#define E2CFG_ROM 0x08
|
||||
#define E2CFG_CLK_EXT 0x80
|
||||
|
||||
/* There are 10 general analog inputs and 7 dedicated inputs
|
||||
/*
|
||||
* There are 10 general analog inputs and 7 dedicated inputs
|
||||
* They are:
|
||||
* 0 - 9 = AIN0 - AIN9
|
||||
* 10 = Vbat
|
||||
@ -117,7 +118,8 @@ static u16 ADM1026_REG_IN_MAX[] = {
|
||||
0x43, 0x44, 0x45, 0x46, 0x47
|
||||
};
|
||||
|
||||
/* Temperatures are:
|
||||
/*
|
||||
* Temperatures are:
|
||||
* 0 - Internal
|
||||
* 1 - External 1
|
||||
* 2 - External 2
|
||||
@ -170,12 +172,14 @@ static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f };
|
||||
#define ADM1026_FAN_CONTROL_TEMP_RANGE 20
|
||||
#define ADM1026_PWM_MAX 255
|
||||
|
||||
/* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
/*
|
||||
* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
* variants. Note that you should be a bit careful with which arguments
|
||||
* these macros are called: arguments may be evaluated more than once.
|
||||
*/
|
||||
|
||||
/* IN are scaled according to built-in resistors. These are the
|
||||
/*
|
||||
* IN are scaled according to built-in resistors. These are the
|
||||
* voltages corresponding to 3/4 of full scale (192 or 0xc0)
|
||||
* NOTE: The -12V input needs an additional factor to account
|
||||
* for the Vref pullup resistor.
|
||||
@ -197,23 +201,25 @@ static int adm1026_scaling[] = { /* .001 Volts */
|
||||
0, 255))
|
||||
#define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n]))
|
||||
|
||||
/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses
|
||||
/*
|
||||
* FAN speed is measured using 22.5kHz clock and counts for 2 pulses
|
||||
* and we assume a 2 pulse-per-rev fan tach signal
|
||||
* 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000
|
||||
*/
|
||||
#define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \
|
||||
SENSORS_LIMIT(1350000/((val)*(div)), 1, 254))
|
||||
SENSORS_LIMIT(1350000 / ((val) * (div)), \
|
||||
1, 254))
|
||||
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 0xff ? 0 : \
|
||||
1350000 / ((val) * (div)))
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
#define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0)
|
||||
|
||||
/* Temperature is reported in 1 degC increments */
|
||||
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\
|
||||
-127, 127))
|
||||
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \
|
||||
/ 1000, -127, 127))
|
||||
#define TEMP_FROM_REG(val) ((val) * 1000)
|
||||
#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\
|
||||
-127, 127))
|
||||
#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \
|
||||
/ 1000, -127, 127))
|
||||
#define OFFSET_FROM_REG(val) ((val) * 1000)
|
||||
|
||||
#define PWM_TO_REG(val) (SENSORS_LIMIT(val, 0, 255))
|
||||
@ -222,14 +228,16 @@ static int adm1026_scaling[] = { /* .001 Volts */
|
||||
#define PWM_MIN_TO_REG(val) ((val) & 0xf0)
|
||||
#define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4))
|
||||
|
||||
/* Analog output is a voltage, and scaled to millivolts. The datasheet
|
||||
/*
|
||||
* Analog output is a voltage, and scaled to millivolts. The datasheet
|
||||
* indicates that the DAC could be used to drive the fans, but in our
|
||||
* example board (Arima HDAMA) it isn't connected to the fans at all.
|
||||
*/
|
||||
#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val) * 255) + 500) / 2500), 0, 255))
|
||||
#define DAC_FROM_REG(val) (((val) * 2500) / 255)
|
||||
|
||||
/* Chip sampling rates
|
||||
/*
|
||||
* Chip sampling rates
|
||||
*
|
||||
* Some sensors are not updated more frequently than once per second
|
||||
* so it doesn't make sense to read them more often than that.
|
||||
@ -243,11 +251,13 @@ static int adm1026_scaling[] = { /* .001 Volts */
|
||||
#define ADM1026_DATA_INTERVAL (1 * HZ)
|
||||
#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ)
|
||||
|
||||
/* We allow for multiple chips in a single system.
|
||||
/*
|
||||
* We allow for multiple chips in a single system.
|
||||
*
|
||||
* For each registered ADM1026, we need to keep state information
|
||||
* at client->data. The adm1026_data structure is dynamically
|
||||
* allocated, when a new client structure is allocated. */
|
||||
* allocated, when a new client structure is allocated.
|
||||
*/
|
||||
|
||||
struct pwm_data {
|
||||
u8 pwm;
|
||||
@ -388,11 +398,10 @@ static void adm1026_init_client(struct i2c_client *client)
|
||||
dev_dbg(&client->dev, "THERM pin enabled. "
|
||||
"GPIO16 disabled.\n");
|
||||
}
|
||||
if (data->config3 & CFG3_VREF_250) {
|
||||
if (data->config3 & CFG3_VREF_250)
|
||||
dev_dbg(&client->dev, "Vref is 2.50 Volts.\n");
|
||||
} else {
|
||||
else
|
||||
dev_dbg(&client->dev, "Vref is 1.82 Volts.\n");
|
||||
}
|
||||
/* Read and pick apart the existing GPIO configuration */
|
||||
value = 0;
|
||||
for (i = 0; i <= 15; ++i) {
|
||||
@ -408,7 +417,8 @@ static void adm1026_init_client(struct i2c_client *client)
|
||||
/* ... and then print it */
|
||||
adm1026_print_gpio(client);
|
||||
|
||||
/* If the user asks us to reprogram the GPIO config, then
|
||||
/*
|
||||
* If the user asks us to reprogram the GPIO config, then
|
||||
* do it now.
|
||||
*/
|
||||
if (gpio_input[0] != -1 || gpio_output[0] != -1
|
||||
@ -417,7 +427,8 @@ static void adm1026_init_client(struct i2c_client *client)
|
||||
adm1026_fixup_gpio(client);
|
||||
}
|
||||
|
||||
/* WE INTENTIONALLY make no changes to the limits,
|
||||
/*
|
||||
* WE INTENTIONALLY make no changes to the limits,
|
||||
* offsets, pwms, fans and zones. If they were
|
||||
* configured, we don't want to mess with them.
|
||||
* If they weren't, the default is 100% PWM, no
|
||||
@ -485,53 +496,47 @@ static void adm1026_fixup_gpio(struct i2c_client *client)
|
||||
int value;
|
||||
|
||||
/* Make the changes requested. */
|
||||
/* We may need to unlock/stop monitoring or soft-reset the
|
||||
/*
|
||||
* We may need to unlock/stop monitoring or soft-reset the
|
||||
* chip before we can make changes. This hasn't been
|
||||
* tested much. FIXME
|
||||
*/
|
||||
|
||||
/* Make outputs */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_output[i] >= 0 && gpio_output[i] <= 16) {
|
||||
if (gpio_output[i] >= 0 && gpio_output[i] <= 16)
|
||||
data->gpio_config[gpio_output[i]] |= 0x01;
|
||||
}
|
||||
/* if GPIO0-7 is output, it isn't a FAN tach */
|
||||
if (gpio_output[i] >= 0 && gpio_output[i] <= 7) {
|
||||
if (gpio_output[i] >= 0 && gpio_output[i] <= 7)
|
||||
data->config2 |= 1 << gpio_output[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Input overrides output */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_input[i] >= 0 && gpio_input[i] <= 16) {
|
||||
if (gpio_input[i] >= 0 && gpio_input[i] <= 16)
|
||||
data->gpio_config[gpio_input[i]] &= ~0x01;
|
||||
}
|
||||
/* if GPIO0-7 is input, it isn't a FAN tach */
|
||||
if (gpio_input[i] >= 0 && gpio_input[i] <= 7) {
|
||||
if (gpio_input[i] >= 0 && gpio_input[i] <= 7)
|
||||
data->config2 |= 1 << gpio_input[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Inverted */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) {
|
||||
if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16)
|
||||
data->gpio_config[gpio_inverted[i]] &= ~0x02;
|
||||
}
|
||||
}
|
||||
|
||||
/* Normal overrides inverted */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) {
|
||||
if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16)
|
||||
data->gpio_config[gpio_normal[i]] |= 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fan overrides input and output */
|
||||
for (i = 0; i <= 7; ++i) {
|
||||
if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7) {
|
||||
if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7)
|
||||
data->config2 &= ~(1 << gpio_fan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write new configs to registers */
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2);
|
||||
@ -563,7 +568,8 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (!data->valid
|
||||
|| time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) {
|
||||
|| time_after(jiffies,
|
||||
data->last_reading + ADM1026_DATA_INTERVAL)) {
|
||||
/* Things that change quickly */
|
||||
dev_dbg(&client->dev, "Reading sensor values\n");
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
@ -577,8 +583,10 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
|
||||
}
|
||||
|
||||
for (i = 0; i <= 2; ++i) {
|
||||
/* NOTE: temp[] is s8 and we assume 2's complement
|
||||
* "conversion" in the assignment */
|
||||
/*
|
||||
* NOTE: temp[] is s8 and we assume 2's complement
|
||||
* "conversion" in the assignment
|
||||
*/
|
||||
data->temp[i] =
|
||||
adm1026_read_value(client, ADM1026_REG_TEMP[i]);
|
||||
}
|
||||
@ -632,7 +640,8 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
|
||||
}
|
||||
|
||||
for (i = 0; i <= 2; ++i) {
|
||||
/* NOTE: temp_xxx[] are s8 and we assume 2's
|
||||
/*
|
||||
* NOTE: temp_xxx[] are s8 and we assume 2's
|
||||
* complement "conversion" in the assignment
|
||||
*/
|
||||
data->temp_min[i] = adm1026_read_value(client,
|
||||
@ -721,7 +730,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_min[nr] = INS_TO_REG(nr, val);
|
||||
@ -744,7 +758,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_max[nr] = INS_TO_REG(nr, val);
|
||||
@ -779,23 +798,31 @@ in_reg(13);
|
||||
in_reg(14);
|
||||
in_reg(15);
|
||||
|
||||
static ssize_t show_in16(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_in16(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in[16]) -
|
||||
NEG12_OFFSET);
|
||||
}
|
||||
static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_min[16])
|
||||
- NEG12_OFFSET);
|
||||
}
|
||||
static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET);
|
||||
@ -803,17 +830,24 @@ static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, c
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_max[16])
|
||||
- NEG12_OFFSET);
|
||||
}
|
||||
static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET);
|
||||
@ -823,10 +857,10 @@ static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, c
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL, 16);
|
||||
static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, set_in16_min, 16);
|
||||
static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, set_in16_max, 16);
|
||||
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min,
|
||||
set_in16_min, 16);
|
||||
static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max,
|
||||
set_in16_max, 16);
|
||||
|
||||
|
||||
/* Now add fan read/write functions */
|
||||
@ -856,7 +890,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]);
|
||||
@ -890,9 +929,8 @@ static void fixup_fan_min(struct device *dev, int fan, int old_div)
|
||||
int new_div = data->fan_div[fan];
|
||||
|
||||
/* 0 and 0xff are special. Don't adjust them */
|
||||
if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) {
|
||||
if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff)
|
||||
return;
|
||||
}
|
||||
|
||||
new_min = data->fan_min[fan] * old_div / new_div;
|
||||
new_min = SENSORS_LIMIT(new_min, 1, 254);
|
||||
@ -916,9 +954,14 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val, orig_div, new_div;
|
||||
long val;
|
||||
int orig_div, new_div;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val = simple_strtol(buf, NULL, 10);
|
||||
new_div = DIV_TO_REG(val);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -939,9 +982,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
(DIV_TO_REG(data->fan_div[7]) << 6));
|
||||
}
|
||||
|
||||
if (data->fan_div[nr] != orig_div) {
|
||||
if (data->fan_div[nr] != orig_div)
|
||||
fixup_fan_min(dev, nr, orig_div);
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
@ -983,7 +1026,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_min[nr] = TEMP_TO_REG(val);
|
||||
@ -1007,7 +1055,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max[nr] = TEMP_TO_REG(val);
|
||||
@ -1046,7 +1099,12 @@ static ssize_t set_temp_offset(struct device *dev,
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_offset[nr] = TEMP_TO_REG(val);
|
||||
@ -1097,7 +1155,12 @@ static ssize_t set_temp_auto_point1_temp(struct device *dev,
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_tmin[nr] = TEMP_TO_REG(val);
|
||||
@ -1131,15 +1194,21 @@ static ssize_t set_temp_crit_enable(struct device *dev,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (val > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if ((val == 1) || (val==0)) {
|
||||
mutex_lock(&data->update_lock);
|
||||
data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4);
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG1,
|
||||
data->config1);
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG1, data->config1);
|
||||
mutex_unlock(&data->update_lock);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1166,7 +1235,12 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_crit[nr] = TEMP_TO_REG(val);
|
||||
@ -1184,17 +1258,24 @@ temp_crit_reg(1);
|
||||
temp_crit_reg(2);
|
||||
temp_crit_reg(3);
|
||||
|
||||
static ssize_t show_analog_out_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_analog_out_reg(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%d\n", DAC_FROM_REG(data->analog_out));
|
||||
}
|
||||
static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_analog_out_reg(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->analog_out = DAC_TO_REG(val);
|
||||
@ -1206,7 +1287,8 @@ static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *a
|
||||
static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg,
|
||||
set_analog_out_reg);
|
||||
|
||||
static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
int vid = (data->gpio >> 11) & 0x1f;
|
||||
@ -1214,25 +1296,35 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, c
|
||||
dev_dbg(dev, "Setting VID from GPIO11-15.\n");
|
||||
return sprintf(buf, "%d\n", vid_from_reg(vid, data->vrm));
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
|
||||
|
||||
static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%d\n", data->vrm);
|
||||
}
|
||||
static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
|
||||
static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
data->vrm = simple_strtol(buf, NULL, 10);
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->vrm = val;
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
|
||||
|
||||
static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_alarms_reg(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%ld\n", data->alarms);
|
||||
@ -1277,18 +1369,24 @@ static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 24);
|
||||
static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 25);
|
||||
static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 26);
|
||||
|
||||
static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_alarm_mask(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%ld\n", data->alarm_mask);
|
||||
}
|
||||
static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
unsigned long mask;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->alarm_mask = val & 0x7fffffff;
|
||||
@ -1313,18 +1411,24 @@ static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask,
|
||||
set_alarm_mask);
|
||||
|
||||
|
||||
static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_gpio(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%ld\n", data->gpio);
|
||||
}
|
||||
static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_gpio(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long gpio;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->gpio = val & 0x1ffff;
|
||||
@ -1340,19 +1444,24 @@ static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const
|
||||
|
||||
static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio);
|
||||
|
||||
|
||||
static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%ld\n", data->gpio_mask);
|
||||
}
|
||||
static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long mask;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->gpio_mask = val & 0x1ffff;
|
||||
@ -1368,19 +1477,26 @@ static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask);
|
||||
|
||||
static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm1.pwm));
|
||||
}
|
||||
static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
|
||||
static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (data->pwm1.enable == 1) {
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm1.pwm = PWM_TO_REG(val);
|
||||
@ -1389,17 +1505,26 @@ static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, co
|
||||
}
|
||||
return count;
|
||||
}
|
||||
static ssize_t show_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
||||
static ssize_t show_auto_pwm_min(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->pwm1.auto_pwm_min);
|
||||
}
|
||||
static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
|
||||
static ssize_t set_auto_pwm_min(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm1.auto_pwm_min = SENSORS_LIMIT(val, 0, 255);
|
||||
@ -1411,44 +1536,53 @@ static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *att
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
||||
static ssize_t show_auto_pwm_max(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", ADM1026_PWM_MAX);
|
||||
}
|
||||
static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
||||
static ssize_t show_pwm_enable(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->pwm1.enable);
|
||||
}
|
||||
static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
|
||||
static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
int old_enable;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (val >= 3)
|
||||
return -EINVAL;
|
||||
|
||||
if ((val >= 0) && (val < 3)) {
|
||||
mutex_lock(&data->update_lock);
|
||||
old_enable = data->pwm1.enable;
|
||||
data->pwm1.enable = val;
|
||||
data->config1 = (data->config1 & ~CFG1_PWM_AFC)
|
||||
| ((val == 2) ? CFG1_PWM_AFC : 0);
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG1,
|
||||
data->config1);
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG1, data->config1);
|
||||
if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */
|
||||
data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
|
||||
PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
|
||||
adm1026_write_value(client, ADM1026_REG_PWM,
|
||||
data->pwm1.pwm);
|
||||
adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
|
||||
} else if (!((old_enable == 1) && (val == 1))) {
|
||||
/* set pwm to safe value */
|
||||
data->pwm1.pwm = 255;
|
||||
adm1026_write_value(client, ADM1026_REG_PWM,
|
||||
data->pwm1.pwm);
|
||||
adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1716,7 +1850,8 @@ static int adm1026_probe(struct i2c_client *client,
|
||||
adm1026_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1026_group)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1026_group);
|
||||
if (err)
|
||||
goto exitfree;
|
||||
if (data->config1 & CFG1_AIN8_9)
|
||||
err = sysfs_create_group(&client->dev.kobj,
|
||||
@ -1761,20 +1896,9 @@ static int adm1026_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init sm_adm1026_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adm1026_driver);
|
||||
}
|
||||
|
||||
static void __exit sm_adm1026_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adm1026_driver);
|
||||
}
|
||||
module_i2c_driver(adm1026_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, "
|
||||
"Justin Thiessen <jthiessen@penguincomputing.com>");
|
||||
MODULE_DESCRIPTION("ADM1026 driver");
|
||||
|
||||
module_init(sm_adm1026_init);
|
||||
module_exit(sm_adm1026_exit);
|
||||
|
@ -200,8 +200,11 @@ static ssize_t set_fan_div(struct device *dev,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1029_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
u8 reg;
|
||||
long val;
|
||||
int ret = kstrtol(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@ -237,8 +240,8 @@ static ssize_t set_fan_div(struct device *dev,
|
||||
}
|
||||
|
||||
/*
|
||||
Access rights on sysfs, S_IRUGO stand for Is Readable by User, Group and Others
|
||||
S_IWUSR stand for Is Writable by User
|
||||
* Access rights on sysfs. S_IRUGO: Is Readable by User, Group and Others
|
||||
* S_IWUSR: Is Writable by User.
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
|
||||
@ -300,7 +303,8 @@ static int adm1029_detect(struct i2c_client *client,
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
/* ADM1029 doesn't have CHIP ID, check just MAN ID
|
||||
/*
|
||||
* ADM1029 doesn't have CHIP ID, check just MAN ID
|
||||
* For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED,
|
||||
* ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values
|
||||
* documented
|
||||
@ -318,8 +322,10 @@ static int adm1029_detect(struct i2c_client *client,
|
||||
return -ENODEV;
|
||||
|
||||
if ((chip_id & 0xF0) != 0x00) {
|
||||
/* There are no "official" CHIP ID, so actually
|
||||
* we use Major/Minor revision for that */
|
||||
/*
|
||||
* There are no "official" CHIP ID, so actually
|
||||
* we use Major/Minor revision for that
|
||||
*/
|
||||
pr_info("adm1029: Unknown major revision %x, "
|
||||
"please let us know\n", chip_id);
|
||||
return -ENODEV;
|
||||
@ -355,7 +361,8 @@ static int adm1029_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1029_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
@ -403,7 +410,7 @@ static int adm1029_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
/*
|
||||
function that update the status of the chips (temperature for example)
|
||||
* function that update the status of the chips (temperature for example)
|
||||
*/
|
||||
static struct adm1029_data *adm1029_update_device(struct device *dev)
|
||||
{
|
||||
@ -446,24 +453,8 @@ static struct adm1029_data *adm1029_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
Common module stuff
|
||||
*/
|
||||
static int __init sensors_adm1029_init(void)
|
||||
{
|
||||
|
||||
return i2c_add_driver(&adm1029_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_adm1029_exit(void)
|
||||
{
|
||||
|
||||
i2c_del_driver(&adm1029_driver);
|
||||
}
|
||||
module_i2c_driver(adm1029_driver);
|
||||
|
||||
MODULE_AUTHOR("Corentin LABBE <corentin.labbe@geomatys.fr>");
|
||||
MODULE_DESCRIPTION("adm1029 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
module_init(sensors_adm1029_init);
|
||||
module_exit(sensors_adm1029_exit);
|
||||
|
@ -1,24 +1,24 @@
|
||||
/*
|
||||
adm1031.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Based on lm75.c and lm85.c
|
||||
Supports adm1030 / adm1031
|
||||
Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org>
|
||||
Reworked by Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* adm1031.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Based on lm75.c and lm85.c
|
||||
* Supports adm1030 / adm1031
|
||||
* Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org>
|
||||
* Reworked by Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -80,7 +80,8 @@ struct adm1031_data {
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
unsigned int update_interval; /* In milliseconds */
|
||||
/* The chan_select_table contains the possible configurations for
|
||||
/*
|
||||
* The chan_select_table contains the possible configurations for
|
||||
* auto fan control.
|
||||
*/
|
||||
const auto_chan_table_t *chan_select_table;
|
||||
@ -205,7 +206,8 @@ static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm)
|
||||
#define GET_FAN_AUTO_BITFIELD(data, idx) \
|
||||
(*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2]
|
||||
|
||||
/* The tables below contains the possible values for the auto fan
|
||||
/*
|
||||
* The tables below contains the possible values for the auto fan
|
||||
* control bitfields. the index in the table is the register value.
|
||||
* MSb is the auto fan control enable bit, so the four first entries
|
||||
* in the table disables auto fan control when both bitfields are zero.
|
||||
@ -226,7 +228,8 @@ static const auto_chan_table_t auto_channel_select_table_adm1030 = {
|
||||
{ 3 /* 0b11 */ , 0 },
|
||||
};
|
||||
|
||||
/* That function checks if a bitfield is valid and returns the other bitfield
|
||||
/*
|
||||
* That function checks if a bitfield is valid and returns the other bitfield
|
||||
* nearest match if no exact match where found.
|
||||
*/
|
||||
static int
|
||||
@ -252,7 +255,8 @@ get_fan_auto_nearest(struct adm1031_data *data,
|
||||
break;
|
||||
} else if (val == (*data->chan_select_table)[i][chan] &&
|
||||
first_match == -1) {
|
||||
/* Save the first match in case of an exact match has
|
||||
/*
|
||||
* Save the first match in case of an exact match has
|
||||
* not been found
|
||||
*/
|
||||
first_match = i;
|
||||
@ -306,9 +310,11 @@ set_fan_auto_channel(struct device *dev, struct device_attribute *attr,
|
||||
if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
|
||||
(old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
|
||||
if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
|
||||
/* Switch to Auto Fan Mode
|
||||
/*
|
||||
* Switch to Auto Fan Mode
|
||||
* Save PWM registers
|
||||
* Set PWM registers to 33% Both */
|
||||
* Set PWM registers to 33% Both
|
||||
*/
|
||||
data->old_pwm[0] = data->pwm[0];
|
||||
data->old_pwm[1] = data->pwm[1];
|
||||
adm1031_write_value(client, ADM1031_REG_PWM, 0x55);
|
||||
@ -1131,19 +1137,8 @@ static struct adm1031_data *adm1031_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_adm1031_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adm1031_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_adm1031_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adm1031_driver);
|
||||
}
|
||||
module_i2c_driver(adm1031_driver);
|
||||
|
||||
MODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>");
|
||||
MODULE_DESCRIPTION("ADM1031/ADM1030 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_adm1031_init);
|
||||
module_exit(sensors_adm1031_exit);
|
||||
|
@ -204,7 +204,12 @@ static ssize_t set_max(struct device *dev, struct device_attribute *devattr,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max[attr->index] = TEMP_TO_REG(val);
|
||||
@ -255,7 +260,12 @@ static ssize_t set_in_min(struct device *dev,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_min[attr->index] = IN_TO_REG(val, attr->index);
|
||||
@ -272,7 +282,12 @@ static ssize_t set_in_max(struct device *dev,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_max[attr->index] = IN_TO_REG(val, attr->index);
|
||||
@ -357,9 +372,14 @@ static ssize_t set_fan_min(struct device *dev,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
int nr = attr->index;
|
||||
u8 new_div;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@ -465,7 +485,12 @@ static ssize_t set_aout(struct device *dev,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->aout = AOUT_TO_REG(val);
|
||||
@ -481,7 +506,12 @@ static ssize_t chassis_clear_legacy(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
unsigned long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dev_warn(dev, "Attribute chassis_clear is deprecated, "
|
||||
"use intrusion0_alarm instead\n");
|
||||
@ -632,7 +662,8 @@ static int adm9240_probe(struct i2c_client *new_client,
|
||||
adm9240_init_client(new_client);
|
||||
|
||||
/* populate sysfs filesystem */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
@ -681,8 +712,7 @@ static void adm9240_init_client(struct i2c_client *client)
|
||||
} else { /* cold start: open limits before starting chip */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
for (i = 0; i < 6; i++) {
|
||||
i2c_smbus_write_byte_data(client,
|
||||
ADM9240_REG_IN_MIN(i), 0);
|
||||
i2c_smbus_write_byte_data(client,
|
||||
@ -717,8 +747,7 @@ static struct adm9240_data *adm9240_update_device(struct device *dev)
|
||||
if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
|
||||
|| !data->valid) {
|
||||
|
||||
for (i = 0; i < 6; i++) /* read voltages */
|
||||
{
|
||||
for (i = 0; i < 6; i++) { /* read voltages */
|
||||
data->in[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_IN(i));
|
||||
}
|
||||
@ -727,16 +756,17 @@ static struct adm9240_data *adm9240_update_device(struct device *dev)
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_INT(1)) << 8;
|
||||
|
||||
/* read temperature: assume temperature changes less than
|
||||
/*
|
||||
* read temperature: assume temperature changes less than
|
||||
* 0.5'C per two measurement cycles thus ignore possible
|
||||
* but unlikely aliasing error on lsb reading. --Grant */
|
||||
* but unlikely aliasing error on lsb reading. --Grant
|
||||
*/
|
||||
data->temp = ((i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP) << 8) |
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP_CONF)) / 128;
|
||||
|
||||
for (i = 0; i < 2; i++) /* read fans */
|
||||
{
|
||||
for (i = 0; i < 2; i++) { /* read fans */
|
||||
data->fan[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_FAN(i));
|
||||
|
||||
@ -760,15 +790,13 @@ static struct adm9240_data *adm9240_update_device(struct device *dev)
|
||||
if (time_after(jiffies, data->last_updated_config + (HZ * 300))
|
||||
|| !data->valid) {
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
for (i = 0; i < 6; i++) {
|
||||
data->in_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_IN_MIN(i));
|
||||
data->in_max[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_IN_MAX(i));
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->fan_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_FAN_MIN(i));
|
||||
}
|
||||
@ -795,21 +823,9 @@ static struct adm9240_data *adm9240_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_adm9240_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adm9240_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_adm9240_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adm9240_driver);
|
||||
}
|
||||
module_i2c_driver(adm9240_driver);
|
||||
|
||||
MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, "
|
||||
"Grant Coady <gcoady.lk@gmail.com> and others");
|
||||
MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_adm9240_init);
|
||||
module_exit(sensors_adm9240_exit);
|
||||
|
||||
|
@ -305,19 +305,8 @@ static struct i2c_driver ads1015_driver = {
|
||||
.id_table = ads1015_id,
|
||||
};
|
||||
|
||||
static int __init sensors_ads1015_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ads1015_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_ads1015_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ads1015_driver);
|
||||
}
|
||||
module_i2c_driver(ads1015_driver);
|
||||
|
||||
MODULE_AUTHOR("Dirk Eibach <eibach@gdsys.de>");
|
||||
MODULE_DESCRIPTION("ADS1015 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_ads1015_init);
|
||||
module_exit(sensors_ads1015_exit);
|
||||
|
@ -1,26 +1,26 @@
|
||||
/*
|
||||
ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC
|
||||
(C) 2007 EADS Astrium
|
||||
|
||||
This driver is based on the lm75 and other lm_sensors/hwmon drivers
|
||||
|
||||
Written by Steve Hardy <shardy@redhat.com>
|
||||
|
||||
Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC
|
||||
* (C) 2007 EADS Astrium
|
||||
*
|
||||
* This driver is based on the lm75 and other lm_sensors/hwmon drivers
|
||||
*
|
||||
* Written by Steve Hardy <shardy@redhat.com>
|
||||
*
|
||||
* Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -188,11 +188,12 @@ static int ads7828_detect(struct i2c_client *client,
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
/* Now, we do the remaining detection. There is no identification
|
||||
dedicated register so attempt to sanity check using knowledge of
|
||||
the chip
|
||||
- Read from the 8 channel addresses
|
||||
- Check the top 4 bits of each result are not set (12 data bits)
|
||||
/*
|
||||
* Now, we do the remaining detection. There is no identification
|
||||
* dedicated register so attempt to sanity check using knowledge of
|
||||
* the chip
|
||||
* - Read from the 8 channel addresses
|
||||
* - Check the top 4 bits of each result are not set (12 data bits)
|
||||
*/
|
||||
for (ch = 0; ch < ADS7828_NCH; ch++) {
|
||||
u16 in_data;
|
||||
|
@ -34,9 +34,11 @@
|
||||
#define REG_SER_CONTROL 24 /*Serial Interface Control Register*/
|
||||
#define REG_ID 31 /*ID Register*/
|
||||
|
||||
/*From figure 17 in the datasheet
|
||||
/*
|
||||
* From figure 17 in the datasheet
|
||||
* These bits get ORed with the address to form
|
||||
* the instruction byte */
|
||||
* the instruction byte
|
||||
*/
|
||||
/*Instruction Bit masks*/
|
||||
#define INST_MODE_bm (1<<7)
|
||||
#define INST_READ_bm (1<<6)
|
||||
@ -105,8 +107,10 @@ static ssize_t show_voltage(struct device *dev,
|
||||
uint8_t channel, mux_cnv;
|
||||
|
||||
channel = attr->index;
|
||||
/*TODO: add support for conversions
|
||||
*other than single ended with a gain of 1*/
|
||||
/*
|
||||
* TODO: add support for conversions
|
||||
* other than single ended with a gain of 1
|
||||
*/
|
||||
/*MUX_M3_bm forces single ended*/
|
||||
/*This is also where the gain of the PGA would be set*/
|
||||
ads7871_write_reg8(spi, REG_GAIN_MUX,
|
||||
@ -114,8 +118,10 @@ static ssize_t show_voltage(struct device *dev,
|
||||
|
||||
ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
|
||||
mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
|
||||
/*on 400MHz arm9 platform the conversion
|
||||
*is already done when we do this test*/
|
||||
/*
|
||||
* on 400MHz arm9 platform the conversion
|
||||
* is already done when we do this test
|
||||
*/
|
||||
while ((i < 2) && mux_cnv) {
|
||||
i++;
|
||||
ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
|
||||
@ -179,8 +185,10 @@ static int __devinit ads7871_probe(struct spi_device *spi)
|
||||
ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
|
||||
|
||||
dev_dbg(&spi->dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret);
|
||||
/*because there is no other error checking on an SPI bus
|
||||
we need to make sure we really have a chip*/
|
||||
/*
|
||||
* because there is no other error checking on an SPI bus
|
||||
* we need to make sure we really have a chip
|
||||
*/
|
||||
if (val != ret) {
|
||||
err = -ENODEV;
|
||||
goto exit;
|
||||
@ -234,18 +242,7 @@ static struct spi_driver ads7871_driver = {
|
||||
.remove = __devexit_p(ads7871_remove),
|
||||
};
|
||||
|
||||
static int __init ads7871_init(void)
|
||||
{
|
||||
return spi_register_driver(&ads7871_driver);
|
||||
}
|
||||
|
||||
static void __exit ads7871_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&ads7871_driver);
|
||||
}
|
||||
|
||||
module_init(ads7871_init);
|
||||
module_exit(ads7871_exit);
|
||||
module_spi_driver(ads7871_driver);
|
||||
|
||||
MODULE_AUTHOR("Paul Thomas <pthomas8589@gmail.com>");
|
||||
MODULE_DESCRIPTION("TI ADS7871 A/D driver");
|
||||
|
@ -348,17 +348,7 @@ static struct i2c_driver adt7411_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
};
|
||||
|
||||
static int __init sensors_adt7411_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adt7411_driver);
|
||||
}
|
||||
module_init(sensors_adt7411_init)
|
||||
|
||||
static void __exit sensors_adt7411_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adt7411_driver);
|
||||
}
|
||||
module_exit(sensors_adt7411_exit)
|
||||
module_i2c_driver(adt7411_driver);
|
||||
|
||||
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de> and "
|
||||
"Wolfram Sang <w.sang@pengutronix.de>");
|
||||
|
@ -135,7 +135,7 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END };
|
||||
#define ADT7462_ALARM_FLAG_MASK 0x0F
|
||||
|
||||
#define ADT7462_TEMP_COUNT 4
|
||||
#define ADT7462_TEMP_REG(x) (ADT7462_REG_TEMP_BASE_ADDR + (x * 2))
|
||||
#define ADT7462_TEMP_REG(x) (ADT7462_REG_TEMP_BASE_ADDR + ((x) * 2))
|
||||
#define ADT7462_TEMP_MIN_REG(x) (ADT7462_REG_MIN_TEMP_BASE_ADDR + (x))
|
||||
#define ADT7462_TEMP_MAX_REG(x) (ADT7462_REG_MAX_TEMP_BASE_ADDR + (x))
|
||||
#define TEMP_FRAC_OFFSET 6
|
||||
@ -1727,8 +1727,7 @@ static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
|
||||
static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
|
||||
show_pwm_auto_temp, set_pwm_auto_temp, 3);
|
||||
|
||||
static struct attribute *adt7462_attr[] =
|
||||
{
|
||||
static struct attribute *adt7462_attr[] = {
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
@ -1975,19 +1974,8 @@ static int adt7462_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init adt7462_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adt7462_driver);
|
||||
}
|
||||
|
||||
static void __exit adt7462_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adt7462_driver);
|
||||
}
|
||||
module_i2c_driver(adt7462_driver);
|
||||
|
||||
MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
|
||||
MODULE_DESCRIPTION("ADT7462 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(adt7462_init);
|
||||
module_exit(adt7462_exit);
|
||||
|
@ -1131,8 +1131,7 @@ static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
|
||||
static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
|
||||
show_pwm_auto_temp, set_pwm_auto_temp, 3);
|
||||
|
||||
static struct attribute *adt7470_attr[] =
|
||||
{
|
||||
static struct attribute *adt7470_attr[] = {
|
||||
&dev_attr_alarm_mask.attr,
|
||||
&dev_attr_num_temp_sensors.attr,
|
||||
&dev_attr_auto_update_interval.attr,
|
||||
@ -1276,7 +1275,8 @@ static int adt7470_probe(struct i2c_client *client,
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->attrs.attrs = adt7470_attr;
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
@ -1317,19 +1317,8 @@ static int adt7470_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init adt7470_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adt7470_driver);
|
||||
}
|
||||
|
||||
static void __exit adt7470_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adt7470_driver);
|
||||
}
|
||||
module_i2c_driver(adt7470_driver);
|
||||
|
||||
MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
|
||||
MODULE_DESCRIPTION("ADT7470 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(adt7470_init);
|
||||
module_exit(adt7470_exit);
|
||||
|
@ -32,8 +32,9 @@
|
||||
#define THERM 5
|
||||
#define HYSTERSIS 6
|
||||
|
||||
/* These are unique identifiers for the sysfs functions - unlike the
|
||||
numbers above, these are not also indexes into an array
|
||||
/*
|
||||
* These are unique identifiers for the sysfs functions - unlike the
|
||||
* numbers above, these are not also indexes into an array
|
||||
*/
|
||||
|
||||
#define ALARM 9
|
||||
@ -288,8 +289,10 @@ static void adt7475_write_word(struct i2c_client *client, int reg, u16 val)
|
||||
i2c_smbus_write_byte_data(client, reg, val & 0xFF);
|
||||
}
|
||||
|
||||
/* Find the nearest value in a table - used for pwm frequency and
|
||||
auto temp range */
|
||||
/*
|
||||
* Find the nearest value in a table - used for pwm frequency and
|
||||
* auto temp range
|
||||
*/
|
||||
static int find_nearest(long val, const int *array, int size)
|
||||
{
|
||||
int i;
|
||||
@ -385,16 +388,20 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
|
||||
out = (out >> 4) & 0xF;
|
||||
else
|
||||
out = (out & 0xF);
|
||||
/* Show the value as an absolute number tied to
|
||||
* THERM */
|
||||
/*
|
||||
* Show the value as an absolute number tied to
|
||||
* THERM
|
||||
*/
|
||||
out = reg2temp(data, data->temp[THERM][sattr->index]) -
|
||||
out * 1000;
|
||||
mutex_unlock(&data->lock);
|
||||
break;
|
||||
|
||||
case OFFSET:
|
||||
/* Offset is always 2's complement, regardless of the
|
||||
* setting in CONFIG5 */
|
||||
/*
|
||||
* Offset is always 2's complement, regardless of the
|
||||
* setting in CONFIG5
|
||||
*/
|
||||
mutex_lock(&data->lock);
|
||||
out = (s8)data->temp[sattr->nr][sattr->index];
|
||||
if (data->config5 & CONFIG5_TEMPOFFSET)
|
||||
@ -452,8 +459,10 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
|
||||
break;
|
||||
|
||||
case HYSTERSIS:
|
||||
/* The value will be given as an absolute value, turn it
|
||||
into an offset based on THERM */
|
||||
/*
|
||||
* The value will be given as an absolute value, turn it
|
||||
* into an offset based on THERM
|
||||
*/
|
||||
|
||||
/* Read fresh THERM and HYSTERSIS values from the chip */
|
||||
data->temp[THERM][sattr->index] =
|
||||
@ -478,8 +487,10 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
|
||||
default:
|
||||
data->temp[sattr->nr][sattr->index] = temp2reg(data, val);
|
||||
|
||||
/* We maintain an extra 2 digits of precision for simplicity
|
||||
* - shift those back off before writing the value */
|
||||
/*
|
||||
* We maintain an extra 2 digits of precision for simplicity
|
||||
* - shift those back off before writing the value
|
||||
*/
|
||||
out = (u8) (data->temp[sattr->nr][sattr->index] >> 2);
|
||||
}
|
||||
|
||||
@ -514,8 +525,10 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Table of autorange values - the user will write the value in millidegrees,
|
||||
and we'll convert it */
|
||||
/*
|
||||
* Table of autorange values - the user will write the value in millidegrees,
|
||||
* and we'll convert it
|
||||
*/
|
||||
static const int autorange_table[] = {
|
||||
2000, 2500, 3330, 4000, 5000, 6670, 8000,
|
||||
10000, 13330, 16000, 20000, 26670, 32000, 40000,
|
||||
@ -558,8 +571,10 @@ static ssize_t set_point2(struct device *dev, struct device_attribute *attr,
|
||||
data->range[sattr->index] =
|
||||
adt7475_read(TEMP_TRANGE_REG(sattr->index));
|
||||
|
||||
/* The user will write an absolute value, so subtract the start point
|
||||
to figure the range */
|
||||
/*
|
||||
* The user will write an absolute value, so subtract the start point
|
||||
* to figure the range
|
||||
*/
|
||||
temp = reg2temp(data, data->temp[AUTOMIN][sattr->index]);
|
||||
val = SENSORS_LIMIT(val, temp + autorange_table[0],
|
||||
temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]);
|
||||
@ -664,8 +679,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
data->pwm[CONTROL][sattr->index] =
|
||||
adt7475_read(PWM_CONFIG_REG(sattr->index));
|
||||
|
||||
/* If we are not in manual mode, then we shouldn't allow
|
||||
* the user to set the pwm speed */
|
||||
/*
|
||||
* If we are not in manual mode, then we shouldn't allow
|
||||
* the user to set the pwm speed
|
||||
*/
|
||||
if (((data->pwm[CONTROL][sattr->index] >> 5) & 7) != 7) {
|
||||
mutex_unlock(&data->lock);
|
||||
return count;
|
||||
@ -1232,7 +1249,7 @@ static void adt7475_remove_files(struct i2c_client *client,
|
||||
static int adt7475_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
static const char *names[] = {
|
||||
static const char * const names[] = {
|
||||
[adt7473] = "ADT7473",
|
||||
[adt7475] = "ADT7475",
|
||||
[adt7476] = "ADT7476",
|
||||
@ -1280,9 +1297,11 @@ static int adt7475_probe(struct i2c_client *client,
|
||||
if ((data->config4 & CONFIG4_PINFUNC) == 0x0)
|
||||
data->has_fan4 = 1;
|
||||
|
||||
/* THERM configuration is more complex on the ADT7476 and ADT7490,
|
||||
because 2 different pins (TACH4 and +2.5 Vin) can be used for
|
||||
this function */
|
||||
/*
|
||||
* THERM configuration is more complex on the ADT7476 and ADT7490,
|
||||
* because 2 different pins (TACH4 and +2.5 Vin) can be used for
|
||||
* this function
|
||||
*/
|
||||
if (id->driver_data == adt7490) {
|
||||
if ((data->config4 & CONFIG4_PINFUNC) == 0x1 &&
|
||||
!(config3 & CONFIG3_THERM))
|
||||
@ -1294,8 +1313,10 @@ static int adt7475_probe(struct i2c_client *client,
|
||||
data->has_voltage |= (1 << 0); /* in0 */
|
||||
}
|
||||
|
||||
/* On the ADT7476, the +12V input pin may instead be used as VID5,
|
||||
and VID pins may alternatively be used as GPIO */
|
||||
/*
|
||||
* On the ADT7476, the +12V input pin may instead be used as VID5,
|
||||
* and VID pins may alternatively be used as GPIO
|
||||
*/
|
||||
if (id->driver_data == adt7476) {
|
||||
u8 vid = adt7475_read(REG_VID);
|
||||
if (!(vid & VID_VIDSEL))
|
||||
@ -1314,8 +1335,10 @@ static int adt7475_probe(struct i2c_client *client,
|
||||
}
|
||||
data->bypass_attn &= data->has_voltage;
|
||||
|
||||
/* Call adt7475_read_pwm for all pwm's as this will reprogram any
|
||||
pwm's which are disabled to manual mode with 0% duty cycle */
|
||||
/*
|
||||
* Call adt7475_read_pwm for all pwm's as this will reprogram any
|
||||
* pwm's which are disabled to manual mode with 0% duty cycle
|
||||
*/
|
||||
for (i = 0; i < ADT7475_PWM_COUNT; i++)
|
||||
adt7475_read_pwm(client, i);
|
||||
|
||||
@ -1431,8 +1454,10 @@ static void adt7475_read_pwm(struct i2c_client *client, int index)
|
||||
|
||||
data->pwm[CONTROL][index] = adt7475_read(PWM_CONFIG_REG(index));
|
||||
|
||||
/* Figure out the internal value for pwmctrl and pwmchan
|
||||
based on the current settings */
|
||||
/*
|
||||
* Figure out the internal value for pwmctrl and pwmchan
|
||||
* based on the current settings
|
||||
*/
|
||||
v = (data->pwm[CONTROL][index] >> 5) & 7;
|
||||
|
||||
if (v == 3)
|
||||
@ -1440,9 +1465,10 @@ static void adt7475_read_pwm(struct i2c_client *client, int index)
|
||||
else if (v == 7)
|
||||
data->pwmctl[index] = 1;
|
||||
else if (v == 4) {
|
||||
/* The fan is disabled - we don't want to
|
||||
support that, so change to manual mode and
|
||||
set the duty cycle to 0 instead
|
||||
/*
|
||||
* The fan is disabled - we don't want to
|
||||
* support that, so change to manual mode and
|
||||
* set the duty cycle to 0 instead
|
||||
*/
|
||||
data->pwm[INPUT][index] = 0;
|
||||
data->pwm[CONTROL][index] &= ~0xE0;
|
||||
@ -1600,19 +1626,8 @@ static struct adt7475_data *adt7475_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_adt7475_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adt7475_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_adt7475_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adt7475_driver);
|
||||
}
|
||||
module_i2c_driver(adt7475_driver);
|
||||
|
||||
MODULE_AUTHOR("Advanced Micro Devices, Inc");
|
||||
MODULE_DESCRIPTION("adt7475 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_adt7475_init);
|
||||
module_exit(sensors_adt7475_exit);
|
||||
|
@ -1,24 +1,24 @@
|
||||
/*
|
||||
amc6821.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si>
|
||||
|
||||
Based on max6650.c:
|
||||
Copyright (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* amc6821.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si>
|
||||
*
|
||||
* Based on max6650.c:
|
||||
* Copyright (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ static const unsigned short normal_i2c[] = {0x18, 0x19, 0x1a, 0x2c, 0x2d, 0x2e,
|
||||
* Insmod parameters
|
||||
*/
|
||||
|
||||
static int pwminv = 0; /*Inverted PWM output. */
|
||||
static int pwminv; /*Inverted PWM output. */
|
||||
module_param(pwminv, int, S_IRUGO);
|
||||
|
||||
static int init = 1; /*Power-on initialization.*/
|
||||
@ -836,8 +836,10 @@ static int amc6821_detect(
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Bit 7 of the address register is ignored, so we can check the
|
||||
ID registers again */
|
||||
/*
|
||||
* Bit 7 of the address register is ignored, so we can check the
|
||||
* ID registers again
|
||||
*/
|
||||
dev_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_DEV_ID);
|
||||
comp_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_COMP_ID);
|
||||
if (dev_id != 0x21 || comp_id != 0x49) {
|
||||
@ -1080,8 +1082,9 @@ static struct amc6821_data *amc6821_update_device(struct device *dev)
|
||||
data->pwm1_auto_channels_temp = 3;
|
||||
data->pwm1_enable = 3;
|
||||
break;
|
||||
case 1: /*semi-open loop: software sets rpm, chip controls pwm1,
|
||||
*currently not implemented
|
||||
case 1: /*
|
||||
* semi-open loop: software sets rpm, chip controls
|
||||
* pwm1, currently not implemented
|
||||
*/
|
||||
data->pwm1_auto_channels_temp = 0;
|
||||
data->pwm1_enable = 0;
|
||||
@ -1095,20 +1098,7 @@ static struct amc6821_data *amc6821_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static int __init amc6821_init(void)
|
||||
{
|
||||
return i2c_add_driver(&amc6821_driver);
|
||||
}
|
||||
|
||||
static void __exit amc6821_exit(void)
|
||||
{
|
||||
i2c_del_driver(&amc6821_driver);
|
||||
}
|
||||
|
||||
module_init(amc6821_init);
|
||||
module_exit(amc6821_exit);
|
||||
|
||||
module_i2c_driver(amc6821_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("T. Mertelj <tomaz.mertelj@guest.arnes.si>");
|
||||
|
@ -344,8 +344,10 @@ static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
|
||||
while (begin != end) {
|
||||
int middle = begin + (end - begin) / 2;
|
||||
entry = applesmc_get_entry_by_index(middle);
|
||||
if (IS_ERR(entry))
|
||||
if (IS_ERR(entry)) {
|
||||
*lo = 0;
|
||||
return PTR_ERR(entry);
|
||||
}
|
||||
if (strcmp(entry->key, key) < 0)
|
||||
begin = middle + 1;
|
||||
else
|
||||
@ -364,8 +366,10 @@ static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
|
||||
while (begin != end) {
|
||||
int middle = begin + (end - begin) / 2;
|
||||
entry = applesmc_get_entry_by_index(middle);
|
||||
if (IS_ERR(entry))
|
||||
if (IS_ERR(entry)) {
|
||||
*hi = smcreg.key_count;
|
||||
return PTR_ERR(entry);
|
||||
}
|
||||
if (strcmp(key, entry->key) < 0)
|
||||
end = middle;
|
||||
else
|
||||
@ -1189,8 +1193,10 @@ static int applesmc_dmi_match(const struct dmi_system_id *id)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
|
||||
* So we need to put "Apple MacBook Pro" before "Apple MacBook". */
|
||||
/*
|
||||
* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
|
||||
* So we need to put "Apple MacBook Pro" before "Apple MacBook".
|
||||
*/
|
||||
static __initdata struct dmi_system_id applesmc_whitelist[] = {
|
||||
{ applesmc_dmi_match, "Apple MacBook Air", {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
|
||||
|
@ -1,39 +1,39 @@
|
||||
/*
|
||||
asb100.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
|
||||
Copyright (C) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
|
||||
|
||||
(derived from w83781d.c)
|
||||
|
||||
Copyright (C) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>, and
|
||||
Mark Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* asb100.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
*
|
||||
* Copyright (C) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
|
||||
*
|
||||
* (derived from w83781d.c)
|
||||
*
|
||||
* Copyright (C) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>,
|
||||
* Philip Edelbrock <phil@netroedge.com>, and
|
||||
* Mark Studebaker <mdsxyz123@yahoo.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
This driver supports the hardware sensor chips: Asus ASB100 and
|
||||
ASB100-A "BACH".
|
||||
|
||||
ASB100-A supports pwm1, while plain ASB100 does not. There is no known
|
||||
way for the driver to tell which one is there.
|
||||
|
||||
Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
|
||||
asb100 7 3 1 4 0x31 0x0694 yes no
|
||||
* This driver supports the hardware sensor chips: Asus ASB100 and
|
||||
* ASB100-A "BACH".
|
||||
*
|
||||
* ASB100-A supports pwm1, while plain ASB100 does not. There is no known
|
||||
* way for the driver to tell which one is there.
|
||||
*
|
||||
* Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
|
||||
* asb100 7 3 1 4 0x31 0x0694 yes no
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -99,15 +99,19 @@ static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19};
|
||||
/* bit 7 -> enable, bits 0-3 -> duty cycle */
|
||||
#define ASB100_REG_PWM1 0x59
|
||||
|
||||
/* CONVERSIONS
|
||||
Rounding and limit checking is only done on the TO_REG variants. */
|
||||
/*
|
||||
* CONVERSIONS
|
||||
* Rounding and limit checking is only done on the TO_REG variants.
|
||||
*/
|
||||
|
||||
/* These constants are a guess, consistent w/ w83781d */
|
||||
#define ASB100_IN_MIN ( 0)
|
||||
#define ASB100_IN_MAX (4080)
|
||||
#define ASB100_IN_MIN 0
|
||||
#define ASB100_IN_MAX 4080
|
||||
|
||||
/* IN: 1/1000 V (0V to 4.08V)
|
||||
REG: 16mV/bit */
|
||||
/*
|
||||
* IN: 1/1000 V (0V to 4.08V)
|
||||
* REG: 16mV/bit
|
||||
*/
|
||||
static u8 IN_TO_REG(unsigned val)
|
||||
{
|
||||
unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX);
|
||||
@ -135,11 +139,13 @@ static int FAN_FROM_REG(u8 val, int div)
|
||||
}
|
||||
|
||||
/* These constants are a guess, consistent w/ w83781d */
|
||||
#define ASB100_TEMP_MIN (-128000)
|
||||
#define ASB100_TEMP_MAX ( 127000)
|
||||
#define ASB100_TEMP_MIN -128000
|
||||
#define ASB100_TEMP_MAX 127000
|
||||
|
||||
/* TEMP: 0.001C/bit (-128C to +127C)
|
||||
REG: 1C/bit, two's complement */
|
||||
/*
|
||||
* TEMP: 0.001C/bit (-128C to +127C)
|
||||
* REG: 1C/bit, two's complement
|
||||
*/
|
||||
static u8 TEMP_TO_REG(long temp)
|
||||
{
|
||||
int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
|
||||
@ -152,8 +158,10 @@ static int TEMP_FROM_REG(u8 reg)
|
||||
return (s8)reg * 1000;
|
||||
}
|
||||
|
||||
/* PWM: 0 - 255 per sensors documentation
|
||||
REG: (6.25% duty cycle per bit) */
|
||||
/*
|
||||
* PWM: 0 - 255 per sensors documentation
|
||||
* REG: (6.25% duty cycle per bit)
|
||||
*/
|
||||
static u8 ASB100_PWM_TO_REG(int pwm)
|
||||
{
|
||||
pwm = SENSORS_LIMIT(pwm, 0, 255);
|
||||
@ -167,16 +175,20 @@ static int ASB100_PWM_FROM_REG(u8 reg)
|
||||
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
|
||||
/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
|
||||
REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
|
||||
/*
|
||||
* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
|
||||
* REG: 0, 1, 2, or 3 (respectively) (defaults to 1)
|
||||
*/
|
||||
static u8 DIV_TO_REG(long val)
|
||||
{
|
||||
return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
/* For each registered client, we need to keep some data in memory. That
|
||||
data is pointed to by client->data. The structure itself is
|
||||
dynamically allocated, at the same time the client itself is allocated. */
|
||||
/*
|
||||
* For each registered client, we need to keep some data in memory. That
|
||||
* data is pointed to by client->data. The structure itself is
|
||||
* dynamically allocated, at the same time the client itself is allocated.
|
||||
*/
|
||||
struct asb100_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
@ -253,8 +265,10 @@ static ssize_t set_in_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
int nr = to_sensor_dev_attr(attr)->index; \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct asb100_data *data = i2c_get_clientdata(client); \
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10); \
|
||||
\
|
||||
unsigned long val; \
|
||||
int err = kstrtoul(buf, 10, &val); \
|
||||
if (err) \
|
||||
return err; \
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->in_##reg[nr] = IN_TO_REG(val); \
|
||||
asb100_write_value(client, ASB100_REG_IN_##REG(nr), \
|
||||
@ -315,7 +329,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct asb100_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
|
||||
@ -324,10 +343,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Note: we save and restore the fan minimum here, because its value is
|
||||
determined in part by the fan divisor. This follows the principle of
|
||||
least surprise; the user doesn't expect the fan minimum to change just
|
||||
because the divisor changed. */
|
||||
/*
|
||||
* Note: we save and restore the fan minimum here, because its value is
|
||||
* determined in part by the fan divisor. This follows the principle of
|
||||
* least surprise; the user doesn't expect the fan minimum to change just
|
||||
* because the divisor changed.
|
||||
*/
|
||||
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
@ -335,8 +356,13 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct asb100_data *data = i2c_get_clientdata(client);
|
||||
unsigned long min;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
int reg;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@ -421,8 +447,10 @@ static ssize_t set_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
int nr = to_sensor_dev_attr(attr)->index; \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct asb100_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
long val; \
|
||||
int err = kstrtol(buf, 10, &val); \
|
||||
if (err) \
|
||||
return err; \
|
||||
mutex_lock(&data->update_lock); \
|
||||
switch (nr) { \
|
||||
case 1: case 2: \
|
||||
@ -476,7 +504,13 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct asb100_data *data = dev_get_drvdata(dev);
|
||||
data->vrm = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
data->vrm = val;
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -524,7 +558,12 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct asb100_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm &= 0x80; /* keep the enable bit */
|
||||
@ -546,7 +585,12 @@ static ssize_t set_pwm_enable1(struct device *dev,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct asb100_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm &= 0x0f; /* keep the duty cycle bits */
|
||||
@ -768,7 +812,8 @@ static int asb100_probe(struct i2c_client *client,
|
||||
data->fan_min[2] = asb100_read_value(client, ASB100_REG_FAN_MIN(2));
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &asb100_group)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &asb100_group);
|
||||
if (err)
|
||||
goto ERROR3;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
@ -805,8 +850,10 @@ static int asb100_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, usually, but nothing may access the chip between
|
||||
bank switches. */
|
||||
/*
|
||||
* The SMBus locks itself, usually, but nothing may access the chip between
|
||||
* bank switches.
|
||||
*/
|
||||
static int asb100_read_value(struct i2c_client *client, u16 reg)
|
||||
{
|
||||
struct asb100_data *data = i2c_get_clientdata(client);
|
||||
@ -971,19 +1018,8 @@ static struct asb100_data *asb100_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init asb100_init(void)
|
||||
{
|
||||
return i2c_add_driver(&asb100_driver);
|
||||
}
|
||||
|
||||
static void __exit asb100_exit(void)
|
||||
{
|
||||
i2c_del_driver(&asb100_driver);
|
||||
}
|
||||
module_i2c_driver(asb100_driver);
|
||||
|
||||
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
|
||||
MODULE_DESCRIPTION("ASB100 Bach driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(asb100_init);
|
||||
module_exit(asb100_exit);
|
||||
|
@ -268,9 +268,11 @@ static ssize_t store_fan16(struct device *dev,
|
||||
if (kstrtol(buf, 10, &reqval))
|
||||
return -EINVAL;
|
||||
|
||||
/* If a minimum RPM of zero is requested, then we set the register to
|
||||
0xffff. This value allows the fan to be stopped completely without
|
||||
generating an alarm. */
|
||||
/*
|
||||
* If a minimum RPM of zero is requested, then we set the register to
|
||||
* 0xffff. This value allows the fan to be stopped completely without
|
||||
* generating an alarm.
|
||||
*/
|
||||
reqval =
|
||||
(reqval <= 0 ? 0xffff : SENSORS_LIMIT(5400000 / reqval, 0, 0xfffe));
|
||||
|
||||
|
@ -38,7 +38,8 @@ static const struct dmi_system_id __initconst atk_force_new_if[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
/* Minimum time between readings, enforced in order to avoid
|
||||
/*
|
||||
* Minimum time between readings, enforced in order to avoid
|
||||
* hogging the CPU.
|
||||
*/
|
||||
#define CACHE_TIME HZ
|
||||
@ -161,7 +162,8 @@ struct atk_sensor_data {
|
||||
char const *acpi_name;
|
||||
};
|
||||
|
||||
/* Return buffer format:
|
||||
/*
|
||||
* Return buffer format:
|
||||
* [0-3] "value" is valid flag
|
||||
* [4-7] value
|
||||
* [8- ] unknown stuff on newer mobos
|
||||
@ -310,7 +312,8 @@ static union acpi_object *atk_get_pack_member(struct atk_data *data,
|
||||
}
|
||||
|
||||
|
||||
/* New package format is:
|
||||
/*
|
||||
* New package format is:
|
||||
* - flag (int)
|
||||
* class - used for de-muxing the request to the correct GITn
|
||||
* type (volt, temp, fan)
|
||||
@ -613,7 +616,8 @@ static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
|
||||
|
||||
buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
|
||||
if (buf->flags == 0) {
|
||||
/* The reading is not valid, possible causes:
|
||||
/*
|
||||
* The reading is not valid, possible causes:
|
||||
* - sensor failure
|
||||
* - enumeration was FUBAR (and we didn't notice)
|
||||
*/
|
||||
@ -1311,14 +1315,16 @@ static int atk_probe_if(struct atk_data *data)
|
||||
dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n",
|
||||
acpi_format_exception(status));
|
||||
|
||||
/* Check for hwmon methods: first check "old" style methods; note that
|
||||
/*
|
||||
* Check for hwmon methods: first check "old" style methods; note that
|
||||
* both may be present: in this case we stick to the old interface;
|
||||
* analysis of multiple DSDTs indicates that when both interfaces
|
||||
* are present the new one (GGRP/GITM) is not functional.
|
||||
*/
|
||||
if (new_if)
|
||||
dev_info(dev, "Overriding interface detection\n");
|
||||
if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle && !new_if)
|
||||
if (data->rtmp_handle &&
|
||||
data->rvlt_handle && data->rfan_handle && !new_if)
|
||||
data->old_interface = true;
|
||||
else if (data->enumerate_handle && data->read_handle &&
|
||||
data->write_handle)
|
||||
|
@ -1,21 +1,21 @@
|
||||
/*
|
||||
atxp1.c - kernel module for setting CPU VID and general purpose
|
||||
I/Os using the Attansic ATXP1 chip.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* atxp1.c - kernel module for setting CPU VID and general purpose
|
||||
* I/Os using the Attansic ATXP1 chip.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -97,7 +97,8 @@ static struct atxp1_data * atxp1_update_device(struct device *dev)
|
||||
|
||||
/* Update local register data */
|
||||
data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID);
|
||||
data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID);
|
||||
data->reg.cpu_vid = i2c_smbus_read_byte_data(client,
|
||||
ATXP1_CVID);
|
||||
data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1);
|
||||
data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2);
|
||||
|
||||
@ -106,33 +107,41 @@ static struct atxp1_data * atxp1_update_device(struct device *dev)
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* sys file functions for cpu0_vid */
|
||||
static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t atxp1_showvcore(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int size;
|
||||
struct atxp1_data *data;
|
||||
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm));
|
||||
size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK,
|
||||
data->vrm));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t atxp1_storevcore(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
int vid, cvid;
|
||||
unsigned int vcore;
|
||||
unsigned long vcore;
|
||||
int err;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
vcore = simple_strtoul(buf, NULL, 10);
|
||||
err = kstrtoul(buf, 10, &vcore);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
vcore /= 25;
|
||||
vcore *= 25;
|
||||
|
||||
@ -144,7 +153,10 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If output enabled, use control register value. Otherwise original CPU VID */
|
||||
/*
|
||||
* If output enabled, use control register value.
|
||||
* Otherwise original CPU VID
|
||||
*/
|
||||
if (data->reg.vid & ATXP1_VIDENA)
|
||||
cvid = data->reg.vid & ATXP1_VIDMASK;
|
||||
else
|
||||
@ -154,18 +166,17 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att
|
||||
if (vid == cvid)
|
||||
return count;
|
||||
|
||||
dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid);
|
||||
dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", (int)vcore, vid);
|
||||
|
||||
/* Write every 25 mV step to increase stability */
|
||||
if (cvid > vid) {
|
||||
for (; cvid >= vid; cvid--) {
|
||||
i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (; cvid <= vid; cvid++) {
|
||||
i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA);
|
||||
}
|
||||
for (; cvid >= vid; cvid--)
|
||||
i2c_smbus_write_byte_data(client,
|
||||
ATXP1_VID, cvid | ATXP1_VIDENA);
|
||||
} else {
|
||||
for (; cvid <= vid; cvid++)
|
||||
i2c_smbus_write_byte_data(client,
|
||||
ATXP1_VID, cvid | ATXP1_VIDENA);
|
||||
}
|
||||
|
||||
data->valid = 0;
|
||||
@ -173,13 +184,16 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att
|
||||
return count;
|
||||
}
|
||||
|
||||
/* CPU core reference voltage
|
||||
unit: millivolt
|
||||
/*
|
||||
* CPU core reference voltage
|
||||
* unit: millivolt
|
||||
*/
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore);
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore,
|
||||
atxp1_storevcore);
|
||||
|
||||
/* sys file functions for GPIO1 */
|
||||
static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t atxp1_showgpio1(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int size;
|
||||
struct atxp1_data *data;
|
||||
@ -191,21 +205,26 @@ static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count)
|
||||
static ssize_t atxp1_storegpio1(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
unsigned int value;
|
||||
unsigned long value;
|
||||
int err;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
value = simple_strtoul(buf, NULL, 16);
|
||||
err = kstrtoul(buf, 16, &value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
value &= ATXP1_GPIO1MASK;
|
||||
|
||||
if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) {
|
||||
dev_info(dev, "Writing 0x%x to GPIO1.\n", value);
|
||||
dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
|
||||
|
||||
i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value);
|
||||
|
||||
@ -215,13 +234,15 @@ static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *att
|
||||
return count;
|
||||
}
|
||||
|
||||
/* GPIO1 data register
|
||||
unit: Four bit as hex (e.g. 0x0f)
|
||||
/*
|
||||
* GPIO1 data register
|
||||
* unit: Four bit as hex (e.g. 0x0f)
|
||||
*/
|
||||
static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1);
|
||||
|
||||
/* sys file functions for GPIO2 */
|
||||
static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t atxp1_showgpio2(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int size;
|
||||
struct atxp1_data *data;
|
||||
@ -233,19 +254,22 @@ static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t atxp1_storegpio2(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
unsigned int value;
|
||||
struct atxp1_data *data = atxp1_update_device(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
unsigned long value;
|
||||
int err;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
value = simple_strtoul(buf, NULL, 16) & 0xff;
|
||||
err = kstrtoul(buf, 16, &value);
|
||||
if (err)
|
||||
return err;
|
||||
value &= 0xff;
|
||||
|
||||
if (value != data->reg.gpio2) {
|
||||
dev_info(dev, "Writing 0x%x to GPIO1.\n", value);
|
||||
dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
|
||||
|
||||
i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value);
|
||||
|
||||
@ -255,8 +279,9 @@ static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *att
|
||||
return count;
|
||||
}
|
||||
|
||||
/* GPIO2 data register
|
||||
unit: Eight bit as hex (e.g. 0xff)
|
||||
/*
|
||||
* GPIO2 data register
|
||||
* unit: Eight bit as hex (e.g. 0xff)
|
||||
*/
|
||||
static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
|
||||
|
||||
@ -290,8 +315,10 @@ static int atxp1_detect(struct i2c_client *new_client,
|
||||
(i2c_smbus_read_byte_data(new_client, 0xff) == 0)))
|
||||
return -ENODEV;
|
||||
|
||||
/* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
|
||||
* showing the same as register 0x00 */
|
||||
/*
|
||||
* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
|
||||
* showing the same as register 0x00
|
||||
*/
|
||||
temp = i2c_smbus_read_byte_data(new_client, 0x00);
|
||||
|
||||
if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
|
||||
@ -333,7 +360,8 @@ static int atxp1_probe(struct i2c_client *new_client,
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
@ -367,15 +395,4 @@ static int atxp1_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int __init atxp1_init(void)
|
||||
{
|
||||
return i2c_add_driver(&atxp1_driver);
|
||||
};
|
||||
|
||||
static void __exit atxp1_exit(void)
|
||||
{
|
||||
i2c_del_driver(&atxp1_driver);
|
||||
};
|
||||
|
||||
module_init(atxp1_init);
|
||||
module_exit(atxp1_exit);
|
||||
module_i2c_driver(atxp1_driver);
|
||||
|
@ -58,8 +58,8 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
|
||||
#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1)
|
||||
#define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
|
||||
|
||||
#define TO_PHYS_ID(cpu) cpu_data(cpu).phys_proc_id
|
||||
#define TO_CORE_ID(cpu) cpu_data(cpu).cpu_core_id
|
||||
#define TO_PHYS_ID(cpu) (cpu_data(cpu).phys_proc_id)
|
||||
#define TO_CORE_ID(cpu) (cpu_data(cpu).cpu_core_id)
|
||||
#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO)
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,24 @@
|
||||
/*
|
||||
ds1621.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Christian W. Zuckschwerdt <zany@triq.net> 2000-11-23
|
||||
based on lm75.c by Frodo Looijaard <frodol@dds.nl>
|
||||
Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
|
||||
the help of Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* ds1621.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Christian W. Zuckschwerdt <zany@triq.net> 2000-11-23
|
||||
* based on lm75.c by Frodo Looijaard <frodol@dds.nl>
|
||||
* Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
|
||||
* the help of Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -155,10 +155,15 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ds1621_data *data = i2c_get_clientdata(client);
|
||||
u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[attr->index] = val;
|
||||
data->temp[attr->index] = LM75_TEMP_TO_REG(val);
|
||||
i2c_smbus_write_word_swapped(client, DS1621_REG_TEMP[attr->index],
|
||||
data->temp[attr->index]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
@ -217,9 +222,12 @@ static int ds1621_detect(struct i2c_client *client,
|
||||
| I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||
return -ENODEV;
|
||||
|
||||
/* Now, we do the remaining detection. It is lousy. */
|
||||
/* The NVB bit should be low if no EEPROM write has been requested
|
||||
during the latest 10ms, which is highly improbable in our case. */
|
||||
/*
|
||||
* Now, we do the remaining detection. It is lousy.
|
||||
*
|
||||
* The NVB bit should be low if no EEPROM write has been requested
|
||||
* during the latest 10ms, which is highly improbable in our case.
|
||||
*/
|
||||
conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
|
||||
if (conf < 0 || conf & DS1621_REG_CONFIG_NVB)
|
||||
return -ENODEV;
|
||||
@ -254,7 +262,8 @@ static int ds1621_probe(struct i2c_client *client,
|
||||
ds1621_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &ds1621_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
@ -305,20 +314,8 @@ static struct i2c_driver ds1621_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init ds1621_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ds1621_driver);
|
||||
}
|
||||
|
||||
static void __exit ds1621_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ds1621_driver);
|
||||
}
|
||||
|
||||
module_i2c_driver(ds1621_driver);
|
||||
|
||||
MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>");
|
||||
MODULE_DESCRIPTION("DS1621 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ds1621_init);
|
||||
module_exit(ds1621_exit);
|
||||
|
@ -297,19 +297,8 @@ static struct i2c_driver ds620_driver = {
|
||||
.id_table = ds620_id,
|
||||
};
|
||||
|
||||
static int __init ds620_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ds620_driver);
|
||||
}
|
||||
|
||||
static void __exit ds620_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ds620_driver);
|
||||
}
|
||||
module_i2c_driver(ds620_driver);
|
||||
|
||||
MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
|
||||
MODULE_DESCRIPTION("DS620 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ds620_init);
|
||||
module_exit(ds620_exit);
|
||||
|
@ -41,8 +41,10 @@
|
||||
struct thermal_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex mutex;
|
||||
/* Cache the hyst value so we don't keep re-reading it. In theory
|
||||
we could cache it forever as nobody else should be writing it. */
|
||||
/*
|
||||
* Cache the hyst value so we don't keep re-reading it. In theory
|
||||
* we could cache it forever as nobody else should be writing it.
|
||||
*/
|
||||
u8 cached_hyst;
|
||||
unsigned long hyst_valid;
|
||||
};
|
||||
@ -283,8 +285,10 @@ static int emc1403_detect(struct i2c_client *client,
|
||||
case 0x23:
|
||||
strlcpy(info->type, "emc1423", I2C_NAME_SIZE);
|
||||
break;
|
||||
/* Note: 0x25 is the 1404 which is very similar and this
|
||||
driver could be extended */
|
||||
/*
|
||||
* Note: 0x25 is the 1404 which is very similar and this
|
||||
* driver could be extended
|
||||
*/
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -366,18 +370,7 @@ static struct i2c_driver sensor_emc1403 = {
|
||||
.address_list = emc1403_address_list,
|
||||
};
|
||||
|
||||
static int __init sensor_emc1403_init(void)
|
||||
{
|
||||
return i2c_add_driver(&sensor_emc1403);
|
||||
}
|
||||
|
||||
static void __exit sensor_emc1403_exit(void)
|
||||
{
|
||||
i2c_del_driver(&sensor_emc1403);
|
||||
}
|
||||
|
||||
module_init(sensor_emc1403_init);
|
||||
module_exit(sensor_emc1403_exit);
|
||||
module_i2c_driver(sensor_emc1403);
|
||||
|
||||
MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
|
||||
MODULE_DESCRIPTION("emc1403 Thermal Driver");
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
emc2103.c - Support for SMSC EMC2103
|
||||
Copyright (c) 2010 SMSC
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* emc2103.c - Support for SMSC EMC2103
|
||||
* Copyright (c) 2010 SMSC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -48,12 +48,14 @@ static const u8 REG_TEMP_MAX[4] = { 0x34, 0x30, 0x31, 0x32 };
|
||||
/* equation 4 from datasheet: rpm = (3932160 * multipler) / count */
|
||||
#define FAN_RPM_FACTOR 3932160
|
||||
|
||||
/* 2103-2 and 2103-4's 3rd temperature sensor can be connected to two diodes
|
||||
/*
|
||||
* 2103-2 and 2103-4's 3rd temperature sensor can be connected to two diodes
|
||||
* in anti-parallel mode, and in this configuration both can be read
|
||||
* independently (so we have 4 temperature inputs). The device can't
|
||||
* detect if it's connected in this mode, so we have to manually enable
|
||||
* it. Default is to leave the device in the state it's already in (-1).
|
||||
* This parameter allows APD mode to be optionally forced on or off */
|
||||
* This parameter allows APD mode to be optionally forced on or off
|
||||
*/
|
||||
static int apd = -1;
|
||||
module_param(apd, bint, 0);
|
||||
MODULE_PARM_DESC(init, "Set to zero to disable anti-parallel diode mode");
|
||||
@ -302,10 +304,12 @@ show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
|
||||
return sprintf(buf, "%d\n", fan_div);
|
||||
}
|
||||
|
||||
/* Note: we also update the fan target here, because its value is
|
||||
determined in part by the fan clock divider. This follows the principle
|
||||
of least surprise; the user doesn't expect the fan target to change just
|
||||
because the divider changed. */
|
||||
/*
|
||||
* Note: we also update the fan target here, because its value is
|
||||
* determined in part by the fan clock divider. This follows the principle
|
||||
* of least surprise; the user doesn't expect the fan target to change just
|
||||
* because the divider changed.
|
||||
*/
|
||||
static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
@ -722,19 +726,8 @@ static struct i2c_driver emc2103_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init sensors_emc2103_init(void)
|
||||
{
|
||||
return i2c_add_driver(&emc2103_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_emc2103_exit(void)
|
||||
{
|
||||
i2c_del_driver(&emc2103_driver);
|
||||
}
|
||||
module_i2c_driver(emc2103_driver);
|
||||
|
||||
MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>");
|
||||
MODULE_DESCRIPTION("SMSC EMC2103 hwmon driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_emc2103_init);
|
||||
module_exit(sensors_emc2103_exit);
|
||||
|
@ -552,17 +552,7 @@ static struct i2c_driver emc6w201_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init sensors_emc6w201_init(void)
|
||||
{
|
||||
return i2c_add_driver(&emc6w201_driver);
|
||||
}
|
||||
module_init(sensors_emc6w201_init);
|
||||
|
||||
static void __exit sensors_emc6w201_exit(void)
|
||||
{
|
||||
i2c_del_driver(&emc6w201_driver);
|
||||
}
|
||||
module_exit(sensors_emc6w201_exit);
|
||||
module_i2c_driver(emc6w201_driver);
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("SMSC EMC6W201 hardware monitoring driver");
|
||||
|
@ -202,7 +202,7 @@ struct f71805f_sio_data {
|
||||
|
||||
static inline long in_from_reg(u8 reg)
|
||||
{
|
||||
return (reg * 8);
|
||||
return reg * 8;
|
||||
}
|
||||
|
||||
/* The 2 least significant bits are not used */
|
||||
@ -212,13 +212,13 @@ static inline u8 in_to_reg(long val)
|
||||
return 0;
|
||||
if (val >= 2016)
|
||||
return 0xfc;
|
||||
return (((val + 16) / 32) << 2);
|
||||
return ((val + 16) / 32) << 2;
|
||||
}
|
||||
|
||||
/* in0 is downscaled by a factor 2 internally */
|
||||
static inline long in0_from_reg(u8 reg)
|
||||
{
|
||||
return (reg * 16);
|
||||
return reg * 16;
|
||||
}
|
||||
|
||||
static inline u8 in0_to_reg(long val)
|
||||
@ -227,7 +227,7 @@ static inline u8 in0_to_reg(long val)
|
||||
return 0;
|
||||
if (val >= 4032)
|
||||
return 0xfc;
|
||||
return (((val + 32) / 64) << 2);
|
||||
return ((val + 32) / 64) << 2;
|
||||
}
|
||||
|
||||
/* The 4 most significant bits are not used */
|
||||
@ -236,17 +236,19 @@ static inline long fan_from_reg(u16 reg)
|
||||
reg &= 0xfff;
|
||||
if (!reg || reg == 0xfff)
|
||||
return 0;
|
||||
return (1500000 / reg);
|
||||
return 1500000 / reg;
|
||||
}
|
||||
|
||||
static inline u16 fan_to_reg(long rpm)
|
||||
{
|
||||
/* If the low limit is set below what the chip can measure,
|
||||
store the largest possible 12-bit value in the registers,
|
||||
so that no alarm will ever trigger. */
|
||||
/*
|
||||
* If the low limit is set below what the chip can measure,
|
||||
* store the largest possible 12-bit value in the registers,
|
||||
* so that no alarm will ever trigger.
|
||||
*/
|
||||
if (rpm < 367)
|
||||
return 0xfff;
|
||||
return (1500000 / rpm);
|
||||
return 1500000 / rpm;
|
||||
}
|
||||
|
||||
static inline unsigned long pwm_freq_from_reg(u8 reg)
|
||||
@ -278,7 +280,7 @@ static inline int pwm_mode_from_reg(u8 reg)
|
||||
|
||||
static inline long temp_from_reg(u8 reg)
|
||||
{
|
||||
return (reg * 1000);
|
||||
return reg * 1000;
|
||||
}
|
||||
|
||||
static inline u8 temp_to_reg(long val)
|
||||
@ -308,9 +310,11 @@ static void f71805f_write8(struct f71805f_data *data, u8 reg, u8 val)
|
||||
outb(val, data->addr + DATA_REG_OFFSET);
|
||||
}
|
||||
|
||||
/* It is important to read the MSB first, because doing so latches the
|
||||
value of the LSB, so we are sure both bytes belong to the same value.
|
||||
Must be called with data->update_lock held, except during initialization */
|
||||
/*
|
||||
* It is important to read the MSB first, because doing so latches the
|
||||
* value of the LSB, so we are sure both bytes belong to the same value.
|
||||
* Must be called with data->update_lock held, except during initialization
|
||||
*/
|
||||
static u16 f71805f_read16(struct f71805f_data *data, u8 reg)
|
||||
{
|
||||
u16 val;
|
||||
@ -455,7 +459,12 @@ static ssize_t set_in0_max(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_high[nr] = in0_to_reg(val);
|
||||
@ -471,7 +480,12 @@ static ssize_t set_in0_min(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_low[nr] = in0_to_reg(val);
|
||||
@ -517,7 +531,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_high[nr] = in_to_reg(val);
|
||||
@ -533,7 +552,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_low[nr] = in_to_reg(val);
|
||||
@ -579,7 +603,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_low[nr] = fan_to_reg(val);
|
||||
@ -595,7 +624,12 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_target[nr] = fan_to_reg(val);
|
||||
@ -664,7 +698,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (val > 255)
|
||||
return -EINVAL;
|
||||
@ -685,8 +724,13 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
u8 reg;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (val < 1 || val > 3)
|
||||
return -EINVAL;
|
||||
@ -730,7 +774,12 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm_freq[nr] = pwm_freq_to_reg(val);
|
||||
@ -761,7 +810,12 @@ static ssize_t set_pwm_auto_point_temp(struct device *dev,
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
int pwmnr = attr->nr;
|
||||
int apnr = attr->index;
|
||||
unsigned long val = simple_strtol(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val);
|
||||
@ -793,7 +847,12 @@ static ssize_t set_pwm_auto_point_fan(struct device *dev,
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
int pwmnr = attr->nr;
|
||||
int apnr = attr->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val);
|
||||
@ -851,7 +910,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_high[nr] = temp_to_reg(val);
|
||||
@ -867,7 +931,12 @@ static ssize_t set_temp_hyst(struct device *dev, struct device_attribute
|
||||
struct f71805f_data *data = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int nr = attr->index;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_hyst[nr] = temp_to_reg(val);
|
||||
@ -1010,8 +1079,10 @@ static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp_hyst, set_temp_hyst, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2);
|
||||
|
||||
/* pwm (value) files are created read-only, write permission is
|
||||
then added or removed dynamically as needed */
|
||||
/*
|
||||
* pwm (value) files are created read-only, write permission is
|
||||
* then added or removed dynamically as needed
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, show_pwm, set_pwm, 0);
|
||||
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
|
||||
show_pwm_enable, set_pwm_enable, 0);
|
||||
@ -1246,8 +1317,10 @@ static const struct attribute_group f71805f_group_optin[4] = {
|
||||
{ .attrs = f71805f_attributes_optin[3] },
|
||||
};
|
||||
|
||||
/* We don't include pwm_freq files in the arrays above, because they must be
|
||||
created conditionally (only if pwm_mode is 1 == PWM) */
|
||||
/*
|
||||
* We don't include pwm_freq files in the arrays above, because they must be
|
||||
* created conditionally (only if pwm_mode is 1 == PWM)
|
||||
*/
|
||||
static struct attribute *f71805f_attributes_pwm_freq[] = {
|
||||
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
|
||||
@ -1282,13 +1355,17 @@ static void __devinit f71805f_init_device(struct f71805f_data *data)
|
||||
f71805f_write8(data, F71805F_REG_START, (reg | 0x01) & ~0x40);
|
||||
}
|
||||
|
||||
/* Fan monitoring can be disabled. If it is, we won't be polling
|
||||
the register values, and won't create the related sysfs files. */
|
||||
/*
|
||||
* Fan monitoring can be disabled. If it is, we won't be polling
|
||||
* the register values, and won't create the related sysfs files.
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->fan_ctrl[i] = f71805f_read8(data,
|
||||
F71805F_REG_FAN_CTRL(i));
|
||||
/* Clear latch full bit, else "speed mode" fan speed control
|
||||
doesn't work */
|
||||
/*
|
||||
* Clear latch full bit, else "speed mode" fan speed control
|
||||
* doesn't work
|
||||
*/
|
||||
if (data->fan_ctrl[i] & FAN_CTRL_LATCH_FULL) {
|
||||
data->fan_ctrl[i] &= ~FAN_CTRL_LATCH_FULL;
|
||||
f71805f_write8(data, F71805F_REG_FAN_CTRL(i),
|
||||
@ -1304,12 +1381,13 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int i, err;
|
||||
|
||||
static const char *names[] = {
|
||||
static const char * const names[] = {
|
||||
"f71805f",
|
||||
"f71872f",
|
||||
};
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) {
|
||||
data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
err = -ENOMEM;
|
||||
pr_err("Out of memory\n");
|
||||
goto exit;
|
||||
@ -1347,40 +1425,47 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
|
||||
f71805f_init_device(data);
|
||||
|
||||
/* Register sysfs interface files */
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group)))
|
||||
err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group);
|
||||
if (err)
|
||||
goto exit_release_region;
|
||||
if (data->has_in & (1 << 4)) { /* in4 */
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&f71805f_group_optin[0])))
|
||||
err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&f71805f_group_optin[0]);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
if (data->has_in & (1 << 8)) { /* in8 */
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&f71805f_group_optin[1])))
|
||||
err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&f71805f_group_optin[1]);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
if (data->has_in & (1 << 9)) { /* in9 (F71872F/FG only) */
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&f71805f_group_optin[2])))
|
||||
err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&f71805f_group_optin[2]);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
if (data->has_in & (1 << 10)) { /* in9 (F71872F/FG only) */
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&f71805f_group_optin[3])))
|
||||
err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&f71805f_group_optin[3]);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* If control mode is PWM, create pwm_freq file */
|
||||
if (!(data->fan_ctrl[i] & FAN_CTRL_DC_MODE)) {
|
||||
if ((err = sysfs_create_file(&pdev->dev.kobj,
|
||||
f71805f_attributes_pwm_freq[i])))
|
||||
err = sysfs_create_file(&pdev->dev.kobj,
|
||||
f71805f_attributes_pwm_freq[i]);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
/* If PWM is in manual mode, add write permission */
|
||||
if (data->fan_ctrl[i] & FAN_CTRL_MODE_MANUAL) {
|
||||
if ((err = sysfs_chmod_file(&pdev->dev.kobj,
|
||||
err = sysfs_chmod_file(&pdev->dev.kobj,
|
||||
f71805f_attr_pwm[i],
|
||||
S_IRUGO | S_IWUSR))) {
|
||||
S_IRUGO | S_IWUSR);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "chmod +w pwm%d failed\n",
|
||||
i + 1);
|
||||
goto exit_remove_files;
|
||||
@ -1495,7 +1580,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address,
|
||||
int err = -ENODEV;
|
||||
u16 devid;
|
||||
|
||||
static const char *names[] = {
|
||||
static const char * const names[] = {
|
||||
"F71805F/FG",
|
||||
"F71872F/FG or F71806F/FG",
|
||||
};
|
||||
|
@ -112,7 +112,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
|
||||
enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71869a, f71882fg,
|
||||
f71889fg, f71889ed, f71889a, f8000, f81865f };
|
||||
|
||||
static const char *f71882fg_names[] = {
|
||||
static const char *const f71882fg_names[] = {
|
||||
"f71808e",
|
||||
"f71808a",
|
||||
"f71858fg",
|
||||
@ -252,9 +252,11 @@ struct f71882fg_data {
|
||||
u16 fan_full_speed[4];
|
||||
u8 fan_status;
|
||||
u8 fan_beep;
|
||||
/* Note: all models have max 3 temperature channels, but on some
|
||||
they are addressed as 0-2 and on others as 1-3, so for coding
|
||||
convenience we reserve space for 4 channels */
|
||||
/*
|
||||
* Note: all models have max 3 temperature channels, but on some
|
||||
* they are addressed as 0-2 and on others as 1-3, so for coding
|
||||
* convenience we reserve space for 4 channels
|
||||
*/
|
||||
u16 temp[4];
|
||||
u8 temp_ovt[4];
|
||||
u8 temp_high[4];
|
||||
@ -376,8 +378,10 @@ static struct platform_driver f71882fg_driver = {
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
/* Temp attr for the f71858fg, the f71858fg is special as it has its
|
||||
temperature indexes start at 0 (the others start at 1) */
|
||||
/*
|
||||
* Temp attr for the f71858fg, the f71858fg is special as it has its
|
||||
* temperature indexes start at 0 (the others start at 1)
|
||||
*/
|
||||
static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
|
||||
SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
|
||||
SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
|
||||
@ -424,9 +428,11 @@ static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
|
||||
store_temp_max, 0, 1),
|
||||
SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
|
||||
store_temp_max_hyst, 0, 1),
|
||||
/* Should really be temp1_max_alarm, but older versions did not handle
|
||||
the max and crit alarms separately and lm_sensors v2 depends on the
|
||||
presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
|
||||
/*
|
||||
* Should really be temp1_max_alarm, but older versions did not handle
|
||||
* the max and crit alarms separately and lm_sensors v2 depends on the
|
||||
* presence of temp#_alarm files. The same goes for temp2/3 _alarm.
|
||||
*/
|
||||
SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
|
||||
SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
|
||||
store_temp_crit, 0, 1),
|
||||
@ -485,10 +491,11 @@ static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
|
||||
store_temp_beep, 0, 7),
|
||||
} };
|
||||
|
||||
/* Temp attr for the f8000
|
||||
Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
|
||||
is used as hysteresis value to clear alarms
|
||||
Also like the f71858fg its temperature indexes start at 0
|
||||
/*
|
||||
* Temp attr for the f8000
|
||||
* Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
|
||||
* is used as hysteresis value to clear alarms
|
||||
* Also like the f71858fg its temperature indexes start at 0
|
||||
*/
|
||||
static struct sensor_device_attribute_2 f8000_temp_attr[] = {
|
||||
SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
|
||||
@ -603,8 +610,10 @@ static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
|
||||
store_fan_beep, 0, 3),
|
||||
};
|
||||
|
||||
/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
|
||||
standard models */
|
||||
/*
|
||||
* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
|
||||
* standard models
|
||||
*/
|
||||
static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[3][7] = { {
|
||||
SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
|
||||
show_pwm_auto_point_channel,
|
||||
@ -673,9 +682,11 @@ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[3][7] = { {
|
||||
show_pwm_auto_point_temp_hyst, NULL, 3, 2),
|
||||
} };
|
||||
|
||||
/* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
|
||||
pwm setting when the temperature is above the pwmX_auto_point1_temp can be
|
||||
programmed instead of being hardcoded to 0xff */
|
||||
/*
|
||||
* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
|
||||
* pwm setting when the temperature is above the pwmX_auto_point1_temp can be
|
||||
* programmed instead of being hardcoded to 0xff
|
||||
*/
|
||||
static struct sensor_device_attribute_2 f71869_auto_pwm_attr[3][8] = { {
|
||||
SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
|
||||
show_pwm_auto_point_channel,
|
||||
@ -925,9 +936,11 @@ static struct sensor_device_attribute_2 f8000_fan_attr[] = {
|
||||
SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
|
||||
};
|
||||
|
||||
/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
|
||||
Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
|
||||
F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
|
||||
/*
|
||||
* PWM attr for the f8000, zones mapped to temp instead of to pwm!
|
||||
* Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
|
||||
* F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0
|
||||
*/
|
||||
static struct sensor_device_attribute_2 f8000_auto_pwm_attr[3][14] = { {
|
||||
SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
|
||||
show_pwm_auto_point_channel,
|
||||
@ -2295,8 +2308,10 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
|
||||
data->temp_config =
|
||||
f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
|
||||
if (data->temp_config & 0x10)
|
||||
/* The f71858fg temperature alarms behave as
|
||||
the f8000 alarms in this mode */
|
||||
/*
|
||||
* The f71858fg temperature alarms behave as
|
||||
* the f8000 alarms in this mode
|
||||
*/
|
||||
err = f71882fg_create_sysfs_files(pdev,
|
||||
f8000_temp_attr,
|
||||
ARRAY_SIZE(f8000_temp_attr));
|
||||
|
@ -917,19 +917,8 @@ static int f75375_detect(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init sensors_f75375_init(void)
|
||||
{
|
||||
return i2c_add_driver(&f75375_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_f75375_exit(void)
|
||||
{
|
||||
i2c_del_driver(&f75375_driver);
|
||||
}
|
||||
module_i2c_driver(f75375_driver);
|
||||
|
||||
MODULE_AUTHOR("Riku Voipio");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("F75373/F75375/F75387 hardware monitoring driver");
|
||||
|
||||
module_init(sensors_f75375_init);
|
||||
module_exit(sensors_f75375_exit);
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* fschmd.c
|
||||
/*
|
||||
* fschmd.c
|
||||
*
|
||||
* Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
@ -76,12 +77,12 @@ enum chips { fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl };
|
||||
#define FSCHMD_CONTROL_ALERT_LED 0x01
|
||||
|
||||
/* watchdog */
|
||||
static const u8 FSCHMD_REG_WDOG_CONTROL[7] =
|
||||
{ 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
|
||||
static const u8 FSCHMD_REG_WDOG_STATE[7] =
|
||||
{ 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
|
||||
static const u8 FSCHMD_REG_WDOG_PRESET[7] =
|
||||
{ 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
|
||||
static const u8 FSCHMD_REG_WDOG_CONTROL[7] = {
|
||||
0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
|
||||
static const u8 FSCHMD_REG_WDOG_STATE[7] = {
|
||||
0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
|
||||
static const u8 FSCHMD_REG_WDOG_PRESET[7] = {
|
||||
0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
|
||||
|
||||
#define FSCHMD_WDOG_CONTROL_TRIGGER 0x10
|
||||
#define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */
|
||||
@ -103,10 +104,12 @@ static const u8 FSCHMD_REG_VOLT[7][6] = {
|
||||
|
||||
static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 };
|
||||
|
||||
/* minimum pwm at which the fan is driven (pwm can by increased depending on
|
||||
the temp. Notice that for the scy some fans share there minimum speed.
|
||||
Also notice that with the scy the sensor order is different than with the
|
||||
other chips, this order was in the 2.4 driver and kept for consistency. */
|
||||
/*
|
||||
* minimum pwm at which the fan is driven (pwm can by increased depending on
|
||||
* the temp. Notice that for the scy some fans share there minimum speed.
|
||||
* Also notice that with the scy the sensor order is different than with the
|
||||
* other chips, this order was in the 2.4 driver and kept for consistency.
|
||||
*/
|
||||
static const u8 FSCHMD_REG_FAN_MIN[7][7] = {
|
||||
{ 0x55, 0x65 }, /* pos */
|
||||
{ 0x55, 0x65, 0xb5 }, /* her */
|
||||
@ -182,11 +185,13 @@ static const u8 FSCHMD_REG_TEMP_STATE[7][11] = {
|
||||
0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
|
||||
};
|
||||
|
||||
/* temperature high limit registers, FSC does not document these. Proven to be
|
||||
there with field testing on the fscher and fschrc, already supported / used
|
||||
in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
|
||||
at these addresses, but doesn't want to confirm they are the same as with
|
||||
the fscher?? */
|
||||
/*
|
||||
* temperature high limit registers, FSC does not document these. Proven to be
|
||||
* there with field testing on the fscher and fschrc, already supported / used
|
||||
* in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
|
||||
* at these addresses, but doesn't want to confirm they are the same as with
|
||||
* the fscher??
|
||||
*/
|
||||
static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
|
||||
{ 0, 0, 0 }, /* pos */
|
||||
{ 0x76, 0x86, 0x96 }, /* her */
|
||||
@ -198,13 +203,15 @@ static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
|
||||
0xba, 0xca, 0xda, 0xea, 0xfa },
|
||||
};
|
||||
|
||||
/* These were found through experimenting with an fscher, currently they are
|
||||
not used, but we keep them around for future reference.
|
||||
On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc),
|
||||
AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence
|
||||
the fan speed.
|
||||
static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
|
||||
static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
|
||||
/*
|
||||
* These were found through experimenting with an fscher, currently they are
|
||||
* not used, but we keep them around for future reference.
|
||||
* On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc),
|
||||
* AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence
|
||||
* the fan speed.
|
||||
* static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
|
||||
* static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 };
|
||||
*/
|
||||
|
||||
static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 };
|
||||
|
||||
@ -290,24 +297,30 @@ struct fschmd_data {
|
||||
u8 fan_ripple[7]; /* divider for rps */
|
||||
};
|
||||
|
||||
/* Global variables to hold information read from special DMI tables, which are
|
||||
available on FSC machines with an fscher or later chip. There is no need to
|
||||
protect these with a lock as they are only modified from our attach function
|
||||
which always gets called with the i2c-core lock held and never accessed
|
||||
before the attach function is done with them. */
|
||||
/*
|
||||
* Global variables to hold information read from special DMI tables, which are
|
||||
* available on FSC machines with an fscher or later chip. There is no need to
|
||||
* protect these with a lock as they are only modified from our attach function
|
||||
* which always gets called with the i2c-core lock held and never accessed
|
||||
* before the attach function is done with them.
|
||||
*/
|
||||
static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
|
||||
static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
|
||||
static int dmi_vref = -1;
|
||||
|
||||
/* Somewhat ugly :( global data pointer list with all fschmd devices, so that
|
||||
we can find our device data as when using misc_register there is no other
|
||||
method to get to ones device data from the open fop. */
|
||||
/*
|
||||
* Somewhat ugly :( global data pointer list with all fschmd devices, so that
|
||||
* we can find our device data as when using misc_register there is no other
|
||||
* method to get to ones device data from the open fop.
|
||||
*/
|
||||
static LIST_HEAD(watchdog_data_list);
|
||||
/* Note this lock not only protect list access, but also data.kref access */
|
||||
static DEFINE_MUTEX(watchdog_data_mutex);
|
||||
|
||||
/* Release our data struct when we're detached from the i2c client *and* all
|
||||
references to our watchdog device are released */
|
||||
/*
|
||||
* Release our data struct when we're detached from the i2c client *and* all
|
||||
* references to our watchdog device are released
|
||||
*/
|
||||
static void fschmd_release_resources(struct kref *ref)
|
||||
{
|
||||
struct fschmd_data *data = container_of(ref, struct fschmd_data, kref);
|
||||
@ -359,9 +372,14 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = dev_get_drvdata(dev);
|
||||
long v = simple_strtol(buf, NULL, 10) / 1000;
|
||||
long v;
|
||||
int err;
|
||||
|
||||
v = SENSORS_LIMIT(v, -128, 127) + 128;
|
||||
err = kstrtol(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
v = SENSORS_LIMIT(v / 1000, -128, 127) + 128;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||
@ -427,12 +445,23 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = dev_get_drvdata(dev);
|
||||
/* supported values: 2, 4, 8 */
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long v;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (v) {
|
||||
case 2: v = 1; break;
|
||||
case 4: v = 2; break;
|
||||
case 8: v = 3; break;
|
||||
case 2:
|
||||
v = 1;
|
||||
break;
|
||||
case 4:
|
||||
v = 2;
|
||||
break;
|
||||
case 8:
|
||||
v = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "fan_div value %lu not supported. "
|
||||
"Choose one of 2, 4 or 8!\n", v);
|
||||
@ -502,7 +531,12 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = dev_get_drvdata(dev);
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long v;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
|
||||
if (v || data->kind == fscsyl) {
|
||||
@ -522,8 +556,10 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
|
||||
}
|
||||
|
||||
|
||||
/* The FSC hwmon family has the ability to force an attached alert led to flash
|
||||
from software, we export this as an alert_led sysfs attr */
|
||||
/*
|
||||
* The FSC hwmon family has the ability to force an attached alert led to flash
|
||||
* from software, we export this as an alert_led sysfs attr
|
||||
*/
|
||||
static ssize_t show_alert_led(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
@ -540,7 +576,12 @@ static ssize_t store_alert_led(struct device *dev,
|
||||
{
|
||||
u8 reg;
|
||||
struct fschmd_data *data = dev_get_drvdata(dev);
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long v;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@ -754,8 +795,10 @@ static int watchdog_stop(struct fschmd_data *data)
|
||||
}
|
||||
|
||||
data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
|
||||
/* Don't store the stop flag in our watchdog control register copy, as
|
||||
its a write only bit (read always returns 0) */
|
||||
/*
|
||||
* Don't store the stop flag in our watchdog control register copy, as
|
||||
* its a write only bit (read always returns 0)
|
||||
*/
|
||||
i2c_smbus_write_byte_data(data->client,
|
||||
FSCHMD_REG_WDOG_CONTROL[data->kind],
|
||||
data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
|
||||
@ -769,10 +812,12 @@ static int watchdog_open(struct inode *inode, struct file *filp)
|
||||
struct fschmd_data *pos, *data = NULL;
|
||||
int watchdog_is_open;
|
||||
|
||||
/* We get called from drivers/char/misc.c with misc_mtx hold, and we
|
||||
call misc_register() from fschmd_probe() with watchdog_data_mutex
|
||||
hold, as misc_register() takes the misc_mtx lock, this is a possible
|
||||
deadlock, so we use mutex_trylock here. */
|
||||
/*
|
||||
* We get called from drivers/char/misc.c with misc_mtx hold, and we
|
||||
* call misc_register() from fschmd_probe() with watchdog_data_mutex
|
||||
* hold, as misc_register() takes the misc_mtx lock, this is a possible
|
||||
* deadlock, so we use mutex_trylock here.
|
||||
*/
|
||||
if (!mutex_trylock(&watchdog_data_mutex))
|
||||
return -ERESTARTSYS;
|
||||
list_for_each_entry(pos, &watchdog_data_list, list) {
|
||||
@ -847,7 +892,8 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf,
|
||||
return count;
|
||||
}
|
||||
|
||||
static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
static long watchdog_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct watchdog_info ident = {
|
||||
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
|
||||
@ -930,30 +976,38 @@ static const struct file_operations watchdog_fops = {
|
||||
* Detect, register, unregister and update device functions
|
||||
*/
|
||||
|
||||
/* DMI decode routine to read voltage scaling factors from special DMI tables,
|
||||
which are available on FSC machines with an fscher or later chip. */
|
||||
/*
|
||||
* DMI decode routine to read voltage scaling factors from special DMI tables,
|
||||
* which are available on FSC machines with an fscher or later chip.
|
||||
*/
|
||||
static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
|
||||
{
|
||||
int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
|
||||
|
||||
/* dmi code ugliness, we get passed the address of the contents of
|
||||
a complete DMI record, but in the form of a dmi_header pointer, in
|
||||
reality this address holds header->length bytes of which the header
|
||||
are the first 4 bytes */
|
||||
/*
|
||||
* dmi code ugliness, we get passed the address of the contents of
|
||||
* a complete DMI record, but in the form of a dmi_header pointer, in
|
||||
* reality this address holds header->length bytes of which the header
|
||||
* are the first 4 bytes
|
||||
*/
|
||||
u8 *dmi_data = (u8 *)header;
|
||||
|
||||
/* We are looking for OEM-specific type 185 */
|
||||
if (header->type != 185)
|
||||
return;
|
||||
|
||||
/* we are looking for what Siemens calls "subtype" 19, the subtype
|
||||
is stored in byte 5 of the dmi block */
|
||||
/*
|
||||
* we are looking for what Siemens calls "subtype" 19, the subtype
|
||||
* is stored in byte 5 of the dmi block
|
||||
*/
|
||||
if (header->length < 5 || dmi_data[4] != 19)
|
||||
return;
|
||||
|
||||
/* After the subtype comes 1 unknown byte and then blocks of 5 bytes,
|
||||
consisting of what Siemens calls an "Entity" number, followed by
|
||||
2 16-bit words in LSB first order */
|
||||
/*
|
||||
* After the subtype comes 1 unknown byte and then blocks of 5 bytes,
|
||||
* consisting of what Siemens calls an "Entity" number, followed by
|
||||
* 2 16-bit words in LSB first order
|
||||
*/
|
||||
for (i = 6; (i + 4) < header->length; i += 5) {
|
||||
/* entity 1 - 3: voltage multiplier and offset */
|
||||
if (dmi_data[i] >= 1 && dmi_data[i] <= 3) {
|
||||
@ -988,9 +1042,11 @@ static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
|
||||
dmi_mult[i] = mult[i] * 10;
|
||||
dmi_offset[i] = offset[i] * 10;
|
||||
}
|
||||
/* According to the docs there should be separate dmi entries
|
||||
for the mult's and offsets of in3-5 of the syl, but on
|
||||
my test machine these are not present */
|
||||
/*
|
||||
* According to the docs there should be separate dmi entries
|
||||
* for the mult's and offsets of in3-5 of the syl, but on
|
||||
* my test machine these are not present
|
||||
*/
|
||||
dmi_mult[3] = dmi_mult[2];
|
||||
dmi_mult[4] = dmi_mult[1];
|
||||
dmi_mult[5] = dmi_mult[2];
|
||||
@ -1058,15 +1114,19 @@ static int fschmd_probe(struct i2c_client *client,
|
||||
mutex_init(&data->watchdog_lock);
|
||||
INIT_LIST_HEAD(&data->list);
|
||||
kref_init(&data->kref);
|
||||
/* Store client pointer in our data struct for watchdog usage
|
||||
(where the client is found through a data ptr instead of the
|
||||
otherway around) */
|
||||
/*
|
||||
* Store client pointer in our data struct for watchdog usage
|
||||
* (where the client is found through a data ptr instead of the
|
||||
* otherway around)
|
||||
*/
|
||||
data->client = client;
|
||||
data->kind = kind;
|
||||
|
||||
if (kind == fscpos) {
|
||||
/* The Poseidon has hardwired temp limits, fill these
|
||||
in for the alarm resetting code */
|
||||
/*
|
||||
* The Poseidon has hardwired temp limits, fill these
|
||||
* in for the alarm resetting code
|
||||
*/
|
||||
data->temp_max[0] = 70 + 128;
|
||||
data->temp_max[1] = 50 + 128;
|
||||
data->temp_max[2] = 50 + 128;
|
||||
@ -1157,9 +1217,11 @@ static int fschmd_probe(struct i2c_client *client,
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
/* We take the data_mutex lock early so that watchdog_open() cannot
|
||||
run when misc_register() has completed, but we've not yet added
|
||||
our data to the watchdog_data_list (and set the default timeout) */
|
||||
/*
|
||||
* We take the data_mutex lock early so that watchdog_open() cannot
|
||||
* run when misc_register() has completed, but we've not yet added
|
||||
* our data to the watchdog_data_list (and set the default timeout)
|
||||
*/
|
||||
mutex_lock(&watchdog_data_mutex);
|
||||
for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
|
||||
/* Register our watchdog part */
|
||||
@ -1225,8 +1287,10 @@ static int fschmd_remove(struct i2c_client *client)
|
||||
mutex_unlock(&data->watchdog_lock);
|
||||
}
|
||||
|
||||
/* Check if registered in case we're called from fschmd_detect
|
||||
to cleanup after an error */
|
||||
/*
|
||||
* Check if registered in case we're called from fschmd_detect
|
||||
* to cleanup after an error
|
||||
*/
|
||||
if (data->hwmon_dev)
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
@ -1269,8 +1333,10 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
|
||||
client,
|
||||
FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
|
||||
|
||||
/* reset alarm if the alarm condition is gone,
|
||||
the chip doesn't do this itself */
|
||||
/*
|
||||
* reset alarm if the alarm condition is gone,
|
||||
* the chip doesn't do this itself
|
||||
*/
|
||||
if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
|
||||
FSCHMD_TEMP_ALARM_MASK &&
|
||||
data->temp_act[i] < data->temp_max[i])
|
||||
@ -1314,20 +1380,9 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init fschmd_init(void)
|
||||
{
|
||||
return i2c_add_driver(&fschmd_driver);
|
||||
}
|
||||
|
||||
static void __exit fschmd_exit(void)
|
||||
{
|
||||
i2c_del_driver(&fschmd_driver);
|
||||
}
|
||||
module_i2c_driver(fschmd_driver);
|
||||
|
||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
||||
MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
|
||||
"and Syleus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(fschmd_init);
|
||||
module_exit(fschmd_exit);
|
||||
|
@ -1,16 +1,16 @@
|
||||
/*
|
||||
g760a - Driver for the Global Mixed-mode Technology Inc. G760A
|
||||
fan speed PWM controller chip
|
||||
|
||||
Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
|
||||
Complete datasheet is available at GMT's website:
|
||||
http://www.gmt.com.tw/product/datasheet/EDS-760A.pdf
|
||||
|
||||
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.
|
||||
* g760a - Driver for the Global Mixed-mode Technology Inc. G760A
|
||||
* fan speed PWM controller chip
|
||||
*
|
||||
* Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
*
|
||||
* Complete datasheet is available at GMT's website:
|
||||
* http://www.gmt.com.tw/product/datasheet/EDS-760A.pdf
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -59,7 +59,8 @@ struct g760a_data {
|
||||
u8 act_cnt; /* formula: cnt = (CLK * 30)/(rpm * P) */
|
||||
u8 fan_sta; /* bit 0: set when actual fan speed more than 20%
|
||||
* outside requested fan speed
|
||||
* bit 1: set when fan speed below 1920 rpm */
|
||||
* bit 1: set when fan speed below 1920 rpm
|
||||
*/
|
||||
};
|
||||
|
||||
#define G760A_DEFAULT_CLK 32768
|
||||
@ -99,7 +100,7 @@ static int g760a_write_value(struct i2c_client *client, enum g760a_regs reg,
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
/*
|
||||
* sysfs attributes
|
||||
*/
|
||||
|
||||
@ -192,7 +193,7 @@ static const struct attribute_group g760a_group = {
|
||||
.attrs = g760a_attributes,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
/*
|
||||
* new-style driver model code
|
||||
*/
|
||||
|
||||
@ -250,21 +251,8 @@ static int g760a_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* module management */
|
||||
|
||||
static int __init g760a_init(void)
|
||||
{
|
||||
return i2c_add_driver(&g760a_driver);
|
||||
}
|
||||
|
||||
static void __exit g760a_exit(void)
|
||||
{
|
||||
i2c_del_driver(&g760a_driver);
|
||||
}
|
||||
module_i2c_driver(g760a_driver);
|
||||
|
||||
MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
|
||||
MODULE_DESCRIPTION("GMT G760A driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(g760a_init);
|
||||
module_exit(g760a_exit);
|
||||
|
@ -86,8 +86,9 @@ enum chips { gl518sm_r00, gl518sm_r80 };
|
||||
#define BOOL_FROM_REG(val) ((val) ? 0 : 1)
|
||||
#define BOOL_TO_REG(val) ((val) ? 0 : 1)
|
||||
|
||||
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0? \
|
||||
(val)-500:(val)+500)/1000)+119),0,255))
|
||||
#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \
|
||||
(val) - 500 : \
|
||||
(val) + 500) / 1000) + 119), 0, 255)
|
||||
#define TEMP_FROM_REG(val) (((val) - 119) * 1000)
|
||||
|
||||
static inline u8 FAN_TO_REG(long rpm, int div)
|
||||
@ -100,10 +101,10 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
||||
}
|
||||
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) * (div))))
|
||||
|
||||
#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255))
|
||||
#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255)
|
||||
#define IN_FROM_REG(val) ((val) * 19)
|
||||
|
||||
#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255))
|
||||
#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255)
|
||||
#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4)
|
||||
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
@ -169,7 +170,8 @@ static struct i2c_driver gl518_driver = {
|
||||
*/
|
||||
|
||||
#define show(type, suffix, value) \
|
||||
static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
static ssize_t show_##suffix(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct gl518_data *data = gl518_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \
|
||||
@ -222,12 +224,16 @@ static ssize_t show_fan_div(struct device *dev,
|
||||
}
|
||||
|
||||
#define set(type, suffix, value, reg) \
|
||||
static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
static ssize_t set_##suffix(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct gl518_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
long val; \
|
||||
int err = kstrtol(buf, 10, &val); \
|
||||
if (err) \
|
||||
return err; \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->value = type##_TO_REG(val); \
|
||||
@ -237,13 +243,17 @@ static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, c
|
||||
}
|
||||
|
||||
#define set_bits(type, suffix, value, reg, mask, shift) \
|
||||
static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
static ssize_t set_##suffix(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct gl518_data *data = i2c_get_clientdata(client); \
|
||||
int regvalue; \
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10); \
|
||||
unsigned long val; \
|
||||
int err = kstrtoul(buf, 10, &val); \
|
||||
if (err) \
|
||||
return err; \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
regvalue = gl518_read_value(client, reg); \
|
||||
@ -280,7 +290,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
struct gl518_data *data = i2c_get_clientdata(client);
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
int regvalue;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
|
||||
@ -308,13 +323,26 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
struct gl518_data *data = i2c_get_clientdata(client);
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
int regvalue;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (val) {
|
||||
case 1: val = 0; break;
|
||||
case 2: val = 1; break;
|
||||
case 4: val = 2; break;
|
||||
case 8: val = 3; break;
|
||||
case 1:
|
||||
val = 0;
|
||||
break;
|
||||
case 2:
|
||||
val = 1;
|
||||
break;
|
||||
case 4:
|
||||
val = 2;
|
||||
break;
|
||||
case 8:
|
||||
val = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid fan clock divider %lu, choose one "
|
||||
"of 1, 2, 4 or 8\n", val);
|
||||
@ -395,8 +423,12 @@ static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
|
||||
struct gl518_data *data = i2c_get_clientdata(client);
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
unsigned long bit;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &bit);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bit = simple_strtoul(buf, NULL, 10);
|
||||
if (bit & ~1)
|
||||
return -EINVAL;
|
||||
|
||||
@ -528,12 +560,14 @@ static int gl518_probe(struct i2c_client *client,
|
||||
gl518_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl518_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
if (data->type == gl518sm_r80)
|
||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||
&gl518_group_r80)))
|
||||
if (data->type == gl518sm_r80) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl518_group_r80);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
@ -554,8 +588,10 @@ exit:
|
||||
}
|
||||
|
||||
|
||||
/* Called when we have found a new GL518SM.
|
||||
Note that we preserve D4:NoFan2 and D2:beep_enable. */
|
||||
/*
|
||||
* Called when we have found a new GL518SM.
|
||||
* Note that we preserve D4:NoFan2 and D2:beep_enable.
|
||||
*/
|
||||
static void gl518_init_client(struct i2c_client *client)
|
||||
{
|
||||
/* Make sure we leave D7:Reset untouched */
|
||||
@ -585,9 +621,11 @@ static int gl518_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
|
||||
GL518 uses a high-byte first convention, which is exactly opposite to
|
||||
the SMBus standard. */
|
||||
/*
|
||||
* Registers 0x07 to 0x0c are word-sized, others are byte-sized
|
||||
* GL518 uses a high-byte first convention, which is exactly opposite to
|
||||
* the SMBus standard.
|
||||
*/
|
||||
static int gl518_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
@ -676,21 +714,10 @@ static struct gl518_data *gl518_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_gl518sm_init(void)
|
||||
{
|
||||
return i2c_add_driver(&gl518_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_gl518sm_exit(void)
|
||||
{
|
||||
i2c_del_driver(&gl518_driver);
|
||||
}
|
||||
module_i2c_driver(gl518_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
|
||||
"Kyosti Malkki <kmalkki@cc.hut.fi> and "
|
||||
"Hong-Gunn Chew <hglinux@gunnet.org>");
|
||||
MODULE_DESCRIPTION("GL518SM driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_gl518sm_init);
|
||||
module_exit(sensors_gl518sm_exit);
|
||||
|
@ -1,24 +1,24 @@
|
||||
/*
|
||||
gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
|
||||
Kyösti Mälkki <kmalkki@cc.hut.fi>
|
||||
Copyright (c) 2005 Maarten Deprez <maartendeprez@users.sourceforge.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
|
||||
* Kyösti Mälkki <kmalkki@cc.hut.fi>
|
||||
* Copyright (c) 2005 Maarten Deprez <maartendeprez@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -41,9 +41,10 @@ MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=tempe
|
||||
/* Addresses to scan */
|
||||
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
|
||||
|
||||
/* Many GL520 constants specified below
|
||||
One of the inputs can be configured as either temp or voltage.
|
||||
That's why _TEMP2 and _IN4 access the same register
|
||||
/*
|
||||
* Many GL520 constants specified below
|
||||
* One of the inputs can be configured as either temp or voltage.
|
||||
* That's why _TEMP2 and _IN4 access the same register
|
||||
*/
|
||||
|
||||
/* The GL520 registers */
|
||||
@ -143,10 +144,10 @@ static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr,
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL);
|
||||
|
||||
#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4)
|
||||
#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255))
|
||||
#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255)
|
||||
|
||||
#define IN_FROM_REG(val) ((val) * 19)
|
||||
#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255))
|
||||
#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255)
|
||||
|
||||
static ssize_t get_in_input(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -193,8 +194,13 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
long v = simple_strtol(buf, NULL, 10);
|
||||
u8 r;
|
||||
long v;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@ -222,8 +228,13 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
long v = simple_strtol(buf, NULL, 10);
|
||||
u8 r;
|
||||
long v;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (n == 0)
|
||||
r = VDD_TO_REG(v);
|
||||
@ -273,7 +284,9 @@ static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
|
||||
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div))))
|
||||
#define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255))
|
||||
#define FAN_TO_REG(val, div) ((val) <= 0 ? 0 : \
|
||||
SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, \
|
||||
255))
|
||||
|
||||
static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -317,8 +330,13 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
u8 r;
|
||||
unsigned long v;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
r = FAN_TO_REG(v, data->fan_div[n]);
|
||||
@ -351,16 +369,30 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
u8 r;
|
||||
unsigned long v;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (v) {
|
||||
case 1: r = 0; break;
|
||||
case 2: r = 1; break;
|
||||
case 4: r = 2; break;
|
||||
case 8: r = 3; break;
|
||||
case 1:
|
||||
r = 0;
|
||||
break;
|
||||
case 2:
|
||||
r = 1;
|
||||
break;
|
||||
case 4:
|
||||
r = 2;
|
||||
break;
|
||||
case 8:
|
||||
r = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v);
|
||||
dev_err(&client->dev,
|
||||
"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -385,7 +417,15 @@ static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
u8 r = simple_strtoul(buf, NULL, 10)?1:0;
|
||||
u8 r;
|
||||
unsigned long v;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
r = (v ? 1 : 0);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_off = r;
|
||||
@ -410,7 +450,8 @@ static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR,
|
||||
get_fan_off, set_fan_off);
|
||||
|
||||
#define TEMP_FROM_REG(val) (((val) - 130) * 1000)
|
||||
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255))
|
||||
#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \
|
||||
(val) - 500 : (val) + 500) / 1000) + 130), 0, 255)
|
||||
|
||||
static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -430,8 +471,8 @@ static ssize_t get_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n]));
|
||||
}
|
||||
|
||||
static ssize_t get_temp_max_hyst(struct device *dev, struct device_attribute
|
||||
*attr, char *buf)
|
||||
static ssize_t get_temp_max_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
struct gl520_data *data = gl520_update_device(dev);
|
||||
@ -445,7 +486,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
long v = simple_strtol(buf, NULL, 10);
|
||||
long v;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max[n] = TEMP_TO_REG(v);
|
||||
@ -460,7 +506,12 @@ static ssize_t set_temp_max_hyst(struct device *dev, struct device_attribute
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
long v = simple_strtol(buf, NULL, 10);
|
||||
long v;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max_hyst[n] = TEMP_TO_REG(v);
|
||||
@ -507,7 +558,15 @@ static ssize_t set_beep_enable(struct device *dev, struct device_attribute
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
u8 r = simple_strtoul(buf, NULL, 10)?0:1;
|
||||
u8 r;
|
||||
unsigned long v;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
r = (v ? 0 : 1);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->beep_enable = !r;
|
||||
@ -523,7 +582,12 @@ static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
u8 r = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long r;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &r);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
r &= data->alarm_mask;
|
||||
@ -575,7 +639,11 @@ static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
unsigned long bit;
|
||||
|
||||
bit = simple_strtoul(buf, NULL, 10);
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &bit);
|
||||
if (err)
|
||||
return err;
|
||||
if (bit & ~1)
|
||||
return -EINVAL;
|
||||
|
||||
@ -652,13 +720,16 @@ static const struct attribute_group gl520_group = {
|
||||
.attrs = gl520_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *gl520_attributes_opt[] = {
|
||||
static struct attribute *gl520_attributes_in4[] = {
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_beep.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *gl520_attributes_temp2[] = {
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
|
||||
@ -667,8 +738,12 @@ static struct attribute *gl520_attributes_opt[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group gl520_group_opt = {
|
||||
.attrs = gl520_attributes_opt,
|
||||
static const struct attribute_group gl520_group_in4 = {
|
||||
.attrs = gl520_attributes_in4,
|
||||
};
|
||||
|
||||
static const struct attribute_group gl520_group_temp2 = {
|
||||
.attrs = gl520_attributes_temp2,
|
||||
};
|
||||
|
||||
|
||||
@ -717,35 +792,17 @@ static int gl520_probe(struct i2c_client *client,
|
||||
gl520_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group)))
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl520_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
if (data->two_temps) {
|
||||
if ((err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr))
|
||||
|| (err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp2_max.dev_attr))
|
||||
|| (err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp2_max_hyst.dev_attr))
|
||||
|| (err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp2_alarm.dev_attr))
|
||||
|| (err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp2_beep.dev_attr)))
|
||||
goto exit_remove_files;
|
||||
} else {
|
||||
if ((err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_in4_input.dev_attr))
|
||||
|| (err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_in4_min.dev_attr))
|
||||
|| (err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_in4_max.dev_attr))
|
||||
|| (err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_in4_alarm.dev_attr))
|
||||
|| (err = device_create_file(&client->dev,
|
||||
&sensor_dev_attr_in4_beep.dev_attr)))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
if (data->two_temps)
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl520_group_temp2);
|
||||
else
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl520_group_in4);
|
||||
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
@ -757,7 +814,8 @@ static int gl520_probe(struct i2c_client *client,
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_in4);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_temp2);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
@ -809,15 +867,18 @@ static int gl520_remove(struct i2c_client *client)
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_in4);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_temp2);
|
||||
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
|
||||
GL520 uses a high-byte first convention */
|
||||
/*
|
||||
* Registers 0x07 to 0x0c are word-sized, others are byte-sized
|
||||
* GL520 uses a high-byte first convention
|
||||
*/
|
||||
static int gl520_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
@ -849,7 +910,8 @@ static struct gl520_data *gl520_update_device(struct device *dev)
|
||||
|
||||
data->alarms = gl520_read_value(client, GL520_REG_ALARMS);
|
||||
data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
|
||||
data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f;
|
||||
data->vid = gl520_read_value(client,
|
||||
GL520_REG_VID_INPUT) & 0x1f;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
data->in_input[i] = gl520_read_value(client,
|
||||
@ -910,23 +972,10 @@ static struct gl520_data *gl520_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static int __init sensors_gl520sm_init(void)
|
||||
{
|
||||
return i2c_add_driver(&gl520_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_gl520sm_exit(void)
|
||||
{
|
||||
i2c_del_driver(&gl520_driver);
|
||||
}
|
||||
|
||||
module_i2c_driver(gl520_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
|
||||
"Kyösti Mälkki <kmalkki@cc.hut.fi>, "
|
||||
"Maarten Deprez <maartendeprez@users.sourceforge.net>");
|
||||
MODULE_DESCRIPTION("GL520SM driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_gl520sm_init);
|
||||
module_exit(sensors_gl520sm_exit);
|
||||
|
@ -96,14 +96,14 @@ int vid_from_reg(int val, u8 vrm)
|
||||
vid = 1862500 - (val & 0x1f) * 25000;
|
||||
if (val & 0x20)
|
||||
vid -= 12500;
|
||||
return((vid + 500) / 1000);
|
||||
return (vid + 500) / 1000;
|
||||
|
||||
case 110: /* Intel Conroe */
|
||||
/* compute in uV, round to mV */
|
||||
val &= 0xff;
|
||||
if (val < 0x02 || val > 0xb2)
|
||||
return 0;
|
||||
return((1600000 - (val - 2) * 6250 + 500) / 1000);
|
||||
return (1600000 - (val - 2) * 6250 + 500) / 1000;
|
||||
|
||||
case 24: /* Athlon64 & Opteron */
|
||||
val &= 0x1f;
|
||||
@ -118,38 +118,38 @@ int vid_from_reg(int val, u8 vrm)
|
||||
case 91: /* VRM 9.1 */
|
||||
case 90: /* VRM 9.0 */
|
||||
val &= 0x1f;
|
||||
return(val == 0x1f ? 0 :
|
||||
1850 - val * 25);
|
||||
return val == 0x1f ? 0 :
|
||||
1850 - val * 25;
|
||||
|
||||
case 85: /* VRM 8.5 */
|
||||
val &= 0x1f;
|
||||
return((val & 0x10 ? 25 : 0) +
|
||||
return (val & 0x10 ? 25 : 0) +
|
||||
((val & 0x0f) > 0x04 ? 2050 : 1250) -
|
||||
((val & 0x0f) * 50));
|
||||
((val & 0x0f) * 50);
|
||||
|
||||
case 84: /* VRM 8.4 */
|
||||
val &= 0x0f;
|
||||
/* fall through */
|
||||
case 82: /* VRM 8.2 */
|
||||
val &= 0x1f;
|
||||
return(val == 0x1f ? 0 :
|
||||
return val == 0x1f ? 0 :
|
||||
val & 0x10 ? 5100 - (val) * 100 :
|
||||
2050 - (val) * 50);
|
||||
2050 - (val) * 50;
|
||||
case 17: /* Intel IMVP-II */
|
||||
val &= 0x1f;
|
||||
return(val & 0x10 ? 975 - (val & 0xF) * 25 :
|
||||
1750 - val * 50);
|
||||
return val & 0x10 ? 975 - (val & 0xF) * 25 :
|
||||
1750 - val * 50;
|
||||
case 13:
|
||||
case 131:
|
||||
val &= 0x3f;
|
||||
/* Exception for Eden ULV 500 MHz */
|
||||
if (vrm == 131 && val == 0x3f)
|
||||
val++;
|
||||
return(1708 - val * 16);
|
||||
return 1708 - val * 16;
|
||||
case 14: /* Intel Core */
|
||||
/* compute in uV, round to mV */
|
||||
val &= 0x7f;
|
||||
return(val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000);
|
||||
return val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000;
|
||||
default: /* report 0 for unknown */
|
||||
if (vrm)
|
||||
pr_warn("Requested unsupported VRM version (%u)\n",
|
||||
@ -157,7 +157,7 @@ int vid_from_reg(int val, u8 vrm)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vid_from_reg);
|
||||
|
||||
/*
|
||||
* After this point is the code to automatically determine which
|
||||
@ -166,9 +166,10 @@ int vid_from_reg(int val, u8 vrm)
|
||||
|
||||
struct vrm_model {
|
||||
u8 vendor;
|
||||
u8 eff_family;
|
||||
u8 eff_model;
|
||||
u8 eff_stepping;
|
||||
u8 family;
|
||||
u8 model_from;
|
||||
u8 model_to;
|
||||
u8 stepping_to;
|
||||
u8 vrm_type;
|
||||
};
|
||||
|
||||
@ -177,42 +178,52 @@ struct vrm_model {
|
||||
#ifdef CONFIG_X86
|
||||
|
||||
/*
|
||||
* The stepping parameter is highest acceptable stepping for current line.
|
||||
* The stepping_to parameter is highest acceptable stepping for current line.
|
||||
* The model match must be exact for 4-bit values. For model values 0x10
|
||||
* and above (extended model), all models below the parameter will match.
|
||||
*/
|
||||
|
||||
static struct vrm_model vrm_models[] = {
|
||||
{X86_VENDOR_AMD, 0x6, ANY, ANY, 90}, /* Athlon Duron etc */
|
||||
{X86_VENDOR_AMD, 0xF, 0x3F, ANY, 24}, /* Athlon 64, Opteron */
|
||||
/* In theory, all NPT family 0Fh processors have 6 VID pins and should
|
||||
thus use vrm 25, however in practice not all mainboards route the
|
||||
6th VID pin because it is never needed. So we use the 5 VID pin
|
||||
variant (vrm 24) for the models which exist today. */
|
||||
{X86_VENDOR_AMD, 0xF, 0x7F, ANY, 24}, /* NPT family 0Fh */
|
||||
{X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* future fam. 0Fh */
|
||||
{X86_VENDOR_AMD, 0x10, ANY, ANY, 25}, /* NPT family 10h */
|
||||
{X86_VENDOR_AMD, 0x6, 0x0, ANY, ANY, 90}, /* Athlon Duron etc */
|
||||
{X86_VENDOR_AMD, 0xF, 0x0, 0x3F, ANY, 24}, /* Athlon 64, Opteron */
|
||||
/*
|
||||
* In theory, all NPT family 0Fh processors have 6 VID pins and should
|
||||
* thus use vrm 25, however in practice not all mainboards route the
|
||||
* 6th VID pin because it is never needed. So we use the 5 VID pin
|
||||
* variant (vrm 24) for the models which exist today.
|
||||
*/
|
||||
{X86_VENDOR_AMD, 0xF, 0x40, 0x7F, ANY, 24}, /* NPT family 0Fh */
|
||||
{X86_VENDOR_AMD, 0xF, 0x80, ANY, ANY, 25}, /* future fam. 0Fh */
|
||||
{X86_VENDOR_AMD, 0x10, 0x0, ANY, ANY, 25}, /* NPT family 10h */
|
||||
|
||||
{X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */
|
||||
{X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */
|
||||
{X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */
|
||||
{X86_VENDOR_INTEL, 0x6, 0xE, ANY, 14}, /* Intel Core (65 nm) */
|
||||
{X86_VENDOR_INTEL, 0x6, 0xF, ANY, 110}, /* Intel Conroe */
|
||||
{X86_VENDOR_INTEL, 0x6, ANY, ANY, 82}, /* any P6 */
|
||||
{X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90}, /* P4 */
|
||||
{X86_VENDOR_INTEL, 0xF, 0x1, ANY, 90}, /* P4 Willamette */
|
||||
{X86_VENDOR_INTEL, 0xF, 0x2, ANY, 90}, /* P4 Northwood */
|
||||
{X86_VENDOR_INTEL, 0xF, ANY, ANY, 100}, /* Prescott and above assume VRD 10 */
|
||||
{X86_VENDOR_INTEL, 0x6, 0x0, 0x6, ANY, 82}, /* Pentium Pro,
|
||||
* Pentium II, Xeon,
|
||||
* Mobile Pentium,
|
||||
* Celeron */
|
||||
{X86_VENDOR_INTEL, 0x6, 0x7, 0x7, ANY, 84}, /* Pentium III, Xeon */
|
||||
{X86_VENDOR_INTEL, 0x6, 0x8, 0x8, ANY, 82}, /* Pentium III, Xeon */
|
||||
{X86_VENDOR_INTEL, 0x6, 0x9, 0x9, ANY, 13}, /* Pentium M (130 nm) */
|
||||
{X86_VENDOR_INTEL, 0x6, 0xA, 0xA, ANY, 82}, /* Pentium III Xeon */
|
||||
{X86_VENDOR_INTEL, 0x6, 0xB, 0xB, ANY, 85}, /* Tualatin */
|
||||
{X86_VENDOR_INTEL, 0x6, 0xD, 0xD, ANY, 13}, /* Pentium M (90 nm) */
|
||||
{X86_VENDOR_INTEL, 0x6, 0xE, 0xE, ANY, 14}, /* Intel Core (65 nm) */
|
||||
{X86_VENDOR_INTEL, 0x6, 0xF, ANY, ANY, 110}, /* Intel Conroe and
|
||||
* later */
|
||||
{X86_VENDOR_INTEL, 0xF, 0x0, 0x0, ANY, 90}, /* P4 */
|
||||
{X86_VENDOR_INTEL, 0xF, 0x1, 0x1, ANY, 90}, /* P4 Willamette */
|
||||
{X86_VENDOR_INTEL, 0xF, 0x2, 0x2, ANY, 90}, /* P4 Northwood */
|
||||
{X86_VENDOR_INTEL, 0xF, 0x3, ANY, ANY, 100}, /* Prescott and above
|
||||
* assume VRD 10 */
|
||||
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nehemiah */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7-M, C7, Eden (Esther) */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0xD, ANY, 134}, /* C7-D, C7-M, C7, Eden (Esther) */
|
||||
|
||||
{X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0} /* stop here */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0x7, 0x7, ANY, 85}, /* Eden ESP/Ezra */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0x8, 0x8, 0x7, 85}, /* Ezra T */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x9, 0x7, 85}, /* Nehemiah */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x9, ANY, 17}, /* C3-M, Eden-N */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0xA, 0xA, 0x7, 0}, /* No information */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0xA, 0xA, ANY, 13}, /* C7-M, C7,
|
||||
* Eden (Esther) */
|
||||
{X86_VENDOR_CENTAUR, 0x6, 0xD, 0xD, ANY, 134}, /* C7-D, C7-M, C7,
|
||||
* Eden (Esther) */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -248,20 +259,17 @@ static u8 get_via_model_d_vrm(void)
|
||||
}
|
||||
}
|
||||
|
||||
static u8 find_vrm(u8 eff_family, u8 eff_model, u8 eff_stepping, u8 vendor)
|
||||
static u8 find_vrm(u8 family, u8 model, u8 stepping, u8 vendor)
|
||||
{
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) {
|
||||
if (vrm_models[i].vendor==vendor)
|
||||
if ((vrm_models[i].eff_family==eff_family)
|
||||
&& ((vrm_models[i].eff_model==eff_model) ||
|
||||
(vrm_models[i].eff_model >= 0x10 &&
|
||||
eff_model <= vrm_models[i].eff_model) ||
|
||||
(vrm_models[i].eff_model==ANY)) &&
|
||||
(eff_stepping <= vrm_models[i].eff_stepping))
|
||||
for (i = 0; i < ARRAY_SIZE(vrm_models); i++) {
|
||||
if (vendor == vrm_models[i].vendor &&
|
||||
family == vrm_models[i].family &&
|
||||
model >= vrm_models[i].model_from &&
|
||||
model <= vrm_models[i].model_to &&
|
||||
stepping <= vrm_models[i].stepping_to)
|
||||
return vrm_models[i].vrm_type;
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -270,21 +278,12 @@ static u8 find_vrm(u8 eff_family, u8 eff_model, u8 eff_stepping, u8 vendor)
|
||||
u8 vid_which_vrm(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||
u32 eax;
|
||||
u8 eff_family, eff_model, eff_stepping, vrm_ret;
|
||||
u8 vrm_ret;
|
||||
|
||||
if (c->x86 < 6) /* Any CPU with family lower than 6 */
|
||||
return 0; /* doesn't have VID and/or CPUID */
|
||||
return 0; /* doesn't have VID */
|
||||
|
||||
eax = cpuid_eax(1);
|
||||
eff_family = ((eax & 0x00000F00)>>8);
|
||||
eff_model = ((eax & 0x000000F0)>>4);
|
||||
eff_stepping = eax & 0xF;
|
||||
if (eff_family == 0xF) { /* use extended model & family */
|
||||
eff_family += ((eax & 0x00F00000)>>20);
|
||||
eff_model += ((eax & 0x000F0000)>>16)<<4;
|
||||
}
|
||||
vrm_ret = find_vrm(eff_family, eff_model, eff_stepping, c->x86_vendor);
|
||||
vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_mask, c->x86_vendor);
|
||||
if (vrm_ret == 134)
|
||||
vrm_ret = get_via_model_d_vrm();
|
||||
if (vrm_ret == 0)
|
||||
@ -300,8 +299,6 @@ u8 vid_which_vrm(void)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
EXPORT_SYMBOL(vid_from_reg);
|
||||
EXPORT_SYMBOL(vid_which_vrm);
|
||||
|
||||
MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
|
||||
|
@ -1,13 +1,13 @@
|
||||
/*
|
||||
hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
|
||||
|
||||
This file defines the sysfs class "hwmon", for use by sensors drivers.
|
||||
|
||||
Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.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; version 2 of the License.
|
||||
* hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
|
||||
*
|
||||
* This file defines the sysfs class "hwmon", for use by sensors drivers.
|
||||
*
|
||||
* Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.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; version 2 of the License.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -55,6 +55,7 @@ struct device *hwmon_device_register(struct device *dev)
|
||||
|
||||
return hwdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hwmon_device_register);
|
||||
|
||||
/**
|
||||
* hwmon_device_unregister - removes the previously registered class device
|
||||
@ -72,6 +73,7 @@ void hwmon_device_unregister(struct device *dev)
|
||||
dev_dbg(dev->parent,
|
||||
"hwmon_device_unregister() failed: bad class ID!\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hwmon_device_unregister);
|
||||
|
||||
static void __init hwmon_pci_quirks(void)
|
||||
{
|
||||
@ -119,9 +121,6 @@ static void __exit hwmon_exit(void)
|
||||
subsys_initcall(hwmon_init);
|
||||
module_exit(hwmon_exit);
|
||||
|
||||
EXPORT_SYMBOL_GPL(hwmon_device_register);
|
||||
EXPORT_SYMBOL_GPL(hwmon_device_unregister);
|
||||
|
||||
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
|
||||
MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -159,8 +159,12 @@ static ssize_t store_amb_min(struct device *dev,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i5k_amb_data *data = dev_get_drvdata(dev);
|
||||
unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
|
||||
unsigned long temp;
|
||||
int ret = kstrtoul(buf, 10, &temp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
temp = temp / 500;
|
||||
if (temp > 255)
|
||||
temp = 255;
|
||||
|
||||
@ -175,8 +179,12 @@ static ssize_t store_amb_mid(struct device *dev,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i5k_amb_data *data = dev_get_drvdata(dev);
|
||||
unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
|
||||
unsigned long temp;
|
||||
int ret = kstrtoul(buf, 10, &temp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
temp = temp / 500;
|
||||
if (temp > 255)
|
||||
temp = 255;
|
||||
|
||||
@ -191,8 +199,12 @@ static ssize_t store_amb_max(struct device *dev,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i5k_amb_data *data = dev_get_drvdata(dev);
|
||||
unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
|
||||
unsigned long temp;
|
||||
int ret = kstrtoul(buf, 10, &temp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
temp = temp / 500;
|
||||
if (temp > 255)
|
||||
temp = 255;
|
||||
|
||||
|
@ -176,12 +176,16 @@ static bool fix_pwm_polarity;
|
||||
#define IT87_REG_ALARM2 0x02
|
||||
#define IT87_REG_ALARM3 0x03
|
||||
|
||||
/* The IT8718F and IT8720F have the VID value in a different register, in
|
||||
Super-I/O configuration space. */
|
||||
/*
|
||||
* The IT8718F and IT8720F have the VID value in a different register, in
|
||||
* Super-I/O configuration space.
|
||||
*/
|
||||
#define IT87_REG_VID 0x0a
|
||||
/* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
|
||||
for fan divisors. Later IT8712F revisions must use 16-bit tachometer
|
||||
mode. */
|
||||
/*
|
||||
* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
|
||||
* for fan divisors. Later IT8712F revisions must use 16-bit tachometer
|
||||
* mode.
|
||||
*/
|
||||
#define IT87_REG_FAN_DIV 0x0b
|
||||
#define IT87_REG_FAN_16BIT 0x0c
|
||||
|
||||
@ -227,8 +231,10 @@ struct it87_sio_data {
|
||||
u8 skip_pwm;
|
||||
};
|
||||
|
||||
/* For each registered chip, we need to keep some data in memory.
|
||||
The structure is dynamically allocated. */
|
||||
/*
|
||||
* For each registered chip, we need to keep some data in memory.
|
||||
* The structure is dynamically allocated.
|
||||
*/
|
||||
struct it87_data {
|
||||
struct device *hwmon_dev;
|
||||
enum chips type;
|
||||
@ -259,14 +265,16 @@ struct it87_data {
|
||||
u8 fan_main_ctrl; /* Register value */
|
||||
u8 fan_ctl; /* Register value */
|
||||
|
||||
/* The following 3 arrays correspond to the same registers up to
|
||||
/*
|
||||
* The following 3 arrays correspond to the same registers up to
|
||||
* the IT8720F. The meaning of bits 6-0 depends on the value of bit
|
||||
* 7, and we want to preserve settings on mode changes, so we have
|
||||
* to track all values separately.
|
||||
* Starting with the IT8721F, the manual PWM duty cycles are stored
|
||||
* in separate registers (8-bit values), so the separate tracking
|
||||
* is no longer needed, but it is still done to keep the driver
|
||||
* simple. */
|
||||
* simple.
|
||||
*/
|
||||
u8 pwm_ctrl[3]; /* Register value */
|
||||
u8 pwm_duty[3]; /* Manual PWM value set by user */
|
||||
u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */
|
||||
@ -388,9 +396,11 @@ static const unsigned int pwm_freq[8] = {
|
||||
|
||||
static inline int has_16bit_fans(const struct it87_data *data)
|
||||
{
|
||||
/* IT8705F Datasheet 0.4.1, 3h == Version G.
|
||||
IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
|
||||
These are the first revisions with 16bit tachometer support. */
|
||||
/*
|
||||
* IT8705F Datasheet 0.4.1, 3h == Version G.
|
||||
* IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
|
||||
* These are the first revisions with 16-bit tachometer support.
|
||||
*/
|
||||
return (data->type == it87 && data->revision >= 0x03)
|
||||
|| (data->type == it8712 && data->revision >= 0x08)
|
||||
|| data->type == it8716
|
||||
@ -402,9 +412,11 @@ static inline int has_16bit_fans(const struct it87_data *data)
|
||||
|
||||
static inline int has_old_autopwm(const struct it87_data *data)
|
||||
{
|
||||
/* The old automatic fan speed control interface is implemented
|
||||
by IT8705F chips up to revision F and IT8712F chips up to
|
||||
revision G. */
|
||||
/*
|
||||
* The old automatic fan speed control interface is implemented
|
||||
* by IT8705F chips up to revision F and IT8712F chips up to
|
||||
* revision G.
|
||||
*/
|
||||
return (data->type == it87 && data->revision < 0x03)
|
||||
|| (data->type == it8712 && data->revision < 0x08);
|
||||
}
|
||||
@ -606,10 +618,8 @@ static ssize_t show_sensor(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
u8 reg = data->sensor; /* In case the value is updated while
|
||||
we use it */
|
||||
u8 reg = data->sensor; /* In case value is updated while used */
|
||||
|
||||
if (reg & (1 << nr))
|
||||
return sprintf(buf, "3\n"); /* thermal diode */
|
||||
@ -894,8 +904,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (has_newer_autopwm(data)) {
|
||||
/* If we are in automatic mode, the PWM duty cycle register
|
||||
* is read-only so we can't write the value */
|
||||
/*
|
||||
* If we are in automatic mode, the PWM duty cycle register
|
||||
* is read-only so we can't write the value.
|
||||
*/
|
||||
if (data->pwm_ctrl[nr] & 0x80) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
return -EBUSY;
|
||||
@ -905,8 +917,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
data->pwm_duty[nr]);
|
||||
} else {
|
||||
data->pwm_duty[nr] = pwm_to_reg(data, val);
|
||||
/* If we are in manual mode, write the duty cycle immediately;
|
||||
* otherwise, just store it for later use. */
|
||||
/*
|
||||
* If we are in manual mode, write the duty cycle immediately;
|
||||
* otherwise, just store it for later use.
|
||||
*/
|
||||
if (!(data->pwm_ctrl[nr] & 0x80)) {
|
||||
data->pwm_ctrl[nr] = data->pwm_duty[nr];
|
||||
it87_write_value(data, IT87_REG_PWM(nr),
|
||||
@ -965,8 +979,10 @@ static ssize_t set_pwm_temp_map(struct device *dev,
|
||||
long val;
|
||||
u8 reg;
|
||||
|
||||
/* This check can go away if we ever support automatic fan speed
|
||||
control on newer chips. */
|
||||
/*
|
||||
* This check can go away if we ever support automatic fan speed
|
||||
* control on newer chips.
|
||||
*/
|
||||
if (!has_old_autopwm(data)) {
|
||||
dev_notice(dev, "Mapping change disabled for safety reasons\n");
|
||||
return -EINVAL;
|
||||
@ -991,8 +1007,10 @@ static ssize_t set_pwm_temp_map(struct device *dev,
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm_temp_map[nr] = reg;
|
||||
/* If we are in automatic mode, write the temp mapping immediately;
|
||||
* otherwise, just store it for later use. */
|
||||
/*
|
||||
* If we are in automatic mode, write the temp mapping immediately;
|
||||
* otherwise, just store it for later use.
|
||||
*/
|
||||
if (data->pwm_ctrl[nr] & 0x80) {
|
||||
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
|
||||
it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
|
||||
@ -1162,9 +1180,11 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
/* We want to use the same sysfs file names as 8-bit fans, but we need
|
||||
different variable names, so we have to use SENSOR_ATTR instead of
|
||||
SENSOR_DEVICE_ATTR. */
|
||||
/*
|
||||
* We want to use the same sysfs file names as 8-bit fans, but we need
|
||||
* different variable names, so we have to use SENSOR_ATTR instead of
|
||||
* SENSOR_DEVICE_ATTR.
|
||||
*/
|
||||
#define show_fan16_offset(offset) \
|
||||
static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \
|
||||
= SENSOR_ATTR(fan##offset##_input, S_IRUGO, \
|
||||
@ -1321,12 +1341,12 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
|
||||
static ssize_t show_label(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
static const char *labels[] = {
|
||||
static const char * const labels[] = {
|
||||
"+5V",
|
||||
"5VSB",
|
||||
"Vbat",
|
||||
};
|
||||
static const char *labels_it8721[] = {
|
||||
static const char * const labels_it8721[] = {
|
||||
"+3.3V",
|
||||
"3VSB",
|
||||
"Vbat",
|
||||
@ -1736,12 +1756,14 @@ static int __init it87_find(unsigned short *address,
|
||||
if (board_vendor && board_name) {
|
||||
if (strcmp(board_vendor, "nVIDIA") == 0
|
||||
&& strcmp(board_name, "FN68PT") == 0) {
|
||||
/* On the Shuttle SN68PT, FAN_CTL2 is apparently not
|
||||
connected to a fan, but to something else. One user
|
||||
has reported instant system power-off when changing
|
||||
the PWM2 duty cycle, so we disable it.
|
||||
I use the board name string as the trigger in case
|
||||
the same board is ever used in other systems. */
|
||||
/*
|
||||
* On the Shuttle SN68PT, FAN_CTL2 is apparently not
|
||||
* connected to a fan, but to something else. One user
|
||||
* has reported instant system power-off when changing
|
||||
* the PWM2 duty cycle, so we disable it.
|
||||
* I use the board name string as the trigger in case
|
||||
* the same board is ever used in other systems.
|
||||
*/
|
||||
pr_info("Disabling pwm2 due to hardware constraints\n");
|
||||
sio_data->skip_pwm = (1 << 1);
|
||||
}
|
||||
@ -1793,7 +1815,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
||||
int err = 0, i;
|
||||
int enable_pwm_interface;
|
||||
int fan_beep_need_rw;
|
||||
static const char *names[] = {
|
||||
static const char * const names[] = {
|
||||
"it87",
|
||||
"it8712",
|
||||
"it8716",
|
||||
@ -1879,9 +1901,11 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
||||
if (!fan_beep_need_rw)
|
||||
continue;
|
||||
|
||||
/* As we have a single beep enable bit for all fans,
|
||||
/*
|
||||
* As we have a single beep enable bit for all fans,
|
||||
* only the first enabled fan has a writable attribute
|
||||
* for it. */
|
||||
* for it.
|
||||
*/
|
||||
if (sysfs_chmod_file(&dev->kobj,
|
||||
it87_attributes_fan_beep[i],
|
||||
S_IRUGO | S_IWUSR))
|
||||
@ -1961,18 +1985,22 @@ static int __devexit it87_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must be called with data->update_lock held, except during initialization.
|
||||
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
would slow down the IT87 access and should not be necessary. */
|
||||
/*
|
||||
* Must be called with data->update_lock held, except during initialization.
|
||||
* We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
* would slow down the IT87 access and should not be necessary.
|
||||
*/
|
||||
static int it87_read_value(struct it87_data *data, u8 reg)
|
||||
{
|
||||
outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
|
||||
return inb_p(data->addr + IT87_DATA_REG_OFFSET);
|
||||
}
|
||||
|
||||
/* Must be called with data->update_lock held, except during initialization.
|
||||
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
would slow down the IT87 access and should not be necessary. */
|
||||
/*
|
||||
* Must be called with data->update_lock held, except during initialization.
|
||||
* We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
* would slow down the IT87 access and should not be necessary.
|
||||
*/
|
||||
static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
|
||||
{
|
||||
outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
|
||||
@ -1983,15 +2011,19 @@ static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
|
||||
static int __devinit it87_check_pwm(struct device *dev)
|
||||
{
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
/* Some BIOSes fail to correctly configure the IT87 fans. All fans off
|
||||
/*
|
||||
* Some BIOSes fail to correctly configure the IT87 fans. All fans off
|
||||
* and polarity set to active low is sign that this is the case so we
|
||||
* disable pwm control to protect the user. */
|
||||
* disable pwm control to protect the user.
|
||||
*/
|
||||
int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
|
||||
if ((tmp & 0x87) == 0) {
|
||||
if (fix_pwm_polarity) {
|
||||
/* The user asks us to attempt a chip reconfiguration.
|
||||
/*
|
||||
* The user asks us to attempt a chip reconfiguration.
|
||||
* This means switching to active high polarity and
|
||||
* inverting all fan speed values. */
|
||||
* inverting all fan speed values.
|
||||
*/
|
||||
int i;
|
||||
u8 pwm[3];
|
||||
|
||||
@ -1999,10 +2031,12 @@ static int __devinit it87_check_pwm(struct device *dev)
|
||||
pwm[i] = it87_read_value(data,
|
||||
IT87_REG_PWM(i));
|
||||
|
||||
/* If any fan is in automatic pwm mode, the polarity
|
||||
/*
|
||||
* If any fan is in automatic pwm mode, the polarity
|
||||
* might be correct, as suspicious as it seems, so we
|
||||
* better don't change anything (but still disable the
|
||||
* PWM interface). */
|
||||
* PWM interface).
|
||||
*/
|
||||
if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
|
||||
dev_info(dev, "Reconfiguring PWM to "
|
||||
"active high polarity\n");
|
||||
@ -2038,7 +2072,8 @@ static void __devinit it87_init_device(struct platform_device *pdev)
|
||||
int tmp, i;
|
||||
u8 mask;
|
||||
|
||||
/* For each PWM channel:
|
||||
/*
|
||||
* For each PWM channel:
|
||||
* - If it is in automatic mode, setting to manual mode should set
|
||||
* the fan to full speed by default.
|
||||
* - If it is in manual mode, we need a mapping to temperature
|
||||
@ -2048,18 +2083,21 @@ static void __devinit it87_init_device(struct platform_device *pdev)
|
||||
* prior to switching to a different mode.
|
||||
* Note that this is no longer needed for the IT8721F and later, as
|
||||
* these have separate registers for the temperature mapping and the
|
||||
* manual duty cycle. */
|
||||
* manual duty cycle.
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->pwm_temp_map[i] = i;
|
||||
data->pwm_duty[i] = 0x7f; /* Full speed */
|
||||
data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */
|
||||
}
|
||||
|
||||
/* Some chips seem to have default value 0xff for all limit
|
||||
/*
|
||||
* Some chips seem to have default value 0xff for all limit
|
||||
* registers. For low voltage limits it makes no sense and triggers
|
||||
* alarms, so change to 0 instead. For high temperature limits, it
|
||||
* means -1 degree C, which surprisingly doesn't trigger an alarm,
|
||||
* but is still confusing, so change to 127 degrees C. */
|
||||
* but is still confusing, so change to 127 degrees C.
|
||||
*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
|
||||
if (tmp == 0xff)
|
||||
@ -2071,10 +2109,12 @@ static void __devinit it87_init_device(struct platform_device *pdev)
|
||||
it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
|
||||
}
|
||||
|
||||
/* Temperature channels are not forcibly enabled, as they can be
|
||||
/*
|
||||
* Temperature channels are not forcibly enabled, as they can be
|
||||
* set to two different sensor types and we can't guess which one
|
||||
* is correct for a given system. These channels can be enabled at
|
||||
* run-time through the temp{1-3}_type sysfs accessors if needed. */
|
||||
* run-time through the temp{1-3}_type sysfs accessors if needed.
|
||||
*/
|
||||
|
||||
/* Check if voltage monitors are reset manually or by some reason */
|
||||
tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
|
||||
@ -2157,8 +2197,10 @@ static struct it87_data *it87_update_device(struct device *dev)
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
if (update_vbat) {
|
||||
/* Cleared after each update, so reenable. Value
|
||||
returned by this read will be previous value */
|
||||
/*
|
||||
* Cleared after each update, so reenable. Value
|
||||
* returned by this read will be previous value
|
||||
*/
|
||||
it87_write_value(data, IT87_REG_CONFIG,
|
||||
it87_read_value(data, IT87_REG_CONFIG) | 0x40);
|
||||
}
|
||||
@ -2220,13 +2262,17 @@ static struct it87_data *it87_update_device(struct device *dev)
|
||||
it87_update_pwm_ctrl(data, i);
|
||||
|
||||
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
|
||||
/* The 8705 does not have VID capability.
|
||||
The 8718 and later don't use IT87_REG_VID for the
|
||||
same purpose. */
|
||||
/*
|
||||
* The IT8705F does not have VID capability.
|
||||
* The IT8718F and later don't use IT87_REG_VID for the
|
||||
* same purpose.
|
||||
*/
|
||||
if (data->type == it8712 || data->type == it8716) {
|
||||
data->vid = it87_read_value(data, IT87_REG_VID);
|
||||
/* The older IT8712F revisions had only 5 VID pins,
|
||||
but we assume it is always safe to read 6 bits. */
|
||||
/*
|
||||
* The older IT8712F revisions had only 5 VID pins,
|
||||
* but we assume it is always safe to read 6 bits.
|
||||
*/
|
||||
data->vid &= 0x3f;
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
|
@ -180,25 +180,7 @@ static int jc42_remove(struct i2c_client *client);
|
||||
static struct jc42_data *jc42_update_device(struct device *dev);
|
||||
|
||||
static const struct i2c_device_id jc42_id[] = {
|
||||
{ "adt7408", 0 },
|
||||
{ "at30ts00", 0 },
|
||||
{ "cat94ts02", 0 },
|
||||
{ "cat6095", 0 },
|
||||
{ "jc42", 0 },
|
||||
{ "max6604", 0 },
|
||||
{ "mcp9804", 0 },
|
||||
{ "mcp9805", 0 },
|
||||
{ "mcp98242", 0 },
|
||||
{ "mcp98243", 0 },
|
||||
{ "mcp9843", 0 },
|
||||
{ "se97", 0 },
|
||||
{ "se97b", 0 },
|
||||
{ "se98", 0 },
|
||||
{ "stts424", 0 },
|
||||
{ "stts2002", 0 },
|
||||
{ "stts3000", 0 },
|
||||
{ "tse2002", 0 },
|
||||
{ "ts3000", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, jc42_id);
|
||||
@ -350,8 +332,10 @@ set(temp_min, JC42_REG_TEMP_LOWER);
|
||||
set(temp_max, JC42_REG_TEMP_UPPER);
|
||||
set(temp_crit, JC42_REG_TEMP_CRITICAL);
|
||||
|
||||
/* JC42.4 compliant chips only support four hysteresis values.
|
||||
* Pick best choice and go from there. */
|
||||
/*
|
||||
* JC42.4 compliant chips only support four hysteresis values.
|
||||
* Pick best choice and go from there.
|
||||
*/
|
||||
static ssize_t set_temp_crit_hyst(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@ -467,20 +451,19 @@ static const struct attribute_group jc42_group = {
|
||||
};
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int jc42_detect(struct i2c_client *new_client,
|
||||
struct i2c_board_info *info)
|
||||
static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||
{
|
||||
struct i2c_adapter *adapter = new_client->adapter;
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
int i, config, cap, manid, devid;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
cap = i2c_smbus_read_word_swapped(new_client, JC42_REG_CAP);
|
||||
config = i2c_smbus_read_word_swapped(new_client, JC42_REG_CONFIG);
|
||||
manid = i2c_smbus_read_word_swapped(new_client, JC42_REG_MANID);
|
||||
devid = i2c_smbus_read_word_swapped(new_client, JC42_REG_DEVICEID);
|
||||
cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP);
|
||||
config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG);
|
||||
manid = i2c_smbus_read_word_swapped(client, JC42_REG_MANID);
|
||||
devid = i2c_smbus_read_word_swapped(client, JC42_REG_DEVICEID);
|
||||
|
||||
if (cap < 0 || config < 0 || manid < 0 || devid < 0)
|
||||
return -ENODEV;
|
||||
@ -499,47 +482,42 @@ static int jc42_detect(struct i2c_client *new_client,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int jc42_probe(struct i2c_client *new_client,
|
||||
const struct i2c_device_id *id)
|
||||
static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct jc42_data *data;
|
||||
int config, cap, err;
|
||||
struct device *dev = &client->dev;
|
||||
|
||||
data = kzalloc(sizeof(struct jc42_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
data = devm_kzalloc(dev, sizeof(struct jc42_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(new_client, data);
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
cap = i2c_smbus_read_word_swapped(new_client, JC42_REG_CAP);
|
||||
if (cap < 0) {
|
||||
err = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP);
|
||||
if (cap < 0)
|
||||
return cap;
|
||||
|
||||
data->extended = !!(cap & JC42_CAP_RANGE);
|
||||
|
||||
config = i2c_smbus_read_word_swapped(new_client, JC42_REG_CONFIG);
|
||||
if (config < 0) {
|
||||
err = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG);
|
||||
if (config < 0)
|
||||
return config;
|
||||
|
||||
data->orig_config = config;
|
||||
if (config & JC42_CFG_SHUTDOWN) {
|
||||
config &= ~JC42_CFG_SHUTDOWN;
|
||||
i2c_smbus_write_word_swapped(new_client, JC42_REG_CONFIG,
|
||||
config);
|
||||
i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config);
|
||||
}
|
||||
data->config = config;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &jc42_group);
|
||||
err = sysfs_create_group(&dev->kobj, &jc42_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
@ -548,10 +526,7 @@ static int jc42_probe(struct i2c_client *new_client,
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &jc42_group);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
sysfs_remove_group(&dev->kobj, &jc42_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -563,7 +538,6 @@ static int jc42_remove(struct i2c_client *client)
|
||||
if (data->config != data->orig_config)
|
||||
i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG,
|
||||
data->orig_config);
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -614,19 +588,8 @@ abort:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init sensors_jc42_init(void)
|
||||
{
|
||||
return i2c_add_driver(&jc42_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_jc42_exit(void)
|
||||
{
|
||||
i2c_del_driver(&jc42_driver);
|
||||
}
|
||||
module_i2c_driver(jc42_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
|
||||
MODULE_DESCRIPTION("JC42 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_jc42_init);
|
||||
module_exit(sensors_jc42_exit);
|
||||
|
@ -205,7 +205,7 @@ static void __devexit k10temp_remove(struct pci_dev *pdev)
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
static const struct pci_device_id k10temp_id_table[] = {
|
||||
static DEFINE_PCI_DEVICE_TABLE(k10temp_id_table) = {
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
|
||||
|
@ -46,7 +46,7 @@ struct k8temp_data {
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
||||
/* registers values */
|
||||
u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */
|
||||
u8 sensorsp; /* sensor presence bits - SEL_CORE, SEL_PLACE */
|
||||
u32 temp[2][2]; /* core, place */
|
||||
u8 swap_core_select; /* meaning of SEL_CORE is inverted */
|
||||
u32 temp_offset;
|
||||
@ -136,7 +136,7 @@ static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1);
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
static const struct pci_device_id k8temp_ids[] = {
|
||||
static DEFINE_PCI_DEVICE_TABLE(k8temp_ids) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
|
||||
{ 0 },
|
||||
};
|
||||
@ -183,7 +183,8 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
|
||||
u8 model, stepping;
|
||||
struct k8temp_data *data;
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) {
|
||||
data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
@ -238,7 +239,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
|
||||
pci_write_config_byte(pdev, REG_TEMP, scfg);
|
||||
pci_read_config_dword(pdev, REG_TEMP, &temp);
|
||||
scfg |= SEL_CORE; /* prepare for next selection */
|
||||
if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
|
||||
if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is unlikely */
|
||||
data->sensorsp &= ~SEL_PLACE;
|
||||
}
|
||||
|
||||
@ -246,7 +247,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
|
||||
scfg &= ~SEL_PLACE; /* Select sensor 0, core1 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, scfg);
|
||||
pci_read_config_dword(pdev, REG_TEMP, &temp);
|
||||
if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
|
||||
if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is unlikely */
|
||||
data->sensorsp &= ~SEL_CORE;
|
||||
}
|
||||
|
||||
|
@ -448,7 +448,7 @@ static int pem_probe(struct i2c_client *client,
|
||||
| I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||
return -ENODEV;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -462,11 +462,11 @@ static int pem_probe(struct i2c_client *client,
|
||||
ret = pem_read_block(client, PEM_READ_FIRMWARE_REV,
|
||||
data->firmware_rev, sizeof(data->firmware_rev));
|
||||
if (ret < 0)
|
||||
goto out_kfree;
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte(client, PEM_CLEAR_INFO_FLAGS);
|
||||
if (ret < 0)
|
||||
goto out_kfree;
|
||||
return ret;
|
||||
|
||||
dev_info(&client->dev, "Firmware revision %d.%d.%d\n",
|
||||
data->firmware_rev[0], data->firmware_rev[1],
|
||||
@ -475,7 +475,7 @@ static int pem_probe(struct i2c_client *client,
|
||||
/* Register sysfs hooks */
|
||||
ret = sysfs_create_group(&client->dev.kobj, &pem_group);
|
||||
if (ret)
|
||||
goto out_kfree;
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Check if input readings are supported.
|
||||
@ -534,8 +534,6 @@ out_remove_groups:
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_input_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_fan_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_group);
|
||||
out_kfree:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -549,7 +547,6 @@ static int pem_remove(struct i2c_client *client)
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_fan_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_group);
|
||||
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -568,19 +565,8 @@ static struct i2c_driver pem_driver = {
|
||||
.id_table = pem_id,
|
||||
};
|
||||
|
||||
static int __init pem_init(void)
|
||||
{
|
||||
return i2c_add_driver(&pem_driver);
|
||||
}
|
||||
|
||||
static void __exit pem_exit(void)
|
||||
{
|
||||
i2c_del_driver(&pem_driver);
|
||||
}
|
||||
module_i2c_driver(pem_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
|
||||
MODULE_DESCRIPTION("Lineage CPL PEM hardware monitoring driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(pem_init);
|
||||
module_exit(pem_exit);
|
||||
|
@ -1119,19 +1119,8 @@ static struct lm63_data *lm63_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_lm63_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm63_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm63_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm63_driver);
|
||||
}
|
||||
module_i2c_driver(lm63_driver);
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("LM63 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm63_init);
|
||||
module_exit(sensors_lm63_exit);
|
||||
|
@ -156,6 +156,15 @@ static int __devinit lm70_probe(struct spi_device *spi)
|
||||
mutex_init(&p_lm70->lock);
|
||||
p_lm70->chip = chip;
|
||||
|
||||
spi_set_drvdata(spi, p_lm70);
|
||||
|
||||
status = device_create_file(&spi->dev, &dev_attr_temp1_input);
|
||||
if (status)
|
||||
goto out_dev_create_temp_file_failed;
|
||||
status = device_create_file(&spi->dev, &dev_attr_name);
|
||||
if (status)
|
||||
goto out_dev_create_file_failed;
|
||||
|
||||
/* sysfs hook */
|
||||
p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
|
||||
if (IS_ERR(p_lm70->hwmon_dev)) {
|
||||
@ -163,20 +172,14 @@ static int __devinit lm70_probe(struct spi_device *spi)
|
||||
status = PTR_ERR(p_lm70->hwmon_dev);
|
||||
goto out_dev_reg_failed;
|
||||
}
|
||||
spi_set_drvdata(spi, p_lm70);
|
||||
|
||||
if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
|
||||
|| (status = device_create_file(&spi->dev, &dev_attr_name))) {
|
||||
dev_dbg(&spi->dev, "device_create_file failure.\n");
|
||||
goto out_dev_create_file_failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_dev_reg_failed:
|
||||
device_remove_file(&spi->dev, &dev_attr_name);
|
||||
out_dev_create_file_failed:
|
||||
device_remove_file(&spi->dev, &dev_attr_temp1_input);
|
||||
hwmon_device_unregister(p_lm70->hwmon_dev);
|
||||
out_dev_reg_failed:
|
||||
out_dev_create_temp_file_failed:
|
||||
spi_set_drvdata(spi, NULL);
|
||||
kfree(p_lm70);
|
||||
return status;
|
||||
@ -186,9 +189,9 @@ static int __devexit lm70_remove(struct spi_device *spi)
|
||||
{
|
||||
struct lm70 *p_lm70 = spi_get_drvdata(spi);
|
||||
|
||||
hwmon_device_unregister(p_lm70->hwmon_dev);
|
||||
device_remove_file(&spi->dev, &dev_attr_temp1_input);
|
||||
device_remove_file(&spi->dev, &dev_attr_name);
|
||||
hwmon_device_unregister(p_lm70->hwmon_dev);
|
||||
spi_set_drvdata(spi, NULL);
|
||||
kfree(p_lm70);
|
||||
|
||||
@ -213,18 +216,7 @@ static struct spi_driver lm70_driver = {
|
||||
.remove = __devexit_p(lm70_remove),
|
||||
};
|
||||
|
||||
static int __init init_lm70(void)
|
||||
{
|
||||
return spi_register_driver(&lm70_driver);
|
||||
}
|
||||
|
||||
static void __exit cleanup_lm70(void)
|
||||
{
|
||||
spi_unregister_driver(&lm70_driver);
|
||||
}
|
||||
|
||||
module_init(init_lm70);
|
||||
module_exit(cleanup_lm70);
|
||||
module_spi_driver(lm70_driver);
|
||||
|
||||
MODULE_AUTHOR("Kaiwan N Billimoria");
|
||||
MODULE_DESCRIPTION("NS LM70 / TI TMP121/TMP123 Linux driver");
|
||||
|
@ -194,21 +194,8 @@ static struct i2c_driver lm73_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
/* module glue */
|
||||
|
||||
static int __init sensors_lm73_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm73_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm73_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm73_driver);
|
||||
}
|
||||
module_i2c_driver(lm73_driver);
|
||||
|
||||
MODULE_AUTHOR("Guillaume Ligneul <guillaume.ligneul@gmail.com>");
|
||||
MODULE_DESCRIPTION("LM73 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm73_init);
|
||||
module_exit(sensors_lm73_exit);
|
||||
|
@ -438,23 +438,8 @@ abort:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/* module glue */
|
||||
|
||||
static int __init sensors_lm75_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm75_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm75_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm75_driver);
|
||||
}
|
||||
module_i2c_driver(lm75_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
|
||||
MODULE_DESCRIPTION("LM75 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm75_init);
|
||||
module_exit(sensors_lm75_exit);
|
||||
|
@ -1,28 +1,28 @@
|
||||
/*
|
||||
lm77.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
|
||||
Copyright (c) 2004 Andras BALI <drewie@freemail.hu>
|
||||
|
||||
Heavily based on lm75.c by Frodo Looijaard <frodol@dds.nl>. The LM77
|
||||
is a temperature sensor and thermal window comparator with 0.5 deg
|
||||
resolution made by National Semiconductor. Complete datasheet can be
|
||||
obtained at their site:
|
||||
http://www.national.com/pf/LM/LM77.html
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* lm77.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
*
|
||||
* Copyright (c) 2004 Andras BALI <drewie@freemail.hu>
|
||||
*
|
||||
* Heavily based on lm75.c by Frodo Looijaard <frodol@dds.nl>. The LM77
|
||||
* is a temperature sensor and thermal window comparator with 0.5 deg
|
||||
* resolution made by National Semiconductor. Complete datasheet can be
|
||||
* obtained at their site:
|
||||
* http://www.national.com/pf/LM/LM77.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -95,8 +95,10 @@ static struct i2c_driver lm77_driver = {
|
||||
#define LM77_TEMP_MIN (-55000)
|
||||
#define LM77_TEMP_MAX 125000
|
||||
|
||||
/* In the temperature registers, the low 3 bits are not part of the
|
||||
temperature values; they are the status bits. */
|
||||
/*
|
||||
* In the temperature registers, the low 3 bits are not part of the
|
||||
* temperature values; they are the status bits.
|
||||
*/
|
||||
static inline s16 LM77_TEMP_TO_REG(int temp)
|
||||
{
|
||||
int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX);
|
||||
@ -112,7 +114,9 @@ static inline int LM77_TEMP_FROM_REG(s16 reg)
|
||||
|
||||
/* read routines for temperature limits */
|
||||
#define show(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
static ssize_t show_##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct lm77_data *data = lm77_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", data->value); \
|
||||
@ -124,17 +128,20 @@ show(temp_min);
|
||||
show(temp_max);
|
||||
|
||||
/* read routines for hysteresis values */
|
||||
static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_temp_crit_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lm77_data *data = lm77_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst);
|
||||
}
|
||||
static ssize_t show_temp_min_hyst(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_temp_min_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lm77_data *data = lm77_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst);
|
||||
}
|
||||
static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_temp_max_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lm77_data *data = lm77_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst);
|
||||
@ -142,11 +149,15 @@ static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute *a
|
||||
|
||||
/* write routines */
|
||||
#define set(value, reg) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm77_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
long val; \
|
||||
int err = kstrtol(buf, 10, &val); \
|
||||
if (err) \
|
||||
return err; \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->value = val; \
|
||||
@ -158,13 +169,22 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co
|
||||
set(temp_min, LM77_REG_TEMP_MIN);
|
||||
set(temp_max, LM77_REG_TEMP_MAX);
|
||||
|
||||
/* hysteresis is stored as a relative value on the chip, so it has to be
|
||||
converted first */
|
||||
static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
/*
|
||||
* hysteresis is stored as a relative value on the chip, so it has to be
|
||||
* converted first
|
||||
*/
|
||||
static ssize_t set_temp_crit_hyst(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm77_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_hyst = data->temp_crit - val;
|
||||
@ -175,12 +195,18 @@ static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *a
|
||||
}
|
||||
|
||||
/* preserve hysteresis when setting T_crit */
|
||||
static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm77_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtoul(buf, NULL, 10);
|
||||
int oldcrithyst;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
oldcrithyst = data->temp_crit - data->temp_hyst;
|
||||
@ -251,17 +277,19 @@ static int lm77_detect(struct i2c_client *new_client,
|
||||
I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
/* Here comes the remaining detection. Since the LM77 has no
|
||||
register dedicated to identification, we have to rely on the
|
||||
following tricks:
|
||||
|
||||
1. the high 4 bits represent the sign and thus they should
|
||||
always be the same
|
||||
2. the high 3 bits are unused in the configuration register
|
||||
3. addresses 0x06 and 0x07 return the last read value
|
||||
4. registers cycling over 8-address boundaries
|
||||
|
||||
Word-sized registers are high-byte first. */
|
||||
/*
|
||||
* Here comes the remaining detection. Since the LM77 has no
|
||||
* register dedicated to identification, we have to rely on the
|
||||
* following tricks:
|
||||
*
|
||||
* 1. the high 4 bits represent the sign and thus they should
|
||||
* always be the same
|
||||
* 2. the high 3 bits are unused in the configuration register
|
||||
* 3. addresses 0x06 and 0x07 return the last read value
|
||||
* 4. registers cycling over 8-address boundaries
|
||||
*
|
||||
* Word-sized registers are high-byte first.
|
||||
*/
|
||||
|
||||
/* addresses cycling */
|
||||
cur = i2c_smbus_read_word_data(new_client, 0);
|
||||
@ -330,7 +358,8 @@ static int lm77_probe(struct i2c_client *new_client,
|
||||
lm77_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &lm77_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
@ -358,8 +387,10 @@ static int lm77_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* All registers are word-sized, except for the configuration register.
|
||||
The LM77 uses the high-byte first convention. */
|
||||
/*
|
||||
* All registers are word-sized, except for the configuration register.
|
||||
* The LM77 uses the high-byte first convention.
|
||||
*/
|
||||
static u16 lm77_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
if (reg == LM77_REG_CONF)
|
||||
@ -420,19 +451,8 @@ static struct lm77_data *lm77_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_lm77_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm77_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm77_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm77_driver);
|
||||
}
|
||||
module_i2c_driver(lm77_driver);
|
||||
|
||||
MODULE_AUTHOR("Andras BALI <drewie@freemail.hu>");
|
||||
MODULE_DESCRIPTION("LM77 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm77_init);
|
||||
module_exit(sensors_lm77_exit);
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
lm78.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
Copyright (c) 2007, 2011 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* lm78.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
* Copyright (c) 2007, 2011 Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -74,11 +74,15 @@ enum chips { lm78, lm79 };
|
||||
#define LM78_REG_I2C_ADDR 0x48
|
||||
|
||||
|
||||
/* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
variants. */
|
||||
/*
|
||||
* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
* variants.
|
||||
*/
|
||||
|
||||
/* IN: mV, (0V to 4.08V)
|
||||
REG: 16mV/bit */
|
||||
/*
|
||||
* IN: mV (0V to 4.08V)
|
||||
* REG: 16mV/bit
|
||||
*/
|
||||
static inline u8 IN_TO_REG(unsigned long val)
|
||||
{
|
||||
unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
|
||||
@ -98,8 +102,10 @@ static inline int FAN_FROM_REG(u8 val, int div)
|
||||
return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div);
|
||||
}
|
||||
|
||||
/* TEMP: mC (-128C to +127C)
|
||||
REG: 1C/bit, two's complement */
|
||||
/*
|
||||
* TEMP: mC (-128C to +127C)
|
||||
* REG: 1C/bit, two's complement
|
||||
*/
|
||||
static inline s8 TEMP_TO_REG(int val)
|
||||
{
|
||||
int nval = SENSORS_LIMIT(val, -128000, 127000) ;
|
||||
@ -177,8 +183,13 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct lm78_data *data = dev_get_drvdata(dev);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
int nr = attr->index;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_min[nr] = IN_TO_REG(val);
|
||||
@ -192,8 +203,13 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct lm78_data *data = dev_get_drvdata(dev);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
int nr = attr->index;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_max[nr] = IN_TO_REG(val);
|
||||
@ -237,7 +253,12 @@ static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lm78_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_over = TEMP_TO_REG(val);
|
||||
@ -257,7 +278,12 @@ static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lm78_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_hyst = TEMP_TO_REG(val);
|
||||
@ -299,7 +325,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct lm78_data *data = dev_get_drvdata(dev);
|
||||
int nr = attr->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
|
||||
@ -316,29 +347,44 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
|
||||
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
|
||||
}
|
||||
|
||||
/* Note: we save and restore the fan minimum here, because its value is
|
||||
determined in part by the fan divisor. This follows the principle of
|
||||
least surprise; the user doesn't expect the fan minimum to change just
|
||||
because the divisor changed. */
|
||||
/*
|
||||
* Note: we save and restore the fan minimum here, because its value is
|
||||
* determined in part by the fan divisor. This follows the principle of
|
||||
* least surprise; the user doesn't expect the fan minimum to change just
|
||||
* because the divisor changed.
|
||||
*/
|
||||
static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct lm78_data *data = dev_get_drvdata(dev);
|
||||
int nr = attr->index;
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long min;
|
||||
u8 reg;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
min = FAN_FROM_REG(data->fan_min[nr],
|
||||
DIV_FROM_REG(data->fan_div[nr]));
|
||||
|
||||
switch (val) {
|
||||
case 1: data->fan_div[nr] = 0; break;
|
||||
case 2: data->fan_div[nr] = 1; break;
|
||||
case 4: data->fan_div[nr] = 2; break;
|
||||
case 8: data->fan_div[nr] = 3; break;
|
||||
case 1:
|
||||
data->fan_div[nr] = 0;
|
||||
break;
|
||||
case 2:
|
||||
data->fan_div[nr] = 1;
|
||||
break;
|
||||
case 4:
|
||||
data->fan_div[nr] = 2;
|
||||
break;
|
||||
case 8:
|
||||
data->fan_div[nr] = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "fan_div value %ld not "
|
||||
"supported. Choose one of 1, 2, 4 or 8!\n", val);
|
||||
@ -484,8 +530,10 @@ static struct platform_device *pdev;
|
||||
|
||||
static unsigned short isa_address = 0x290;
|
||||
|
||||
/* I2C devices get this name attribute automatically, but for ISA devices
|
||||
we must create it by ourselves. */
|
||||
/*
|
||||
* I2C devices get this name attribute automatically, but for ISA devices
|
||||
* we must create it by ourselves.
|
||||
*/
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
@ -515,8 +563,10 @@ static int lm78_alias_detect(struct i2c_client *client, u8 chipid)
|
||||
if ((lm78_read_value(isa, LM78_REG_CHIPID) & 0xfe) != (chipid & 0xfe))
|
||||
return 0; /* Chip type doesn't match */
|
||||
|
||||
/* We compare all the limit registers, the config register and the
|
||||
* interrupt mask registers */
|
||||
/*
|
||||
* We compare all the limit registers, the config register and the
|
||||
* interrupt mask registers
|
||||
*/
|
||||
for (i = 0x2b; i <= 0x3d; i++) {
|
||||
if (lm78_read_value(isa, i) !=
|
||||
i2c_smbus_read_byte_data(client, i))
|
||||
@ -558,9 +608,11 @@ static int lm78_i2c_detect(struct i2c_client *client,
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
/* We block updates of the ISA device to minimize the risk of
|
||||
concurrent access to the same LM78 chip through different
|
||||
interfaces. */
|
||||
/*
|
||||
* We block updates of the ISA device to minimize the risk of
|
||||
* concurrent access to the same LM78 chip through different
|
||||
* interfaces.
|
||||
*/
|
||||
if (isa)
|
||||
mutex_lock(&isa->update_lock);
|
||||
|
||||
@ -669,11 +721,13 @@ static struct i2c_driver lm78_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
/* The SMBus locks itself, but ISA access must be locked explicitly!
|
||||
We don't want to lock the whole ISA bus, so we lock each client
|
||||
separately.
|
||||
We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
|
||||
would slow down the LM78 access and should not be necessary. */
|
||||
/*
|
||||
* The SMBus locks itself, but ISA access must be locked explicitly!
|
||||
* We don't want to lock the whole ISA bus, so we lock each client
|
||||
* separately.
|
||||
* We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
|
||||
* would slow down the LM78 access and should not be necessary.
|
||||
*/
|
||||
static int lm78_read_value(struct lm78_data *data, u8 reg)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
@ -691,13 +745,6 @@ static int lm78_read_value(struct lm78_data *data, u8 reg)
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, but ISA access muse be locked explicitly!
|
||||
We don't want to lock the whole ISA bus, so we lock each client
|
||||
separately.
|
||||
We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
|
||||
would slow down the LM78 access and should not be necessary.
|
||||
There are some ugly typecasts here, but the good new is - they should
|
||||
nowhere else be necessary! */
|
||||
static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
@ -823,8 +870,11 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev)
|
||||
lm78_init_device(data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj, &lm78_group))
|
||||
|| (err = device_create_file(&pdev->dev, &dev_attr_name)))
|
||||
err = sysfs_create_group(&pdev->dev.kobj, &lm78_group);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
err = device_create_file(&pdev->dev, &dev_attr_name);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
@ -876,9 +926,11 @@ static int __init lm78_isa_found(unsigned short address)
|
||||
int val, save, found = 0;
|
||||
int port;
|
||||
|
||||
/* Some boards declare base+0 to base+7 as a PNP device, some base+4
|
||||
/*
|
||||
* Some boards declare base+0 to base+7 as a PNP device, some base+4
|
||||
* to base+7 and some base+5 to base+6. So we better request each port
|
||||
* individually for the probing phase. */
|
||||
* individually for the probing phase.
|
||||
*/
|
||||
for (port = address; port < address + LM78_EXTENT; port++) {
|
||||
if (!request_region(port, 1, "lm78")) {
|
||||
pr_debug("Failed to request port 0x%x\n", port);
|
||||
@ -887,8 +939,10 @@ static int __init lm78_isa_found(unsigned short address)
|
||||
}
|
||||
|
||||
#define REALLY_SLOW_IO
|
||||
/* We need the timeouts for at least some LM78-like
|
||||
chips. But only if we read 'undefined' registers. */
|
||||
/*
|
||||
* We need the timeouts for at least some LM78-like
|
||||
* chips. But only if we read 'undefined' registers.
|
||||
*/
|
||||
val = inb_p(address + 1);
|
||||
if (inb_p(address + 2) != val
|
||||
|| inb_p(address + 3) != val
|
||||
@ -896,8 +950,10 @@ static int __init lm78_isa_found(unsigned short address)
|
||||
goto release;
|
||||
#undef REALLY_SLOW_IO
|
||||
|
||||
/* We should be able to change the 7 LSB of the address port. The
|
||||
MSB (busy flag) should be clear initially, set after the write. */
|
||||
/*
|
||||
* We should be able to change the 7 LSB of the address port. The
|
||||
* MSB (busy flag) should be clear initially, set after the write.
|
||||
*/
|
||||
save = inb_p(address + LM78_ADDR_REG_OFFSET);
|
||||
if (save & 0x80)
|
||||
goto release;
|
||||
@ -1036,8 +1092,10 @@ static int __init sm_lm78_init(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* We register the ISA device first, so that we can skip the
|
||||
* registration of an I2C interface to the same device. */
|
||||
/*
|
||||
* We register the ISA device first, so that we can skip the
|
||||
* registration of an I2C interface to the same device.
|
||||
*/
|
||||
res = lm78_isa_register();
|
||||
if (res)
|
||||
goto exit;
|
||||
|
@ -60,11 +60,17 @@ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
#define LM80_REG_FANDIV 0x05
|
||||
#define LM80_REG_RES 0x06
|
||||
|
||||
#define LM96080_REG_CONV_RATE 0x07
|
||||
#define LM96080_REG_MAN_ID 0x3e
|
||||
#define LM96080_REG_DEV_ID 0x3f
|
||||
|
||||
/* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
variants. Note that you should be a bit careful with which arguments
|
||||
these macros are called: arguments may be evaluated more than once.
|
||||
Fixing this is just not worth it. */
|
||||
|
||||
/*
|
||||
* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
* variants. Note that you should be a bit careful with which arguments
|
||||
* these macros are called: arguments may be evaluated more than once.
|
||||
* Fixing this is just not worth it.
|
||||
*/
|
||||
|
||||
#define IN_TO_REG(val) (SENSORS_LIMIT(((val) + 5) / 10, 0, 255))
|
||||
#define IN_FROM_REG(val) ((val) * 10)
|
||||
@ -108,6 +114,7 @@ static inline long TEMP_FROM_REG(u16 temp)
|
||||
struct lm80_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char error; /* !=0 if error occurred during last update */
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
@ -144,6 +151,7 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
|
||||
|
||||
static const struct i2c_device_id lm80_id[] = {
|
||||
{ "lm80", 0 },
|
||||
{ "lm96080", 1 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm80_id);
|
||||
@ -170,6 +178,8 @@ static ssize_t show_in_##suffix(struct device *dev, \
|
||||
{ \
|
||||
int nr = to_sensor_dev_attr(attr)->index; \
|
||||
struct lm80_data *data = lm80_update_device(dev); \
|
||||
if (IS_ERR(data)) \
|
||||
return PTR_ERR(data); \
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \
|
||||
}
|
||||
show_in(min, in_min)
|
||||
@ -183,7 +193,10 @@ static ssize_t set_in_##suffix(struct device *dev, \
|
||||
int nr = to_sensor_dev_attr(attr)->index; \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm80_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
long val; \
|
||||
int err = kstrtol(buf, 10, &val); \
|
||||
if (err < 0) \
|
||||
return err; \
|
||||
\
|
||||
mutex_lock(&data->update_lock);\
|
||||
data->value[nr] = IN_TO_REG(val); \
|
||||
@ -200,6 +213,8 @@ static ssize_t show_fan_##suffix(struct device *dev, \
|
||||
{ \
|
||||
int nr = to_sensor_dev_attr(attr)->index; \
|
||||
struct lm80_data *data = lm80_update_device(dev); \
|
||||
if (IS_ERR(data)) \
|
||||
return PTR_ERR(data); \
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \
|
||||
DIV_FROM_REG(data->fan_div[nr]))); \
|
||||
}
|
||||
@ -211,6 +226,8 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct lm80_data *data = lm80_update_device(dev);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
|
||||
}
|
||||
|
||||
@ -220,7 +237,10 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm80_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err = kstrtoul(buf, 10, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
|
||||
@ -229,18 +249,23 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Note: we save and restore the fan minimum here, because its value is
|
||||
determined in part by the fan divisor. This follows the principle of
|
||||
least surprise; the user doesn't expect the fan minimum to change just
|
||||
because the divisor changed. */
|
||||
/*
|
||||
* Note: we save and restore the fan minimum here, because its value is
|
||||
* determined in part by the fan divisor. This follows the principle of
|
||||
* least surprise; the user doesn't expect the fan minimum to change just
|
||||
* because the divisor changed.
|
||||
*/
|
||||
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm80_data *data = i2c_get_clientdata(client);
|
||||
unsigned long min, val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long min, val;
|
||||
u8 reg;
|
||||
int err = kstrtoul(buf, 10, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Save fan_min */
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -283,6 +308,8 @@ static ssize_t show_temp_input1(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lm80_data *data = lm80_update_device(dev);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp));
|
||||
}
|
||||
|
||||
@ -291,6 +318,8 @@ static ssize_t show_temp_##suffix(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm80_data *data = lm80_update_device(dev); \
|
||||
if (IS_ERR(data)) \
|
||||
return PTR_ERR(data); \
|
||||
return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \
|
||||
}
|
||||
show_temp(hot_max, temp_hot_max);
|
||||
@ -304,7 +333,10 @@ static ssize_t set_temp_##suffix(struct device *dev, \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm80_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtoul(buf, NULL, 10); \
|
||||
long val; \
|
||||
int err = kstrtol(buf, 10, &val); \
|
||||
if (err < 0) \
|
||||
return err; \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->value = TEMP_LIMIT_TO_REG(val); \
|
||||
@ -321,6 +353,8 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lm80_data *data = lm80_update_device(dev);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
@ -329,6 +363,8 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
struct lm80_data *data = lm80_update_device(dev);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
|
||||
@ -459,14 +495,32 @@ static const struct attribute_group lm80_group = {
|
||||
static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
int i, cur;
|
||||
int i, cur, man_id, dev_id;
|
||||
const char *name = NULL;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
/* Now, we do the remaining detection. It is lousy. */
|
||||
if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
|
||||
/* First check for unused bits, common to both chip types */
|
||||
if ((lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
|
||||
|| (lm80_read_value(client, LM80_REG_CONFIG) & 0x80))
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* The LM96080 has manufacturer and stepping/die rev registers so we
|
||||
* can just check that. The LM80 does not have such registers so we
|
||||
* have to use a more expensive trick.
|
||||
*/
|
||||
man_id = lm80_read_value(client, LM96080_REG_MAN_ID);
|
||||
dev_id = lm80_read_value(client, LM96080_REG_DEV_ID);
|
||||
if (man_id == 0x01 && dev_id == 0x08) {
|
||||
/* Check more unused bits for confirmation */
|
||||
if (lm80_read_value(client, LM96080_REG_CONV_RATE) & 0xfe)
|
||||
return -ENODEV;
|
||||
|
||||
name = "lm96080";
|
||||
} else {
|
||||
/* Check 6-bit addressing */
|
||||
for (i = 0x2a; i <= 0x3d; i++) {
|
||||
cur = i2c_smbus_read_byte_data(client, i);
|
||||
if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
|
||||
@ -475,7 +529,10 @@ static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
strlcpy(info->type, "lm80", I2C_NAME_SIZE);
|
||||
name = "lm80";
|
||||
}
|
||||
|
||||
strlcpy(info->type, name, I2C_NAME_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -547,9 +604,11 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
|
||||
/* Called when we have found a new LM80. */
|
||||
static void lm80_init_client(struct i2c_client *client)
|
||||
{
|
||||
/* Reset all except Watchdog values and last conversion values
|
||||
This sets fan-divs to 2, among others. This makes most other
|
||||
initializations unnecessary */
|
||||
/*
|
||||
* Reset all except Watchdog values and last conversion values
|
||||
* This sets fan-divs to 2, among others. This makes most other
|
||||
* initializations unnecessary
|
||||
*/
|
||||
lm80_write_value(client, LM80_REG_CONFIG, 0x80);
|
||||
/* Set 11-bit temperature resolution */
|
||||
lm80_write_value(client, LM80_REG_RES, 0x08);
|
||||
@ -563,66 +622,116 @@ static struct lm80_data *lm80_update_device(struct device *dev)
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm80_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
int rv;
|
||||
int prev_rv;
|
||||
struct lm80_data *ret = data;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (data->error)
|
||||
lm80_init_client(client);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
|
||||
dev_dbg(&client->dev, "Starting lm80 update\n");
|
||||
for (i = 0; i <= 6; i++) {
|
||||
data->in[i] =
|
||||
lm80_read_value(client, LM80_REG_IN(i));
|
||||
data->in_min[i] =
|
||||
lm80_read_value(client, LM80_REG_IN_MIN(i));
|
||||
data->in_max[i] =
|
||||
lm80_read_value(client, LM80_REG_IN_MAX(i));
|
||||
rv = lm80_read_value(client, LM80_REG_IN(i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->in[i] = rv;
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_IN_MIN(i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->in_min[i] = rv;
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_IN_MAX(i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->in_max[i] = rv;
|
||||
}
|
||||
data->fan[0] = lm80_read_value(client, LM80_REG_FAN1);
|
||||
data->fan_min[0] =
|
||||
lm80_read_value(client, LM80_REG_FAN_MIN(1));
|
||||
data->fan[1] = lm80_read_value(client, LM80_REG_FAN2);
|
||||
data->fan_min[1] =
|
||||
lm80_read_value(client, LM80_REG_FAN_MIN(2));
|
||||
|
||||
data->temp =
|
||||
(lm80_read_value(client, LM80_REG_TEMP) << 8) |
|
||||
(lm80_read_value(client, LM80_REG_RES) & 0xf0);
|
||||
data->temp_os_max =
|
||||
lm80_read_value(client, LM80_REG_TEMP_OS_MAX);
|
||||
data->temp_os_hyst =
|
||||
lm80_read_value(client, LM80_REG_TEMP_OS_HYST);
|
||||
data->temp_hot_max =
|
||||
lm80_read_value(client, LM80_REG_TEMP_HOT_MAX);
|
||||
data->temp_hot_hyst =
|
||||
lm80_read_value(client, LM80_REG_TEMP_HOT_HYST);
|
||||
rv = lm80_read_value(client, LM80_REG_FAN1);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->fan[0] = rv;
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_FAN_MIN(1));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->fan_min[0] = rv;
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_FAN2);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->fan[1] = rv;
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_FAN_MIN(2));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->fan_min[1] = rv;
|
||||
|
||||
prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
rv = lm80_read_value(client, LM80_REG_RES);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->temp = (prev_rv << 8) | (rv & 0xf0);
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_TEMP_OS_MAX);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->temp_os_max = rv;
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_TEMP_OS_HYST);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->temp_os_hyst = rv;
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_TEMP_HOT_MAX);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->temp_hot_max = rv;
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_TEMP_HOT_HYST);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->temp_hot_hyst = rv;
|
||||
|
||||
rv = lm80_read_value(client, LM80_REG_FANDIV);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->fan_div[0] = (rv >> 2) & 0x03;
|
||||
data->fan_div[1] = (rv >> 4) & 0x03;
|
||||
|
||||
prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
rv = lm80_read_value(client, LM80_REG_ALARM2);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
data->alarms = prev_rv + (rv << 8);
|
||||
|
||||
i = lm80_read_value(client, LM80_REG_FANDIV);
|
||||
data->fan_div[0] = (i >> 2) & 0x03;
|
||||
data->fan_div[1] = (i >> 4) & 0x03;
|
||||
data->alarms = lm80_read_value(client, LM80_REG_ALARM1) +
|
||||
(lm80_read_value(client, LM80_REG_ALARM2) << 8);
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
data->error = 0;
|
||||
}
|
||||
goto done;
|
||||
|
||||
abort:
|
||||
ret = ERR_PTR(rv);
|
||||
data->valid = 0;
|
||||
data->error = 1;
|
||||
|
||||
done:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init sensors_lm80_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm80_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm80_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm80_driver);
|
||||
}
|
||||
module_i2c_driver(lm80_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
|
||||
"Philip Edelbrock <phil@netroedge.com>");
|
||||
MODULE_DESCRIPTION("LM80 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm80_init);
|
||||
module_exit(sensors_lm80_exit);
|
||||
|
@ -179,8 +179,13 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm83_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int nr = attr->index;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[nr] = TEMP_TO_REG(val);
|
||||
@ -355,12 +360,14 @@ static int lm83_probe(struct i2c_client *new_client,
|
||||
* declare 1 and 3 common, and then 2 and 4 only for the LM83.
|
||||
*/
|
||||
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group)))
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &lm83_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
if (id->driver_data == lm83) {
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
||||
&lm83_group_opt)))
|
||||
err = sysfs_create_group(&new_client->dev.kobj,
|
||||
&lm83_group_opt);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -423,19 +430,8 @@ static struct lm83_data *lm83_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_lm83_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm83_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm83_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm83_driver);
|
||||
}
|
||||
module_i2c_driver(lm83_driver);
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("LM83 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm83_init);
|
||||
module_exit(sensors_lm83_exit);
|
||||
|
@ -1,27 +1,27 @@
|
||||
/*
|
||||
lm85.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
|
||||
Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de>
|
||||
Copyright (c) 2004 Justin Thiessen <jthiessen@penguincomputing.com>
|
||||
Copyright (C) 2007--2009 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Chip details at <http://www.national.com/ds/LM/LM85.pdf>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* lm85.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
* Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
|
||||
* Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de>
|
||||
* Copyright (c) 2004 Justin Thiessen <jthiessen@penguincomputing.com>
|
||||
* Copyright (C) 2007--2009 Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* Chip details at <http://www.national.com/ds/LM/LM85.pdf>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -125,9 +125,10 @@ enum chips {
|
||||
#define EMC6D102_REG_EXTEND_ADC4 0x88
|
||||
|
||||
|
||||
/* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
variants. Note that you should be a bit careful with which arguments
|
||||
these macros are called: arguments may be evaluated more than once.
|
||||
/*
|
||||
* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
* variants. Note that you should be a bit careful with which arguments
|
||||
* these macros are called: arguments may be evaluated more than once.
|
||||
*/
|
||||
|
||||
/* IN are scaled according to built-in resistors */
|
||||
@ -166,7 +167,8 @@ static inline u16 FAN_TO_REG(unsigned long val)
|
||||
#define PWM_FROM_REG(val) (val)
|
||||
|
||||
|
||||
/* ZONEs have the following parameters:
|
||||
/*
|
||||
* ZONEs have the following parameters:
|
||||
* Limit (low) temp, 1. degC
|
||||
* Hysteresis (below limit), 1. degC (0-15)
|
||||
* Range of speed control, .1 degC (2-80)
|
||||
@ -228,7 +230,8 @@ static int FREQ_FROM_REG(const int *map, u8 reg)
|
||||
return map[reg & 0x07];
|
||||
}
|
||||
|
||||
/* Since we can't use strings, I'm abusing these numbers
|
||||
/*
|
||||
* Since we can't use strings, I'm abusing these numbers
|
||||
* to stand in for the following meanings:
|
||||
* 1 -- PWM responds to Zone 1
|
||||
* 2 -- PWM responds to Zone 2
|
||||
@ -258,7 +261,8 @@ static int ZONE_TO_REG(int zone)
|
||||
#define HYST_TO_REG(val) SENSORS_LIMIT(((val) + 500) / 1000, 0, 15)
|
||||
#define HYST_FROM_REG(val) ((val) * 1000)
|
||||
|
||||
/* Chip sampling rates
|
||||
/*
|
||||
* Chip sampling rates
|
||||
*
|
||||
* Some sensors are not updated more frequently than once per second
|
||||
* so it doesn't make sense to read them more often than that.
|
||||
@ -274,7 +278,8 @@ static int ZONE_TO_REG(int zone)
|
||||
#define LM85_DATA_INTERVAL (HZ + HZ / 2)
|
||||
#define LM85_CONFIG_INTERVAL (1 * 60 * HZ)
|
||||
|
||||
/* LM85 can automatically adjust fan speeds based on temperature
|
||||
/*
|
||||
* LM85 can automatically adjust fan speeds based on temperature
|
||||
* This structure encapsulates an entire Zone config. There are
|
||||
* three zones (one for each temperature input) on the lm85
|
||||
*/
|
||||
@ -283,7 +288,8 @@ struct lm85_zone {
|
||||
u8 hyst; /* Low limit hysteresis. (0-15) */
|
||||
u8 range; /* Temp range, encoded */
|
||||
s8 critical; /* "All fans ON" temp limit */
|
||||
u8 max_desired; /* Actual "max" temperature specified. Preserved
|
||||
u8 max_desired; /*
|
||||
* Actual "max" temperature specified. Preserved
|
||||
* to prevent "drift" as other autofan control
|
||||
* values change.
|
||||
*/
|
||||
@ -295,8 +301,10 @@ struct lm85_autofan {
|
||||
u8 min_off; /* Min PWM or OFF below "limit", flag */
|
||||
};
|
||||
|
||||
/* For each registered chip, we need to keep some data in memory.
|
||||
The structure is dynamically allocated. */
|
||||
/*
|
||||
* For each registered chip, we need to keep some data in memory.
|
||||
* The structure is dynamically allocated.
|
||||
*/
|
||||
struct lm85_data {
|
||||
struct device *hwmon_dev;
|
||||
const int *freq_map;
|
||||
@ -391,7 +399,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_min[nr] = FAN_TO_REG(val);
|
||||
@ -443,7 +456,14 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
data->vrm = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->vrm = val;
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -500,7 +520,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm[nr] = PWM_TO_REG(val);
|
||||
@ -537,8 +562,13 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
u8 config;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (val) {
|
||||
case 0:
|
||||
@ -548,8 +578,10 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
|
||||
config = 7;
|
||||
break;
|
||||
case 2:
|
||||
/* Here we have to choose arbitrarily one of the 5 possible
|
||||
configurations; I go for the safest */
|
||||
/*
|
||||
* Here we have to choose arbitrarily one of the 5 possible
|
||||
* configurations; I go for the safest
|
||||
*/
|
||||
config = 6;
|
||||
break;
|
||||
default:
|
||||
@ -588,12 +620,19 @@ static ssize_t set_pwm_freq(struct device *dev,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/* The ADT7468 has a special high-frequency PWM output mode,
|
||||
/*
|
||||
* The ADT7468 has a special high-frequency PWM output mode,
|
||||
* where all PWM outputs are driven by a 22.5 kHz clock.
|
||||
* This might confuse the user, but there's not much we can do. */
|
||||
* This might confuse the user, but there's not much we can do.
|
||||
*/
|
||||
if (data->type == adt7468 && val >= 11300) { /* High freq. mode */
|
||||
data->cfg5 &= ~ADT7468_HFPWM;
|
||||
lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5);
|
||||
@ -648,7 +687,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_min[nr] = INS_TO_REG(nr, val);
|
||||
@ -671,7 +715,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_max[nr] = INS_TO_REG(nr, val);
|
||||
@ -722,7 +771,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (IS_ADT7468_OFF64(data))
|
||||
val += 64;
|
||||
@ -748,7 +802,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (IS_ADT7468_OFF64(data))
|
||||
val += 64;
|
||||
@ -789,7 +848,12 @@ static ssize_t set_pwm_auto_channels(struct device *dev,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->autofan[nr].config = (data->autofan[nr].config & (~0xe0))
|
||||
@ -814,7 +878,12 @@ static ssize_t set_pwm_auto_pwm_min(struct device *dev,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->autofan[nr].min_pwm = PWM_TO_REG(val);
|
||||
@ -838,8 +907,13 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
u8 tmp;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->autofan[nr].min_off = val;
|
||||
@ -885,7 +959,12 @@ static ssize_t set_temp_auto_temp_off(struct device *dev,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
int min;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
min = TEMP_FROM_REG(data->zone[nr].limit);
|
||||
@ -916,7 +995,12 @@ static ssize_t set_temp_auto_temp_min(struct device *dev,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->zone[nr].limit = TEMP_TO_REG(val);
|
||||
@ -951,7 +1035,12 @@ static ssize_t set_temp_auto_temp_max(struct device *dev,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
int min;
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
min = TEMP_FROM_REG(data->zone[nr].limit);
|
||||
@ -979,7 +1068,12 @@ static ssize_t set_temp_auto_temp_crit(struct device *dev,
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->zone[nr].critical = TEMP_TO_REG(val);
|
||||
@ -1338,24 +1432,28 @@ static int lm85_probe(struct i2c_client *client,
|
||||
goto err_remove_files;
|
||||
}
|
||||
|
||||
/* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used
|
||||
as a sixth digital VID input rather than an analog input. */
|
||||
/*
|
||||
* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used
|
||||
* as a sixth digital VID input rather than an analog input.
|
||||
*/
|
||||
if (data->type == adt7463 || data->type == adt7468) {
|
||||
u8 vid = lm85_read_value(client, LM85_REG_VID);
|
||||
if (vid & 0x80)
|
||||
data->has_vid5 = true;
|
||||
}
|
||||
|
||||
if (!data->has_vid5)
|
||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||
&lm85_group_in4)))
|
||||
if (!data->has_vid5) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &lm85_group_in4);
|
||||
if (err)
|
||||
goto err_remove_files;
|
||||
}
|
||||
|
||||
/* The EMC6D100 has 3 additional voltage inputs */
|
||||
if (data->type == emc6d100)
|
||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||
&lm85_group_in567)))
|
||||
if (data->type == emc6d100) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &lm85_group_in567);
|
||||
if (err)
|
||||
goto err_remove_files;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
@ -1443,7 +1541,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
|
||||
/* Things that change quickly */
|
||||
dev_dbg(&client->dev, "Reading sensor values\n");
|
||||
|
||||
/* Have to read extended bits first to "freeze" the
|
||||
/*
|
||||
* Have to read extended bits first to "freeze" the
|
||||
* more significant bits that are read later.
|
||||
* There are 2 additional resolution bits per channel and we
|
||||
* have room for 4, so we shift them to the left.
|
||||
@ -1503,9 +1602,10 @@ static struct lm85_data *lm85_update_device(struct device *dev)
|
||||
EMC6D100_REG_ALARM3) << 16;
|
||||
} else if (data->type == emc6d102 || data->type == emc6d103 ||
|
||||
data->type == emc6d103s) {
|
||||
/* Have to read LSB bits after the MSB ones because
|
||||
the reading of the MSB bits has frozen the
|
||||
LSBs (backward from the ADM1027).
|
||||
/*
|
||||
* Have to read LSB bits after the MSB ones because
|
||||
* the reading of the MSB bits has frozen the
|
||||
* LSBs (backward from the ADM1027).
|
||||
*/
|
||||
int ext1 = lm85_read_value(client,
|
||||
EMC6D102_REG_EXTEND_ADC1);
|
||||
@ -1611,22 +1711,10 @@ static struct lm85_data *lm85_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static int __init sm_lm85_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm85_driver);
|
||||
}
|
||||
|
||||
static void __exit sm_lm85_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm85_driver);
|
||||
}
|
||||
module_i2c_driver(lm85_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, "
|
||||
"Margit Schubert-While <margitsw@t-online.de>, "
|
||||
"Justin Thiessen <jthiessen@penguincomputing.com>");
|
||||
MODULE_DESCRIPTION("LM85-B, LM85-C driver");
|
||||
|
||||
module_init(sm_lm85_init);
|
||||
module_exit(sm_lm85_exit);
|
||||
|
1440
drivers/hwmon/lm87.c
1440
drivers/hwmon/lm87.c
File diff suppressed because it is too large
Load Diff
@ -1514,19 +1514,8 @@ static struct i2c_driver lm90_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init sensors_lm90_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm90_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm90_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm90_driver);
|
||||
}
|
||||
module_i2c_driver(lm90_driver);
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("LM90/ADM1032 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm90_init);
|
||||
module_exit(sensors_lm90_exit);
|
||||
|
@ -49,8 +49,10 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
/* The LM92 and MAX6635 have 2 two-state pins for address selection,
|
||||
resulting in 4 possible addresses. */
|
||||
/*
|
||||
* The LM92 and MAX6635 have 2 two-state pins for address selection,
|
||||
* resulting in 4 possible addresses.
|
||||
*/
|
||||
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
|
||||
I2C_CLIENT_END };
|
||||
|
||||
@ -63,11 +65,13 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
|
||||
#define LM92_REG_TEMP_HIGH 0x05 /* 16-bit, RW */
|
||||
#define LM92_REG_MAN_ID 0x07 /* 16-bit, RO, LM92 only */
|
||||
|
||||
/* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius,
|
||||
left-justified in 16-bit registers. No rounding is done, with such
|
||||
a resolution it's just not worth it. Note that the MAX6635 doesn't
|
||||
make use of the 4 lower bits for limits (i.e. effective resolution
|
||||
for limits is 1 degree Celsius). */
|
||||
/*
|
||||
* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius,
|
||||
* left-justified in 16-bit registers. No rounding is done, with such
|
||||
* a resolution it's just not worth it. Note that the MAX6635 doesn't
|
||||
* make use of the 4 lower bits for limits (i.e. effective resolution
|
||||
* for limits is 1 degree Celsius).
|
||||
*/
|
||||
static inline int TEMP_FROM_REG(s16 reg)
|
||||
{
|
||||
return reg / 8 * 625 / 10;
|
||||
@ -138,7 +142,8 @@ static struct lm92_data *lm92_update_device(struct device *dev)
|
||||
}
|
||||
|
||||
#define show_temp(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct lm92_data *data = lm92_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
|
||||
@ -149,12 +154,16 @@ show_temp(temp1_min);
|
||||
show_temp(temp1_max);
|
||||
|
||||
#define set_temp(value, reg) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm92_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
long val; \
|
||||
int err = kstrtol(buf, 10, &val); \
|
||||
if (err) \
|
||||
return err; \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->value = TEMP_TO_REG(val); \
|
||||
@ -166,31 +175,40 @@ set_temp(temp1_crit, LM92_REG_TEMP_CRIT);
|
||||
set_temp(temp1_min, LM92_REG_TEMP_LOW);
|
||||
set_temp(temp1_max, LM92_REG_TEMP_HIGH);
|
||||
|
||||
static ssize_t show_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_temp1_crit_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lm92_data *data = lm92_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit)
|
||||
- TEMP_FROM_REG(data->temp1_hyst));
|
||||
}
|
||||
static ssize_t show_temp1_max_hyst(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_temp1_max_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lm92_data *data = lm92_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max)
|
||||
- TEMP_FROM_REG(data->temp1_hyst));
|
||||
}
|
||||
static ssize_t show_temp1_min_hyst(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_temp1_min_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lm92_data *data = lm92_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min)
|
||||
+ TEMP_FROM_REG(data->temp1_hyst));
|
||||
}
|
||||
|
||||
static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_temp1_crit_hyst(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm92_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val;
|
||||
@ -200,7 +218,8 @@ static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute *
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lm92_data *data = lm92_update_device(dev);
|
||||
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input));
|
||||
@ -246,19 +265,23 @@ static void lm92_init_client(struct i2c_client *client)
|
||||
config & 0xFE);
|
||||
}
|
||||
|
||||
/* The MAX6635 has no identification register, so we have to use tricks
|
||||
to identify it reliably. This is somewhat slow.
|
||||
Note that we do NOT rely on the 2 MSB of the configuration register
|
||||
always reading 0, as suggested by the datasheet, because it was once
|
||||
reported not to be true. */
|
||||
/*
|
||||
* The MAX6635 has no identification register, so we have to use tricks
|
||||
* to identify it reliably. This is somewhat slow.
|
||||
* Note that we do NOT rely on the 2 MSB of the configuration register
|
||||
* always reading 0, as suggested by the datasheet, because it was once
|
||||
* reported not to be true.
|
||||
*/
|
||||
static int max6635_check(struct i2c_client *client)
|
||||
{
|
||||
u16 temp_low, temp_high, temp_hyst, temp_crit;
|
||||
u8 conf;
|
||||
int i;
|
||||
|
||||
/* No manufacturer ID register, so a read from this address will
|
||||
always return the last read value. */
|
||||
/*
|
||||
* No manufacturer ID register, so a read from this address will
|
||||
* always return the last read value.
|
||||
*/
|
||||
temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW);
|
||||
if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low)
|
||||
return 0;
|
||||
@ -274,10 +297,12 @@ static int max6635_check(struct i2c_client *client)
|
||||
if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00))
|
||||
return 0;
|
||||
|
||||
/* Registers addresses were found to cycle over 16-byte boundaries.
|
||||
We don't test all registers with all offsets so as to save some
|
||||
reads and time, but this should still be sufficient to dismiss
|
||||
non-MAX6635 chips. */
|
||||
/*
|
||||
* Registers addresses were found to cycle over 16-byte boundaries.
|
||||
* We don't test all registers with all offsets so as to save some
|
||||
* reads and time, but this should still be sufficient to dismiss
|
||||
* non-MAX6635 chips.
|
||||
*/
|
||||
conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG);
|
||||
for (i = 16; i < 96; i *= 2) {
|
||||
if (temp_hyst != i2c_smbus_read_word_data(client,
|
||||
@ -362,7 +387,8 @@ static int lm92_probe(struct i2c_client *new_client,
|
||||
lm92_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &lm92_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
@ -416,19 +442,8 @@ static struct i2c_driver lm92_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init sensors_lm92_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm92_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm92_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm92_driver);
|
||||
}
|
||||
module_i2c_driver(lm92_driver);
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("LM92/MAX6635 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm92_init);
|
||||
module_exit(sensors_lm92_exit);
|
||||
|
@ -1,41 +1,41 @@
|
||||
/*
|
||||
lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
|
||||
|
||||
Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com>
|
||||
Copyright (c) 2004 Utilitek Systems, Inc.
|
||||
|
||||
derived in part from lm78.c:
|
||||
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
|
||||
derived in part from lm85.c:
|
||||
Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
|
||||
Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de>
|
||||
|
||||
derived in part from w83l785ts.c:
|
||||
Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com>
|
||||
Copyright (c) 2005 Aspen Systems, Inc.
|
||||
|
||||
Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org>
|
||||
Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab
|
||||
|
||||
Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de>
|
||||
Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
|
||||
*
|
||||
* Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com>
|
||||
* Copyright (c) 2004 Utilitek Systems, Inc.
|
||||
*
|
||||
* derived in part from lm78.c:
|
||||
* Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
*
|
||||
* derived in part from lm85.c:
|
||||
* Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
|
||||
* Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de>
|
||||
*
|
||||
* derived in part from w83l785ts.c:
|
||||
* Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com>
|
||||
* Copyright (c) 2005 Aspen Systems, Inc.
|
||||
*
|
||||
* Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org>
|
||||
* Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab
|
||||
*
|
||||
* Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de>
|
||||
* Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -187,8 +187,10 @@ static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = {
|
||||
{ 0xfd, 9 },
|
||||
};
|
||||
|
||||
/* ALARMS: SYSCTL format described further below
|
||||
REG: 64 bits in 8 registers, as immediately below */
|
||||
/*
|
||||
* ALARMS: SYSCTL format described further below
|
||||
* REG: 64 bits in 8 registers, as immediately below
|
||||
*/
|
||||
struct block1_t {
|
||||
u8 host_status_1;
|
||||
u8 host_status_2;
|
||||
@ -217,8 +219,10 @@ struct lm93_data {
|
||||
/* register values, arranged by block read groups */
|
||||
struct block1_t block1;
|
||||
|
||||
/* temp1 - temp4: unfiltered readings
|
||||
temp1 - temp2: filtered readings */
|
||||
/*
|
||||
* temp1 - temp4: unfiltered readings
|
||||
* temp1 - temp2: filtered readings
|
||||
*/
|
||||
u8 block2[6];
|
||||
|
||||
/* vin1 - vin16: readings */
|
||||
@ -295,14 +299,18 @@ struct lm93_data {
|
||||
u8 sfc2;
|
||||
u8 sf_tach_to_pwm;
|
||||
|
||||
/* The two PWM CTL2 registers can read something other than what was
|
||||
last written for the OVR_DC field (duty cycle override). So, we
|
||||
save the user-commanded value here. */
|
||||
/*
|
||||
* The two PWM CTL2 registers can read something other than what was
|
||||
* last written for the OVR_DC field (duty cycle override). So, we
|
||||
* save the user-commanded value here.
|
||||
*/
|
||||
u8 pwm_override[2];
|
||||
};
|
||||
|
||||
/* VID: mV
|
||||
REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */
|
||||
/*
|
||||
* VID: mV
|
||||
* REG: 6-bits, right justified, *always* using Intel VRM/VRD 10
|
||||
*/
|
||||
static int LM93_VID_FROM_REG(u8 reg)
|
||||
{
|
||||
return vid_from_reg((reg & 0x3f), 100);
|
||||
@ -317,11 +325,12 @@ static const u8 lm93_vin_reg_max[16] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1,
|
||||
};
|
||||
/* Values from the datasheet. They're here for documentation only.
|
||||
static const u8 lm93_vin_reg_nom[16] = {
|
||||
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
|
||||
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0,
|
||||
};
|
||||
/*
|
||||
* Values from the datasheet. They're here for documentation only.
|
||||
* static const u8 lm93_vin_reg_nom[16] = {
|
||||
* 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
|
||||
* 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0,
|
||||
* };
|
||||
*/
|
||||
|
||||
/* min, max, and nominal voltage readings, per channel (mV)*/
|
||||
@ -334,11 +343,12 @@ static const unsigned long lm93_vin_val_max[16] = {
|
||||
1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600,
|
||||
4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600,
|
||||
};
|
||||
/* Values from the datasheet. They're here for documentation only.
|
||||
static const unsigned long lm93_vin_val_nom[16] = {
|
||||
927, 927, 927, 1200, 1500, 1500, 1200, 1200,
|
||||
3300, 5000, 2500, 1969, 984, 984, 309, 3300,
|
||||
};
|
||||
/*
|
||||
* Values from the datasheet. They're here for documentation only.
|
||||
* static const unsigned long lm93_vin_val_nom[16] = {
|
||||
* 927, 927, 927, 1200, 1500, 1500, 1200, 1200,
|
||||
* 3300, 5000, 2500, 1969, 984, 984, 309, 3300,
|
||||
* };
|
||||
*/
|
||||
|
||||
static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
|
||||
@ -353,8 +363,10 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
|
||||
return (slope * reg + intercept + 500) / 1000;
|
||||
}
|
||||
|
||||
/* IN: mV, limits determined by channel nr
|
||||
REG: scaling determined by channel nr */
|
||||
/*
|
||||
* IN: mV, limits determined by channel nr
|
||||
* REG: scaling determined by channel nr
|
||||
*/
|
||||
static u8 LM93_IN_TO_REG(int nr, unsigned val)
|
||||
{
|
||||
/* range limit */
|
||||
@ -386,12 +398,14 @@ static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
|
||||
return (uV_vid + uV_offset + 5000) / 10000;
|
||||
}
|
||||
|
||||
#define LM93_IN_MIN_FROM_REG(reg,vid) LM93_IN_REL_FROM_REG(reg,0,vid)
|
||||
#define LM93_IN_MAX_FROM_REG(reg,vid) LM93_IN_REL_FROM_REG(reg,1,vid)
|
||||
#define LM93_IN_MIN_FROM_REG(reg, vid) LM93_IN_REL_FROM_REG((reg), 0, (vid))
|
||||
#define LM93_IN_MAX_FROM_REG(reg, vid) LM93_IN_REL_FROM_REG((reg), 1, (vid))
|
||||
|
||||
/* vid in mV , upper == 0 indicates low limit, otherwise upper limit
|
||||
upper also determines which nibble of the register is returned
|
||||
(the other nibble will be 0x0) */
|
||||
/*
|
||||
* vid in mV , upper == 0 indicates low limit, otherwise upper limit
|
||||
* upper also determines which nibble of the register is returned
|
||||
* (the other nibble will be 0x0)
|
||||
*/
|
||||
static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
|
||||
{
|
||||
long uV_offset = vid * 1000 - val * 10000;
|
||||
@ -404,8 +418,10 @@ static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
|
||||
}
|
||||
}
|
||||
|
||||
/* TEMP: 1/1000 degrees C (-128C to +127C)
|
||||
REG: 1C/bit, two's complement */
|
||||
/*
|
||||
* TEMP: 1/1000 degrees C (-128C to +127C)
|
||||
* REG: 1C/bit, two's complement
|
||||
*/
|
||||
static int LM93_TEMP_FROM_REG(u8 reg)
|
||||
{
|
||||
return (s8)reg * 1000;
|
||||
@ -414,8 +430,10 @@ static int LM93_TEMP_FROM_REG(u8 reg)
|
||||
#define LM93_TEMP_MIN (-128000)
|
||||
#define LM93_TEMP_MAX (127000)
|
||||
|
||||
/* TEMP: 1/1000 degrees C (-128C to +127C)
|
||||
REG: 1C/bit, two's complement */
|
||||
/*
|
||||
* TEMP: 1/1000 degrees C (-128C to +127C)
|
||||
* REG: 1C/bit, two's complement
|
||||
*/
|
||||
static u8 LM93_TEMP_TO_REG(long temp)
|
||||
{
|
||||
int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
|
||||
@ -430,9 +448,11 @@ static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr)
|
||||
return sfc2 & (nr < 2 ? 0x10 : 0x20);
|
||||
}
|
||||
|
||||
/* This function is common to all 4-bit temperature offsets
|
||||
reg is 4 bits right justified
|
||||
mode 0 => 1C/bit, mode !0 => 0.5C/bit */
|
||||
/*
|
||||
* This function is common to all 4-bit temperature offsets
|
||||
* reg is 4 bits right justified
|
||||
* mode 0 => 1C/bit, mode !0 => 0.5C/bit
|
||||
*/
|
||||
static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode)
|
||||
{
|
||||
return (reg & 0x0f) * (mode ? 5 : 10);
|
||||
@ -442,9 +462,11 @@ static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode)
|
||||
#define LM93_TEMP_OFFSET_MAX0 (150)
|
||||
#define LM93_TEMP_OFFSET_MAX1 (75)
|
||||
|
||||
/* This function is common to all 4-bit temperature offsets
|
||||
returns 4 bits right justified
|
||||
mode 0 => 1C/bit, mode !0 => 0.5C/bit */
|
||||
/*
|
||||
* This function is common to all 4-bit temperature offsets
|
||||
* returns 4 bits right justified
|
||||
* mode 0 => 1C/bit, mode !0 => 0.5C/bit
|
||||
*/
|
||||
static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode)
|
||||
{
|
||||
int factor = mode ? 5 : 10;
|
||||
@ -466,9 +488,11 @@ static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode)
|
||||
return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode);
|
||||
}
|
||||
|
||||
/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero))
|
||||
REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero)
|
||||
0 <= nr <= 3 */
|
||||
/*
|
||||
* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero))
|
||||
* REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero)
|
||||
* 0 <= nr <= 3
|
||||
*/
|
||||
static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode)
|
||||
{
|
||||
u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode);
|
||||
@ -532,9 +556,12 @@ static u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst,
|
||||
return reg;
|
||||
}
|
||||
|
||||
/* PWM: 0-255 per sensors documentation
|
||||
REG: 0-13 as mapped below... right justified */
|
||||
typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t;
|
||||
/*
|
||||
* PWM: 0-255 per sensors documentation
|
||||
* REG: 0-13 as mapped below... right justified
|
||||
*/
|
||||
enum pwm_freq { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ };
|
||||
|
||||
static int lm93_pwm_map[2][16] = {
|
||||
{
|
||||
0x00, /* 0.00% */ 0x40, /* 25.00% */
|
||||
@ -558,13 +585,13 @@ static int lm93_pwm_map[2][16] = {
|
||||
},
|
||||
};
|
||||
|
||||
static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq)
|
||||
static int LM93_PWM_FROM_REG(u8 reg, enum pwm_freq freq)
|
||||
{
|
||||
return lm93_pwm_map[freq][reg & 0x0f];
|
||||
}
|
||||
|
||||
/* round up to nearest match */
|
||||
static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq)
|
||||
static u8 LM93_PWM_TO_REG(int pwm, enum pwm_freq freq)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 13; i++)
|
||||
@ -600,8 +627,10 @@ static u16 LM93_FAN_TO_REG(long rpm)
|
||||
return cpu_to_le16(regs);
|
||||
}
|
||||
|
||||
/* PWM FREQ: HZ
|
||||
REG: 0-7 as mapped below */
|
||||
/*
|
||||
* PWM FREQ: HZ
|
||||
* REG: 0-7 as mapped below
|
||||
*/
|
||||
static int lm93_pwm_freq_map[8] = {
|
||||
22500, 96, 84, 72, 60, 48, 36, 12
|
||||
};
|
||||
@ -623,8 +652,10 @@ static u8 LM93_PWM_FREQ_TO_REG(int freq)
|
||||
return (u8)i;
|
||||
}
|
||||
|
||||
/* TIME: 1/100 seconds
|
||||
* REG: 0-7 as mapped below */
|
||||
/*
|
||||
* TIME: 1/100 seconds
|
||||
* REG: 0-7 as mapped below
|
||||
*/
|
||||
static int lm93_spinup_time_map[8] = {
|
||||
0, 10, 25, 40, 70, 100, 200, 400,
|
||||
};
|
||||
@ -654,24 +685,30 @@ static int LM93_RAMP_FROM_REG(u8 reg)
|
||||
return (reg & 0x0f) * 5;
|
||||
}
|
||||
|
||||
/* RAMP: 1/100 seconds
|
||||
REG: 50mS/bit 4-bits right justified */
|
||||
/*
|
||||
* RAMP: 1/100 seconds
|
||||
* REG: 50mS/bit 4-bits right justified
|
||||
*/
|
||||
static u8 LM93_RAMP_TO_REG(int ramp)
|
||||
{
|
||||
ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
|
||||
return (u8)((ramp + 2) / 5);
|
||||
}
|
||||
|
||||
/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6%
|
||||
* REG: (same) */
|
||||
/*
|
||||
* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6%
|
||||
* REG: (same)
|
||||
*/
|
||||
static u8 LM93_PROCHOT_TO_REG(long prochot)
|
||||
{
|
||||
prochot = SENSORS_LIMIT(prochot, 0, 255);
|
||||
return (u8)prochot;
|
||||
}
|
||||
|
||||
/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds)
|
||||
* REG: 0-9 as mapped below */
|
||||
/*
|
||||
* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds)
|
||||
* REG: 0-9 as mapped below
|
||||
*/
|
||||
static int lm93_interval_map[10] = {
|
||||
73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200,
|
||||
};
|
||||
@ -693,21 +730,24 @@ static u8 LM93_INTERVAL_TO_REG(long interval)
|
||||
return (u8)i;
|
||||
}
|
||||
|
||||
/* GPIO: 0-255, GPIO0 is LSB
|
||||
* REG: inverted */
|
||||
/*
|
||||
* GPIO: 0-255, GPIO0 is LSB
|
||||
* REG: inverted
|
||||
*/
|
||||
static unsigned LM93_GPI_FROM_REG(u8 reg)
|
||||
{
|
||||
return ~reg & 0xff;
|
||||
}
|
||||
|
||||
/* alarm bitmask definitions
|
||||
The LM93 has nearly 64 bits of error status... I've pared that down to
|
||||
what I think is a useful subset in order to fit it into 32 bits.
|
||||
|
||||
Especially note that the #VRD_HOT alarms are missing because we provide
|
||||
that information as values in another sysfs file.
|
||||
|
||||
If libsensors is extended to support 64 bit values, this could be revisited.
|
||||
/*
|
||||
* alarm bitmask definitions
|
||||
* The LM93 has nearly 64 bits of error status... I've pared that down to
|
||||
* what I think is a useful subset in order to fit it into 32 bits.
|
||||
*
|
||||
* Especially note that the #VRD_HOT alarms are missing because we provide
|
||||
* that information as values in another sysfs file.
|
||||
*
|
||||
* If libsensors is extended to support 64 bit values, this could be revisited.
|
||||
*/
|
||||
#define LM93_ALARM_IN1 0x00000001
|
||||
#define LM93_ALARM_IN2 0x00000002
|
||||
@ -773,7 +813,8 @@ static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
|
||||
|
||||
/* retry in case of read errors */
|
||||
for (i = 1; i <= MAX_RETRIES; i++) {
|
||||
if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) {
|
||||
value = i2c_smbus_read_byte_data(client, reg);
|
||||
if (value >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
dev_warn(&client->dev, "lm93: read byte data failed, "
|
||||
@ -808,7 +849,8 @@ static u16 lm93_read_word(struct i2c_client *client, u8 reg)
|
||||
|
||||
/* retry in case of read errors */
|
||||
for (i = 1; i <= MAX_RETRIES; i++) {
|
||||
if ((value = i2c_smbus_read_word_data(client, reg)) >= 0) {
|
||||
value = i2c_smbus_read_word_data(client, reg);
|
||||
if (value >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
dev_warn(&client->dev, "lm93: read word data failed, "
|
||||
@ -840,9 +882,9 @@ static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
|
||||
static u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX];
|
||||
|
||||
/*
|
||||
read block data into values, retry if not expected length
|
||||
fbn => index to lm93_block_read_cmds table
|
||||
(Fixed Block Number - section 14.5.2 of LM93 datasheet)
|
||||
* read block data into values, retry if not expected length
|
||||
* fbn => index to lm93_block_read_cmds table
|
||||
* (Fixed Block Number - section 14.5.2 of LM93 datasheet)
|
||||
*/
|
||||
static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
|
||||
{
|
||||
@ -863,7 +905,8 @@ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
|
||||
}
|
||||
|
||||
if (result == lm93_block_read_cmds[fbn].len) {
|
||||
memcpy(values,lm93_block_buffer,lm93_block_read_cmds[fbn].len);
|
||||
memcpy(values, lm93_block_buffer,
|
||||
lm93_block_read_cmds[fbn].len);
|
||||
} else {
|
||||
/* <TODO> what to do in case of error? */
|
||||
}
|
||||
@ -1097,14 +1140,13 @@ static ssize_t show_in_min(struct device *dev,
|
||||
int vccp = nr - 6;
|
||||
long rc, vid;
|
||||
|
||||
if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
|
||||
if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) {
|
||||
vid = LM93_VID_FROM_REG(data->vid[vccp]);
|
||||
rc = LM93_IN_MIN_FROM_REG(data->vccp_limits[vccp], vid);
|
||||
} else {
|
||||
rc = LM93_IN_FROM_REG(nr, data->block7[nr].min);
|
||||
}
|
||||
else {
|
||||
rc = LM93_IN_FROM_REG(nr, data->block7[nr].min); \
|
||||
}
|
||||
return sprintf(buf, "%ld\n", rc); \
|
||||
return sprintf(buf, "%ld\n", rc);
|
||||
}
|
||||
|
||||
static ssize_t store_in_min(struct device *dev, struct device_attribute *attr,
|
||||
@ -1113,19 +1155,23 @@ static ssize_t store_in_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
int vccp = nr - 6;
|
||||
long vid;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
|
||||
if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) {
|
||||
vid = LM93_VID_FROM_REG(data->vid[vccp]);
|
||||
data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0xf0) |
|
||||
LM93_IN_REL_TO_REG(val, 0, vid);
|
||||
lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
|
||||
data->vccp_limits[vccp]);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
data->block7[nr].min = LM93_IN_TO_REG(nr, val);
|
||||
lm93_write_byte(client, LM93_REG_IN_MIN(nr),
|
||||
data->block7[nr].min);
|
||||
@ -1175,14 +1221,13 @@ static ssize_t show_in_max(struct device *dev,
|
||||
int vccp = nr - 6;
|
||||
long rc, vid;
|
||||
|
||||
if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
|
||||
if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) {
|
||||
vid = LM93_VID_FROM_REG(data->vid[vccp]);
|
||||
rc = LM93_IN_MAX_FROM_REG(data->vccp_limits[vccp], vid);
|
||||
} else {
|
||||
rc = LM93_IN_FROM_REG(nr, data->block7[nr].max);
|
||||
}
|
||||
else {
|
||||
rc = LM93_IN_FROM_REG(nr,data->block7[nr].max); \
|
||||
}
|
||||
return sprintf(buf,"%ld\n",rc); \
|
||||
return sprintf(buf, "%ld\n", rc);
|
||||
}
|
||||
|
||||
static ssize_t store_in_max(struct device *dev, struct device_attribute *attr,
|
||||
@ -1191,19 +1236,23 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute *attr,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
int vccp = nr - 6;
|
||||
long vid;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
|
||||
if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) {
|
||||
vid = LM93_VID_FROM_REG(data->vid[vccp]);
|
||||
data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0x0f) |
|
||||
LM93_IN_REL_TO_REG(val, 1, vid);
|
||||
lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
|
||||
data->vccp_limits[vccp]);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
data->block7[nr].max = LM93_IN_TO_REG(nr, val);
|
||||
lm93_write_byte(client, LM93_REG_IN_MAX(nr),
|
||||
data->block7[nr].max);
|
||||
@ -1271,7 +1320,12 @@ static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
|
||||
@ -1301,7 +1355,12 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
|
||||
@ -1332,7 +1391,12 @@ static ssize_t store_temp_auto_base(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->block10.base[nr] = LM93_TEMP_TO_REG(val);
|
||||
@ -1363,7 +1427,12 @@ static ssize_t store_temp_auto_boost(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->boost[nr] = LM93_TEMP_TO_REG(val);
|
||||
@ -1397,7 +1466,12 @@ static ssize_t store_temp_auto_boost_hyst(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/* force 0.5C/bit mode */
|
||||
@ -1443,7 +1517,12 @@ static ssize_t store_temp_auto_offset(struct device *dev,
|
||||
int ofs = s_attr->nr;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/* force 0.5C/bit mode */
|
||||
@ -1550,8 +1629,13 @@ static ssize_t store_temp_auto_pwm_min(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 reg, ctl4;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr));
|
||||
@ -1593,8 +1677,13 @@ static ssize_t store_temp_auto_offset_hyst(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 reg;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/* force 0.5C/bit mode */
|
||||
@ -1649,7 +1738,12 @@ static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->block8[nr] = LM93_FAN_TO_REG(val);
|
||||
@ -1667,17 +1761,18 @@ static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
|
||||
static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
|
||||
show_fan_min, store_fan_min, 3);
|
||||
|
||||
/* some tedious bit-twiddling here to deal with the register format:
|
||||
|
||||
data->sf_tach_to_pwm: (tach to pwm mapping bits)
|
||||
|
||||
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
||||
T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1
|
||||
|
||||
data->sfc2: (enable bits)
|
||||
|
||||
bit | 3 | 2 | 1 | 0
|
||||
T4 T3 T2 T1
|
||||
/*
|
||||
* some tedious bit-twiddling here to deal with the register format:
|
||||
*
|
||||
* data->sf_tach_to_pwm: (tach to pwm mapping bits)
|
||||
*
|
||||
* bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
||||
* T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1
|
||||
*
|
||||
* data->sfc2: (enable bits)
|
||||
*
|
||||
* bit | 3 | 2 | 1 | 0
|
||||
* T4 T3 T2 T1
|
||||
*/
|
||||
|
||||
static ssize_t show_fan_smart_tach(struct device *dev,
|
||||
@ -1697,8 +1792,10 @@ static ssize_t show_fan_smart_tach(struct device *dev,
|
||||
return sprintf(buf, "%ld\n", rc);
|
||||
}
|
||||
|
||||
/* helper function - must grab data->update_lock before calling
|
||||
fan is 0-3, indicating fan1-fan4 */
|
||||
/*
|
||||
* helper function - must grab data->update_lock before calling
|
||||
* fan is 0-3, indicating fan1-fan4
|
||||
*/
|
||||
static void lm93_write_fan_smart_tach(struct i2c_client *client,
|
||||
struct lm93_data *data, int fan, long value)
|
||||
{
|
||||
@ -1724,7 +1821,12 @@ static ssize_t store_fan_smart_tach(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/* sanity test, ignore the write otherwise */
|
||||
@ -1775,8 +1877,13 @@ static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 ctl2, ctl4;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ctl2 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2));
|
||||
@ -1818,8 +1925,13 @@ static ssize_t store_pwm_enable(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 ctl2;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ctl2 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2));
|
||||
@ -1828,9 +1940,11 @@ static ssize_t store_pwm_enable(struct device *dev,
|
||||
case 0:
|
||||
ctl2 |= 0xF1; /* enable manual override, set PWM to max */
|
||||
break;
|
||||
case 1: ctl2 |= 0x01; /* enable manual override */
|
||||
case 1:
|
||||
ctl2 |= 0x01; /* enable manual override */
|
||||
break;
|
||||
case 2: ctl2 &= ~0x01; /* disable manual override */
|
||||
case 2:
|
||||
ctl2 &= ~0x01; /* disable manual override */
|
||||
break;
|
||||
default:
|
||||
mutex_unlock(&data->update_lock);
|
||||
@ -1858,9 +1972,11 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
|
||||
return sprintf(buf, "%d\n", LM93_PWM_FREQ_FROM_REG(ctl4));
|
||||
}
|
||||
|
||||
/* helper function - must grab data->update_lock before calling
|
||||
pwm is 0-1, indicating pwm1-pwm2
|
||||
this disables smart tach for all tach channels bound to the given pwm */
|
||||
/*
|
||||
* helper function - must grab data->update_lock before calling
|
||||
* pwm is 0-1, indicating pwm1-pwm2
|
||||
* this disables smart tach for all tach channels bound to the given pwm
|
||||
*/
|
||||
static void lm93_disable_fan_smart_tach(struct i2c_client *client,
|
||||
struct lm93_data *data, int pwm)
|
||||
{
|
||||
@ -1887,8 +2003,13 @@ static ssize_t store_pwm_freq(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 ctl4;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4));
|
||||
@ -1922,7 +2043,12 @@ static ssize_t store_pwm_auto_channels(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255);
|
||||
@ -1958,8 +2084,13 @@ static ssize_t store_pwm_auto_spinup_min(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 ctl3, ctl4;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ctl3 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
|
||||
@ -1996,8 +2127,13 @@ static ssize_t store_pwm_auto_spinup_time(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 ctl3;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ctl3 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
|
||||
@ -2029,8 +2165,13 @@ static ssize_t store_pwm_auto_prochot_ramp(struct device *dev,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 ramp;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
|
||||
@ -2058,8 +2199,13 @@ static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 ramp;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
|
||||
@ -2121,7 +2267,12 @@ static ssize_t store_prochot_max(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->prochot_max[nr] = LM93_PROCHOT_TO_REG(val);
|
||||
@ -2154,7 +2305,12 @@ static ssize_t store_prochot_override(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (val)
|
||||
@ -2192,8 +2348,13 @@ static ssize_t store_prochot_interval(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u8 tmp;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
tmp = lm93_read_byte(client, LM93_REG_PROCHOT_INTERVAL);
|
||||
@ -2226,7 +2387,12 @@ static ssize_t store_prochot_override_duty_cycle(struct device *dev,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->prochot_override = (data->prochot_override & 0xf0) |
|
||||
@ -2254,7 +2420,12 @@ static ssize_t store_prochot_short(struct device *dev,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (val)
|
||||
@ -2635,20 +2806,9 @@ static struct i2c_driver lm93_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init lm93_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm93_driver);
|
||||
}
|
||||
|
||||
static void __exit lm93_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm93_driver);
|
||||
}
|
||||
module_i2c_driver(lm93_driver);
|
||||
|
||||
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, "
|
||||
"Hans J. Koch <hjk@hansjkoch.de>");
|
||||
MODULE_DESCRIPTION("LM93 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(lm93_init);
|
||||
module_exit(lm93_exit);
|
||||
|
@ -455,19 +455,8 @@ static struct i2c_driver lm95241_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init sensors_lm95241_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm95241_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm95241_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm95241_driver);
|
||||
}
|
||||
module_i2c_driver(lm95241_driver);
|
||||
|
||||
MODULE_AUTHOR("Davide Rizzo <elpa.rizzo@gmail.com>");
|
||||
MODULE_DESCRIPTION("LM95241 sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm95241_init);
|
||||
module_exit(sensors_lm95241_exit);
|
||||
|
@ -525,19 +525,8 @@ static struct i2c_driver lm95245_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init sensors_lm95245_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm95245_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_lm95245_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm95245_driver);
|
||||
}
|
||||
module_i2c_driver(lm95245_driver);
|
||||
|
||||
MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
|
||||
MODULE_DESCRIPTION("LM95245 sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_lm95245_init);
|
||||
module_exit(sensors_lm95245_exit);
|
||||
|
@ -154,7 +154,8 @@ static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, \
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
|
||||
ltc4151_show_value, NULL, LTC4151_SENSE_H);
|
||||
|
||||
/* Finally, construct an array of pointers to members of the above objects,
|
||||
/*
|
||||
* Finally, construct an array of pointers to members of the above objects,
|
||||
* as required for sysfs_create_group()
|
||||
*/
|
||||
static struct attribute *ltc4151_attributes[] = {
|
||||
@ -238,19 +239,8 @@ static struct i2c_driver ltc4151_driver = {
|
||||
.id_table = ltc4151_id,
|
||||
};
|
||||
|
||||
static int __init ltc4151_init(void)
|
||||
{
|
||||
return i2c_add_driver(<c4151_driver);
|
||||
}
|
||||
|
||||
static void __exit ltc4151_exit(void)
|
||||
{
|
||||
i2c_del_driver(<c4151_driver);
|
||||
}
|
||||
module_i2c_driver(ltc4151_driver);
|
||||
|
||||
MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
|
||||
MODULE_DESCRIPTION("LTC4151 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ltc4151_init);
|
||||
module_exit(ltc4151_exit);
|
||||
|
@ -91,8 +91,10 @@ static int ltc4215_get_voltage(struct device *dev, u8 reg)
|
||||
voltage = regval * 605 / 10;
|
||||
break;
|
||||
case LTC4215_ADIN:
|
||||
/* The ADIN input is divided by 12.5, and has 4.82 mV
|
||||
* per increment, so we have the additional multiply */
|
||||
/*
|
||||
* The ADIN input is divided by 12.5, and has 4.82 mV
|
||||
* per increment, so we have the additional multiply
|
||||
*/
|
||||
voltage = regval * 482 * 125 / 1000;
|
||||
break;
|
||||
default:
|
||||
@ -109,7 +111,8 @@ static unsigned int ltc4215_get_current(struct device *dev)
|
||||
{
|
||||
struct ltc4215_data *data = ltc4215_update_device(dev);
|
||||
|
||||
/* The strange looking conversions that follow are fixed-point
|
||||
/*
|
||||
* The strange looking conversions that follow are fixed-point
|
||||
* math, since we cannot do floating point in the kernel.
|
||||
*
|
||||
* Step 1: convert sense register to microVolts
|
||||
@ -176,7 +179,8 @@ static ssize_t ltc4215_show_alarm(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
|
||||
}
|
||||
|
||||
/* These macros are used below in constructing device attribute objects
|
||||
/*
|
||||
* These macros are used below in constructing device attribute objects
|
||||
* for use with sysfs_create_group() to make a sysfs device file
|
||||
* for each register.
|
||||
*/
|
||||
@ -215,7 +219,8 @@ LTC4215_ALARM(in1_min_alarm, (1 << 1), LTC4215_STATUS);
|
||||
LTC4215_VOLTAGE(in2_input, LTC4215_SOURCE);
|
||||
LTC4215_ALARM(in2_min_alarm, (1 << 3), LTC4215_STATUS);
|
||||
|
||||
/* Finally, construct an array of pointers to members of the above objects,
|
||||
/*
|
||||
* Finally, construct an array of pointers to members of the above objects,
|
||||
* as required for sysfs_create_group()
|
||||
*/
|
||||
static struct attribute *ltc4215_attributes[] = {
|
||||
@ -309,19 +314,8 @@ static struct i2c_driver ltc4215_driver = {
|
||||
.id_table = ltc4215_id,
|
||||
};
|
||||
|
||||
static int __init ltc4215_init(void)
|
||||
{
|
||||
return i2c_add_driver(<c4215_driver);
|
||||
}
|
||||
|
||||
static void __exit ltc4215_exit(void)
|
||||
{
|
||||
i2c_del_driver(<c4215_driver);
|
||||
}
|
||||
module_i2c_driver(ltc4215_driver);
|
||||
|
||||
MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
|
||||
MODULE_DESCRIPTION("LTC4215 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ltc4215_init);
|
||||
module_exit(ltc4215_exit);
|
||||
|
@ -214,7 +214,8 @@ static unsigned int ltc4245_get_current(struct device *dev, u8 reg)
|
||||
unsigned int voltage;
|
||||
unsigned int curr;
|
||||
|
||||
/* The strange looking conversions that follow are fixed-point
|
||||
/*
|
||||
* The strange looking conversions that follow are fixed-point
|
||||
* math, since we cannot do floating point in the kernel.
|
||||
*
|
||||
* Step 1: convert sense register to microVolts
|
||||
@ -317,7 +318,8 @@ static ssize_t ltc4245_show_gpio(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", val * 10);
|
||||
}
|
||||
|
||||
/* These macros are used below in constructing device attribute objects
|
||||
/*
|
||||
* These macros are used below in constructing device attribute objects
|
||||
* for use with sysfs_create_group() to make a sysfs device file
|
||||
* for each register.
|
||||
*/
|
||||
@ -391,7 +393,8 @@ LTC4245_POWER(power2_input, LTC4245_5VSENSE);
|
||||
LTC4245_POWER(power3_input, LTC4245_3VSENSE);
|
||||
LTC4245_POWER(power4_input, LTC4245_VEESENSE);
|
||||
|
||||
/* Finally, construct an array of pointers to members of the above objects,
|
||||
/*
|
||||
* Finally, construct an array of pointers to members of the above objects,
|
||||
* as required for sysfs_create_group()
|
||||
*/
|
||||
static struct attribute *ltc4245_std_attributes[] = {
|
||||
@ -578,19 +581,8 @@ static struct i2c_driver ltc4245_driver = {
|
||||
.id_table = ltc4245_id,
|
||||
};
|
||||
|
||||
static int __init ltc4245_init(void)
|
||||
{
|
||||
return i2c_add_driver(<c4245_driver);
|
||||
}
|
||||
|
||||
static void __exit ltc4245_exit(void)
|
||||
{
|
||||
i2c_del_driver(<c4245_driver);
|
||||
}
|
||||
module_i2c_driver(ltc4245_driver);
|
||||
|
||||
MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
|
||||
MODULE_DESCRIPTION("LTC4245 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ltc4245_init);
|
||||
module_exit(ltc4245_exit);
|
||||
|
@ -235,11 +235,9 @@ static int ltc4261_probe(struct i2c_client *client,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto out_kzalloc;
|
||||
}
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
@ -250,7 +248,7 @@ static int ltc4261_probe(struct i2c_client *client,
|
||||
/* Register sysfs hooks */
|
||||
ret = sysfs_create_group(&client->dev.kobj, <c4261_group);
|
||||
if (ret)
|
||||
goto out_sysfs_create_group;
|
||||
return ret;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
@ -262,9 +260,6 @@ static int ltc4261_probe(struct i2c_client *client,
|
||||
|
||||
out_hwmon_device_register:
|
||||
sysfs_remove_group(&client->dev.kobj, <c4261_group);
|
||||
out_sysfs_create_group:
|
||||
kfree(data);
|
||||
out_kzalloc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -275,8 +270,6 @@ static int ltc4261_remove(struct i2c_client *client)
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, <c4261_group);
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -297,19 +290,8 @@ static struct i2c_driver ltc4261_driver = {
|
||||
.id_table = ltc4261_id,
|
||||
};
|
||||
|
||||
static int __init ltc4261_init(void)
|
||||
{
|
||||
return i2c_add_driver(<c4261_driver);
|
||||
}
|
||||
|
||||
static void __exit ltc4261_exit(void)
|
||||
{
|
||||
i2c_del_driver(<c4261_driver);
|
||||
}
|
||||
module_i2c_driver(ltc4261_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
|
||||
MODULE_DESCRIPTION("LTC4261 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ltc4261_init);
|
||||
module_exit(ltc4261_exit);
|
||||
|
@ -106,7 +106,8 @@ static ssize_t show_adc(struct device *dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* assume the reference voltage to be 2.048V, with an 8-bit sample,
|
||||
/*
|
||||
* assume the reference voltage to be 2.048V, with an 8-bit sample,
|
||||
* the LSB weight is 8mV
|
||||
*/
|
||||
return sprintf(buf, "%d\n", ret * 8);
|
||||
@ -227,17 +228,7 @@ static struct spi_driver max1111_driver = {
|
||||
.remove = __devexit_p(max1111_remove),
|
||||
};
|
||||
|
||||
static int __init max1111_init(void)
|
||||
{
|
||||
return spi_register_driver(&max1111_driver);
|
||||
}
|
||||
module_init(max1111_init);
|
||||
|
||||
static void __exit max1111_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&max1111_driver);
|
||||
}
|
||||
module_exit(max1111_exit);
|
||||
module_spi_driver(max1111_driver);
|
||||
|
||||
MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
|
||||
MODULE_DESCRIPTION("MAX1111 ADC Driver");
|
||||
|
@ -554,7 +554,7 @@ static int max16065_probe(struct i2c_client *client,
|
||||
| I2C_FUNC_SMBUS_READ_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (unlikely(!data))
|
||||
return -ENOMEM;
|
||||
|
||||
@ -567,20 +567,16 @@ static int max16065_probe(struct i2c_client *client,
|
||||
|
||||
if (have_secondary) {
|
||||
val = i2c_smbus_read_byte_data(client, MAX16065_SW_ENABLE);
|
||||
if (unlikely(val < 0)) {
|
||||
ret = val;
|
||||
goto out_free;
|
||||
}
|
||||
if (unlikely(val < 0))
|
||||
return val;
|
||||
secondary_is_max = val & MAX16065_WARNING_OV;
|
||||
}
|
||||
|
||||
/* Read scale registers, convert to range */
|
||||
for (i = 0; i < DIV_ROUND_UP(data->num_adc, 4); i++) {
|
||||
val = i2c_smbus_read_byte_data(client, MAX16065_SCALE(i));
|
||||
if (unlikely(val < 0)) {
|
||||
ret = val;
|
||||
goto out_free;
|
||||
}
|
||||
if (unlikely(val < 0))
|
||||
return val;
|
||||
for (j = 0; j < 4 && i * 4 + j < data->num_adc; j++) {
|
||||
data->range[i * 4 + j] =
|
||||
max16065_adc_range[(val >> (j * 2)) & 0x3];
|
||||
@ -595,10 +591,8 @@ static int max16065_probe(struct i2c_client *client,
|
||||
for (j = 0; j < data->num_adc; j++) {
|
||||
val = i2c_smbus_read_byte_data(client,
|
||||
MAX16065_LIMIT(i, j));
|
||||
if (unlikely(val < 0)) {
|
||||
ret = val;
|
||||
goto out_free;
|
||||
}
|
||||
if (unlikely(val < 0))
|
||||
return val;
|
||||
data->limit[i][j] = LIMIT_TO_MV(val, data->range[j]);
|
||||
}
|
||||
}
|
||||
@ -661,8 +655,6 @@ static int max16065_probe(struct i2c_client *client,
|
||||
|
||||
out:
|
||||
max16065_cleanup(client);
|
||||
out_free:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -672,7 +664,6 @@ static int max16065_remove(struct i2c_client *client)
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
max16065_cleanup(client);
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -699,19 +690,8 @@ static struct i2c_driver max16065_driver = {
|
||||
.id_table = max16065_id,
|
||||
};
|
||||
|
||||
static int __init max16065_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max16065_driver);
|
||||
}
|
||||
|
||||
static void __exit max16065_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max16065_driver);
|
||||
}
|
||||
module_i2c_driver(max16065_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
|
||||
MODULE_DESCRIPTION("MAX16065 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(max16065_init);
|
||||
module_exit(max16065_exit);
|
||||
|
@ -133,7 +133,8 @@ struct max1619_data {
|
||||
*/
|
||||
|
||||
#define show_temp(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct max1619_data *data = max1619_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", temp_from_reg(data->value)); \
|
||||
@ -146,12 +147,16 @@ show_temp(temp_crit2);
|
||||
show_temp(temp_hyst2);
|
||||
|
||||
#define set_temp2(value, reg) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct max1619_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
long val; \
|
||||
int err = kstrtol(buf, 10, &val); \
|
||||
if (err) \
|
||||
return err; \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->value = temp_to_reg(val); \
|
||||
@ -165,7 +170,8 @@ set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH);
|
||||
set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT);
|
||||
set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST);
|
||||
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct max1619_data *data = max1619_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->alarms);
|
||||
@ -275,7 +281,8 @@ static int max1619_probe(struct i2c_client *new_client,
|
||||
max1619_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &max1619_group);
|
||||
if (err)
|
||||
goto exit_free;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
@ -353,20 +360,9 @@ static struct max1619_data *max1619_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_max1619_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max1619_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_max1619_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max1619_driver);
|
||||
}
|
||||
module_i2c_driver(max1619_driver);
|
||||
|
||||
MODULE_AUTHOR("Alexey Fisher <fishor@mail.ru> and "
|
||||
"Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("MAX1619 sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_max1619_init);
|
||||
module_exit(sensors_max1619_exit);
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
Copyright (c) 2011 David George <david.george@ska.ac.za>
|
||||
|
||||
based on adm1021.c
|
||||
some credit to Christoph Scheurer, but largely a rewrite
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Copyright (c) 2011 David George <david.george@ska.ac.za>
|
||||
*
|
||||
* based on adm1021.c
|
||||
* some credit to Christoph Scheurer, but largely a rewrite
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -484,19 +484,8 @@ static struct i2c_driver max1668_driver = {
|
||||
.address_list = max1668_addr_list,
|
||||
};
|
||||
|
||||
static int __init sensors_max1668_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max1668_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_max1668_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max1668_driver);
|
||||
}
|
||||
module_i2c_driver(max1668_driver);
|
||||
|
||||
MODULE_AUTHOR("David George <david.george@ska.ac.za>");
|
||||
MODULE_DESCRIPTION("MAX1668 remote temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_max1668_init)
|
||||
module_exit(sensors_max1668_exit)
|
||||
|
@ -637,19 +637,8 @@ static struct i2c_driver max6639_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init max6639_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max6639_driver);
|
||||
}
|
||||
|
||||
static void __exit max6639_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max6639_driver);
|
||||
}
|
||||
module_i2c_driver(max6639_driver);
|
||||
|
||||
MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
|
||||
MODULE_DESCRIPTION("max6639 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(max6639_init);
|
||||
module_exit(max6639_exit);
|
||||
|
@ -352,19 +352,8 @@ static struct i2c_driver max6642_driver = {
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int __init max6642_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max6642_driver);
|
||||
}
|
||||
|
||||
static void __exit max6642_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max6642_driver);
|
||||
}
|
||||
module_i2c_driver(max6642_driver);
|
||||
|
||||
MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
|
||||
MODULE_DESCRIPTION("MAX6642 sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(max6642_init);
|
||||
module_exit(max6642_exit);
|
||||
|
@ -135,8 +135,7 @@ static struct i2c_driver max6650_driver = {
|
||||
* Client data (each client gets its own)
|
||||
*/
|
||||
|
||||
struct max6650_data
|
||||
{
|
||||
struct max6650_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
int nr_fans;
|
||||
@ -238,8 +237,13 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
int rpm = simple_strtoul(buf, NULL, 10);
|
||||
int kscale, ktach;
|
||||
unsigned long rpm;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &rpm);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
|
||||
|
||||
@ -282,8 +286,10 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
int pwm;
|
||||
struct max6650_data *data = max6650_update_device(dev);
|
||||
|
||||
/* Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
|
||||
Lower DAC values mean higher speeds. */
|
||||
/*
|
||||
* Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
|
||||
* Lower DAC values mean higher speeds.
|
||||
*/
|
||||
if (data->config & MAX6650_CFG_V12)
|
||||
pwm = 255 - (255 * (int)data->dac)/180;
|
||||
else
|
||||
@ -300,7 +306,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
int pwm = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long pwm;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &pwm);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pwm = SENSORS_LIMIT(pwm, 0, 255);
|
||||
|
||||
@ -341,14 +352,16 @@ static ssize_t set_enable(struct device *dev, struct device_attribute *devattr,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
int mode = simple_strtoul(buf, NULL, 10);
|
||||
int max6650_modes[3] = {0, 3, 2};
|
||||
unsigned long mode;
|
||||
int err;
|
||||
|
||||
if ((mode < 0)||(mode > 2)) {
|
||||
dev_err(&client->dev,
|
||||
"illegal value for pwm1_enable (%d)\n", mode);
|
||||
err = kstrtoul(buf, 10, &mode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (mode > 2)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@ -389,7 +402,12 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6650_data *data = i2c_get_clientdata(client);
|
||||
int div = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long div;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &div);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
switch (div) {
|
||||
@ -407,8 +425,6 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
|
||||
break;
|
||||
default:
|
||||
mutex_unlock(&data->update_lock);
|
||||
dev_err(&client->dev,
|
||||
"illegal value for fan divider (%d)\n", div);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -529,7 +545,8 @@ static int max6650_probe(struct i2c_client *client,
|
||||
struct max6650_data *data;
|
||||
int err;
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) {
|
||||
data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
dev_err(&client->dev, "out of memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -605,8 +622,7 @@ 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(&client->dev, "illegal value for fan_voltage (%d)\n",
|
||||
fan_voltage);
|
||||
}
|
||||
|
||||
@ -636,15 +652,15 @@ 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",
|
||||
dev_err(&client->dev, "illegal value for prescaler (%d)\n",
|
||||
prescaler);
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "Prescaler is set to %d.\n",
|
||||
1 << (config & MAX6650_CFG_PRESCALER_MASK));
|
||||
|
||||
/* If mode is set to "full off", we change it to "open loop" and
|
||||
/*
|
||||
* If mode is set to "full off", we change it to "open loop" and
|
||||
* set DAC to 255, which has the same effect. We do this because
|
||||
* there's no "full off" mode defined in hwmon specifcations.
|
||||
*/
|
||||
@ -698,9 +714,11 @@ static struct max6650_data *max6650_update_device(struct device *dev)
|
||||
MAX6650_REG_COUNT);
|
||||
data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
|
||||
|
||||
/* Alarms are cleared on read in case the condition that
|
||||
/*
|
||||
* 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. */
|
||||
* for providing the register through different alarm files.
|
||||
*/
|
||||
data->alarm |= i2c_smbus_read_byte_data(client,
|
||||
MAX6650_REG_ALARM);
|
||||
|
||||
@ -713,19 +731,8 @@ static struct max6650_data *max6650_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_max6650_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max6650_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_max6650_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max6650_driver);
|
||||
}
|
||||
module_i2c_driver(max6650_driver);
|
||||
|
||||
MODULE_AUTHOR("Hans J. Koch");
|
||||
MODULE_DESCRIPTION("MAX6650 sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_max6650_init);
|
||||
module_exit(sensors_max6650_exit);
|
||||
|
@ -126,12 +126,12 @@ static inline void superio_exit(int sioaddr)
|
||||
480000 / ((val) * (div)))
|
||||
#define FAN_TO_REG(val, div) ((val) <= 100 ? 0 : \
|
||||
480000 / ((val) * (div)))
|
||||
#define FAN_DIV_FROM_REG(val) (1 << ((val >> 5) & 0x03))
|
||||
#define FAN_DIV_FROM_REG(val) (1 << (((val) >> 5) & 0x03))
|
||||
#define FAN_STATUS_FROM_REG(val) ((val) & 0x07)
|
||||
|
||||
#define FAN_CONFIG_MONITOR(val,nr) (((val) >> (2 + nr * 3)) & 1)
|
||||
#define FAN_CONFIG_CONTROL(val,nr) (((val) >> (3 + nr * 3)) & 1)
|
||||
#define FAN_CONFIG_INVERT(val,nr) (((val) >> (4 + nr * 3)) & 1)
|
||||
#define FAN_CONFIG_MONITOR(val, nr) (((val) >> (2 + (nr) * 3)) & 1)
|
||||
#define FAN_CONFIG_CONTROL(val, nr) (((val) >> (3 + (nr) * 3)) & 1)
|
||||
#define FAN_CONFIG_INVERT(val, nr) (((val) >> (4 + (nr) * 3)) & 1)
|
||||
|
||||
#define PWM_FROM_REG(val, inv) ((inv) ? 255 - (val) : (val))
|
||||
static inline u8 PWM_TO_REG(int val, int inv)
|
||||
@ -255,43 +255,54 @@ static struct platform_driver pc87360_driver = {
|
||||
* Sysfs stuff
|
||||
*/
|
||||
|
||||
static ssize_t show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_fan_input(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index],
|
||||
FAN_DIV_FROM_REG(data->fan_status[attr->index])));
|
||||
}
|
||||
static ssize_t show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_fan_min(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index],
|
||||
FAN_DIV_FROM_REG(data->fan_status[attr->index])));
|
||||
}
|
||||
static ssize_t show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_fan_div(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n",
|
||||
FAN_DIV_FROM_REG(data->fan_status[attr->index]));
|
||||
}
|
||||
static ssize_t show_fan_status(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_fan_status(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n",
|
||||
FAN_STATUS_FROM_REG(data->fan_status[attr->index]));
|
||||
}
|
||||
static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
static ssize_t set_fan_min(struct device *dev,
|
||||
struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long fan_min = simple_strtol(buf, NULL, 10);
|
||||
long fan_min;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &fan_min);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[attr->index]));
|
||||
fan_min = FAN_TO_REG(fan_min,
|
||||
FAN_DIV_FROM_REG(data->fan_status[attr->index]));
|
||||
|
||||
/* If it wouldn't fit, change clock divisor */
|
||||
while (fan_min > 255
|
||||
@ -301,11 +312,13 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr,
|
||||
data->fan_status[attr->index] += 0x20;
|
||||
}
|
||||
data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min;
|
||||
pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(attr->index),
|
||||
pc87360_write_value(data, LD_FAN, NO_BANK,
|
||||
PC87360_REG_FAN_MIN(attr->index),
|
||||
data->fan_min[attr->index]);
|
||||
|
||||
/* Write new divider, preserve alarm bits */
|
||||
pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(attr->index),
|
||||
pc87360_write_value(data, LD_FAN, NO_BANK,
|
||||
PC87360_REG_FAN_STATUS(attr->index),
|
||||
data->fan_status[attr->index] & 0xF9);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
@ -334,12 +347,15 @@ static struct sensor_device_attribute fan_min[] = {
|
||||
};
|
||||
|
||||
#define FAN_UNIT_ATTRS(X) \
|
||||
&fan_input[X].dev_attr.attr, \
|
||||
{ &fan_input[X].dev_attr.attr, \
|
||||
&fan_status[X].dev_attr.attr, \
|
||||
&fan_div[X].dev_attr.attr, \
|
||||
&fan_min[X].dev_attr.attr
|
||||
&fan_min[X].dev_attr.attr, \
|
||||
NULL \
|
||||
}
|
||||
|
||||
static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
@ -348,12 +364,17 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, ch
|
||||
FAN_CONFIG_INVERT(data->fan_conf,
|
||||
attr->index)));
|
||||
}
|
||||
static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm[attr->index] = PWM_TO_REG(val,
|
||||
@ -370,52 +391,60 @@ static struct sensor_device_attribute pwm[] = {
|
||||
SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2),
|
||||
};
|
||||
|
||||
static struct attribute * pc8736x_fan_attr_array[] = {
|
||||
static struct attribute *pc8736x_fan_attr[][5] = {
|
||||
FAN_UNIT_ATTRS(0),
|
||||
FAN_UNIT_ATTRS(1),
|
||||
FAN_UNIT_ATTRS(2),
|
||||
&pwm[0].dev_attr.attr,
|
||||
&pwm[1].dev_attr.attr,
|
||||
&pwm[2].dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
static const struct attribute_group pc8736x_fan_group = {
|
||||
.attrs = pc8736x_fan_attr_array,
|
||||
FAN_UNIT_ATTRS(2)
|
||||
};
|
||||
|
||||
static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static const struct attribute_group pc8736x_fan_attr_group[] = {
|
||||
{ .attrs = pc8736x_fan_attr[0], },
|
||||
{ .attrs = pc8736x_fan_attr[1], },
|
||||
{ .attrs = pc8736x_fan_attr[2], },
|
||||
};
|
||||
|
||||
static ssize_t show_in_input(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
|
||||
data->in_vref));
|
||||
}
|
||||
static ssize_t show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_in_min(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
|
||||
data->in_vref));
|
||||
}
|
||||
static ssize_t show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_in_max(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
|
||||
data->in_vref));
|
||||
}
|
||||
static ssize_t show_in_status(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_in_status(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->in_status[attr->index]);
|
||||
}
|
||||
static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
|
||||
@ -424,12 +453,17 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr,
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_max[attr->index] = IN_TO_REG(val,
|
||||
@ -498,9 +532,11 @@ static struct sensor_device_attribute in_max[] = {
|
||||
#define CHAN_ALM_MAX 0x04 /* max limit exceeded */
|
||||
#define TEMP_ALM_CRIT 0x08 /* temp crit exceeded (temp only) */
|
||||
|
||||
/* show_in_min/max_alarm() reads data from the per-channel status
|
||||
register (sec 11.5.12), not the vin event status registers (sec
|
||||
11.5.2) that (legacy) show_in_alarm() resds (via data->in_alarms) */
|
||||
/*
|
||||
* show_in_min/max_alarm() reads data from the per-channel status
|
||||
* register (sec 11.5.12), not the vin event status registers (sec
|
||||
* 11.5.2) that (legacy) show_in_alarm() resds (via data->in_alarms)
|
||||
*/
|
||||
|
||||
static ssize_t show_in_min_alarm(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
@ -554,27 +590,38 @@ static struct sensor_device_attribute in_max_alarm[] = {
|
||||
&in_min_alarm[X].dev_attr.attr, \
|
||||
&in_max_alarm[X].dev_attr.attr
|
||||
|
||||
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
|
||||
|
||||
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%u\n", data->vrm);
|
||||
}
|
||||
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
data->vrm = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->vrm = val;
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
|
||||
|
||||
static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_in_alarms(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->in_alarms);
|
||||
@ -602,46 +649,58 @@ static const struct attribute_group pc8736x_vin_group = {
|
||||
.attrs = pc8736x_vin_attr_array,
|
||||
};
|
||||
|
||||
static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_therm_input(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
|
||||
data->in_vref));
|
||||
}
|
||||
static ssize_t show_therm_min(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_therm_min(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
|
||||
data->in_vref));
|
||||
}
|
||||
static ssize_t show_therm_max(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_therm_max(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
|
||||
data->in_vref));
|
||||
}
|
||||
static ssize_t show_therm_crit(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_therm_crit(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11],
|
||||
data->in_vref));
|
||||
}
|
||||
static ssize_t show_therm_status(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_therm_status(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->in_status[attr->index]);
|
||||
}
|
||||
static ssize_t set_therm_min(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
|
||||
static ssize_t set_therm_min(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
|
||||
@ -650,12 +709,19 @@ static ssize_t set_therm_min(struct device *dev, struct device_attribute *devatt
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_therm_max(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
|
||||
static ssize_t set_therm_max(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_max[attr->index] = IN_TO_REG(val, data->in_vref);
|
||||
@ -664,12 +730,18 @@ static ssize_t set_therm_max(struct device *dev, struct device_attribute *devatt
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_therm_crit(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref);
|
||||
@ -679,8 +751,9 @@ static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devat
|
||||
return count;
|
||||
}
|
||||
|
||||
/* the +11 term below reflects the fact that VLM units 11,12,13 are
|
||||
used in the chip to measure voltage across the thermistors
|
||||
/*
|
||||
* the +11 term below reflects the fact that VLM units 11,12,13 are
|
||||
* used in the chip to measure voltage across the thermistors
|
||||
*/
|
||||
static struct sensor_device_attribute therm_input[] = {
|
||||
SENSOR_ATTR(temp4_input, S_IRUGO, show_therm_input, NULL, 0 + 11),
|
||||
@ -717,8 +790,10 @@ static struct sensor_device_attribute therm_crit[] = {
|
||||
show_therm_crit, set_therm_crit, 2 + 11),
|
||||
};
|
||||
|
||||
/* show_therm_min/max_alarm() reads data from the per-channel voltage
|
||||
status register (sec 11.5.12) */
|
||||
/*
|
||||
* show_therm_min/max_alarm() reads data from the per-channel voltage
|
||||
* status register (sec 11.5.12)
|
||||
*/
|
||||
|
||||
static ssize_t show_therm_min_alarm(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
@ -790,42 +865,59 @@ static const struct attribute_group pc8736x_therm_group = {
|
||||
.attrs = pc8736x_therm_attr_array,
|
||||
};
|
||||
|
||||
static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_temp_input(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
|
||||
}
|
||||
static ssize_t show_temp_min(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
|
||||
static ssize_t show_temp_min(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index]));
|
||||
}
|
||||
static ssize_t show_temp_max(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
|
||||
static ssize_t show_temp_max(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index]));
|
||||
}
|
||||
static ssize_t show_temp_crit(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
|
||||
static ssize_t show_temp_crit(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[attr->index]));
|
||||
return sprintf(buf, "%d\n",
|
||||
TEMP_FROM_REG(data->temp_crit[attr->index]));
|
||||
}
|
||||
static ssize_t show_temp_status(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
|
||||
static ssize_t show_temp_status(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->temp_status[attr->index]);
|
||||
}
|
||||
static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
|
||||
static ssize_t set_temp_min(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_min[attr->index] = TEMP_TO_REG(val);
|
||||
@ -834,12 +926,19 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
|
||||
static ssize_t set_temp_max(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max[attr->index] = TEMP_TO_REG(val);
|
||||
@ -848,12 +947,19 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
|
||||
|
||||
static ssize_t set_temp_crit(struct device *dev,
|
||||
struct device_attribute *devattr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_crit[attr->index] = TEMP_TO_REG(val);
|
||||
@ -898,16 +1004,20 @@ static struct sensor_device_attribute temp_crit[] = {
|
||||
show_temp_crit, set_temp_crit, 2),
|
||||
};
|
||||
|
||||
static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_temp_alarms(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->temp_alarms);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
|
||||
|
||||
/* show_temp_min/max_alarm() reads data from the per-channel status
|
||||
register (sec 12.3.7), not the temp event status registers (sec
|
||||
12.3.2) that show_temp_alarm() reads (via data->temp_alarms) */
|
||||
/*
|
||||
* show_temp_min/max_alarm() reads data from the per-channel status
|
||||
* register (sec 12.3.7), not the temp event status registers (sec
|
||||
* 12.3.2) that show_temp_alarm() reads (via data->temp_alarms)
|
||||
*/
|
||||
|
||||
static ssize_t show_temp_min_alarm(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
@ -917,6 +1027,7 @@ static ssize_t show_temp_min_alarm(struct device *dev,
|
||||
|
||||
return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MIN));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max_alarm(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
@ -925,6 +1036,7 @@ static ssize_t show_temp_max_alarm(struct device *dev,
|
||||
|
||||
return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MAX));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_crit_alarm(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
@ -939,11 +1051,13 @@ static struct sensor_device_attribute temp_min_alarm[] = {
|
||||
SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 1),
|
||||
SENSOR_ATTR(temp3_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 2),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute temp_max_alarm[] = {
|
||||
SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 0),
|
||||
SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 1),
|
||||
SENSOR_ATTR(temp3_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 2),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute temp_crit_alarm[] = {
|
||||
SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 0),
|
||||
SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 1),
|
||||
@ -966,7 +1080,7 @@ static struct sensor_device_attribute temp_fault[] = {
|
||||
};
|
||||
|
||||
#define TEMP_UNIT_ATTRS(X) \
|
||||
&temp_input[X].dev_attr.attr, \
|
||||
{ &temp_input[X].dev_attr.attr, \
|
||||
&temp_status[X].dev_attr.attr, \
|
||||
&temp_min[X].dev_attr.attr, \
|
||||
&temp_max[X].dev_attr.attr, \
|
||||
@ -974,18 +1088,20 @@ static struct sensor_device_attribute temp_fault[] = {
|
||||
&temp_min_alarm[X].dev_attr.attr, \
|
||||
&temp_max_alarm[X].dev_attr.attr, \
|
||||
&temp_crit_alarm[X].dev_attr.attr, \
|
||||
&temp_fault[X].dev_attr.attr
|
||||
&temp_fault[X].dev_attr.attr, \
|
||||
NULL \
|
||||
}
|
||||
|
||||
static struct attribute * pc8736x_temp_attr_array[] = {
|
||||
static struct attribute *pc8736x_temp_attr[][10] = {
|
||||
TEMP_UNIT_ATTRS(0),
|
||||
TEMP_UNIT_ATTRS(1),
|
||||
TEMP_UNIT_ATTRS(2),
|
||||
/* include the few miscellaneous atts here */
|
||||
&dev_attr_alarms_temp.attr,
|
||||
NULL
|
||||
TEMP_UNIT_ATTRS(2)
|
||||
};
|
||||
static const struct attribute_group pc8736x_temp_group = {
|
||||
.attrs = pc8736x_temp_attr_array,
|
||||
|
||||
static const struct attribute_group pc8736x_temp_attr_group[] = {
|
||||
{ .attrs = pc8736x_temp_attr[0] },
|
||||
{ .attrs = pc8736x_temp_attr[1] },
|
||||
{ .attrs = pc8736x_temp_attr[2] }
|
||||
};
|
||||
|
||||
static ssize_t show_name(struct device *dev,
|
||||
@ -994,13 +1110,15 @@ static ssize_t show_name(struct device *dev,
|
||||
struct pc87360_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%s\n", data->name);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
/*
|
||||
* Device detection, registration and update
|
||||
*/
|
||||
|
||||
static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses)
|
||||
static int __init pc87360_find(int sioaddr, u8 *devid,
|
||||
unsigned short *addresses)
|
||||
{
|
||||
u16 val;
|
||||
int i;
|
||||
@ -1063,9 +1181,11 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
|
||||
} else if (i == 1) { /* Voltages */
|
||||
/* Are we using thermistors? */
|
||||
if (*devid == 0xE9) { /* PC87366 */
|
||||
/* These registers are not logical-device
|
||||
specific, just that we won't need them if
|
||||
we don't use the VLM device */
|
||||
/*
|
||||
* These registers are not logical-device
|
||||
* specific, just that we won't need them if
|
||||
* we don't use the VLM device
|
||||
*/
|
||||
confreg[2] = superio_inb(sioaddr, 0x2B);
|
||||
confreg[3] = superio_inb(sioaddr, 0x25);
|
||||
|
||||
@ -1085,6 +1205,22 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pc87360_remove_files(struct device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
device_remove_file(dev, &dev_attr_name);
|
||||
device_remove_file(dev, &dev_attr_alarms_temp);
|
||||
for (i = 0; i < ARRAY_SIZE(pc8736x_temp_attr_group); i++)
|
||||
sysfs_remove_group(&dev->kobj, &pc8736x_temp_attr_group[i]);
|
||||
for (i = 0; i < ARRAY_SIZE(pc8736x_fan_attr_group); i++) {
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_attr_group[i]);
|
||||
device_remove_file(dev, &pwm[i].dev_attr);
|
||||
}
|
||||
sysfs_remove_group(&dev->kobj, &pc8736x_therm_group);
|
||||
sysfs_remove_group(&dev->kobj, &pc8736x_vin_group);
|
||||
}
|
||||
|
||||
static int __devinit pc87360_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
@ -1094,7 +1230,8 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
|
||||
int use_thermistors = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
|
||||
data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->fannr = 2;
|
||||
@ -1130,7 +1267,8 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
for (i = 0; i < LDNI_MAX; i++) {
|
||||
if (((data->address[i] = extra_isa[i]))
|
||||
data->address[i] = extra_isa[i];
|
||||
if (data->address[i]
|
||||
&& !request_region(extra_isa[i], PC87360_EXTENT,
|
||||
pc87360_driver.driver.name)) {
|
||||
dev_err(dev, "Region 0x%x-0x%x already "
|
||||
@ -1147,9 +1285,11 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
|
||||
if (data->fannr)
|
||||
data->fan_conf = confreg[0] | (confreg[1] << 8);
|
||||
|
||||
/* Use the correct reference voltage
|
||||
Unless both the VLM and the TMS logical devices agree to
|
||||
use an external Vref, the internal one is used. */
|
||||
/*
|
||||
* Use the correct reference voltage
|
||||
* Unless both the VLM and the TMS logical devices agree to
|
||||
* use an external Vref, the internal one is used.
|
||||
*/
|
||||
if (data->innr) {
|
||||
i = pc87360_read_value(data, LD_IN, NO_BANK,
|
||||
PC87365_REG_IN_CONFIG);
|
||||
@ -1182,62 +1322,48 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
|
||||
|
||||
/* Register all-or-nothing sysfs groups */
|
||||
|
||||
if (data->innr &&
|
||||
(err = sysfs_create_group(&dev->kobj,
|
||||
&pc8736x_vin_group)))
|
||||
if (data->innr) {
|
||||
err = sysfs_create_group(&dev->kobj, &pc8736x_vin_group);
|
||||
if (err)
|
||||
goto ERROR3;
|
||||
}
|
||||
|
||||
if (data->innr == 14 &&
|
||||
(err = sysfs_create_group(&dev->kobj,
|
||||
&pc8736x_therm_group)))
|
||||
if (data->innr == 14) {
|
||||
err = sysfs_create_group(&dev->kobj, &pc8736x_therm_group);
|
||||
if (err)
|
||||
goto ERROR3;
|
||||
}
|
||||
|
||||
/* create device attr-files for varying sysfs groups */
|
||||
|
||||
if (data->tempnr) {
|
||||
for (i = 0; i < data->tempnr; i++) {
|
||||
if ((err = device_create_file(dev,
|
||||
&temp_input[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_min[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_max[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_crit[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_status[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_min_alarm[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_max_alarm[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_crit_alarm[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_fault[i].dev_attr)))
|
||||
err = sysfs_create_group(&dev->kobj,
|
||||
&pc8736x_temp_attr_group[i]);
|
||||
if (err)
|
||||
goto ERROR3;
|
||||
}
|
||||
if ((err = device_create_file(dev, &dev_attr_alarms_temp)))
|
||||
err = device_create_file(dev, &dev_attr_alarms_temp);
|
||||
if (err)
|
||||
goto ERROR3;
|
||||
}
|
||||
|
||||
for (i = 0; i < data->fannr; i++) {
|
||||
if (FAN_CONFIG_MONITOR(data->fan_conf, i)
|
||||
&& ((err = device_create_file(dev,
|
||||
&fan_input[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&fan_min[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&fan_div[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&fan_status[i].dev_attr))))
|
||||
goto ERROR3;
|
||||
|
||||
if (FAN_CONFIG_CONTROL(data->fan_conf, i)
|
||||
&& (err = device_create_file(dev, &pwm[i].dev_attr)))
|
||||
if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
|
||||
err = sysfs_create_group(&dev->kobj,
|
||||
&pc8736x_fan_attr_group[i]);
|
||||
if (err)
|
||||
goto ERROR3;
|
||||
}
|
||||
if (FAN_CONFIG_CONTROL(data->fan_conf, i)) {
|
||||
err = device_create_file(dev, &pwm[i].dev_attr);
|
||||
if (err)
|
||||
goto ERROR3;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = device_create_file(dev, &dev_attr_name)))
|
||||
err = device_create_file(dev, &dev_attr_name);
|
||||
if (err)
|
||||
goto ERROR3;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
@ -1248,17 +1374,11 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
ERROR3:
|
||||
device_remove_file(dev, &dev_attr_name);
|
||||
/* can still remove groups whose members were added individually */
|
||||
sysfs_remove_group(&dev->kobj, &pc8736x_temp_group);
|
||||
sysfs_remove_group(&dev->kobj, &pc8736x_fan_group);
|
||||
sysfs_remove_group(&dev->kobj, &pc8736x_therm_group);
|
||||
sysfs_remove_group(&dev->kobj, &pc8736x_vin_group);
|
||||
pc87360_remove_files(dev);
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (data->address[i]) {
|
||||
if (data->address[i])
|
||||
release_region(data->address[i], PC87360_EXTENT);
|
||||
}
|
||||
}
|
||||
ERROR1:
|
||||
kfree(data);
|
||||
return err;
|
||||
@ -1270,25 +1390,20 @@ static int __devexit pc87360_remove(struct platform_device *pdev)
|
||||
int i;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_group);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_therm_group);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_vin_group);
|
||||
|
||||
pc87360_remove_files(&pdev->dev);
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (data->address[i]) {
|
||||
if (data->address[i])
|
||||
release_region(data->address[i], PC87360_EXTENT);
|
||||
}
|
||||
}
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ldi is the logical device index
|
||||
bank is for voltages and temperatures only */
|
||||
/*
|
||||
* ldi is the logical device index
|
||||
* bank is for voltages and temperatures only
|
||||
*/
|
||||
static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
|
||||
u8 reg)
|
||||
{
|
||||
@ -1359,8 +1474,10 @@ static void pc87360_init_device(struct platform_device *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
/* We can't blindly trust the Super-I/O space configuration bit,
|
||||
most BIOS won't set it properly */
|
||||
/*
|
||||
* We can't blindly trust the Super-I/O space configuration bit,
|
||||
* most BIOS won't set it properly
|
||||
*/
|
||||
dev_dbg(&pdev->dev, "bios thermistors:%d\n", use_thermistors);
|
||||
for (i = 11; i < data->innr; i++) {
|
||||
reg = pc87360_read_value(data, LD_IN, i,
|
||||
@ -1379,8 +1496,8 @@ static void pc87360_init_device(struct platform_device *pdev,
|
||||
if (init >= init_temp[i]) {
|
||||
/* Forcibly enable temperature channel */
|
||||
if (!(reg & CHAN_ENA)) {
|
||||
dev_dbg(&pdev->dev, "Forcibly "
|
||||
"enabling temp%d\n", i+1);
|
||||
dev_dbg(&pdev->dev,
|
||||
"Forcibly enabling temp%d\n", i + 1);
|
||||
pc87360_write_value(data, LD_TEMP, i,
|
||||
PC87365_REG_TEMP_STATUS,
|
||||
0xCF);
|
||||
@ -1391,14 +1508,16 @@ static void pc87360_init_device(struct platform_device *pdev,
|
||||
if (use_thermistors) {
|
||||
for (i = 11; i < data->innr; i++) {
|
||||
if (init >= init_in[i]) {
|
||||
/* The pin may already be used by thermal
|
||||
diodes */
|
||||
/*
|
||||
* The pin may already be used by thermal
|
||||
* diodes
|
||||
*/
|
||||
reg = pc87360_read_value(data, LD_TEMP,
|
||||
(i - 11) / 2, PC87365_REG_TEMP_STATUS);
|
||||
if (reg & CHAN_ENA) {
|
||||
dev_dbg(&pdev->dev, "Skipping "
|
||||
"temp%d, pin already in use "
|
||||
"by temp%d\n", i-7, (i-11)/2);
|
||||
dev_dbg(&pdev->dev,
|
||||
"Skipping temp%d, pin already in use by temp%d\n",
|
||||
i - 7, (i - 11) / 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1406,8 +1525,9 @@ static void pc87360_init_device(struct platform_device *pdev,
|
||||
reg = pc87360_read_value(data, LD_IN, i,
|
||||
PC87365_REG_IN_STATUS);
|
||||
if (!(reg & CHAN_ENA)) {
|
||||
dev_dbg(&pdev->dev, "Forcibly "
|
||||
"enabling temp%d\n", i-7);
|
||||
dev_dbg(&pdev->dev,
|
||||
"Forcibly enabling temp%d\n",
|
||||
i - 7);
|
||||
pc87360_write_value(data, LD_IN, i,
|
||||
PC87365_REG_TEMP_STATUS,
|
||||
(reg & 0x60) | 0x8F);
|
||||
@ -1421,8 +1541,8 @@ static void pc87360_init_device(struct platform_device *pdev,
|
||||
PC87365_REG_IN_CONFIG);
|
||||
dev_dbg(&pdev->dev, "bios vin-cfg:0x%02x\n", reg);
|
||||
if (reg & CHAN_ENA) {
|
||||
dev_dbg(&pdev->dev, "Forcibly "
|
||||
"enabling monitoring (VLM)\n");
|
||||
dev_dbg(&pdev->dev,
|
||||
"Forcibly enabling monitoring (VLM)\n");
|
||||
pc87360_write_value(data, LD_IN, NO_BANK,
|
||||
PC87365_REG_IN_CONFIG,
|
||||
reg & 0xFE);
|
||||
@ -1434,8 +1554,8 @@ static void pc87360_init_device(struct platform_device *pdev,
|
||||
PC87365_REG_TEMP_CONFIG);
|
||||
dev_dbg(&pdev->dev, "bios temp-cfg:0x%02x\n", reg);
|
||||
if (reg & CHAN_ENA) {
|
||||
dev_dbg(&pdev->dev, "Forcibly enabling "
|
||||
"monitoring (TMS)\n");
|
||||
dev_dbg(&pdev->dev,
|
||||
"Forcibly enabling monitoring (TMS)\n");
|
||||
pc87360_write_value(data, LD_TEMP, NO_BANK,
|
||||
PC87365_REG_TEMP_CONFIG,
|
||||
reg & 0xFE);
|
||||
@ -1444,10 +1564,12 @@ static void pc87360_init_device(struct platform_device *pdev,
|
||||
if (init >= 2) {
|
||||
/* Chip config as documented by National Semi. */
|
||||
pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08);
|
||||
/* We voluntarily omit the bank here, in case the
|
||||
sequence itself matters. It shouldn't be a problem,
|
||||
since nobody else is supposed to access the
|
||||
device at that point. */
|
||||
/*
|
||||
* We voluntarily omit the bank here, in case the
|
||||
* sequence itself matters. It shouldn't be a problem,
|
||||
* since nobody else is supposed to access the
|
||||
* device at that point.
|
||||
*/
|
||||
pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04);
|
||||
pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35);
|
||||
pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05);
|
||||
|
@ -46,9 +46,11 @@ static struct platform_device *pdev;
|
||||
|
||||
#define DRVNAME "pc87427"
|
||||
|
||||
/* The lock mutex protects both the I/O accesses (needed because the
|
||||
device is using banked registers) and the register cache (needed to keep
|
||||
the data in the registers and the cache in sync at any time). */
|
||||
/*
|
||||
* The lock mutex protects both the I/O accesses (needed because the
|
||||
* device is using banked registers) and the register cache (needed to keep
|
||||
* the data in the registers and the cache in sync at any time).
|
||||
*/
|
||||
struct pc87427_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
@ -173,10 +175,12 @@ static inline void pc87427_write8_bank(struct pc87427_data *data, u8 ldi,
|
||||
#define FAN_STATUS_LOSPD (1 << 1)
|
||||
#define FAN_STATUS_MONEN (1 << 0)
|
||||
|
||||
/* Dedicated function to read all registers related to a given fan input.
|
||||
This saves us quite a few locks and bank selections.
|
||||
Must be called with data->lock held.
|
||||
nr is from 0 to 7 */
|
||||
/*
|
||||
* Dedicated function to read all registers related to a given fan input.
|
||||
* This saves us quite a few locks and bank selections.
|
||||
* Must be called with data->lock held.
|
||||
* nr is from 0 to 7
|
||||
*/
|
||||
static void pc87427_readall_fan(struct pc87427_data *data, u8 nr)
|
||||
{
|
||||
int iobase = data->address[LD_FAN];
|
||||
@ -189,8 +193,10 @@ static void pc87427_readall_fan(struct pc87427_data *data, u8 nr)
|
||||
outb(data->fan_status[nr], iobase + PC87427_REG_FAN_STATUS);
|
||||
}
|
||||
|
||||
/* The 2 LSB of fan speed registers are used for something different.
|
||||
The actual 2 LSB of the measurements are not available. */
|
||||
/*
|
||||
* The 2 LSB of fan speed registers are used for something different.
|
||||
* The actual 2 LSB of the measurements are not available.
|
||||
*/
|
||||
static inline unsigned long fan_from_reg(u16 reg)
|
||||
{
|
||||
reg &= 0xfffc;
|
||||
@ -224,10 +230,12 @@ static inline u16 fan_to_reg(unsigned long val)
|
||||
#define PWM_MODE_OFF (2 << 4)
|
||||
#define PWM_MODE_ON (7 << 4)
|
||||
|
||||
/* Dedicated function to read all registers related to a given PWM output.
|
||||
This saves us quite a few locks and bank selections.
|
||||
Must be called with data->lock held.
|
||||
nr is from 0 to 3 */
|
||||
/*
|
||||
* Dedicated function to read all registers related to a given PWM output.
|
||||
* This saves us quite a few locks and bank selections.
|
||||
* Must be called with data->lock held.
|
||||
* nr is from 0 to 3
|
||||
*/
|
||||
static void pc87427_readall_pwm(struct pc87427_data *data, u8 nr)
|
||||
{
|
||||
int iobase = data->address[LD_FAN];
|
||||
@ -286,10 +294,12 @@ static inline u8 pwm_enable_to_reg(unsigned long val, u8 pwmval)
|
||||
#define TEMP_TYPE_REMOTE_DIODE (2 << 5)
|
||||
#define TEMP_TYPE_LOCAL_DIODE (3 << 5)
|
||||
|
||||
/* Dedicated function to read all registers related to a given temperature
|
||||
input. This saves us quite a few locks and bank selections.
|
||||
Must be called with data->lock held.
|
||||
nr is from 0 to 5 */
|
||||
/*
|
||||
* Dedicated function to read all registers related to a given temperature
|
||||
* input. This saves us quite a few locks and bank selections.
|
||||
* Must be called with data->lock held.
|
||||
* nr is from 0 to 5
|
||||
*/
|
||||
static void pc87427_readall_temp(struct pc87427_data *data, u8 nr)
|
||||
{
|
||||
int iobase = data->address[LD_TEMP];
|
||||
@ -318,8 +328,10 @@ static inline unsigned int temp_type_from_reg(u8 reg)
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume 8-bit thermal sensors; 9-bit thermal sensors are possible
|
||||
too, but I have no idea how to figure out when they are used. */
|
||||
/*
|
||||
* We assume 8-bit thermal sensors; 9-bit thermal sensors are possible
|
||||
* too, but I have no idea how to figure out when they are used.
|
||||
*/
|
||||
static inline long temp_from_reg(s16 reg)
|
||||
{
|
||||
return reg * 1000 / 256;
|
||||
@ -423,9 +435,11 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
outb(BANK_FM(nr), iobase + PC87427_REG_BANK);
|
||||
/* The low speed limit registers are read-only while monitoring
|
||||
is enabled, so we have to disable monitoring, then change the
|
||||
limit, and finally enable monitoring again. */
|
||||
/*
|
||||
* The low speed limit registers are read-only while monitoring
|
||||
* is enabled, so we have to disable monitoring, then change the
|
||||
* limit, and finally enable monitoring again.
|
||||
*/
|
||||
outb(0, iobase + PC87427_REG_FAN_STATUS);
|
||||
data->fan_min[nr] = fan_to_reg(val);
|
||||
outw(data->fan_min[nr], iobase + PC87427_REG_FAN_MIN);
|
||||
@ -542,8 +556,10 @@ static const struct attribute_group pc87427_group_fan[8] = {
|
||||
{ .attrs = pc87427_attributes_fan[7] },
|
||||
};
|
||||
|
||||
/* Must be called with data->lock held and pc87427_readall_pwm() freshly
|
||||
called */
|
||||
/*
|
||||
* Must be called with data->lock held and pc87427_readall_pwm() freshly
|
||||
* called
|
||||
*/
|
||||
static void update_pwm_enable(struct pc87427_data *data, int nr, u8 mode)
|
||||
{
|
||||
int iobase = data->address[LD_FAN];
|
||||
@ -1023,9 +1039,11 @@ static void __devinit pc87427_init_device(struct device *dev)
|
||||
if (reg & PWM_ENABLE_CTLEN)
|
||||
data->pwm_enabled |= (1 << i);
|
||||
|
||||
/* We don't expose an interface to reconfigure the automatic
|
||||
fan control mode, so only allow to return to this mode if
|
||||
it was originally set. */
|
||||
/*
|
||||
* We don't expose an interface to reconfigure the automatic
|
||||
* fan control mode, so only allow to return to this mode if
|
||||
* it was originally set.
|
||||
*/
|
||||
if ((reg & PWM_ENABLE_MODE_MASK) == PWM_MODE_AUTO) {
|
||||
dev_dbg(dev, "PWM%d is in automatic control mode\n",
|
||||
i + 1);
|
||||
|
@ -1,21 +1,21 @@
|
||||
/*
|
||||
Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
|
||||
Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
|
||||
the help of Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
|
||||
* Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
|
||||
* the help of Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -39,28 +39,34 @@ MODULE_PARM_DESC(input_mode,
|
||||
" 2 = single ended and differential mixed\n"
|
||||
" 3 = two differential inputs\n");
|
||||
|
||||
/* The PCF8591 control byte
|
||||
7 6 5 4 3 2 1 0
|
||||
| 0 |AOEF| AIP | 0 |AINC| AICH | */
|
||||
/*
|
||||
* The PCF8591 control byte
|
||||
* 7 6 5 4 3 2 1 0
|
||||
* | 0 |AOEF| AIP | 0 |AINC| AICH |
|
||||
*/
|
||||
|
||||
/* Analog Output Enable Flag (analog output active if 1) */
|
||||
#define PCF8591_CONTROL_AOEF 0x40
|
||||
|
||||
/* Analog Input Programming
|
||||
0x00 = four single ended inputs
|
||||
0x10 = three differential inputs
|
||||
0x20 = single ended and differential mixed
|
||||
0x30 = two differential inputs */
|
||||
/*
|
||||
* Analog Input Programming
|
||||
* 0x00 = four single ended inputs
|
||||
* 0x10 = three differential inputs
|
||||
* 0x20 = single ended and differential mixed
|
||||
* 0x30 = two differential inputs
|
||||
*/
|
||||
#define PCF8591_CONTROL_AIP_MASK 0x30
|
||||
|
||||
/* Autoincrement Flag (switch on if 1) */
|
||||
#define PCF8591_CONTROL_AINC 0x04
|
||||
|
||||
/* Channel selection
|
||||
0x00 = channel 0
|
||||
0x01 = channel 1
|
||||
0x02 = channel 2
|
||||
0x03 = channel 3 */
|
||||
/*
|
||||
* Channel selection
|
||||
* 0x00 = channel 0
|
||||
* 0x01 = channel 1
|
||||
* 0x02 = channel 2
|
||||
* 0x03 = channel 3
|
||||
*/
|
||||
#define PCF8591_CONTROL_AICH_MASK 0x03
|
||||
|
||||
/* Initial values */
|
||||
@ -83,7 +89,9 @@ static int pcf8591_read_channel(struct device *dev, int channel);
|
||||
|
||||
/* following are the sysfs callback functions */
|
||||
#define show_in_channel(channel) \
|
||||
static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
static ssize_t show_in##channel##_input(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\
|
||||
} \
|
||||
@ -95,39 +103,57 @@ show_in_channel(1);
|
||||
show_in_channel(2);
|
||||
show_in_channel(3);
|
||||
|
||||
static ssize_t show_out0_ouput(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_out0_ouput(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
|
||||
return sprintf(buf, "%d\n", data->aout * 10);
|
||||
}
|
||||
|
||||
static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t set_out0_output(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int value;
|
||||
unsigned long val;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf8591_data *data = i2c_get_clientdata(client);
|
||||
if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255) {
|
||||
data->aout = value;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val /= 10;
|
||||
if (val > 255)
|
||||
return -EINVAL;
|
||||
|
||||
data->aout = val;
|
||||
i2c_smbus_write_byte_data(client, data->control, data->aout);
|
||||
return count;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO,
|
||||
show_out0_ouput, set_out0_output);
|
||||
|
||||
static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_out0_enable(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
|
||||
return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF)));
|
||||
}
|
||||
|
||||
static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t set_out0_enable(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf8591_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (val)
|
||||
@ -174,7 +200,8 @@ static int pcf8591_probe(struct i2c_client *client,
|
||||
struct pcf8591_data *data;
|
||||
int err;
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) {
|
||||
data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
@ -192,15 +219,15 @@ static int pcf8591_probe(struct i2c_client *client,
|
||||
|
||||
/* Register input2 if not in "two differential inputs" mode */
|
||||
if (input_mode != 3) {
|
||||
if ((err = device_create_file(&client->dev,
|
||||
&dev_attr_in2_input)))
|
||||
err = device_create_file(&client->dev, &dev_attr_in2_input);
|
||||
if (err)
|
||||
goto exit_sysfs_remove;
|
||||
}
|
||||
|
||||
/* Register input3 only in "four single ended inputs" mode */
|
||||
if (input_mode == 0) {
|
||||
if ((err = device_create_file(&client->dev,
|
||||
&dev_attr_in3_input)))
|
||||
err = device_create_file(&client->dev, &dev_attr_in3_input);
|
||||
if (err)
|
||||
goto exit_sysfs_remove;
|
||||
}
|
||||
|
||||
@ -241,8 +268,10 @@ static void pcf8591_init_client(struct i2c_client *client)
|
||||
|
||||
i2c_smbus_write_byte_data(client, data->control, data->aout);
|
||||
|
||||
/* The first byte transmitted contains the conversion code of the
|
||||
previous read cycle. FLUSH IT! */
|
||||
/*
|
||||
* The first byte transmitted contains the conversion code of the
|
||||
* previous read cycle. FLUSH IT!
|
||||
*/
|
||||
i2c_smbus_read_byte(client);
|
||||
}
|
||||
|
||||
@ -259,8 +288,10 @@ static int pcf8591_read_channel(struct device *dev, int channel)
|
||||
| channel;
|
||||
i2c_smbus_write_byte(client, data->control);
|
||||
|
||||
/* The first byte transmitted contains the conversion code of
|
||||
the previous read cycle. FLUSH IT! */
|
||||
/*
|
||||
* The first byte transmitted contains the conversion code of
|
||||
* the previous read cycle. FLUSH IT!
|
||||
*/
|
||||
i2c_smbus_read_byte(client);
|
||||
}
|
||||
value = i2c_smbus_read_byte(client);
|
||||
@ -269,9 +300,9 @@ static int pcf8591_read_channel(struct device *dev, int channel)
|
||||
|
||||
if ((channel == 2 && input_mode == 2) ||
|
||||
(channel != 3 && (input_mode == 1 || input_mode == 3)))
|
||||
return (10 * REG_TO_SIGNED(value));
|
||||
return 10 * REG_TO_SIGNED(value);
|
||||
else
|
||||
return (10 * value);
|
||||
return 10 * value;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id pcf8591_id[] = {
|
||||
|
@ -20,7 +20,8 @@ config SENSORS_PMBUS
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for generic
|
||||
PMBus devices, including but not limited to ADP4000, BMR453, BMR454,
|
||||
NCP4200, and NCP4208.
|
||||
MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, UDT020, TPS40400,
|
||||
and TPS40422.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called pmbus.
|
||||
@ -30,8 +31,8 @@ config SENSORS_ADM1275
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Analog
|
||||
Devices ADM1275 and ADM1276 Hot-Swap Controller and Digital Power
|
||||
Monitor.
|
||||
Devices ADM1075, ADM1275, and ADM1276 Hot-Swap Controller and Digital
|
||||
Power Monitors.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called adm1275.
|
||||
@ -67,11 +68,11 @@ config SENSORS_MAX16064
|
||||
be called max16064.
|
||||
|
||||
config SENSORS_MAX34440
|
||||
tristate "Maxim MAX34440/MAX34441"
|
||||
tristate "Maxim MAX34440 and compatibles"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Maxim
|
||||
MAX34440 and MAX34441.
|
||||
MAX34440, MAX34441, and MAX34446.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called max34440.
|
||||
@ -113,9 +114,9 @@ config SENSORS_ZL6100
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Intersil
|
||||
ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105
|
||||
Digital DC/DC Controllers, as well as for Ericsson BMR450, BMR451,
|
||||
BMR462, BMR463, and BMR464.
|
||||
ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105,
|
||||
ZL9101M, and ZL9117M Digital DC/DC Controllers, as well as for
|
||||
Ericsson BMR450, BMR451, BMR462, BMR463, and BMR464.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called zl6100.
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
enum chips { adm1275, adm1276 };
|
||||
enum chips { adm1075, adm1275, adm1276 };
|
||||
|
||||
#define ADM1275_PEAK_IOUT 0xd0
|
||||
#define ADM1275_PEAK_VIN 0xd1
|
||||
@ -32,6 +32,9 @@ enum chips { adm1275, adm1276 };
|
||||
|
||||
#define ADM1275_VIN_VOUT_SELECT (1 << 6)
|
||||
#define ADM1275_VRANGE (1 << 5)
|
||||
#define ADM1075_IRANGE_50 (1 << 4)
|
||||
#define ADM1075_IRANGE_25 (1 << 3)
|
||||
#define ADM1075_IRANGE_MASK ((1 << 3) | (1 << 4))
|
||||
|
||||
#define ADM1275_IOUT_WARN2_LIMIT 0xd7
|
||||
#define ADM1275_DEVICE_CONFIG 0xd8
|
||||
@ -42,6 +45,14 @@ enum chips { adm1275, adm1276 };
|
||||
|
||||
#define ADM1275_MFR_STATUS_IOUT_WARN2 (1 << 0)
|
||||
|
||||
#define ADM1075_READ_VAUX 0xdd
|
||||
#define ADM1075_VAUX_OV_WARN_LIMIT 0xde
|
||||
#define ADM1075_VAUX_UV_WARN_LIMIT 0xdf
|
||||
#define ADM1075_VAUX_STATUS 0xf6
|
||||
|
||||
#define ADM1075_VAUX_OV_WARN (1<<7)
|
||||
#define ADM1075_VAUX_UV_WARN (1<<6)
|
||||
|
||||
struct adm1275_data {
|
||||
int id;
|
||||
bool have_oc_fault;
|
||||
@ -74,6 +85,29 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
}
|
||||
ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
|
||||
break;
|
||||
case PMBUS_VOUT_OV_WARN_LIMIT:
|
||||
if (data->id != adm1075) {
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
}
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
ADM1075_VAUX_OV_WARN_LIMIT);
|
||||
break;
|
||||
case PMBUS_VOUT_UV_WARN_LIMIT:
|
||||
if (data->id != adm1075) {
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
}
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
ADM1075_VAUX_UV_WARN_LIMIT);
|
||||
break;
|
||||
case PMBUS_READ_VOUT:
|
||||
if (data->id != adm1075) {
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
}
|
||||
ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
|
||||
break;
|
||||
@ -84,7 +118,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_PIN_MAX:
|
||||
if (data->id != adm1276) {
|
||||
if (data->id == adm1275) {
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
@ -95,7 +129,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
case PMBUS_VIRT_RESET_VIN_HISTORY:
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_PIN_HISTORY:
|
||||
if (data->id != adm1276)
|
||||
if (data->id == adm1275)
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
default:
|
||||
@ -163,6 +197,19 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT;
|
||||
}
|
||||
break;
|
||||
case PMBUS_STATUS_VOUT:
|
||||
if (data->id != adm1075) {
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
mfr_status = pmbus_read_byte_data(client, 0,
|
||||
ADM1075_VAUX_STATUS);
|
||||
if (mfr_status & ADM1075_VAUX_OV_WARN)
|
||||
ret |= PB_VOLTAGE_OV_WARNING;
|
||||
if (mfr_status & ADM1075_VAUX_UV_WARN)
|
||||
ret |= PB_VOLTAGE_UV_WARNING;
|
||||
break;
|
||||
default:
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
@ -171,6 +218,7 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adm1275_id[] = {
|
||||
{ "adm1075", adm1075 },
|
||||
{ "adm1275", adm1275 },
|
||||
{ "adm1276", adm1276 },
|
||||
{ }
|
||||
@ -229,7 +277,8 @@ static int adm1275_probe(struct i2c_client *client,
|
||||
if (device_config < 0)
|
||||
return device_config;
|
||||
|
||||
data = kzalloc(sizeof(struct adm1275_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -250,7 +299,14 @@ static int adm1275_probe(struct i2c_client *client,
|
||||
info->read_byte_data = adm1275_read_byte_data;
|
||||
info->write_word_data = adm1275_write_word_data;
|
||||
|
||||
if (config & ADM1275_VRANGE) {
|
||||
if (data->id == adm1075) {
|
||||
info->m[PSC_VOLTAGE_IN] = 27169;
|
||||
info->b[PSC_VOLTAGE_IN] = 0;
|
||||
info->R[PSC_VOLTAGE_IN] = -1;
|
||||
info->m[PSC_VOLTAGE_OUT] = 27169;
|
||||
info->b[PSC_VOLTAGE_OUT] = 0;
|
||||
info->R[PSC_VOLTAGE_OUT] = -1;
|
||||
} else if (config & ADM1275_VRANGE) {
|
||||
info->m[PSC_VOLTAGE_IN] = 19199;
|
||||
info->b[PSC_VOLTAGE_IN] = 0;
|
||||
info->R[PSC_VOLTAGE_IN] = -2;
|
||||
@ -270,6 +326,31 @@ static int adm1275_probe(struct i2c_client *client,
|
||||
data->have_oc_fault = true;
|
||||
|
||||
switch (data->id) {
|
||||
case adm1075:
|
||||
info->format[PSC_POWER] = direct;
|
||||
info->b[PSC_POWER] = 0;
|
||||
info->R[PSC_POWER] = -1;
|
||||
switch (config & ADM1075_IRANGE_MASK) {
|
||||
case ADM1075_IRANGE_25:
|
||||
info->m[PSC_POWER] = 8549;
|
||||
info->m[PSC_CURRENT_OUT] = 806;
|
||||
break;
|
||||
case ADM1075_IRANGE_50:
|
||||
info->m[PSC_POWER] = 4279;
|
||||
info->m[PSC_CURRENT_OUT] = 404;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev, "Invalid input current range");
|
||||
info->m[PSC_POWER] = 0;
|
||||
info->m[PSC_CURRENT_OUT] = 0;
|
||||
break;
|
||||
}
|
||||
info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
|
||||
| PMBUS_HAVE_STATUS_INPUT;
|
||||
if (config & ADM1275_VIN_VOUT_SELECT)
|
||||
info->func[0] |=
|
||||
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
|
||||
break;
|
||||
case adm1275:
|
||||
if (config & ADM1275_VIN_VOUT_SELECT)
|
||||
info->func[0] |=
|
||||
@ -297,24 +378,7 @@ static int adm1275_probe(struct i2c_client *client,
|
||||
break;
|
||||
}
|
||||
|
||||
ret = pmbus_do_probe(client, id, info);
|
||||
if (ret)
|
||||
goto err_mem;
|
||||
return 0;
|
||||
|
||||
err_mem:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adm1275_remove(struct i2c_client *client)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct adm1275_data *data = to_adm1275_data(info);
|
||||
|
||||
pmbus_do_remove(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
return pmbus_do_probe(client, id, info);
|
||||
}
|
||||
|
||||
static struct i2c_driver adm1275_driver = {
|
||||
@ -322,22 +386,12 @@ static struct i2c_driver adm1275_driver = {
|
||||
.name = "adm1275",
|
||||
},
|
||||
.probe = adm1275_probe,
|
||||
.remove = adm1275_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = adm1275_id,
|
||||
};
|
||||
|
||||
static int __init adm1275_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adm1275_driver);
|
||||
}
|
||||
|
||||
static void __exit adm1275_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adm1275_driver);
|
||||
}
|
||||
module_i2c_driver(adm1275_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(adm1275_init);
|
||||
module_exit(adm1275_exit);
|
||||
|
@ -176,7 +176,6 @@ static int lm25066_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int config;
|
||||
int ret;
|
||||
struct lm25066_data *data;
|
||||
struct pmbus_driver_info *info;
|
||||
|
||||
@ -184,15 +183,14 @@ static int lm25066_probe(struct i2c_client *client,
|
||||
I2C_FUNC_SMBUS_READ_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
data = kzalloc(sizeof(struct lm25066_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct lm25066_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
config = i2c_smbus_read_byte_data(client, LM25066_DEVICE_SETUP);
|
||||
if (config < 0) {
|
||||
ret = config;
|
||||
goto err_mem;
|
||||
}
|
||||
if (config < 0)
|
||||
return config;
|
||||
|
||||
data->id = id->driver_data;
|
||||
info = &data->info;
|
||||
@ -291,28 +289,10 @@ static int lm25066_probe(struct i2c_client *client,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -ENODEV;
|
||||
goto err_mem;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = pmbus_do_probe(client, id, info);
|
||||
if (ret)
|
||||
goto err_mem;
|
||||
return 0;
|
||||
|
||||
err_mem:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lm25066_remove(struct i2c_client *client)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct lm25066_data *data = to_lm25066_data(info);
|
||||
|
||||
pmbus_do_remove(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
return pmbus_do_probe(client, id, info);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lm25066_id[] = {
|
||||
@ -330,22 +310,12 @@ static struct i2c_driver lm25066_driver = {
|
||||
.name = "lm25066",
|
||||
},
|
||||
.probe = lm25066_probe,
|
||||
.remove = lm25066_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = lm25066_id,
|
||||
};
|
||||
|
||||
static int __init lm25066_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm25066_driver);
|
||||
}
|
||||
|
||||
static void __exit lm25066_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm25066_driver);
|
||||
}
|
||||
module_i2c_driver(lm25066_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(lm25066_init);
|
||||
module_exit(lm25066_exit);
|
||||
|
@ -287,7 +287,7 @@ MODULE_DEVICE_TABLE(i2c, ltc2978_id);
|
||||
static int ltc2978_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int chip_id, ret, i;
|
||||
int chip_id, i;
|
||||
struct ltc2978_data *data;
|
||||
struct pmbus_driver_info *info;
|
||||
|
||||
@ -295,15 +295,14 @@ static int ltc2978_probe(struct i2c_client *client,
|
||||
I2C_FUNC_SMBUS_READ_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
data = kzalloc(sizeof(struct ltc2978_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct ltc2978_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID);
|
||||
if (chip_id < 0) {
|
||||
ret = chip_id;
|
||||
goto err_mem;
|
||||
}
|
||||
if (chip_id < 0)
|
||||
return chip_id;
|
||||
|
||||
if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
|
||||
data->id = ltc2978;
|
||||
@ -311,8 +310,7 @@ static int ltc2978_probe(struct i2c_client *client,
|
||||
data->id = ltc3880;
|
||||
} else {
|
||||
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
|
||||
ret = -ENODEV;
|
||||
goto err_mem;
|
||||
return -ENODEV;
|
||||
}
|
||||
if (data->id != id->driver_data)
|
||||
dev_warn(&client->dev,
|
||||
@ -357,28 +355,10 @@ static int ltc2978_probe(struct i2c_client *client,
|
||||
data->vout_min[1] = 0xffff;
|
||||
break;
|
||||
default:
|
||||
ret = -ENODEV;
|
||||
goto err_mem;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = pmbus_do_probe(client, id, info);
|
||||
if (ret)
|
||||
goto err_mem;
|
||||
return 0;
|
||||
|
||||
err_mem:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc2978_remove(struct i2c_client *client)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct ltc2978_data *data = to_ltc2978_data(info);
|
||||
|
||||
pmbus_do_remove(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
return pmbus_do_probe(client, id, info);
|
||||
}
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
@ -387,22 +367,12 @@ static struct i2c_driver ltc2978_driver = {
|
||||
.name = "ltc2978",
|
||||
},
|
||||
.probe = ltc2978_probe,
|
||||
.remove = ltc2978_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = ltc2978_id,
|
||||
};
|
||||
|
||||
static int __init ltc2978_init(void)
|
||||
{
|
||||
return i2c_add_driver(<c2978_driver);
|
||||
}
|
||||
|
||||
static void __exit ltc2978_exit(void)
|
||||
{
|
||||
i2c_del_driver(<c2978_driver);
|
||||
}
|
||||
module_i2c_driver(ltc2978_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(ltc2978_init);
|
||||
module_exit(ltc2978_exit);
|
||||
|
@ -103,12 +103,6 @@ static int max16064_probe(struct i2c_client *client,
|
||||
return pmbus_do_probe(client, id, &max16064_info);
|
||||
}
|
||||
|
||||
static int max16064_remove(struct i2c_client *client)
|
||||
{
|
||||
pmbus_do_remove(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max16064_id[] = {
|
||||
{"max16064", 0},
|
||||
{}
|
||||
@ -122,22 +116,12 @@ static struct i2c_driver max16064_driver = {
|
||||
.name = "max16064",
|
||||
},
|
||||
.probe = max16064_probe,
|
||||
.remove = max16064_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = max16064_id,
|
||||
};
|
||||
|
||||
static int __init max16064_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max16064_driver);
|
||||
}
|
||||
|
||||
static void __exit max16064_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max16064_driver);
|
||||
}
|
||||
module_i2c_driver(max16064_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(max16064_init);
|
||||
module_exit(max16064_exit);
|
||||
|
@ -25,34 +25,82 @@
|
||||
#include <linux/i2c.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
enum chips { max34440, max34441 };
|
||||
enum chips { max34440, max34441, max34446 };
|
||||
|
||||
#define MAX34440_MFR_VOUT_PEAK 0xd4
|
||||
#define MAX34440_MFR_IOUT_PEAK 0xd5
|
||||
#define MAX34440_MFR_TEMPERATURE_PEAK 0xd6
|
||||
#define MAX34440_MFR_VOUT_MIN 0xd7
|
||||
|
||||
#define MAX34446_MFR_POUT_PEAK 0xe0
|
||||
#define MAX34446_MFR_POUT_AVG 0xe1
|
||||
#define MAX34446_MFR_IOUT_AVG 0xe2
|
||||
#define MAX34446_MFR_TEMPERATURE_AVG 0xe3
|
||||
|
||||
#define MAX34440_STATUS_OC_WARN (1 << 0)
|
||||
#define MAX34440_STATUS_OC_FAULT (1 << 1)
|
||||
#define MAX34440_STATUS_OT_FAULT (1 << 5)
|
||||
#define MAX34440_STATUS_OT_WARN (1 << 6)
|
||||
|
||||
struct max34440_data {
|
||||
int id;
|
||||
struct pmbus_driver_info info;
|
||||
};
|
||||
|
||||
#define to_max34440_data(x) container_of(x, struct max34440_data, info)
|
||||
|
||||
static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
int ret;
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct max34440_data *data = to_max34440_data(info);
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_VOUT_MIN:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
MAX34440_MFR_VOUT_MIN);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
MAX34440_MFR_VOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_AVG:
|
||||
if (data->id != max34446)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
MAX34446_MFR_IOUT_AVG);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
MAX34440_MFR_IOUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_POUT_AVG:
|
||||
if (data->id != max34446)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
MAX34446_MFR_POUT_AVG);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_POUT_MAX:
|
||||
if (data->id != max34446)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
MAX34446_MFR_POUT_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_AVG:
|
||||
if (data->id != max34446)
|
||||
return -ENXIO;
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
MAX34446_MFR_TEMPERATURE_AVG);
|
||||
break;
|
||||
case PMBUS_VIRT_READ_TEMP_MAX:
|
||||
ret = pmbus_read_word_data(client, page,
|
||||
MAX34440_MFR_TEMPERATURE_PEAK);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_POUT_HISTORY:
|
||||
if (data->id != max34446)
|
||||
return -ENXIO;
|
||||
ret = 0;
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_VOUT_HISTORY:
|
||||
case PMBUS_VIRT_RESET_IOUT_HISTORY:
|
||||
case PMBUS_VIRT_RESET_TEMP_HISTORY:
|
||||
@ -68,21 +116,42 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
static int max34440_write_word_data(struct i2c_client *client, int page,
|
||||
int reg, u16 word)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct max34440_data *data = to_max34440_data(info);
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_RESET_POUT_HISTORY:
|
||||
ret = pmbus_write_word_data(client, page,
|
||||
MAX34446_MFR_POUT_PEAK, 0);
|
||||
if (ret)
|
||||
break;
|
||||
ret = pmbus_write_word_data(client, page,
|
||||
MAX34446_MFR_POUT_AVG, 0);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_VOUT_HISTORY:
|
||||
ret = pmbus_write_word_data(client, page,
|
||||
MAX34440_MFR_VOUT_MIN, 0x7fff);
|
||||
if (ret)
|
||||
break;
|
||||
ret = pmbus_write_word_data(client, page,
|
||||
MAX34440_MFR_VOUT_PEAK, 0);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_IOUT_HISTORY:
|
||||
ret = pmbus_write_word_data(client, page,
|
||||
MAX34440_MFR_IOUT_PEAK, 0);
|
||||
if (!ret && data->id == max34446)
|
||||
ret = pmbus_write_word_data(client, page,
|
||||
MAX34446_MFR_IOUT_AVG, 0);
|
||||
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_TEMP_HISTORY:
|
||||
ret = pmbus_write_word_data(client, page,
|
||||
MAX34440_MFR_TEMPERATURE_PEAK,
|
||||
0x8000);
|
||||
if (!ret && data->id == max34446)
|
||||
ret = pmbus_write_word_data(client, page,
|
||||
MAX34446_MFR_TEMPERATURE_AVG, 0);
|
||||
break;
|
||||
default:
|
||||
ret = -ENODATA;
|
||||
@ -216,26 +285,66 @@ static struct pmbus_driver_info max34440_info[] = {
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
},
|
||||
[max34446] = {
|
||||
.pages = 7,
|
||||
.format[PSC_VOLTAGE_IN] = direct,
|
||||
.format[PSC_VOLTAGE_OUT] = direct,
|
||||
.format[PSC_TEMPERATURE] = direct,
|
||||
.format[PSC_CURRENT_OUT] = direct,
|
||||
.format[PSC_POWER] = direct,
|
||||
.m[PSC_VOLTAGE_IN] = 1,
|
||||
.b[PSC_VOLTAGE_IN] = 0,
|
||||
.R[PSC_VOLTAGE_IN] = 3,
|
||||
.m[PSC_VOLTAGE_OUT] = 1,
|
||||
.b[PSC_VOLTAGE_OUT] = 0,
|
||||
.R[PSC_VOLTAGE_OUT] = 3,
|
||||
.m[PSC_CURRENT_OUT] = 1,
|
||||
.b[PSC_CURRENT_OUT] = 0,
|
||||
.R[PSC_CURRENT_OUT] = 3,
|
||||
.m[PSC_POWER] = 1,
|
||||
.b[PSC_POWER] = 0,
|
||||
.R[PSC_POWER] = 3,
|
||||
.m[PSC_TEMPERATURE] = 1,
|
||||
.b[PSC_TEMPERATURE] = 0,
|
||||
.R[PSC_TEMPERATURE] = 2,
|
||||
.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
|
||||
.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
|
||||
.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
|
||||
.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
|
||||
.func[4] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.func[5] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = max34440_read_byte_data,
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
},
|
||||
};
|
||||
|
||||
static int max34440_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
return pmbus_do_probe(client, id, &max34440_info[id->driver_data]);
|
||||
}
|
||||
struct max34440_data *data;
|
||||
|
||||
static int max34440_remove(struct i2c_client *client)
|
||||
{
|
||||
pmbus_do_remove(client);
|
||||
return 0;
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct max34440_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
data->id = id->driver_data;
|
||||
data->info = max34440_info[id->driver_data];
|
||||
|
||||
return pmbus_do_probe(client, id, &data->info);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max34440_id[] = {
|
||||
{"max34440", max34440},
|
||||
{"max34441", max34441},
|
||||
{"max34446", max34446},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, max34440_id);
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
@ -244,22 +353,12 @@ static struct i2c_driver max34440_driver = {
|
||||
.name = "max34440",
|
||||
},
|
||||
.probe = max34440_probe,
|
||||
.remove = max34440_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = max34440_id,
|
||||
};
|
||||
|
||||
static int __init max34440_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max34440_driver);
|
||||
}
|
||||
|
||||
static void __exit max34440_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max34440_driver);
|
||||
}
|
||||
module_i2c_driver(max34440_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(max34440_init);
|
||||
module_exit(max34440_exit);
|
||||
|
@ -180,12 +180,6 @@ static int max8688_probe(struct i2c_client *client,
|
||||
return pmbus_do_probe(client, id, &max8688_info);
|
||||
}
|
||||
|
||||
static int max8688_remove(struct i2c_client *client)
|
||||
{
|
||||
pmbus_do_remove(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max8688_id[] = {
|
||||
{"max8688", 0},
|
||||
{ }
|
||||
@ -199,22 +193,12 @@ static struct i2c_driver max8688_driver = {
|
||||
.name = "max8688",
|
||||
},
|
||||
.probe = max8688_probe,
|
||||
.remove = max8688_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = max8688_id,
|
||||
};
|
||||
|
||||
static int __init max8688_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max8688_driver);
|
||||
}
|
||||
|
||||
static void __exit max8688_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max8688_driver);
|
||||
}
|
||||
module_i2c_driver(max8688_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(max8688_init);
|
||||
module_exit(max8688_exit);
|
||||
|
@ -166,33 +166,16 @@ static int pmbus_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct pmbus_driver_info *info;
|
||||
int ret;
|
||||
|
||||
info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
|
||||
info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
|
||||
GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->pages = id->driver_data;
|
||||
info->identify = pmbus_identify;
|
||||
|
||||
ret = pmbus_do_probe(client, id, info);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
out:
|
||||
kfree(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pmbus_remove(struct i2c_client *client)
|
||||
{
|
||||
const struct pmbus_driver_info *info;
|
||||
|
||||
info = pmbus_get_driver_info(client);
|
||||
pmbus_do_remove(client);
|
||||
kfree(info);
|
||||
return 0;
|
||||
return pmbus_do_probe(client, id, info);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -202,12 +185,15 @@ static const struct i2c_device_id pmbus_id[] = {
|
||||
{"adp4000", 1},
|
||||
{"bmr453", 1},
|
||||
{"bmr454", 1},
|
||||
{"mdt040", 1},
|
||||
{"ncp4200", 1},
|
||||
{"ncp4208", 1},
|
||||
{"pdt003", 1},
|
||||
{"pdt006", 1},
|
||||
{"pdt012", 1},
|
||||
{"pmbus", 0},
|
||||
{"tps40400", 1},
|
||||
{"tps40422", 2},
|
||||
{"udt020", 1},
|
||||
{}
|
||||
};
|
||||
@ -220,22 +206,12 @@ static struct i2c_driver pmbus_driver = {
|
||||
.name = "pmbus",
|
||||
},
|
||||
.probe = pmbus_probe,
|
||||
.remove = pmbus_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = pmbus_id,
|
||||
};
|
||||
|
||||
static int __init pmbus_init(void)
|
||||
{
|
||||
return i2c_add_driver(&pmbus_driver);
|
||||
}
|
||||
|
||||
static void __exit pmbus_exit(void)
|
||||
{
|
||||
i2c_del_driver(&pmbus_driver);
|
||||
}
|
||||
module_i2c_driver(pmbus_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("Generic PMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(pmbus_init);
|
||||
module_exit(pmbus_exit);
|
||||
|
@ -146,31 +146,36 @@
|
||||
* code when reading or writing virtual registers.
|
||||
*/
|
||||
#define PMBUS_VIRT_BASE 0x100
|
||||
#define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 0)
|
||||
#define PMBUS_VIRT_READ_TEMP_MAX (PMBUS_VIRT_BASE + 1)
|
||||
#define PMBUS_VIRT_RESET_TEMP_HISTORY (PMBUS_VIRT_BASE + 2)
|
||||
#define PMBUS_VIRT_READ_VIN_AVG (PMBUS_VIRT_BASE + 3)
|
||||
#define PMBUS_VIRT_READ_VIN_MIN (PMBUS_VIRT_BASE + 4)
|
||||
#define PMBUS_VIRT_READ_VIN_MAX (PMBUS_VIRT_BASE + 5)
|
||||
#define PMBUS_VIRT_RESET_VIN_HISTORY (PMBUS_VIRT_BASE + 6)
|
||||
#define PMBUS_VIRT_READ_IIN_AVG (PMBUS_VIRT_BASE + 7)
|
||||
#define PMBUS_VIRT_READ_IIN_MIN (PMBUS_VIRT_BASE + 8)
|
||||
#define PMBUS_VIRT_READ_IIN_MAX (PMBUS_VIRT_BASE + 9)
|
||||
#define PMBUS_VIRT_RESET_IIN_HISTORY (PMBUS_VIRT_BASE + 10)
|
||||
#define PMBUS_VIRT_READ_PIN_AVG (PMBUS_VIRT_BASE + 11)
|
||||
#define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 12)
|
||||
#define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 13)
|
||||
#define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 14)
|
||||
#define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 15)
|
||||
#define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 16)
|
||||
#define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 17)
|
||||
#define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 18)
|
||||
#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 19)
|
||||
#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 20)
|
||||
#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 21)
|
||||
#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 22)
|
||||
#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 23)
|
||||
#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 24)
|
||||
#define PMBUS_VIRT_READ_TEMP_AVG (PMBUS_VIRT_BASE + 0)
|
||||
#define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 1)
|
||||
#define PMBUS_VIRT_READ_TEMP_MAX (PMBUS_VIRT_BASE + 2)
|
||||
#define PMBUS_VIRT_RESET_TEMP_HISTORY (PMBUS_VIRT_BASE + 3)
|
||||
#define PMBUS_VIRT_READ_VIN_AVG (PMBUS_VIRT_BASE + 4)
|
||||
#define PMBUS_VIRT_READ_VIN_MIN (PMBUS_VIRT_BASE + 5)
|
||||
#define PMBUS_VIRT_READ_VIN_MAX (PMBUS_VIRT_BASE + 6)
|
||||
#define PMBUS_VIRT_RESET_VIN_HISTORY (PMBUS_VIRT_BASE + 7)
|
||||
#define PMBUS_VIRT_READ_IIN_AVG (PMBUS_VIRT_BASE + 8)
|
||||
#define PMBUS_VIRT_READ_IIN_MIN (PMBUS_VIRT_BASE + 9)
|
||||
#define PMBUS_VIRT_READ_IIN_MAX (PMBUS_VIRT_BASE + 10)
|
||||
#define PMBUS_VIRT_RESET_IIN_HISTORY (PMBUS_VIRT_BASE + 11)
|
||||
#define PMBUS_VIRT_READ_PIN_AVG (PMBUS_VIRT_BASE + 12)
|
||||
#define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 13)
|
||||
#define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 14)
|
||||
#define PMBUS_VIRT_READ_POUT_AVG (PMBUS_VIRT_BASE + 15)
|
||||
#define PMBUS_VIRT_READ_POUT_MAX (PMBUS_VIRT_BASE + 16)
|
||||
#define PMBUS_VIRT_RESET_POUT_HISTORY (PMBUS_VIRT_BASE + 17)
|
||||
#define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 18)
|
||||
#define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 19)
|
||||
#define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 20)
|
||||
#define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 21)
|
||||
#define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 22)
|
||||
#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 23)
|
||||
#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 24)
|
||||
#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 25)
|
||||
#define PMBUS_VIRT_READ_TEMP2_AVG (PMBUS_VIRT_BASE + 26)
|
||||
#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 27)
|
||||
#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 28)
|
||||
#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 29)
|
||||
|
||||
/*
|
||||
* CAPABILITY
|
||||
@ -364,7 +369,7 @@ bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
|
||||
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
|
||||
int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
|
||||
struct pmbus_driver_info *info);
|
||||
void pmbus_do_remove(struct i2c_client *client);
|
||||
int pmbus_do_remove(struct i2c_client *client);
|
||||
const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
|
||||
*client);
|
||||
|
||||
|
@ -40,11 +40,14 @@
|
||||
#define PMBUS_IOUT_SENSORS_PER_PAGE 8 /* input, min, max, crit,
|
||||
lowest, highest, avg,
|
||||
reset */
|
||||
#define PMBUS_POUT_SENSORS_PER_PAGE 4 /* input, cap, max, crit */
|
||||
#define PMBUS_POUT_SENSORS_PER_PAGE 7 /* input, cap, max, crit,
|
||||
* highest, avg, reset
|
||||
*/
|
||||
#define PMBUS_MAX_SENSORS_PER_FAN 1 /* input */
|
||||
#define PMBUS_MAX_SENSORS_PER_TEMP 8 /* input, min, max, lcrit,
|
||||
crit, lowest, highest,
|
||||
reset */
|
||||
#define PMBUS_MAX_SENSORS_PER_TEMP 9 /* input, min, max, lcrit,
|
||||
* crit, lowest, highest, avg,
|
||||
* reset
|
||||
*/
|
||||
|
||||
#define PMBUS_MAX_INPUT_BOOLEANS 7 /* v: min_alarm, max_alarm,
|
||||
lcrit_alarm, crit_alarm;
|
||||
@ -782,7 +785,7 @@ static ssize_t pmbus_set_sensor(struct device *dev,
|
||||
int ret;
|
||||
u16 regval;
|
||||
|
||||
if (strict_strtol(buf, 10, &val) < 0)
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -1334,6 +1337,17 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = {
|
||||
.attr = "crit",
|
||||
.alarm = "crit_alarm",
|
||||
.sbit = PB_POUT_OP_FAULT,
|
||||
}, {
|
||||
.reg = PMBUS_VIRT_READ_POUT_AVG,
|
||||
.update = true,
|
||||
.attr = "average",
|
||||
}, {
|
||||
.reg = PMBUS_VIRT_READ_POUT_MAX,
|
||||
.update = true,
|
||||
.attr = "input_highest",
|
||||
}, {
|
||||
.reg = PMBUS_VIRT_RESET_POUT_HISTORY,
|
||||
.attr = "reset_history",
|
||||
}
|
||||
};
|
||||
|
||||
@ -1388,6 +1402,9 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = {
|
||||
}, {
|
||||
.reg = PMBUS_VIRT_READ_TEMP_MIN,
|
||||
.attr = "lowest",
|
||||
}, {
|
||||
.reg = PMBUS_VIRT_READ_TEMP_AVG,
|
||||
.attr = "average",
|
||||
}, {
|
||||
.reg = PMBUS_VIRT_READ_TEMP_MAX,
|
||||
.attr = "highest",
|
||||
@ -1423,6 +1440,9 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = {
|
||||
}, {
|
||||
.reg = PMBUS_VIRT_READ_TEMP2_MIN,
|
||||
.attr = "lowest",
|
||||
}, {
|
||||
.reg = PMBUS_VIRT_READ_TEMP2_AVG,
|
||||
.attr = "average",
|
||||
}, {
|
||||
.reg = PMBUS_VIRT_READ_TEMP2_MAX,
|
||||
.attr = "highest",
|
||||
@ -1676,7 +1696,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
|
||||
| I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
dev_err(&client->dev, "No memory to allocate driver data\n");
|
||||
return -ENOMEM;
|
||||
@ -1688,8 +1708,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
|
||||
/* Bail out if PMBus status register does not exist. */
|
||||
if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) {
|
||||
dev_err(&client->dev, "PMBus status register not found\n");
|
||||
ret = -ENODEV;
|
||||
goto out_data;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pdata)
|
||||
@ -1702,50 +1721,49 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
|
||||
ret = (*info->identify)(client, info);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Chip identification failed\n");
|
||||
goto out_data;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
|
||||
dev_err(&client->dev, "Bad number of PMBus pages: %d\n",
|
||||
info->pages);
|
||||
ret = -ENODEV;
|
||||
goto out_data;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = pmbus_identify_common(client, data);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Failed to identify chip capabilities\n");
|
||||
goto out_data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
data->sensors = kzalloc(sizeof(struct pmbus_sensor) * data->max_sensors,
|
||||
GFP_KERNEL);
|
||||
data->sensors = devm_kzalloc(&client->dev, sizeof(struct pmbus_sensor)
|
||||
* data->max_sensors, GFP_KERNEL);
|
||||
if (!data->sensors) {
|
||||
dev_err(&client->dev, "No memory to allocate sensor data\n");
|
||||
goto out_data;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data->booleans = kzalloc(sizeof(struct pmbus_boolean)
|
||||
data->booleans = devm_kzalloc(&client->dev, sizeof(struct pmbus_boolean)
|
||||
* data->max_booleans, GFP_KERNEL);
|
||||
if (!data->booleans) {
|
||||
dev_err(&client->dev, "No memory to allocate boolean data\n");
|
||||
goto out_sensors;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data->labels = kzalloc(sizeof(struct pmbus_label) * data->max_labels,
|
||||
GFP_KERNEL);
|
||||
data->labels = devm_kzalloc(&client->dev, sizeof(struct pmbus_label)
|
||||
* data->max_labels, GFP_KERNEL);
|
||||
if (!data->labels) {
|
||||
dev_err(&client->dev, "No memory to allocate label data\n");
|
||||
goto out_booleans;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data->attributes = kzalloc(sizeof(struct attribute *)
|
||||
data->attributes = devm_kzalloc(&client->dev, sizeof(struct attribute *)
|
||||
* data->max_attributes, GFP_KERNEL);
|
||||
if (!data->attributes) {
|
||||
dev_err(&client->dev, "No memory to allocate attribute data\n");
|
||||
goto out_labels;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pmbus_find_attributes(client, data);
|
||||
@ -1756,8 +1774,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
|
||||
*/
|
||||
if (!data->num_attributes) {
|
||||
dev_err(&client->dev, "No attributes found\n");
|
||||
ret = -ENODEV;
|
||||
goto out_attributes;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
@ -1765,7 +1782,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
|
||||
ret = sysfs_create_group(&client->dev.kobj, &data->group);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Failed to create sysfs entries\n");
|
||||
goto out_attributes;
|
||||
return ret;
|
||||
}
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
@ -1777,30 +1794,16 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
|
||||
|
||||
out_hwmon_device_register:
|
||||
sysfs_remove_group(&client->dev.kobj, &data->group);
|
||||
out_attributes:
|
||||
kfree(data->attributes);
|
||||
out_labels:
|
||||
kfree(data->labels);
|
||||
out_booleans:
|
||||
kfree(data->booleans);
|
||||
out_sensors:
|
||||
kfree(data->sensors);
|
||||
out_data:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pmbus_do_probe);
|
||||
|
||||
void pmbus_do_remove(struct i2c_client *client)
|
||||
int pmbus_do_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &data->group);
|
||||
kfree(data->attributes);
|
||||
kfree(data->labels);
|
||||
kfree(data->booleans);
|
||||
kfree(data->sensors);
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pmbus_do_remove);
|
||||
|
||||
|
@ -155,7 +155,8 @@ static int ucd9000_probe(struct i2c_client *client,
|
||||
"Device mismatch: Configured %s, detected %s\n",
|
||||
id->name, mid->name);
|
||||
|
||||
data = kzalloc(sizeof(struct ucd9000_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
info = &data->info;
|
||||
@ -164,13 +165,12 @@ static int ucd9000_probe(struct i2c_client *client,
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to read number of active pages\n");
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
info->pages = ret;
|
||||
if (!info->pages) {
|
||||
dev_err(&client->dev, "No pages configured\n");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* The internal temperature sensor is always active */
|
||||
@ -181,8 +181,7 @@ static int ucd9000_probe(struct i2c_client *client,
|
||||
block_buffer);
|
||||
if (ret <= 0) {
|
||||
dev_err(&client->dev, "Failed to read configuration data\n");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
return -ENODEV;
|
||||
}
|
||||
for (i = 0; i < ret; i++) {
|
||||
int page = UCD9000_MON_PAGE(block_buffer[i]);
|
||||
@ -218,7 +217,7 @@ static int ucd9000_probe(struct i2c_client *client,
|
||||
UCD9000_FAN_CONFIG,
|
||||
data->fan_data[i]);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0);
|
||||
|
||||
@ -227,49 +226,21 @@ static int ucd9000_probe(struct i2c_client *client,
|
||||
| PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34;
|
||||
}
|
||||
|
||||
ret = pmbus_do_probe(client, mid, info);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
out:
|
||||
kfree(data);
|
||||
return ret;
|
||||
return pmbus_do_probe(client, mid, info);
|
||||
}
|
||||
|
||||
static int ucd9000_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ucd9000_data *data;
|
||||
|
||||
data = to_ucd9000_data(pmbus_get_driver_info(client));
|
||||
pmbus_do_remove(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver ucd9000_driver = {
|
||||
.driver = {
|
||||
.name = "ucd9000",
|
||||
},
|
||||
.probe = ucd9000_probe,
|
||||
.remove = ucd9000_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = ucd9000_id,
|
||||
};
|
||||
|
||||
static int __init ucd9000_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ucd9000_driver);
|
||||
}
|
||||
|
||||
static void __exit ucd9000_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ucd9000_driver);
|
||||
}
|
||||
module_i2c_driver(ucd9000_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(ucd9000_init);
|
||||
module_exit(ucd9000_exit);
|
||||
|
@ -81,7 +81,8 @@ static int ucd9200_probe(struct i2c_client *client,
|
||||
"Device mismatch: Configured %s, detected %s\n",
|
||||
id->name, mid->name);
|
||||
|
||||
info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
|
||||
info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
|
||||
GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -89,7 +90,7 @@ static int ucd9200_probe(struct i2c_client *client,
|
||||
block_buffer);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Failed to read phase information\n");
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -106,8 +107,7 @@ static int ucd9200_probe(struct i2c_client *client,
|
||||
}
|
||||
if (!info->pages) {
|
||||
dev_err(&client->dev, "No rails configured\n");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_info(&client->dev, "%d rails configured\n", info->pages);
|
||||
|
||||
@ -137,7 +137,7 @@ static int ucd9200_probe(struct i2c_client *client,
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to initialize PHASE registers\n");
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (info->pages > 1)
|
||||
@ -160,48 +160,21 @@ static int ucd9200_probe(struct i2c_client *client,
|
||||
if (mid->driver_data == ucd9240)
|
||||
info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12;
|
||||
|
||||
ret = pmbus_do_probe(client, mid, info);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return 0;
|
||||
out:
|
||||
kfree(info);
|
||||
return ret;
|
||||
return pmbus_do_probe(client, mid, info);
|
||||
}
|
||||
|
||||
static int ucd9200_remove(struct i2c_client *client)
|
||||
{
|
||||
const struct pmbus_driver_info *info;
|
||||
|
||||
info = pmbus_get_driver_info(client);
|
||||
pmbus_do_remove(client);
|
||||
kfree(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver ucd9200_driver = {
|
||||
.driver = {
|
||||
.name = "ucd9200",
|
||||
},
|
||||
.probe = ucd9200_probe,
|
||||
.remove = ucd9200_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = ucd9200_id,
|
||||
};
|
||||
|
||||
static int __init ucd9200_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ucd9200_driver);
|
||||
}
|
||||
|
||||
static void __exit ucd9200_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ucd9200_driver);
|
||||
}
|
||||
module_i2c_driver(ucd9200_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(ucd9200_init);
|
||||
module_exit(ucd9200_exit);
|
||||
|
@ -28,7 +28,8 @@
|
||||
#include <linux/delay.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 };
|
||||
enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105,
|
||||
zl9101, zl9117 };
|
||||
|
||||
struct zl6100_data {
|
||||
int id;
|
||||
@ -152,6 +153,8 @@ static const struct i2c_device_id zl6100_id[] = {
|
||||
{"zl2106", zl2106},
|
||||
{"zl6100", zl6100},
|
||||
{"zl6105", zl6105},
|
||||
{"zl9101", zl9101},
|
||||
{"zl9117", zl9117},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, zl6100_id);
|
||||
@ -193,7 +196,8 @@ static int zl6100_probe(struct i2c_client *client,
|
||||
"Device mismatch: Configured %s, detected %s\n",
|
||||
id->name, mid->name);
|
||||
|
||||
data = kzalloc(sizeof(struct zl6100_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -223,7 +227,8 @@ static int zl6100_probe(struct i2c_client *client,
|
||||
|
||||
ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
|
||||
if (ret < 0)
|
||||
goto err_mem;
|
||||
return ret;
|
||||
|
||||
if (ret & ZL6100_MFR_XTEMP_ENABLE)
|
||||
info->func[0] |= PMBUS_HAVE_TEMP2;
|
||||
|
||||
@ -235,24 +240,7 @@ static int zl6100_probe(struct i2c_client *client,
|
||||
info->write_word_data = zl6100_write_word_data;
|
||||
info->write_byte = zl6100_write_byte;
|
||||
|
||||
ret = pmbus_do_probe(client, mid, info);
|
||||
if (ret)
|
||||
goto err_mem;
|
||||
return 0;
|
||||
|
||||
err_mem:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int zl6100_remove(struct i2c_client *client)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct zl6100_data *data = to_zl6100_data(info);
|
||||
|
||||
pmbus_do_remove(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
return pmbus_do_probe(client, mid, info);
|
||||
}
|
||||
|
||||
static struct i2c_driver zl6100_driver = {
|
||||
@ -260,22 +248,12 @@ static struct i2c_driver zl6100_driver = {
|
||||
.name = "zl6100",
|
||||
},
|
||||
.probe = zl6100_probe,
|
||||
.remove = zl6100_remove,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = zl6100_id,
|
||||
};
|
||||
|
||||
static int __init zl6100_init(void)
|
||||
{
|
||||
return i2c_add_driver(&zl6100_driver);
|
||||
}
|
||||
|
||||
static void __exit zl6100_exit(void)
|
||||
{
|
||||
i2c_del_driver(&zl6100_driver);
|
||||
}
|
||||
module_i2c_driver(zl6100_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(zl6100_init);
|
||||
module_exit(zl6100_exit);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com> *
|
||||
* Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.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 *
|
||||
@ -79,6 +79,7 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
|
||||
struct sch5627_data {
|
||||
unsigned short addr;
|
||||
struct device *hwmon_dev;
|
||||
struct sch56xx_watchdog_data *watchdog;
|
||||
u8 control;
|
||||
u8 temp_max[SCH5627_NO_TEMPS];
|
||||
u8 temp_crit[SCH5627_NO_TEMPS];
|
||||
@ -453,6 +454,9 @@ static int sch5627_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sch5627_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
if (data->watchdog)
|
||||
sch56xx_watchdog_unregister(data->watchdog);
|
||||
|
||||
if (data->hwmon_dev)
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
@ -574,6 +578,11 @@ static int __devinit sch5627_probe(struct platform_device *pdev)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Note failing to register the watchdog is not a fatal error */
|
||||
data->watchdog = sch56xx_watchdog_register(data->addr,
|
||||
(build_code << 24) | (build_id << 8) | hwmon_rev,
|
||||
&data->update_lock, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> *
|
||||
* Copyright (C) 2011-2012 Hans de Goede <hdegoede@redhat.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 *
|
||||
@ -67,6 +67,7 @@ static const u16 SCH5636_REG_FAN_VAL[SCH5636_NO_FANS] = {
|
||||
struct sch5636_data {
|
||||
unsigned short addr;
|
||||
struct device *hwmon_dev;
|
||||
struct sch56xx_watchdog_data *watchdog;
|
||||
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
@ -384,6 +385,9 @@ static int sch5636_remove(struct platform_device *pdev)
|
||||
struct sch5636_data *data = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
if (data->watchdog)
|
||||
sch56xx_watchdog_unregister(data->watchdog);
|
||||
|
||||
if (data->hwmon_dev)
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
@ -505,6 +509,11 @@ static int __devinit sch5636_probe(struct platform_device *pdev)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Note failing to register the watchdog is not a fatal error */
|
||||
data->watchdog = sch56xx_watchdog_register(data->addr,
|
||||
(revision[0] << 8) | revision[1],
|
||||
&data->update_lock, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user