diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-22 10:42:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-22 10:42:54 -0700 |
commit | 4e93d3e8859c834ee18dfd33051d24df8669d0c0 (patch) | |
tree | 13f5b39730857257b5040471618e9bcce30ed9cc | |
parent | a0cd30fd26a398c0c6e50c6760610d4529f17a84 (diff) | |
parent | 0087e5ef577d0d6e664be7ab4be513b6a482e7ec (diff) | |
download | op-kernel-dev-4e93d3e8859c834ee18dfd33051d24df8669d0c0.zip op-kernel-dev-4e93d3e8859c834ee18dfd33051d24df8669d0c0.tar.gz |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/i2c-2.6
155 files changed, 8326 insertions, 1266 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index b9eb209..26414bc 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -83,3 +83,13 @@ Why: Deprecated in favour of the new ioctl-based rawiso interface, which is more efficient. You should really be using libraw1394 for raw1394 access anyway. Who: Jody McIntyre <scjody@steamballoon.com> + +--------------------------- + +What: i2c sysfs name change: in1_ref, vid deprecated in favour of cpu0_vid +When: November 2005 +Files: drivers/i2c/chips/adm1025.c, drivers/i2c/chips/adm1026.c +Why: Match the other drivers' name for the same function, duplicate names + will be available until removal of old names. +Who: Grant Coady <gcoady@gmail.com> + diff --git a/Documentation/i2c/busses/i2c-sis69x b/Documentation/i2c/busses/i2c-sis69x index 5be4876..b88953d 100644 --- a/Documentation/i2c/busses/i2c-sis69x +++ b/Documentation/i2c/busses/i2c-sis69x @@ -42,7 +42,7 @@ I suspect that this driver could be made to work for the following SiS chipsets as well: 635, and 635T. If anyone owns a board with those chips AND is willing to risk crashing & burning an otherwise well-behaved kernel in the name of progress... please contact me at <mhoffman@lightlink.com> or -via the project's mailing list: <sensors@stimpy.netroedge.com>. Please +via the project's mailing list: <lm-sensors@lm-sensors.org>. Please send bug reports and/or success stories as well. diff --git a/Documentation/i2c/chips/adm1021 b/Documentation/i2c/chips/adm1021 new file mode 100644 index 0000000..03d02bf --- /dev/null +++ b/Documentation/i2c/chips/adm1021 @@ -0,0 +1,111 @@ +Kernel driver adm1021 +===================== + +Supported chips: + * Analog Devices ADM1021 + Prefix: 'adm1021' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Analog Devices website + * Analog Devices ADM1021A/ADM1023 + Prefix: 'adm1023' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Analog Devices website + * Genesys Logic GL523SM + Prefix: 'gl523sm' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: + * Intel Xeon Processor + Prefix: - any other - may require 'force_adm1021' parameter + Addresses scanned: none + Datasheet: Publicly available at Intel website + * Maxim MAX1617 + Prefix: 'max1617' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Maxim website + * Maxim MAX1617A + Prefix: 'max1617a' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Maxim website + * National Semiconductor LM84 + Prefix: 'lm84' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the National Semiconductor website + * Philips NE1617 + Prefix: 'max1617' (probably detected as a max1617) + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Philips website + * Philips NE1617A + Prefix: 'max1617' (probably detected as a max1617) + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Philips website + * TI THMC10 + Prefix: 'thmc10' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the TI website + * Onsemi MC1066 + Prefix: 'mc1066' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the Onsemi website + + +Authors: + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com> + +Module Parameters +----------------- + +* read_only: int + Don't set any values, read only mode + + +Description +----------- + +The chips supported by this driver are very similar. The Maxim MAX1617 is +the oldest; it has the problem that it is not very well detectable. The +MAX1617A solves that. The ADM1021 is a straight clone of the MAX1617A. +Ditto for the THMC10. From here on, we will refer to all these chips as +ADM1021-clones. + +The ADM1021 and MAX1617A reports a die code, which is a sort of revision +code. This can help us pinpoint problems; it is not very useful +otherwise. + +ADM1021-clones implement two temperature sensors. One of them is internal, +and measures the temperature of the chip itself; the other is external and +is realised in the form of a transistor-like device. A special alarm +indicates whether the remote sensor is connected. + +Each sensor has its own low and high limits. When they are crossed, the +corresponding alarm is set and remains on as long as the temperature stays +out of range. Temperatures are measured in degrees Celsius. Measurements +are possible between -65 and +127 degrees, with a resolution of one degree. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! + +This driver only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. It is possible to make +ADM1021-clones do faster measurements, but there is really no good reason +for that. + +Xeon support +------------ + +Some Xeon processors have real max1617, adm1021, or compatible chips +within them, with two temperature sensors. + +Other Xeons have chips with only one sensor. + +If you have a Xeon, and the adm1021 module loads, and both temperatures +appear valid, then things are good. + +If the adm1021 module doesn't load, you should try this: + modprobe adm1021 force_adm1021=BUS,ADDRESS + ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. + +If you have dual Xeons you may have appear to have two separate +adm1021-compatible chips, or two single-temperature sensors, at distinct +addresses. diff --git a/Documentation/i2c/chips/adm1025 b/Documentation/i2c/chips/adm1025 new file mode 100644 index 0000000..39d2b78 --- /dev/null +++ b/Documentation/i2c/chips/adm1025 @@ -0,0 +1,51 @@ +Kernel driver adm1025 +===================== + +Supported chips: + * Analog Devices ADM1025, ADM1025A + Prefix: 'adm1025' + Addresses scanned: I2C 0x2c - 0x2e + Datasheet: Publicly available at the Analog Devices website + * Philips NE1619 + Prefix: 'ne1619' + Addresses scanned: I2C 0x2c - 0x2d + Datasheet: Publicly available at the Philips website + +The NE1619 presents some differences with the original ADM1025: + * Only two possible addresses (0x2c - 0x2d). + * No temperature offset register, but we don't use it anyway. + * No INT mode for pin 16. We don't play with it anyway. + +Authors: + Chen-Yuan Wu <gwu@esoft.com>, + Jean Delvare <khali@linux-fr.org> + +Description +----------- + +(This is from Analog Devices.) The ADM1025 is a complete system hardware +monitor for microprocessor-based systems, providing measurement and limit +comparison of various system parameters. Five voltage measurement inputs +are provided, for monitoring +2.5V, +3.3V, +5V and +12V power supplies and +the processor core voltage. The ADM1025 can monitor a sixth power-supply +voltage by measuring its own VCC. One input (two pins) is dedicated to a +remote temperature-sensing diode and an on-chip temperature sensor allows +ambient temperature to be monitored. + +One specificity of this chip is that the pin 11 can be hardwired in two +different manners. It can act as the +12V power-supply voltage analog +input, or as the a fifth digital entry for the VID reading (bit 4). It's +kind of strange since both are useful, and the reason for designing the +chip that way is obscure at least to me. The bit 5 of the configuration +register can be used to define how the chip is hardwired. Please note that +it is not a choice you have to make as the user. The choice was already +made by your motherboard's maker. If the configuration bit isn't set +properly, you'll have a wrong +12V reading or a wrong VID reading. The way +the driver handles that is to preserve this bit through the initialization +process, assuming that the BIOS set it up properly beforehand. If it turns +out not to be true in some cases, we'll provide a module parameter to force +modes. + +This driver also supports the ADM1025A, which differs from the ADM1025 +only in that it has "open-drain VID inputs while the ADM1025 has on-chip +100k pull-ups on the VID inputs". It doesn't make any difference for us. diff --git a/Documentation/i2c/chips/adm1026 b/Documentation/i2c/chips/adm1026 new file mode 100644 index 0000000..473c689 --- /dev/null +++ b/Documentation/i2c/chips/adm1026 @@ -0,0 +1,93 @@ +Kernel driver adm1026 +===================== + +Supported chips: + * Analog Devices ADM1026 + Prefix: 'adm1026' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: Publicly available at the Analog Devices website + http://www.analog.com/en/prod/0,,766_825_ADM1026,00.html + +Authors: + Philip Pokorny <ppokorny@penguincomputing.com> for Penguin Computing + Justin Thiessen <jthiessen@penguincomputing.com> + +Module Parameters +----------------- + +* gpio_input: int array (min = 1, max = 17) + List of GPIO pins (0-16) to program as inputs +* gpio_output: int array (min = 1, max = 17) + List of GPIO pins (0-16) to program as outputs +* gpio_inverted: int array (min = 1, max = 17) + List of GPIO pins (0-16) to program as inverted +* gpio_normal: int array (min = 1, max = 17) + List of GPIO pins (0-16) to program as normal/non-inverted +* gpio_fan: int array (min = 1, max = 8) + List of GPIO pins (0-7) to program as fan tachs + + +Description +----------- + +This driver implements support for the Analog Devices ADM1026. Analog +Devices calls it a "complete thermal system management controller." + +The ADM1026 implements three (3) temperature sensors, 17 voltage sensors, +16 general purpose digital I/O lines, eight (8) fan speed sensors (8-bit), +an analog output and a PWM output along with limit, alarm and mask bits for +all of the above. There is even 8k bytes of EEPROM memory on chip. + +Temperatures are measured in degrees Celsius. There are two external +sensor inputs and one internal sensor. Each sensor has a high and low +limit. If the limit is exceeded, an interrupt (#SMBALERT) can be +generated. The interrupts can be masked. In addition, there are over-temp +limits for each sensor. If this limit is exceeded, the #THERM output will +be asserted. The current temperature and limits have a resolution of 1 +degree. + +Fan rotation speeds are reported in RPM (rotations per minute) but measured +in counts of a 22.5kHz internal clock. Each fan has a high limit which +corresponds to a minimum fan speed. If the limit is exceeded, an interrupt +can be generated. Each fan can be programmed to divide the reference clock +by 1, 2, 4 or 8. Not all RPM values can accurately be represented, so some +rounding is done. With a divider of 8, the slowest measurable speed of a +two pulse per revolution fan is 661 RPM. + +There are 17 voltage sensors. An alarm is triggered if the voltage has +crossed a programmable minimum or maximum limit. Note that minimum in this +case always means 'closest to zero'; this is important for negative voltage +measurements. Several inputs have integrated attenuators so they can measure +higher voltages directly. 3.3V, 5V, 12V, -12V and battery voltage all have +dedicated inputs. There are several inputs scaled to 0-3V full-scale range +for SCSI terminator power. The remaining inputs are not scaled and have +a 0-2.5V full-scale range. A 2.5V or 1.82V reference voltage is provided +for negative voltage measurements. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! Note that in the current implementation, all hardware +registers are read whenever any data is read (unless it is less than 2.0 +seconds since the last update). This means that you can easily miss +once-only alarms. + +The ADM1026 measures continuously. Analog inputs are measured about 4 +times a second. Fan speed measurement time depends on fan speed and +divisor. It can take as long as 1.5 seconds to measure all fan speeds. + +The ADM1026 has the ability to automatically control fan speed based on the +temperature sensor inputs. Both the PWM output and the DAC output can be +used to control fan speed. Usually only one of these two outputs will be +used. Write the minimum PWM or DAC value to the appropriate control +register. Then set the low temperature limit in the tmin values for each +temperature sensor. The range of control is fixed at 20 °C, and the +largest difference between current and tmin of the temperature sensors sets +the control output. See the datasheet for several example circuits for +controlling fan speed with the PWM and DAC outputs. The fan speed sensors +do not have PWM compensation, so it is probably best to control the fan +voltage from the power lead rather than on the ground lead. + +The datasheet shows an example application with VID signals attached to +GPIO lines. Unfortunately, the chip may not be connected to the VID lines +in this way. The driver assumes that the chips *is* connected this way to +get a VID voltage. diff --git a/Documentation/i2c/chips/adm1031 b/Documentation/i2c/chips/adm1031 new file mode 100644 index 0000000..130a383 --- /dev/null +++ b/Documentation/i2c/chips/adm1031 @@ -0,0 +1,35 @@ +Kernel driver adm1031 +===================== + +Supported chips: + * Analog Devices ADM1030 + Prefix: 'adm1030' + Addresses scanned: I2C 0x2c to 0x2e + Datasheet: Publicly available at the Analog Devices website + http://products.analog.com/products/info.asp?product=ADM1030 + + * Analog Devices ADM1031 + Prefix: 'adm1031' + Addresses scanned: I2C 0x2c to 0x2e + Datasheet: Publicly available at the Analog Devices website + http://products.analog.com/products/info.asp?product=ADM1031 + +Authors: + Alexandre d'Alton <alex@alexdalton.org> + Jean Delvare <khali@linux-fr.org> + +Description +----------- + +The ADM1030 and ADM1031 are digital temperature sensors and fan controllers. +They sense their own temperature as well as the temperature of up to one +(ADM1030) or two (ADM1031) external diodes. + +All temperature values are given in degrees Celsius. Resolution is 0.5 +degree for the local temperature, 0.125 degree for the remote temperatures. + +Each temperature channel has its own high and low limits, plus a critical +limit. + +The ADM1030 monitors a single fan speed, while the ADM1031 monitors up to +two. Each fan channel has its own low speed limit. diff --git a/Documentation/i2c/chips/adm9240 b/Documentation/i2c/chips/adm9240 new file mode 100644 index 0000000..35f618f --- /dev/null +++ b/Documentation/i2c/chips/adm9240 @@ -0,0 +1,177 @@ +Kernel driver adm9240 +===================== + +Supported chips: + * Analog Devices ADM9240 + Prefix: 'adm9240' + Addresses scanned: I2C 0x2c - 0x2f + Datasheet: Publicly available at the Analog Devices website + http://www.analog.com/UploadedFiles/Data_Sheets/79857778ADM9240_0.pdf + + * Dallas Semiconductor DS1780 + Prefix: 'ds1780' + Addresses scanned: I2C 0x2c - 0x2f + Datasheet: Publicly available at the Dallas Semiconductor (Maxim) website + http://pdfserv.maxim-ic.com/en/ds/DS1780.pdf + + * National Semiconductor LM81 + Prefix: 'lm81' + Addresses scanned: I2C 0x2c - 0x2f + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ds.cgi/LM/LM81.pdf + +Authors: + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com>, + Michiel Rook <michiel@grendelproject.nl>, + Grant Coady <gcoady@gmail.com> with guidance + from Jean Delvare <khali@linux-fr.org> + +Interface +--------- +The I2C addresses listed above assume BIOS has not changed the +chip MSB 5-bit address. Each chip reports a unique manufacturer +identification code as well as the chip revision/stepping level. + +Description +----------- +[From ADM9240] The ADM9240 is a complete system hardware monitor for +microprocessor-based systems, providing measurement and limit comparison +of up to four power supplies and two processor core voltages, plus +temperature, two fan speeds and chassis intrusion. Measured values can +be read out via an I2C-compatible serial System Management Bus, and values +for limit comparisons can be programmed in over the same serial bus. The +high speed successive approximation ADC allows frequent sampling of all +analog channels to ensure a fast interrupt response to any out-of-limit +measurement. + +The ADM9240, DS1780 and LM81 are register compatible, the following +details are common to the three chips. Chip differences are described +after this section. + + +Measurements +------------ +The measurement cycle + +The adm9240 driver will take a measurement reading no faster than once +each two seconds. User-space may read sysfs interface faster than the +measurement update rate and will receive cached data from the most +recent measurement. + +ADM9240 has a very fast 320us temperature and voltage measurement cycle +with independent fan speed measurement cycles counting alternating rising +edges of the fan tacho inputs. + +DS1780 measurement cycle is about once per second including fan speed. + +LM81 measurement cycle is about once per 400ms including fan speed. +The LM81 12-bit extended temperature measurement mode is not supported. + +Temperature +----------- +On chip temperature is reported as degrees Celsius as 9-bit signed data +with resolution of 0.5 degrees Celsius. High and low temperature limits +are 8-bit signed data with resolution of one degree Celsius. + +Temperature alarm is asserted once the temperature exceeds the high limit, +and is cleared when the temperature falls below the temp1_max_hyst value. + +Fan Speed +--------- +Two fan tacho inputs are provided, the ADM9240 gates an internal 22.5kHz +clock via a divider to an 8-bit counter. Fan speed (rpm) is calculated by: + +rpm = (22500 * 60) / (count * divider) + +Automatic fan clock divider + + * User sets 0 to fan_min limit + - low speed alarm is disabled + - fan clock divider not changed + - auto fan clock adjuster enabled for valid fan speed reading + + * User sets fan_min limit too low + - low speed alarm is enabled + - fan clock divider set to max + - fan_min set to register value 254 which corresponds + to 664 rpm on adm9240 + - low speed alarm will be asserted if fan speed is + less than minimum measurable speed + - auto fan clock adjuster disabled + + * User sets reasonable fan speed + - low speed alarm is enabled + - fan clock divider set to suit fan_min + - auto fan clock adjuster enabled: adjusts fan_min + + * User sets unreasonably high low fan speed limit + - resolution of the low speed limit may be reduced + - alarm will be asserted + - auto fan clock adjuster enabled: adjusts fan_min + + * fan speed may be displayed as zero until the auto fan clock divider + adjuster brings fan speed clock divider back into chip measurement + range, this will occur within a few measurement cycles. + +Analog Output +------------- +An analog output provides a 0 to 1.25 volt signal intended for an external +fan speed amplifier circuit. The analog output is set to maximum value on +power up or reset. This doesn't do much on the test Intel SE440BX-2. + +Voltage Monitor + +Voltage (IN) measurement is internally scaled: + + nr label nominal maximum resolution + mV mV mV + 0 +2.5V 2500 3320 13.0 + 1 Vccp1 2700 3600 14.1 + 2 +3.3V 3300 4380 17.2 + 3 +5V 5000 6640 26.0 + 4 +12V 12000 15940 62.5 + 5 Vccp2 2700 3600 14.1 + +The reading is an unsigned 8-bit value, nominal voltage measurement is +represented by a reading of 192, being 3/4 of the measurement range. + +An alarm is asserted for any voltage going below or above the set limits. + +The driver reports and accepts voltage limits scaled to the above table. + +VID Monitor +----------- +The chip has five inputs to read the 5-bit VID and reports the mV value +based on detected CPU type. + +Chassis Intrusion +----------------- +An alarm is asserted when the CI pin goes active high. The ADM9240 +Datasheet has an example of an external temperature sensor driving +this pin. On an Intel SE440BX-2 the Chassis Intrusion header is +connected to a normally open switch. + +The ADM9240 provides an internal open drain on this line, and may output +a 20 ms active low pulse to reset an external Chassis Intrusion latch. + +Clear the CI latch by writing value 1 to the sysfs chassis_clear file. + +Alarm flags reported as 16-bit word + + bit label comment + --- ------------- -------------------------- + 0 +2.5 V_Error high or low limit exceeded + 1 VCCP_Error high or low limit exceeded + 2 +3.3 V_Error high or low limit exceeded + 3 +5 V_Error high or low limit exceeded + 4 Temp_Error temperature error + 6 FAN1_Error fan low limit exceeded + 7 FAN2_Error fan low limit exceeded + 8 +12 V_Error high or low limit exceeded + 9 VCCP2_Error high or low limit exceeded + 12 Chassis_Error CI pin went high + +Remaining bits are reserved and thus undefined. It is important to note +that alarm bits may be cleared on read, user-space may latch alarms and +provide the end-user with a method to clear alarm memory. diff --git a/Documentation/i2c/chips/asb100 b/Documentation/i2c/chips/asb100 new file mode 100644 index 0000000..ab7365e --- /dev/null +++ b/Documentation/i2c/chips/asb100 @@ -0,0 +1,72 @@ +Kernel driver asb100 +==================== + +Supported Chips: + * Asus ASB100 and ASB100-A "Bach" + Prefix: 'asb100' + Addresses scanned: I2C 0x2d + Datasheet: none released + +Author: Mark M. Hoffman <mhoffman@lightlink.com> + +Description +----------- + +This driver implements support for the Asus ASB100 and ASB100-A "Bach". +These are custom ASICs available only on Asus mainboards. Asus refuses to +supply a datasheet for these chips. Thanks go to many people who helped +investigate their hardware, including: + +Vitaly V. Bursov +Alexander van Kaam (author of MBM for Windows) +Bertrik Sikken + +The ASB100 implements seven voltage sensors, three fan rotation speed +sensors, four temperature sensors, VID lines and alarms. In addition to +these, the ASB100-A also implements a single PWM controller for fans 2 and +3 (i.e. one setting controls both.) If you have a plain ASB100, the PWM +controller will simply not work (or maybe it will for you... it doesn't for +me). + +Temperatures are measured and reported in degrees Celsius. + +Fan speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. + +Voltage sensors (also known as IN sensors) report values in volts. + +The VID lines encode the core voltage value: the voltage level your +processor should work with. This is hardcoded by the mainboard and/or +processor itself. It is a value in volts. + +Alarms: (TODO question marks indicate may or may not work) + +0x0001 => in0 (?) +0x0002 => in1 (?) +0x0004 => in2 +0x0008 => in3 +0x0010 => temp1 (1) +0x0020 => temp2 +0x0040 => fan1 +0x0080 => fan2 +0x0100 => in4 +0x0200 => in5 (?) (2) +0x0400 => in6 (?) (2) +0x0800 => fan3 +0x1000 => chassis switch +0x2000 => temp3 + +Alarm Notes: + +(1) This alarm will only trigger if the hysteresis value is 127C. +I.e. it behaves the same as w83781d. + +(2) The min and max registers for these values appear to +be read-only or otherwise stuck at 0x00. + +TODO: +* Experiment with fan divisors > 8. +* Experiment with temp. sensor types. +* Are there really 13 voltage inputs? Probably not... +* Cleanups, no doubt... + diff --git a/Documentation/i2c/chips/ds1621 b/Documentation/i2c/chips/ds1621 new file mode 100644 index 0000000..1fee6f1 --- /dev/null +++ b/Documentation/i2c/chips/ds1621 @@ -0,0 +1,108 @@ +Kernel driver ds1621 +==================== + +Supported chips: + * Dallas Semiconductor DS1621 + Prefix: 'ds1621' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Dallas Semiconductor website + http://www.dalsemi.com/ + * Dallas Semiconductor DS1625 + Prefix: 'ds1621' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Dallas Semiconductor website + http://www.dalsemi.com/ + +Authors: + Christian W. Zuckschwerdt <zany@triq.net> + valuable contributions by Jan M. Sendler <sendler@sendler.de> + ported to 2.6 by Aurelien Jarno <aurelien@aurel32.net> + with the help of Jean Delvare <khali@linux-fr.org> + +Module Parameters +------------------ + +* polarity int + Output's polarity: 0 = active high, 1 = active low + +Description +----------- + +The DS1621 is a (one instance) digital thermometer and thermostat. It has +both high and low temperature limits which can be user defined (i.e. +programmed into non-volatile on-chip registers). Temperature range is -55 +degree Celsius to +125 in 0.5 increments. You may convert this into a +Fahrenheit range of -67 to +257 degrees with 0.9 steps. If polarity +parameter is not provided, original value is used. + +As for the thermostat, behavior can also be programmed using the polarity +toggle. On the one hand ("heater"), the thermostat output of the chip, +Tout, will trigger when the low limit temperature is met or underrun and +stays high until the high limit is met or exceeded. On the other hand +("cooler"), vice versa. That way "heater" equals "active low", whereas +"conditioner" equals "active high". Please note that the DS1621 data sheet +is somewhat misleading in this point since setting the polarity bit does +not simply invert Tout. + +A second thing is that, during extensive testing, Tout showed a tolerance +of up to +/- 0.5 degrees even when compared against precise temperature +readings. Be sure to have a high vs. low temperature limit gap of al least +1.0 degree Celsius to avoid Tout "bouncing", though! + +As for alarms, you can read the alarm status of the DS1621 via the 'alarms' +/sys file interface. The result consists mainly of bit 6 and 5 of the +configuration register of the chip; bit 6 (0x40 or 64) is the high alarm +bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or +low limits are met or exceeded and are reset by the module as soon as the +respective temperature ranges are left. + +The alarm registers are in no way suitable to find out about the actual +status of Tout. They will only tell you about its history, whether or not +any of the limits have ever been met or exceeded since last power-up or +reset. Be aware: When testing, it showed that the status of Tout can change +with neither of the alarms set. + +Temperature conversion of the DS1621 takes up to 1000ms; internal access to +non-volatile registers may last for 10ms or below. + +High Accuracy Temperature Reading +--------------------------------- + +As said before, the temperature issued via the 9-bit i2c-bus data is +somewhat arbitrary. Internally, the temperature conversion is of a +different kind that is explained (not so...) well in the DS1621 data sheet. +To cut the long story short: Inside the DS1621 there are two oscillators, +both of them biassed by a temperature coefficient. + +Higher resolution of the temperature reading can be achieved using the +internal projection, which means taking account of REG_COUNT and REG_SLOPE +(the driver manages them): + +Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature +Resolution on the DS1620' and App Note 105: 'High Resolution Temperature +Measurement with Dallas Direct-to-Digital Temperature Sensors' + +- Read the 9-bit temperature and strip the LSB (Truncate the .5 degs) +- The resulting value is TEMP_READ. +- Then, read REG_COUNT. +- And then, REG_SLOPE. + + TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE) + +Note that this is what the DONE bit in the DS1621 configuration register is +good for: Internally, one temperature conversion takes up to 1000ms. Before +that conversion is complete you will not be able to read valid things out +of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now, +tells you whether the conversion is complete ("done", in plain English) and +thus, whether the values you read are good or not. + +The DS1621 has two modes of operation: "Continuous" conversion, which can +be understood as the default stand-alone mode where the chip gets the +temperature and controls external devices via its Tout pin or tells other +i2c's about it if they care. The other mode is called "1SHOT", that means +that it only figures out about the temperature when it is explicitly told +to do so; this can be seen as power saving mode. + +Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop +the continuous conversions until the contents of these registers are valid, +or, in 1SHOT mode, you have to have one conversion made. diff --git a/Documentation/i2c/chips/eeprom b/Documentation/i2c/chips/eeprom new file mode 100644 index 0000000..f7e8104 --- /dev/null +++ b/Documentation/i2c/chips/eeprom @@ -0,0 +1,96 @@ +Kernel driver eeprom +==================== + +Supported chips: + * Any EEPROM chip in the designated address range + Prefix: 'eeprom' + Addresses scanned: I2C 0x50 - 0x57 + Datasheets: Publicly available from: + Atmel (www.atmel.com), + Catalyst (www.catsemi.com), + Fairchild (www.fairchildsemi.com), + Microchip (www.microchip.com), + Philips (www.semiconductor.philips.com), + Rohm (www.rohm.com), + ST (www.st.com), + Xicor (www.xicor.com), + and others. + + Chip Size (bits) Address + 24C01 1K 0x50 (shadows at 0x51 - 0x57) + 24C01A 1K 0x50 - 0x57 (Typical device on DIMMs) + 24C02 2K 0x50 - 0x57 + 24C04 4K 0x50, 0x52, 0x54, 0x56 + (additional data at 0x51, 0x53, 0x55, 0x57) + 24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52, + 0x53, 0x55, 0x56, 0x57) + 24C16 16K 0x50 (additional data at 0x51 - 0x57) + Sony 2K 0x57 + + Atmel 34C02B 2K 0x50 - 0x57, SW write protect at 0x30-37 + Catalyst 34FC02 2K 0x50 - 0x57, SW write protect at 0x30-37 + Catalyst 34RC02 2K 0x50 - 0x57, SW write protect at 0x30-37 + Fairchild 34W02 2K 0x50 - 0x57, SW write protect at 0x30-37 + Microchip 24AA52 2K 0x50 - 0x57, SW write protect at 0x30-37 + ST M34C02 2K 0x50 - 0x57, SW write protect at 0x30-37 + + +Authors: + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com>, + Jean Delvare <khali@linux-fr.org>, + Greg Kroah-Hartman <greg@kroah.com>, + IBM Corp. + +Description +----------- + +This is a simple EEPROM module meant to enable reading the first 256 bytes +of an EEPROM (on a SDRAM DIMM for example). However, it will access serial +EEPROMs on any I2C adapter. The supported devices are generically called +24Cxx, and are listed above; however the numbering for these +industry-standard devices may vary by manufacturer. + +This module was a programming exercise to get used to the new project +organization laid out by Frodo, but it should be at least completely +effective for decoding the contents of EEPROMs on DIMMs. + +DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants. +The other devices will not be found on a DIMM because they respond to more +than one address. + +DDC Monitors may contain any device. Often a 24C01, which responds to all 8 +addresses, is found. + +Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the +specification, so it is guess work and far from being complete. + +The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional +software write protect register at 0x30 - 0x37 (0x20 less than the memory +location). The chip responds to "write quick" detection at this address but +does not respond to byte reads. If this register is present, the lower 128 +bytes of the memory array are not write protected. Any byte data write to +this address will write protect the memory array permanently, and the +device will no longer respond at the 0x30-37 address. The eeprom driver +does not support this register. + +Lacking functionality: + +* Full support for larger devices (24C04, 24C08, 24C16). These are not +typically found on a PC. These devices will appear as separate devices at +multiple addresses. + +* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512). +These devices require two-byte address fields and are not supported. + +* Enable Writing. Again, no technical reason why not, but making it easy +to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy +to disable the DIMMs (potentially preventing the computer from booting) +until the values are restored somehow. + +Use: + +After inserting the module (and any other required SMBus/i2c modules), you +should have some EEPROM directories in /sys/bus/i2c/devices/* of names such +as "0-0050". Inside each of these is a series of files, the eeprom file +contains the binary data from EEPROM. diff --git a/Documentation/i2c/chips/fscher b/Documentation/i2c/chips/fscher new file mode 100644 index 0000000..6403165 --- /dev/null +++ b/Documentation/i2c/chips/fscher @@ -0,0 +1,169 @@ +Kernel driver fscher +==================== + +Supported chips: + * Fujitsu-Siemens Hermes chip + Prefix: 'fscher' + Addresses scanned: I2C 0x73 + +Authors: + Reinhard Nissl <rnissl@gmx.de> based on work + from Hermann Jung <hej@odn.de>, + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com> + +Description +----------- + +This driver implements support for the Fujitsu-Siemens Hermes chip. It is +described in the 'Register Set Specification BMC Hermes based Systemboard' +from Fujitsu-Siemens. + +The Hermes chip implements a hardware-based system management, e.g. for +controlling fan speed and core voltage. There is also a watchdog counter on +the chip which can trigger an alarm and even shut the system down. + +The chip provides three temperature values (CPU, motherboard and +auxiliary), three voltage values (+12V, +5V and battery) and three fans +(power supply, CPU and auxiliary). + +Temperatures are measured in degrees Celsius. The resolution is 1 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). The value +can be divided by a programmable divider (1, 2 or 4) which is stored on +the chip. + +Voltage sensors (also known as "in" sensors) report their values in volts. + +All values are reported as final values from the driver. There is no need +for further calculations. + + +Detailed description +-------------------- + +Below you'll find a single line description of all the bit values. With +this information, you're able to decode e. g. alarms, wdog, etc. To make +use of the watchdog, you'll need to set the watchdog time and enable the +watchdog. After that it is necessary to restart the watchdog time within +the specified period of time, or a system reset will occur. + +* revision + READING & 0xff = 0x??: HERMES revision identification + +* alarms + READING & 0x80 = 0x80: CPU throttling active + READING & 0x80 = 0x00: CPU running at full speed + + READING & 0x10 = 0x10: software event (see control:1) + READING & 0x10 = 0x00: no software event + + READING & 0x08 = 0x08: watchdog event (see wdog:2) + READING & 0x08 = 0x00: no watchdog event + + READING & 0x02 = 0x02: thermal event (see temp*:1) + READING & 0x02 = 0x00: no thermal event + + READING & 0x01 = 0x01: fan event (see fan*:1) + READING & 0x01 = 0x00: no fan event + + READING & 0x13 ! 0x00: ALERT LED is flashing + +* control + READING & 0x01 = 0x01: software event + READING & 0x01 = 0x00: no software event + + WRITING & 0x01 = 0x01: set software event + WRITING & 0x01 = 0x00: clear software event + +* watchdog_control + READING & 0x80 = 0x80: power off on watchdog event while thermal event + READING & 0x80 = 0x00: watchdog power off disabled (just system reset enabled) + + READING & 0x40 = 0x40: watchdog timebase 60 seconds (see also wdog:1) + READING & 0x40 = 0x00: watchdog timebase 2 seconds + + READING & 0x10 = 0x10: watchdog enabled + READING & 0x10 = 0x00: watchdog disabled + + WRITING & 0x80 = 0x80: enable "power off on watchdog event while thermal event" + WRITING & 0x80 = 0x00: disable "power off on watchdog event while thermal event" + + WRITING & 0x40 = 0x40: set watchdog timebase to 60 seconds + WRITING & 0x40 = 0x00: set watchdog timebase to 2 seconds + + WRITING & 0x20 = 0x20: disable watchdog + + WRITING & 0x10 = 0x10: enable watchdog / restart watchdog time + +* watchdog_state + READING & 0x02 = 0x02: watchdog system reset occurred + READING & 0x02 = 0x00: no watchdog system reset occurred + + WRITING & 0x02 = 0x02: clear watchdog event + +* watchdog_preset + READING & 0xff = 0x??: configured watch dog time in units (see wdog:3 0x40) + + WRITING & 0xff = 0x??: configure watch dog time in units + +* in* (0: +5V, 1: +12V, 2: onboard 3V battery) + READING: actual voltage value + +* temp*_status (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) + READING & 0x02 = 0x02: thermal event (overtemperature) + READING & 0x02 = 0x00: no thermal event + + READING & 0x01 = 0x01: sensor is working + READING & 0x01 = 0x00: sensor is faulty + + WRITING & 0x02 = 0x02: clear thermal event + +* temp*_input (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) + READING: actual temperature value + +* fan*_status (1: power supply fan, 2: CPU fan, 3: auxiliary fan) + READING & 0x04 = 0x04: fan event (fan fault) + READING & 0x04 = 0x00: no fan event + + WRITING & 0x04 = 0x04: clear fan event + +* fan*_div (1: power supply fan, 2: CPU fan, 3: auxiliary fan) + Divisors 2,4 and 8 are supported, both for reading and writing + +* fan*_pwm (1: power supply fan, 2: CPU fan, 3: auxiliary fan) + READING & 0xff = 0x00: fan may be switched off + READING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) + READING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) + READING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) + + WRITING & 0xff = 0x00: fan may be switched off + WRITING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) + WRITING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) + WRITING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) + +* fan*_input (1: power supply fan, 2: CPU fan, 3: auxiliary fan) + READING: actual RPM value + + +Limitations +----------- + +* Measuring fan speed +It seems that the chip counts "ripples" (typical fans produce 2 ripples per +rotation while VERAX fans produce 18) in a 9-bit register. This register is +read out every second, then the ripple prescaler (2, 4 or 8) is applied and +the result is stored in the 8 bit output register. Due to the limitation of +the counting register to 9 bits, it is impossible to measure a VERAX fan +properly (even with a prescaler of 8). At its maximum speed of 3500 RPM the +fan produces 1080 ripples per second which causes the counting register to +overflow twice, leading to only 186 RPM. + +* Measuring input voltages +in2 ("battery") reports the voltage of the onboard lithium battery and not ++3.3V from the power supply. + +* Undocumented features +Fujitsu-Siemens Computers has not documented all features of the chip so +far. Their software, System Guard, shows that there are a still some +features which cannot be controlled by this implementation. diff --git a/Documentation/i2c/chips/gl518sm b/Documentation/i2c/chips/gl518sm new file mode 100644 index 0000000..ce08818 --- /dev/null +++ b/Documentation/i2c/chips/gl518sm @@ -0,0 +1,74 @@ +Kernel driver gl518sm +===================== + +Supported chips: + * Genesys Logic GL518SM release 0x00 + Prefix: 'gl518sm' + Addresses scanned: I2C 0x2c and 0x2d + Datasheet: http://www.genesyslogic.com/pdf + * Genesys Logic GL518SM release 0x80 + Prefix: 'gl518sm' + Addresses scanned: I2C 0x2c and 0x2d + Datasheet: http://www.genesyslogic.com/pdf + +Authors: + Frodo Looijaard <frodol@dds.nl>, + Kyösti Mälkki <kmalkki@cc.hut.fi> + Hong-Gunn Chew <hglinux@gunnet.org> + Jean Delvare <khali@linux-fr.org> + +Description +----------- + +IMPORTANT: + +For the revision 0x00 chip, the in0, in1, and in2 values (+5V, +3V, +and +12V) CANNOT be read. This is a limitation of the chip, not the driver. + +This driver supports the Genesys Logic GL518SM chip. There are at least +two revision of this chip, which we call revision 0x00 and 0x80. Revision +0x80 chips support the reading of all voltages and revision 0x00 only +for VIN3. + +The GL518SM implements one temperature sensor, two fan rotation speed +sensors, and four voltage sensors. It can report alarms through the +computer speakers. + +Temperatures are measured in degrees Celsius. An alarm goes off while the +temperature is above the over temperature limit, and has not yet dropped +below the hysteresis limit. The alarm always reflects the current +situation. Measurements are guaranteed between -10 degrees and +110 +degrees, with a accuracy of +/-3 degrees. + +Rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. In +case when you have selected to turn fan1 off, no fan1 alarm is triggered. + +Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to +give the readings more range or accuracy. Not all RPM values can +accurately be represented, so some rounding is done. With a divider +of 2, the lowest representable value is around 1900 RPM. + +Voltage sensors (also known as VIN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum or +maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. The VDD input +measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023 +volt. The other inputs measure voltages between 0.000 and 4.845 volt, with +a resolution of 0.019 volt. Note that revision 0x00 chips do not support +reading the current voltage of any input except for VIN3; limit setting and +alarms work fine, though. + +When an alarm is triggered, you can be warned by a beeping signal through your +computer speaker. It is possible to enable all beeping globally, or only the +beeping for some alarms. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once (except for temperature alarms). This means that the +cause for the alarm may already have disappeared! Note that in the current +implementation, all hardware registers are read whenever any data is read +(unless it is less than 1.5 seconds since the last update). This means that +you can easily miss once-only alarms. + +The GL518SM only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. diff --git a/Documentation/i2c/chips/it87 b/Documentation/i2c/chips/it87 new file mode 100644 index 0000000..0d01950 --- /dev/null +++ b/Documentation/i2c/chips/it87 @@ -0,0 +1,96 @@ +Kernel driver it87 +================== + +Supported chips: + * IT8705F + Prefix: 'it87' + Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the ITE website + http://www.ite.com.tw/ + * IT8712F + Prefix: 'it8712' + Addresses scanned: I2C 0x28 - 0x2f + from Super I/O config space, or default ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the ITE website + http://www.ite.com.tw/ + * SiS950 [clone of IT8705F] + Prefix: 'sis950' + Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports) + Datasheet: No longer be available + +Author: Christophe Gauthron <chrisg@0-in.com> + + +Module Parameters +----------------- + +* update_vbat: int + + 0 if vbat should report power on value, 1 if vbat should be updated after + each read. Default is 0. On some boards the battery voltage is provided + by either the battery or the onboard power supply. Only the first reading + at power on will be the actual battery voltage (which the chip does + automatically). On other boards the battery voltage is always fed to + the chip so can be read at any time. Excessive reading may decrease + battery life but no information is given in the datasheet. + +* fix_pwm_polarity int + + Force PWM polarity to active high (DANGEROUS). Some chips are + misconfigured by BIOS - PWM values would be inverted. This option tries + to fix this. Please contact your BIOS manufacturer and ask him for fix. + +Description +----------- + +This driver implements support for the IT8705F, IT8712F and SiS950 chips. + +This driver also supports IT8712F, which adds SMBus access, and a VID +input, used to report the Vcore voltage of the Pentium processor. +The IT8712F additionally features VID inputs. + +These chips are 'Super I/O chips', supporting floppy disks, infrared ports, +joysticks and other miscellaneous stuff. For hardware monitoring, they +include an 'environment controller' with 3 temperature sensors, 3 fan +rotation speed sensors, 8 voltage sensors, and associated alarms. + +Temperatures are measured in degrees Celsius. An alarm is triggered once +when the Overtemperature Shutdown limit is crossed. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give the +readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. An +alarm is triggered if the voltage has crossed a programmable minimum or +maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 4.08 volts, with a resolution of +0.016 volt. The battery voltage in8 does not have limit registers. + +The VID lines (IT8712F only) encode the core voltage value: the voltage +level your processor should work with. This is hardcoded by the mainboard +and/or processor itself. It is a value in volts. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! Note that in the current implementation, all hardware +registers are read whenever any data is read (unless it is less than 1.5 +seconds since the last update). This means that you can easily miss +once-only alarms. + +The IT87xx only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. + +To change sensor N to a thermistor, 'echo 2 > tempN_type' where N is 1, 2, +or 3. To change sensor N to a thermal diode, 'echo 3 > tempN_type'. +Give 0 for unused sensor. Any other value is invalid. To configure this at +startup, consult lm_sensors's /etc/sensors.conf. (2 = thermistor; +3 = thermal diode) + +The fan speed control features are limited to manual PWM mode. Automatic +"Smart Guardian" mode control handling is not implemented. However +if you want to go for "manual mode" just write 1 to pwmN_enable. diff --git a/Documentation/i2c/chips/lm63 b/Documentation/i2c/chips/lm63 new file mode 100644 index 0000000..31660bf --- /dev/null +++ b/Documentation/i2c/chips/lm63 @@ -0,0 +1,57 @@ +Kernel driver lm63 +================== + +Supported chips: + * National Semiconductor LM63 + Prefix: 'lm63' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM63.html + +Author: Jean Delvare <khali@linux-fr.org> + +Thanks go to Tyan and especially Alex Buckingham for setting up a remote +access to their S4882 test platform for this driver. + http://www.tyan.com/ + +Description +----------- + +The LM63 is a digital temperature sensor with integrated fan monitoring +and control. + +The LM63 is basically an LM86 with fan speed monitoring and control +capabilities added. It misses some of the LM86 features though: + - No low limit for local temperature. + - No critical limit for local temperature. + - Critical limit for remote temperature can be changed only once. We + will consider that the critical limit is read-only. + +The datasheet isn't very clear about what the tachometer reading is. + +An explanation from National Semiconductor: The two lower bits of the read +value have to be masked out. The value is still 16 bit in width. + +All temperature values are given in degrees Celsius. Resolution is 1.0 +degree for the local temperature, 0.125 degree for the remote temperature. + +The fan speed is measured using a tachometer. Contrary to most chips which +store the value in an 8-bit register and have a selectable clock divider +to make sure that the result will fit in the register, the LM63 uses 16-bit +value for measuring the speed of the fan. It can measure fan speeds down to +83 RPM, at least in theory. + +Note that the pin used for fan monitoring is shared with an alert out +function. Depending on how the board designer wanted to use the chip, fan +speed monitoring will or will not be possible. The proper chip configuration +is left to the BIOS, and the driver will blindly trust it. + +A PWM output can be used to control the speed of the fan. The LM63 has two +PWM modes: manual and automatic. Automatic mode is not fully implemented yet +(you cannot define your custom PWM/temperature curve), and mode change isn't +supported either. + +The lm63 driver will not update its values more frequently than every +second; reading them more often will do no harm, but will return 'old' +values. + diff --git a/Documentation/i2c/chips/lm75 b/Documentation/i2c/chips/lm75 new file mode 100644 index 0000000..8e6356f --- /dev/null +++ b/Documentation/i2c/chips/lm75 @@ -0,0 +1,65 @@ +Kernel driver lm75 +================== + +Supported chips: + * National Semiconductor LM75 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + * Dallas Semiconductor DS75 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Dallas Semiconductor website + http://www.maxim-ic.com/ + * Dallas Semiconductor DS1775 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Dallas Semiconductor website + http://www.maxim-ic.com/ + * Maxim MAX6625, MAX6626 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4b + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/ + * Microchip (TelCom) TCN75 + Prefix: 'lm75' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Microchip website + http://www.microchip.com/ + +Author: Frodo Looijaard <frodol@dds.nl> + +Description +----------- + +The LM75 implements one temperature sensor. Limits can be set through the +Overtemperature Shutdown register and Hysteresis register. Each value can be +set and read to half-degree accuracy. +An alarm is issued (usually to a connected LM78) when the temperature +gets higher then the Overtemperature Shutdown value; it stays on until +the temperature falls below the Hysteresis value. +All temperatures are in degrees Celsius, and are guaranteed within a +range of -55 to +125 degrees. + +The LM75 only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. + +The LM75 is usually used in combination with LM78-like chips, to measure +the temperature of the processor(s). + +The DS75, DS1775, MAX6625, and MAX6626 are supported as well. +They are not distinguished from an LM75. While most of these chips +have three additional bits of accuracy (12 vs. 9 for the LM75), +the additional bits are not supported. Not only that, but these chips will +not be detected if not in 9-bit precision mode (use the force parameter if +needed). + +The TCN75 is supported as well, and is not distinguished from an LM75. + +The LM75 is essentially an industry standard; there may be other +LM75 clones not listed here, with or without various enhancements, +that are supported. + +The LM77 is not supported, contrary to what we pretended for a long time. +Both chips are simply not compatible, value encoding differs. diff --git a/Documentation/i2c/chips/lm77 b/Documentation/i2c/chips/lm77 new file mode 100644 index 0000000..57c3a46 --- /dev/null +++ b/Documentation/i2c/chips/lm77 @@ -0,0 +1,22 @@ +Kernel driver lm77 +================== + +Supported chips: + * National Semiconductor LM77 + Prefix: 'lm77' + Addresses scanned: I2C 0x48 - 0x4b + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + +Author: Andras BALI <drewie@freemail.hu> + +Description +----------- + +The LM77 implements one temperature sensor. The temperature +sensor incorporates a band-gap type temperature sensor, +10-bit ADC, and a digital comparator with user-programmable upper +and lower limit values. + +Limits can be set through the Overtemperature Shutdown register and +Hysteresis register. diff --git a/Documentation/i2c/chips/lm78 b/Documentation/i2c/chips/lm78 new file mode 100644 index 0000000..357086e --- /dev/null +++ b/Documentation/i2c/chips/lm78 @@ -0,0 +1,82 @@ +Kernel driver lm78 +================== + +Supported chips: + * National Semiconductor LM78 + Prefix: 'lm78' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + * National Semiconductor LM78-J + Prefix: 'lm78-j' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + * National Semiconductor LM79 + Prefix: 'lm79' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + +Author: Frodo Looijaard <frodol@dds.nl> + +Description +----------- + +This driver implements support for the National Semiconductor LM78, LM78-J +and LM79. They are described as 'Microprocessor System Hardware Monitors'. + +There is almost no difference between the three supported chips. Functionally, +the LM78 and LM78-J are exactly identical. The LM79 has one more VID line, +which is used to report the lower voltages newer Pentium processors use. +From here on, LM7* means either of these three types. + +The LM7* implements one temperature sensor, three fan rotation speed sensors, +seven voltage sensors, VID lines, alarms, and some miscellaneous stuff. + +Temperatures are measured in degrees Celsius. An alarm is triggered once +when the Overtemperature Shutdown limit is crossed; it is triggered again +as soon as it drops below the Hysteresis value. A more useful behavior +can be found by setting the Hysteresis value to +127 degrees Celsius; in +this case, alarms are issued during all the time when the actual temperature +is above the Overtemperature Shutdown value. Measurements are guaranteed +between -55 and +125 degrees, with a resolution of 1 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 4.08 volts, with a resolution +of 0.016 volt. + +The VID lines encode the core voltage value: the voltage level your processor +should work with. This is hardcoded by the mainboard and/or processor itself. +It is a value in volts. When it is unconnected, you will often find the +value 3.50 V here. + +In addition to the alarms described above, there are a couple of additional +ones. There is a BTI alarm, which gets triggered when an external chip has +crossed its limits. Usually, this is connected to all LM75 chips; if at +least one crosses its limits, this bit gets set. The CHAS alarm triggers +if your computer case is open. The FIFO alarms should never trigger; it +indicates an internal error. The SMI_IN alarm indicates some other chip +has triggered an SMI interrupt. As we do not use SMI interrupts at all, +this condition usually indicates there is a problem with some other +device. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.5 seconds since the last update). This means that you can easily +miss once-only alarms. + +The LM7* only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. diff --git a/Documentation/i2c/chips/lm80 b/Documentation/i2c/chips/lm80 new file mode 100644 index 0000000..cb5b407 --- /dev/null +++ b/Documentation/i2c/chips/lm80 @@ -0,0 +1,56 @@ +Kernel driver lm80 +================== + +Supported chips: + * National Semiconductor LM80 + Prefix: 'lm80' + Addresses scanned: I2C 0x28 - 0x2f + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ + +Authors: + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com> + +Description +----------- + +This driver implements support for the National Semiconductor LM80. +It is described as a 'Serial Interface ACPI-Compatible Microprocessor +System Hardware Monitor'. + +The LM80 implements one temperature sensor, two fan rotation speed sensors, +seven voltage sensors, alarms, and some miscellaneous stuff. + +Temperatures are measured in degrees Celsius. There are two sets of limits +which operate independently. When the HOT Temperature Limit is crossed, +this will cause an alarm that will be reasserted until the temperature +drops below the HOT Hysteresis. The Overtemperature Shutdown (OS) limits +should work in the same way (but this must be checked; the datasheet +is unclear about this). Measurements are guaranteed between -55 and ++125 degrees. The current temperature measurement has a resolution of +0.0625 degrees; the limits have a resolution of 1 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 2.55 volts, with a resolution +of 0.01 volt. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 2.0 seconds since the last update). This means that you can easily +miss once-only alarms. + +The LM80 only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. diff --git a/Documentation/i2c/chips/lm83 b/Documentation/i2c/chips/lm83 new file mode 100644 index 0000000..061d9ed --- /dev/null +++ b/Documentation/i2c/chips/lm83 @@ -0,0 +1,76 @@ +Kernel driver lm83 +================== + +Supported chips: + * National Semiconductor LM83 + Prefix: 'lm83' + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM83.html + + +Author: Jean Delvare <khali@linux-fr.org> + +Description +----------- + +The LM83 is a digital temperature sensor. It senses its own temperature as +well as the temperature of up to three external diodes. It is compatible +with many other devices such as the LM84 and all other ADM1021 clones. +The main difference between the LM83 and the LM84 in that the later can +only sense the temperature of one external diode. + +Using the adm1021 driver for a LM83 should work, but only two temperatures +will be reported instead of four. + +The LM83 is only found on a handful of motherboards. Both a confirmed +list and an unconfirmed list follow. If you can confirm or infirm the +fact that any of these motherboards do actually have an LM83, please +contact us. Note that the LM90 can easily be misdetected as a LM83. + +Confirmed motherboards: + SBS P014 + +Unconfirmed motherboards: + Gigabyte GA-8IK1100 + Iwill MPX2 + Soltek SL-75DRV5 + +The driver has been successfully tested by Magnus Forsström, who I'd +like to thank here. More testers will be of course welcome. + +The fact that the LM83 is only scarcely used can be easily explained. +Most motherboards come with more than just temperature sensors for +health monitoring. They also have voltage and fan rotation speed +sensors. This means that temperature-only chips are usually used as +secondary chips coupled with another chip such as an IT8705F or similar +chip, which provides more features. Since systems usually need three +temperature sensors (motherboard, processor, power supply) and primary +chips provide some temperature sensors, the secondary chip, if needed, +won't have to handle more than two temperatures. Thus, ADM1021 clones +are sufficient, and there is no need for a four temperatures sensor +chip such as the LM83. The only case where using an LM83 would make +sense is on SMP systems, such as the above-mentioned Iwill MPX2, +because you want an additional temperature sensor for each additional +CPU. + +On the SBS P014, this is different, since the LM83 is the only hardware +monitoring chipset. One temperature sensor is used for the motherboard +(actually measuring the LM83's own temperature), one is used for the +CPU. The two other sensors must be used to measure the temperature of +two other points of the motherboard. We suspect these points to be the +north and south bridges, but this couldn't be confirmed. + +All temperature values are given in degrees Celsius. Local temperature +is given within a range of 0 to +85 degrees. Remote temperatures are +given within a range of 0 to +125 degrees. Resolution is 1.0 degree, +accuracy is guaranteed to 3.0 degrees (see the datasheet for more +details). + +Each sensor has its own high limit, but the critical limit is common to +all four sensors. There is no hysteresis mechanism as found on most +recent temperature sensors. + +The lm83 driver will not update its values more frequently than every +other second; reading them more often will do no harm, but will return +'old' values. diff --git a/Documentation/i2c/chips/lm85 b/Documentation/i2c/chips/lm85 new file mode 100644 index 0000000..9549237 --- /dev/null +++ b/Documentation/i2c/chips/lm85 @@ -0,0 +1,221 @@ +Kernel driver lm85 +================== + +Supported chips: + * National Semiconductor LM85 (B and C versions) + Prefix: 'lm85' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.national.com/pf/LM/LM85.html + * Analog Devices ADM1027 + Prefix: 'adm1027' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.analog.com/en/prod/0,,766_825_ADM1027,00.html + * Analog Devices ADT7463 + Prefix: 'adt7463' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.analog.com/en/prod/0,,766_825_ADT7463,00.html + * SMSC EMC6D100, SMSC EMC6D101 + Prefix: 'emc6d100' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.smsc.com/main/tools/discontinued/6d100.pdf + * SMSC EMC6D102 + Prefix: 'emc6d102' + Addresses scanned: I2C 0x2c, 0x2d, 0x2e + Datasheet: http://www.smsc.com/main/catalog/emc6d102.html + +Authors: + Philip Pokorny <ppokorny@penguincomputing.com>, + Frodo Looijaard <frodol@dds.nl>, + Richard Barrington <rich_b_nz@clear.net.nz>, + Margit Schubert-While <margitsw@t-online.de>, + Justin Thiessen <jthiessen@penguincomputing.com> + +Description +----------- + +This driver implements support for the National Semiconductor LM85 and +compatible chips including the Analog Devices ADM1027, ADT7463 and +SMSC EMC6D10x chips family. + +The LM85 uses the 2-wire interface compatible with the SMBUS 2.0 +specification. Using an analog to digital converter it measures three (3) +temperatures and five (5) voltages. It has four (4) 16-bit counters for +measuring fan speed. Five (5) digital inputs are provided for sampling the +VID signals from the processor to the VRM. Lastly, there are three (3) PWM +outputs that can be used to control fan speed. + +The voltage inputs have internal scaling resistors so that the following +voltage can be measured without external resistors: + + 2.5V, 3.3V, 5V, 12V, and CPU core voltage (2.25V) + +The temperatures measured are one internal diode, and two remote diodes. +Remote 1 is generally the CPU temperature. These inputs are designed to +measure a thermal diode like the one in a Pentium 4 processor in a socket +423 or socket 478 package. They can also measure temperature using a +transistor like the 2N3904. + +A sophisticated control system for the PWM outputs is designed into the +LM85 that allows fan speed to be adjusted automatically based on any of the +three temperature sensors. Each PWM output is individually adjustable and +programmable. Once configured, the LM85 will adjust the PWM outputs in +response to the measured temperatures without further host intervention. +This feature can also be disabled for manual control of the PWM's. + +Each of the measured inputs (voltage, temperature, fan speed) has +corresponding high/low limit values. The LM85 will signal an ALARM if any +measured value exceeds either limit. + +The LM85 samples all inputs continuously. The lm85 driver will not read +the registers more often than once a second. Further, configuration data is +only read once each 5 minutes. There is twice as much config data as +measurements, so this would seem to be a worthwhile optimization. + +Special Features +---------------- + +The LM85 has four fan speed monitoring modes. The ADM1027 has only two. +Both have special circuitry to compensate for PWM interactions with the +TACH signal from the fans. The ADM1027 can be configured to measure the +speed of a two wire fan, but the input conditioning circuitry is different +for 3-wire and 2-wire mode. For this reason, the 2-wire fan modes are not +exposed to user control. The BIOS should initialize them to the correct +mode. If you've designed your own ADM1027, you'll have to modify the +init_client function and add an insmod parameter to set this up. + +To smooth the response of fans to changes in temperature, the LM85 has an +optional filter for smoothing temperatures. The ADM1027 has the same +config option but uses it to rate limit the changes to fan speed instead. + +The ADM1027 and ADT7463 have a 10-bit ADC and can therefore measure +temperatures with 0.25 degC resolution. They also provide an offset to the +temperature readings that is automatically applied during measurement. +This offset can be used to zero out any errors due to traces and placement. +The documentation says that the offset is in 0.25 degC steps, but in +initial testing of the ADM1027 it was 1.00 degC steps. Analog Devices has +confirmed this "bug". The ADT7463 is reported to work as described in the +documentation. The current lm85 driver does not show the offset register. + +The ADT7463 has a THERM asserted counter. This counter has a 22.76ms +resolution and a range of 5.8 seconds. The driver implements a 32-bit +accumulator of the counter value to extend the range to over a year. The +counter will stay at it's max value until read. + +See the vendor datasheets for more information. There is application note +from National (AN-1260) with some additional information about the LM85. +The Analog Devices datasheet is very detailed and describes a procedure for +determining an optimal configuration for the automatic PWM control. + +The SMSC EMC6D100 & EMC6D101 monitor external voltages, temperatures, and +fan speeds. They use this monitoring capability to alert the system to out +of limit conditions and can automatically control the speeds of multiple +fans in a PC or embedded system. The EMC6D101, available in a 24-pin SSOP +package, and the EMC6D100, available in a 28-pin SSOP package, are designed +to be register compatible. The EMC6D100 offers all the features of the +EMC6D101 plus additional voltage monitoring and system control features. +Unfortunately it is not possible to distinguish between the package +versions on register level so these additional voltage inputs may read +zero. The EMC6D102 features addtional ADC bits thus extending precision +of voltage and temperature channels. + + +Hardware Configurations +----------------------- + +The LM85 can be jumpered for 3 different SMBus addresses. There are +no other hardware configuration options for the LM85. + +The lm85 driver detects both LM85B and LM85C revisions of the chip. See the +datasheet for a complete description of the differences. Other than +identifying the chip, the driver behaves no differently with regard to +these two chips. The LM85B is recommended for new designs. + +The ADM1027 and ADT7463 chips have an optional SMBALERT output that can be +used to signal the chipset in case a limit is exceeded or the temperature +sensors fail. Individual sensor interrupts can be masked so they won't +trigger SMBALERT. The SMBALERT output if configured replaces one of the other +functions (PWM2 or IN0). This functionality is not implemented in current +driver. + +The ADT7463 also has an optional THERM output/input which can be connected +to the processor PROC_HOT output. If available, the autofan control +dynamic Tmin feature can be enabled to keep the system temperature within +spec (just?!) with the least possible fan noise. + +Configuration Notes +------------------- + +Besides standard interfaces driver adds following: + +* Temperatures and Zones + +Each temperature sensor is associated with a Zone. There are three +sensors and therefore three zones (# 1, 2 and 3). Each zone has the following +temperature configuration points: + +* temp#_auto_temp_off - temperature below which fans should be off or spinning very low. +* temp#_auto_temp_min - temperature over which fans start to spin. +* temp#_auto_temp_max - temperature when fans spin at full speed. +* temp#_auto_temp_crit - temperature when all fans will run full speed. + +* PWM Control + +There are three PWM outputs. The LM85 datasheet suggests that the +pwm3 output control both fan3 and fan4. Each PWM can be individually +configured and assigned to a zone for it's control value. Each PWM can be +configured individually according to the following options. + +* pwm#_auto_pwm_min - this specifies the PWM value for temp#_auto_temp_off + temperature. (PWM value from 0 to 255) + +* pwm#_auto_pwm_freq - select base frequency of PWM output. You can select + in range of 10.0 to 94.0 Hz in .1 Hz units. + (Values 100 to 940). + +The pwm#_auto_pwm_freq can be set to one of the following 8 values. Setting the +frequency to a value not on this list, will result in the next higher frequency +being selected. The actual device frequency may vary slightly from this +specification as designed by the manufacturer. Consult the datasheet for more +details. (PWM Frequency values: 100, 150, 230, 300, 380, 470, 620, 940) + +* pwm#_auto_pwm_minctl - this flags selects for temp#_auto_temp_off temperature + the bahaviour of fans. Write 1 to let fans spinning at + pwm#_auto_pwm_min or write 0 to let them off. + +NOTE: It has been reported that there is a bug in the LM85 that causes the flag +to be associated with the zones not the PWMs. This contradicts all the +published documentation. Setting pwm#_min_ctl in this case actually affects all +PWMs controlled by zone '#'. + +* PWM Controlling Zone selection + +* pwm#_auto_channels - controls zone that is associated with PWM + +Configuration choices: + + Value Meaning + ------ ------------------------------------------------ + 1 Controlled by Zone 1 + 2 Controlled by Zone 2 + 3 Controlled by Zone 3 + 23 Controlled by higher temp of Zone 2 or 3 + 123 Controlled by highest temp of Zone 1, 2 or 3 + 0 PWM always 0% (off) + -1 PWM always 100% (full on) + -2 Manual control (write to 'pwm#' to set) + +The National LM85's have two vendor specific configuration +features. Tach. mode and Spinup Control. For more details on these, +see the LM85 datasheet or Application Note AN-1260. + +The Analog Devices ADM1027 has several vendor specific enhancements. +The number of pulses-per-rev of the fans can be set, Tach monitoring +can be optimized for PWM operation, and an offset can be applied to +the temperatures to compensate for systemic errors in the +measurements. + +In addition to the ADM1027 features, the ADT7463 also has Tmin control +and THERM asserted counts. Automatic Tmin control acts to adjust the +Tmin value to maintain the measured temperature sensor at a specified +temperature. There isn't much documentation on this feature in the +ADT7463 data sheet. This is not supported by current driver. diff --git a/Documentation/i2c/chips/lm87 b/Documentation/i2c/chips/lm87 new file mode 100644 index 0000000..c952c57 --- /dev/null +++ b/Documentation/i2c/chips/lm87 @@ -0,0 +1,73 @@ +Kernel driver lm87 +================== + +Supported chips: + * National Semiconductor LM87 + Prefix: 'lm87' + Addresses scanned: I2C 0x2c - 0x2f + Datasheet: http://www.national.com/pf/LM/LM87.html + +Authors: + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com>, + Mark Studebaker <mdsxyz123@yahoo.com>, + Stephen Rousset <stephen.rousset@rocketlogix.com>, + Dan Eaton <dan.eaton@rocketlogix.com>, + Jean Delvare <khali@linux-fr.org>, + Original 2.6 port Jeff Oliver + +Description +----------- + +This driver implements support for the National Semiconductor LM87. + +The LM87 implements up to three temperature sensors, up to two fan +rotation speed sensors, up to seven voltage sensors, alarms, and some +miscellaneous stuff. + +Temperatures are measured in degrees Celsius. Each input has a high +and low alarm settings. A high limit produces an alarm when the value +goes above it, and an alarm is also produced when the value goes below +the low limit. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in +volts. An alarm is triggered if the voltage has crossed a programmable +minimum or maximum limit. Note that minimum in this case always means +'closest to zero'; this is important for negative voltage measurements. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.0 seconds since the last update). This means that you can easily +miss once-only alarms. + +The lm87 driver only updates its values each 1.0 seconds; reading it more +often will do no harm, but will return 'old' values. + + +Hardware Configurations +----------------------- + +The LM87 has four pins which can serve one of two possible functions, +depending on the hardware configuration. + +Some functions share pins, so not all functions are available at the same +time. Which are depends on the hardware setup. This driver assumes that +the BIOS configured the chip correctly. In that respect, it differs from +the original driver (from lm_sensors for Linux 2.4), which would force the +LM87 to an arbitrary, compile-time chosen mode, regardless of the actual +chipset wiring. + +For reference, here is the list of exclusive functions: + - in0+in5 (default) or temp3 + - fan1 (default) or in6 + - fan2 (default) or in7 + - VID lines (default) or IRQ lines (not handled by this driver) diff --git a/Documentation/i2c/chips/lm90 b/Documentation/i2c/chips/lm90 new file mode 100644 index 0000000..2c4cf39 --- /dev/null +++ b/Documentation/i2c/chips/lm90 @@ -0,0 +1,121 @@ +Kernel driver lm90 +================== + +Supported chips: + * National Semiconductor LM90 + Prefix: 'lm90' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM90.html + * National Semiconductor LM89 + Prefix: 'lm99' + Addresses scanned: I2C 0x4c and 0x4d + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM89.html + * National Semiconductor LM99 + Prefix: 'lm99' + Addresses scanned: I2C 0x4c and 0x4d + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM99.html + * National Semiconductor LM86 + Prefix: 'lm86' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM86.html + * Analog Devices ADM1032 + Prefix: 'adm1032' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Analog Devices website + http://products.analog.com/products/info.asp?product=ADM1032 + * Analog Devices ADT7461 + Prefix: 'adt7461' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Analog Devices website + http://products.analog.com/products/info.asp?product=ADT7461 + Note: Only if in ADM1032 compatibility mode + * Maxim MAX6657 + Prefix: 'max6657' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 + * Maxim MAX6658 + Prefix: 'max6657' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 + * Maxim MAX6659 + Prefix: 'max6657' + Addresses scanned: I2C 0x4c, 0x4d (unsupported 0x4e) + Datasheet: Publicly available at the Maxim website + http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 + + +Author: Jean Delvare <khali@linux-fr.org> + + +Description +----------- + +The LM90 is a digital temperature sensor. It senses its own temperature as +well as the temperature of up to one external diode. It is compatible +with many other devices such as the LM86, the LM89, the LM99, the ADM1032, +the MAX6657, MAX6658 and the MAX6659 all of which are supported by this driver. +Note that there is no easy way to differentiate between the last three +variants. The extra address and features of the MAX6659 are not supported by +this driver. Additionally, the ADT7461 is supported if found in ADM1032 +compatibility mode. + +The specificity of this family of chipsets over the ADM1021/LM84 +family is that it features critical limits with hysteresis, and an +increased resolution of the remote temperature measurement. + +The different chipsets of the family are not strictly identical, although +very similar. This driver doesn't handle any specific feature for now, +but could if there ever was a need for it. For reference, here comes a +non-exhaustive list of specific features: + +LM90: + * Filter and alert configuration register at 0xBF. + * ALERT is triggered by temperatures over critical limits. + +LM86 and LM89: + * Same as LM90 + * Better external channel accuracy + +LM99: + * Same as LM89 + * External temperature shifted by 16 degrees down + +ADM1032: + * Consecutive alert register at 0x22. + * Conversion averaging. + * Up to 64 conversions/s. + * ALERT is triggered by open remote sensor. + +ADT7461 + * Extended temperature range (breaks compatibility) + * Lower resolution for remote temperature + +MAX6657 and MAX6658: + * Remote sensor type selection + +MAX6659 + * Selectable address + * Second critical temperature limit + * Remote sensor type selection + +All temperature values are given in degrees Celsius. Resolution +is 1.0 degree for the local temperature, 0.125 degree for the remote +temperature. + +Each sensor has its own high and low limits, plus a critical limit. +Additionally, there is a relative hysteresis value common to both critical +values. To make life easier to user-space applications, two absolute values +are exported, one for each channel, but these values are of course linked. +Only the local hysteresis can be set from user-space, and the same delta +applies to the remote hysteresis. + +The lm90 driver will not update its values more frequently than every +other second; reading them more often will do no harm, but will return +'old' values. + diff --git a/Documentation/i2c/chips/lm92 b/Documentation/i2c/chips/lm92 new file mode 100644 index 0000000..7705bfa --- /dev/null +++ b/Documentation/i2c/chips/lm92 @@ -0,0 +1,37 @@ +Kernel driver lm92 +================== + +Supported chips: + * National Semiconductor LM92 + Prefix: 'lm92' + Addresses scanned: I2C 0x48 - 0x4b + Datasheet: http://www.national.com/pf/LM/LM92.html + * National Semiconductor LM76 + Prefix: 'lm92' + Addresses scanned: none, force parameter needed + Datasheet: http://www.national.com/pf/LM/LM76.html + * Maxim MAX6633/MAX6634/MAX6635 + Prefix: 'lm92' + Addresses scanned: I2C 0x48 - 0x4b + MAX6633 with address in 0x40 - 0x47, 0x4c - 0x4f needs force parameter + and MAX6634 with address in 0x4c - 0x4f needs force parameter + Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 + +Authors: + Abraham van der Merwe <abraham@2d3d.co.za> + Jean Delvare <khali@linux-fr.org> + + +Description +----------- + +This driver implements support for the National Semiconductor LM92 +temperature sensor. + +Each LM92 temperature sensor supports a single temperature sensor. There are +alarms for high, low, and critical thresholds. There's also an hysteresis to +control the thresholds for resetting alarms. + +Support was added later for the LM76 and Maxim MAX6633/MAX6634/MAX6635, +which are mostly compatible. They have not all been tested, so you +may need to use the force parameter. diff --git a/Documentation/i2c/chips/max1619 b/Documentation/i2c/chips/max1619 new file mode 100644 index 0000000..d6f8d9c --- /dev/null +++ b/Documentation/i2c/chips/max1619 @@ -0,0 +1,29 @@ +Kernel driver max1619 +===================== + +Supported chips: + * Maxim MAX1619 + Prefix: 'max1619' + Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e + Datasheet: Publicly available at the Maxim website + http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf + +Authors: + Alexey Fisher <fishor@mail.ru>, + Jean Delvare <khali@linux-fr.org> + +Description +----------- + +The MAX1619 is a digital temperature sensor. It senses its own temperature as +well as the temperature of up to one external diode. + +All temperature values are given in degrees Celsius. Resolution +is 1.0 degree for the local temperature and for the remote temperature. + +Only the external sensor has high and low limits. + +The max1619 driver will not update its values more frequently than every +other second; reading them more often will do no harm, but will return +'old' values. + diff --git a/Documentation/i2c/chips/max6875 b/Documentation/i2c/chips/max6875 new file mode 100644 index 0000000..b4fb49b --- /dev/null +++ b/Documentation/i2c/chips/max6875 @@ -0,0 +1,54 @@ +Kernel driver max6875 +===================== + +Supported chips: + * Maxim max6874, max6875 + Prefixes: 'max6875' + Addresses scanned: 0x50, 0x52 + Datasheets: + http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf + +Author: Ben Gardner <bgardner@wabtec.com> + + +Module Parameters +----------------- + +* allow_write int + Set to non-zero to enable write permission: + *0: Read only + 1: Read and write + + +Description +----------- + +The MAXIM max6875 is a EEPROM-programmable power-supply sequencer/supervisor. +It provides timed outputs that can be used as a watchdog, if properly wired. +It also provides 512 bytes of user EEPROM. + +At reset, the max6875 reads the configuration eeprom into its configuration +registers. The chip then begins to operate according to the values in the +registers. + +See the datasheet for details on how to program the EEPROM. + + +Sysfs entries +------------- + +eeprom_user - 512 bytes of user-defined EEPROM space. Only writable if + allow_write was set and register 0x43 is 0. + +eeprom_config - 70 bytes of config EEPROM. Note that changes will not get + loaded into register space until a power cycle or device reset. + +reg_config - 70 bytes of register space. Any changes take affect immediately. + + +General Remarks +--------------- + +A typical application will require that the EEPROMs be programmed once and +never altered afterwards. + diff --git a/Documentation/i2c/chips/pc87360 b/Documentation/i2c/chips/pc87360 new file mode 100644 index 0000000..89a8fcf --- /dev/null +++ b/Documentation/i2c/chips/pc87360 @@ -0,0 +1,189 @@ +Kernel driver pc87360 +===================== + +Supported chips: + * National Semiconductor PC87360, PC87363, PC87364, PC87365 and PC87366 + Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366' + Addresses scanned: none, address read from Super I/O config space + Datasheets: + http://www.national.com/pf/PC/PC87360.html + http://www.national.com/pf/PC/PC87363.html + http://www.national.com/pf/PC/PC87364.html + http://www.national.com/pf/PC/PC87365.html + http://www.national.com/pf/PC/PC87366.html + +Authors: Jean Delvare <khali@linux-fr.org> + +Thanks to Sandeep Mehta, Tonko de Rooy and Daniel Ceregatti for testing. +Thanks to Rudolf Marek for helping me investigate conversion issues. + + +Module Parameters +----------------- + +* init int + Chip initialization level: + 0: None + *1: Forcibly enable internal voltage and temperature channels, except in9 + 2: Forcibly enable all voltage and temperature channels, except in9 + 3: Forcibly enable all voltage and temperature channels, including in9 + +Note that this parameter has no effect for the PC87360, PC87363 and PC87364 +chips. + +Also note that for the PC87366, initialization levels 2 and 3 don't enable +all temperature channels, because some of them share pins with each other, +so they can't be used at the same time. + + +Description +----------- + +The National Semiconductor PC87360 Super I/O chip contains monitoring and +PWM control circuitry for two fans. The PC87363 chip is similar, and the +PC87364 chip has monitoring and PWM control for a third fan. + +The National Semiconductor PC87365 and PC87366 Super I/O chips are complete +hardware monitoring chipsets, not only controlling and monitoring three fans, +but also monitoring eleven voltage inputs and two (PC87365) or up to four +(PC87366) temperatures. + + Chip #vin #fan #pwm #temp devid + + PC87360 - 2 2 - 0xE1 + PC87363 - 2 2 - 0xE8 + PC87364 - 3 3 - 0xE4 + PC87365 11 3 3 2 0xE5 + PC87366 11 3 3 3-4 0xE9 + +The driver assumes that no more than one chip is present, and one of the +standard Super I/O addresses is used (0x2E/0x2F or 0x4E/0x4F) + +Fan Monitoring +-------------- + +Fan rotation speeds are reported in RPM (revolutions per minute). An alarm +is triggered if the rotation speed has dropped below a programmable limit. +A different alarm is triggered if the fan speed is too low to be measured. + +Fan readings are affected by a programmable clock divider, giving the +readings more range or accuracy. Usually, users have to learn how it works, +but this driver implements dynamic clock divider selection, so you don't +have to care no more. + +For reference, here are a few values about clock dividers: + + slowest accuracy highest + measurable around 3000 accurate + divider speed (RPM) RPM (RPM) speed (RPM) + 1 1882 18 6928 + 2 941 37 4898 + 4 470 74 3464 + 8 235 150 2449 + +For the curious, here is how the values above were computed: + * slowest measurable speed: clock/(255*divider) + * accuracy around 3000 RPM: 3000^2/clock + * highest accurate speed: sqrt(clock*100) +The clock speed for the PC87360 family is 480 kHz. I arbitrarily chose 100 +RPM as the lowest acceptable accuracy. + +As mentioned above, you don't have to care about this no more. + +Note that not all RPM values can be represented, even when the best clock +divider is selected. This is not only true for the measured speeds, but +also for the programmable low limits, so don't be surprised if you try to +set, say, fan1_min to 2900 and it finally reads 2909. + + +Fan Control +----------- + +PWM (pulse width modulation) values range from 0 to 255, with 0 meaning +that the fan is stopped, and 255 meaning that the fan goes at full speed. + +Be extremely careful when changing PWM values. Low PWM values, even +non-zero, can stop the fan, which may cause irreversible damage to your +hardware if temperature increases too much. When changing PWM values, go +step by step and keep an eye on temperatures. + +One user reported problems with PWM. Changing PWM values would break fan +speed readings. No explanation nor fix could be found. + + +Temperature Monitoring +---------------------- + +Temperatures are reported in degrees Celsius. Each temperature measured has +associated low, high and overtemperature limits, each of which triggers an +alarm when crossed. + +The first two temperature channels are external. The third one (PC87366 +only) is internal. + +The PC87366 has three additional temperature channels, based on +thermistors (as opposed to thermal diodes for the first three temperature +channels). For technical reasons, these channels are held by the VLM +(voltage level monitor) logical device, not the TMS (temperature +measurement) one. As a consequence, these temperatures are exported as +voltages, and converted into temperatures in user-space. + +Note that these three additional channels share their pins with the +external thermal diode channels, so you (physically) can't use them all at +the same time. Although it should be possible to mix the two sensor types, +the documents from National Semiconductor suggest that motherboard +manufacturers should choose one type and stick to it. So you will more +likely have either channels 1 to 3 (thermal diodes) or 3 to 6 (internal +thermal diode, and thermistors). + + +Voltage Monitoring +------------------ + +Voltages are reported relatively to a reference voltage, either internal or +external. Some of them (in7:Vsb, in8:Vdd and in10:AVdd) are divided by two +internally, you will have to compensate in sensors.conf. Others (in0 to in6) +are likely to be divided externally. The meaning of each of these inputs as +well as the values of the resistors used for division is left to the +motherboard manufacturers, so you will have to document yourself and edit +sensors.conf accordingly. National Semiconductor has a document with +recommended resistor values for some voltages, but this still leaves much +room for per motherboard specificities, unfortunately. Even worse, +motherboard manufacturers don't seem to care about National Semiconductor's +recommendations. + +Each voltage measured has associated low and high limits, each of which +triggers an alarm when crossed. + +When available, VID inputs are used to provide the nominal CPU Core voltage. +The driver will default to VRM 9.0, but this can be changed from user-space. +The chipsets can handle two sets of VID inputs (on dual-CPU systems), but +the driver will only export one for now. This may change later if there is +a need. + + +General Remarks +--------------- + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! Note that all hardware registers are read whenever any +data is read (unless it is less than 2 seconds since the last update, in +which case cached values are returned instead). As a consequence, when +a once-only alarm triggers, it may take 2 seconds for it to show, and 2 +more seconds for it to disappear. + +Monitoring of in9 isn't enabled at lower init levels (<3) because that +channel measures the battery voltage (Vbat). It is a known fact that +repeatedly sampling the battery voltage reduces its lifetime. National +Semiconductor smartly designed their chipset so that in9 is sampled only +once every 1024 sampling cycles (that is every 34 minutes at the default +sampling rate), so the effect is attenuated, but still present. + + +Limitations +----------- + +The datasheets suggests that some values (fan mins, fan dividers) +shouldn't be changed once the monitoring has started, but we ignore that +recommendation. We'll reconsider if it actually causes trouble. diff --git a/Documentation/i2c/chips/pca9539 b/Documentation/i2c/chips/pca9539 new file mode 100644 index 0000000..c4fce6a --- /dev/null +++ b/Documentation/i2c/chips/pca9539 @@ -0,0 +1,47 @@ +Kernel driver pca9539 +===================== + +Supported chips: + * Philips PCA9539 + Prefix: 'pca9539' + Addresses scanned: 0x74 - 0x77 + Datasheet: + http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf + +Author: Ben Gardner <bgardner@wabtec.com> + + +Description +----------- + +The Philips PCA9539 is a 16 bit low power I/O device. +All 16 lines can be individually configured as an input or output. +The input sense can also be inverted. +The 16 lines are split between two bytes. + + +Sysfs entries +------------- + +Each is a byte that maps to the 8 I/O bits. +A '0' suffix is for bits 0-7, while '1' is for bits 8-15. + +input[01] - read the current value +output[01] - sets the output value +direction[01] - direction of each bit: 1=input, 0=output +invert[01] - toggle the input bit sense + +input reads the actual state of the line and is always available. +The direction defaults to input for all channels. + + +General Remarks +--------------- + +Note that each output, direction, and invert entry controls 8 lines. +You should use the read, modify, write sequence. +For example. to set output bit 0 of 1. + val=$(cat output0) + val=$(( $val | 1 )) + echo $val > output0 + diff --git a/Documentation/i2c/chips/pcf8574 b/Documentation/i2c/chips/pcf8574 new file mode 100644 index 0000000..2752c8c --- /dev/null +++ b/Documentation/i2c/chips/pcf8574 @@ -0,0 +1,69 @@ +Kernel driver pcf8574 +===================== + +Supported chips: + * Philips PCF8574 + Prefix: 'pcf8574' + Addresses scanned: I2C 0x20 - 0x27 + Datasheet: Publicly available at the Philips Semiconductors website + http://www.semiconductors.philips.com/pip/PCF8574P.html + + * Philips PCF8574A + Prefix: 'pcf8574a' + Addresses scanned: I2C 0x38 - 0x3f + Datasheet: Publicly available at the Philips Semiconductors website + http://www.semiconductors.philips.com/pip/PCF8574P.html + +Authors: + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com>, + Dan Eaton <dan.eaton@rocketlogix.com>, + Aurelien Jarno <aurelien@aurel32.net>, + Jean Delvare <khali@linux-fr.org>, + + +Description +----------- +The PCF8574(A) is an 8-bit I/O expander for the I2C bus produced by Philips +Semiconductors. It is designed to provide a byte I2C interface to up to 16 +separate devices (8 x PCF8574 and 8 x PCF8574A). + +This device consists of a quasi-bidirectional port. Each of the eight I/Os +can be independently used as an input or output. To setup an I/O as an +input, you have to write a 1 to the corresponding output. + +For more informations see the datasheet. + + +Accessing PCF8574(A) via /sys interface +------------------------------------- + +! Be careful ! +The PCF8574(A) is plainly impossible to detect ! Stupid chip. +So every chip with address in the interval [20..27] and [38..3f] are +detected as PCF8574(A). If you have other chips in this address +range, the workaround is to load this module after the one +for your others chips. + +On detection (i.e. insmod, modprobe et al.), directories are being +created for each detected PCF8574(A): + +/sys/bus/i2c/devices/<0>-<1>/ +where <0> is the bus the chip was detected on (e. g. i2c-0) +and <1> the chip address ([20..27] or [38..3f]): + +(example: /sys/bus/i2c/devices/1-0020/) + +Inside these directories, there are two files each: +read and write (and one file with chip name). + +The read file is read-only. Reading gives you the current I/O input +if the corresponding output is set as 1, otherwise the current output +value, that is to say 0. + +The write file is read/write. Writing a value outputs it on the I/O +port. Reading returns the last written value. + +On module initialization the chip is configured as eight inputs (all +outputs to 1), so you can connect any circuit to the PCF8574(A) without +being afraid of short-circuit. diff --git a/Documentation/i2c/chips/pcf8591 b/Documentation/i2c/chips/pcf8591 new file mode 100644 index 0000000..5628fcf --- /dev/null +++ b/Documentation/i2c/chips/pcf8591 @@ -0,0 +1,90 @@ +Kernel driver pcf8591 +===================== + +Supported chips: + * Philips PCF8591 + Prefix: 'pcf8591' + Addresses scanned: I2C 0x48 - 0x4f + Datasheet: Publicly available at the Philips Semiconductor website + http://www.semiconductors.philips.com/pip/PCF8591P.html + +Authors: + Aurelien Jarno <aurelien@aurel32.net> + valuable contributions by Jan M. Sendler <sendler@sendler.de>, + Jean Delvare <khali@linux-fr.org> + + +Description +----------- +The PCF8591 is an 8-bit A/D and D/A converter (4 analog inputs and one +analog output) for the I2C bus produced by Philips Semiconductors. It +is designed to provide a byte I2C interface to up to 4 separate devices. + +The PCF8591 has 4 analog inputs programmable as single-ended or +differential inputs : +- mode 0 : four single ended inputs + Pins AIN0 to AIN3 are single ended inputs for channels 0 to 3 + +- mode 1 : three differential inputs + Pins AIN3 is the common negative differential input + Pins AIN0 to AIN2 are positive differential inputs for channels 0 to 2 + +- mode 2 : single ended and differential mixed + Pins AIN0 and AIN1 are single ended inputs for channels 0 and 1 + Pins AIN2 is the positive differential input for channel 3 + Pins AIN3 is the negative differential input for channel 3 + +- mode 3 : two differential inputs + Pins AIN0 is the positive differential input for channel 0 + Pins AIN1 is the negative differential input for channel 0 + Pins AIN2 is the positive differential input for channel 1 + Pins AIN3 is the negative differential input for channel 1 + +See the datasheet for details. + +Module parameters +----------------- + +* input_mode int + + Analog input mode: + 0 = four single ended inputs + 1 = three differential inputs + 2 = single ended and differential mixed + 3 = two differential inputs + + +Accessing PCF8591 via /sys interface +------------------------------------- + +! Be careful ! +The PCF8591 is plainly impossible to detect ! Stupid chip. +So every chip with address in the interval [48..4f] is +detected as PCF8591. If you have other chips in this address +range, the workaround is to load this module after the one +for your others chips. + +On detection (i.e. insmod, modprobe et al.), directories are being +created for each detected PCF8591: + +/sys/bus/devices/<0>-<1>/ +where <0> is the bus the chip was detected on (e. g. i2c-0) +and <1> the chip address ([48..4f]) + +Inside these directories, there are such files: +in0, in1, in2, in3, out0_enable, out0_output, name + +Name contains chip name. + +The in0, in1, in2 and in3 files are RO. Reading gives the value of the +corresponding channel. Depending on the current analog inputs configuration, +files in2 and/or in3 do not exist. Values range are from 0 to 255 for single +ended inputs and -128 to +127 for differential inputs (8-bit ADC). + +The out0_enable file is RW. Reading gives "1" for analog output enabled and +"0" for analog output disabled. Writing accepts "0" and "1" accordingly. + +The out0_output file is RW. Writing a number between 0 and 255 (8-bit DAC), send +the value to the digital-to-analog converter. Note that a voltage will +only appears on AOUT pin if aout0_enable equals 1. Reading returns the last +value written. diff --git a/Documentation/i2c/chips/sis5595 b/Documentation/i2c/chips/sis5595 new file mode 100644 index 0000000..b7ae36b --- /dev/null +++ b/Documentation/i2c/chips/sis5595 @@ -0,0 +1,106 @@ +Kernel driver sis5595 +===================== + +Supported chips: + * Silicon Integrated Systems Corp. SiS5595 Southbridge Hardware Monitor + Prefix: 'sis5595' + Addresses scanned: ISA in PCI-space encoded address + Datasheet: Publicly available at the Silicon Integrated Systems Corp. site. + +Authors: + Kyösti Mälkki <kmalkki@cc.hut.fi>, + Mark D. Studebaker <mdsxyz123@yahoo.com>, + Aurelien Jarno <aurelien@aurel32.net> 2.6 port + + SiS southbridge has a LM78-like chip integrated on the same IC. + This driver is a customized copy of lm78.c + + Supports following revisions: + Version PCI ID PCI Revision + 1 1039/0008 AF or less + 2 1039/0008 B0 or greater + + Note: these chips contain a 0008 device which is incompatible with the + 5595. We recognize these by the presence of the listed + "blacklist" PCI ID and refuse to load. + + NOT SUPPORTED PCI ID BLACKLIST PCI ID + 540 0008 0540 + 550 0008 0550 + 5513 0008 5511 + 5581 0008 5597 + 5582 0008 5597 + 5597 0008 5597 + 630 0008 0630 + 645 0008 0645 + 730 0008 0730 + 735 0008 0735 + + +Module Parameters +----------------- +force_addr=0xaddr Set the I/O base address. Useful for boards + that don't set the address in the BIOS. Does not do a + PCI force; the device must still be present in lspci. + Don't use this unless the driver complains that the + base address is not set. + Example: 'modprobe sis5595 force_addr=0x290' + + +Description +----------- + +The SiS5595 southbridge has integrated hardware monitor functions. It also +has an I2C bus, but this driver only supports the hardware monitor. For the +I2C bus driver see i2c-sis5595. + +The SiS5595 implements zero or one temperature sensor, two fan speed +sensors, four or five voltage sensors, and alarms. + +On the first version of the chip, there are four voltage sensors and one +temperature sensor. + +On the second version of the chip, the temperature sensor (temp) and the +fifth voltage sensor (in4) share a pin which is configurable, but not +through the driver. Sorry. The driver senses the configuration of the pin, +which was hopefully set by the BIOS. + +Temperatures are measured in degrees Celsius. An alarm is triggered once +when the max is crossed; it is also triggered when it drops below the min +value. Measurements are guaranteed between -55 and +125 degrees, with a +resolution of 1 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. An +alarm is triggered if the voltage has crossed a programmable minimum or +maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 4.08 volts, with a resolution of +0.016 volt. + +In addition to the alarms described above, there is a BTI alarm, which gets +triggered when an external chip has crossed its limits. Usually, this is +connected to some LM75-like chip; if at least one crosses its limits, this +bit gets set. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may already +have disappeared! Note that in the current implementation, all hardware +registers are read whenever any data is read (unless it is less than 1.5 +seconds since the last update). This means that you can easily miss +once-only alarms. + +The SiS5595 only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. + +Problems +-------- +Some chips refuse to be enabled. We don't know why. +The driver will recognize this and print a message in dmesg. + diff --git a/Documentation/i2c/chips/smsc47b397.txt b/Documentation/i2c/chips/smsc47b397 index 389edae..da9d80c 100644 --- a/Documentation/i2c/chips/smsc47b397.txt +++ b/Documentation/i2c/chips/smsc47b397 @@ -1,7 +1,19 @@ +Kernel driver smsc47b397 +======================== + +Supported chips: + * SMSC LPC47B397-NC + Prefix: 'smsc47b397' + Addresses scanned: none, address read from Super I/O config space + Datasheet: In this file + +Authors: Mark M. Hoffman <mhoffman@lightlink.com> + Utilitek Systems, Inc. + November 23, 2004 The following specification describes the SMSC LPC47B397-NC sensor chip -(for which there is no public datasheet available). This document was +(for which there is no public datasheet available). This document was provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected by Mark M. Hoffman <mhoffman@lightlink.com>. @@ -10,10 +22,10 @@ by Mark M. Hoffman <mhoffman@lightlink.com>. Methods for detecting the HP SIO and reading the thermal data on a dc7100. The thermal information on the dc7100 is contained in the SIO Hardware Monitor -(HWM). The information is accessed through an index/data pair. The index/data -pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The +(HWM). The information is accessed through an index/data pair. The index/data +pair is located at the HWM Base Address + 0 and the HWM Base Address + 1. The HWM Base address can be obtained from Logical Device 8, registers 0x60 (MSB) -and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and +and 0x61 (LSB). Currently we are using 0x480 for the HWM Base Address and 0x480 and 0x481 for the index/data pair. Reading temperature information. @@ -50,7 +62,7 @@ Reading the tach LSB locks the tach MSB. The LSB Must be read first. How to convert the tach reading to RPM. -The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB) +The tach reading (TCount) is given by: (Tach MSB * 256) + (Tach LSB) The SIO counts the number of 90kHz (11.111us) pulses per revolution. RPM = 60/(TCount * 11.111us) @@ -72,20 +84,20 @@ To program the configuration registers, the following sequence must be followed: Enter Configuration Mode To place the chip into the Configuration State The config key (0x55) is written -to the CONFIG PORT (0x2E). +to the CONFIG PORT (0x2E). Configuration Mode In configuration mode, the INDEX PORT is located at the CONFIG PORT address and the DATA PORT is at INDEX PORT address + 1. -The desired configuration registers are accessed in two steps: +The desired configuration registers are accessed in two steps: a. Write the index of the Logical Device Number Configuration Register (i.e., 0x07) to the INDEX PORT and then write the number of the desired logical device to the DATA PORT. b. Write the address of the desired configuration register within the logical device to the INDEX PORT and then write or read the config- - uration register through the DATA PORT. + uration register through the DATA PORT. Note: If accessing the Global Configuration Registers, step (a) is not required. @@ -96,18 +108,18 @@ The chip returns to the RUN State. (This is important). Programming Example The following is an example of how to read the SIO Device ID located at 0x20 -; ENTER CONFIGURATION MODE +; ENTER CONFIGURATION MODE MOV DX,02EH MOV AX,055H OUT DX,AL -; GLOBAL CONFIGURATION REGISTER +; GLOBAL CONFIGURATION REGISTER MOV DX,02EH MOV AL,20H -OUT DX,AL +OUT DX,AL ; READ THE DATA MOV DX,02FH IN AL,DX -; EXIT CONFIGURATION MODE +; EXIT CONFIGURATION MODE MOV DX,02EH MOV AX,0AAH OUT DX,AL @@ -122,12 +134,12 @@ Obtaining the HWM Base Address. The following is an example of how to read the HWM Base Address located in Logical Device 8. -; ENTER CONFIGURATION MODE +; ENTER CONFIGURATION MODE MOV DX,02EH MOV AX,055H OUT DX,AL -; CONFIGURE REGISTER CRE0, -; LOGICAL DEVICE 8 +; CONFIGURE REGISTER CRE0, +; LOGICAL DEVICE 8 MOV DX,02EH MOV AL,07H OUT DX,AL ;Point to LD# Config Reg @@ -135,12 +147,12 @@ MOV DX,02FH MOV AL, 08H OUT DX,AL;Point to Logical Device 8 ; -MOV DX,02EH +MOV DX,02EH MOV AL,60H OUT DX,AL ; Point to HWM Base Addr MSB MOV DX,02FH IN AL,DX ; Get MSB of HWM Base Addr -; EXIT CONFIGURATION MODE +; EXIT CONFIGURATION MODE MOV DX,02EH MOV AX,0AAH OUT DX,AL diff --git a/Documentation/i2c/chips/smsc47m1 b/Documentation/i2c/chips/smsc47m1 new file mode 100644 index 0000000..34e6478 --- /dev/null +++ b/Documentation/i2c/chips/smsc47m1 @@ -0,0 +1,52 @@ +Kernel driver smsc47m1 +====================== + +Supported chips: + * SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 + Addresses scanned: none, address read from Super I/O config space + Prefix: 'smsc47m1' + Datasheets: + http://www.smsc.com/main/datasheets/47b27x.pdf + http://www.smsc.com/main/datasheets/47m10x.pdf + http://www.smsc.com/main/tools/discontinued/47m13x.pdf + http://www.smsc.com/main/datasheets/47m14x.pdf + http://www.smsc.com/main/tools/discontinued/47m15x.pdf + http://www.smsc.com/main/datasheets/47m192.pdf + +Authors: + Mark D. Studebaker <mdsxyz123@yahoo.com>, + With assistance from Bruce Allen <ballen@uwm.edu>, and his + fan.c program: http://www.lsc-group.phys.uwm.edu/%7Eballen/driver/ + Gabriele Gorla <gorlik@yahoo.com>, + Jean Delvare <khali@linux-fr.org> + +Description +----------- + +The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips +contain monitoring and PWM control circuitry for two fans. + +The 47M15x and 47M192 chips contain a full 'hardware monitoring block' +in addition to the fan monitoring and control. The hardware monitoring +block is not supported by the driver. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +PWM values are from 0 to 255. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.5 seconds since the last update). This means that you can easily +miss once-only alarms. + + +********************** +The lm_sensors project gratefully acknowledges the support of +Intel in the development of this driver. diff --git a/Documentation/i2c/chips/via686a b/Documentation/i2c/chips/via686a new file mode 100644 index 0000000..b82014c --- /dev/null +++ b/Documentation/i2c/chips/via686a @@ -0,0 +1,65 @@ +Kernel driver via686a +===================== + +Supported chips: + * Via VT82C686A, VT82C686B Southbridge Integrated Hardware Monitor + Prefix: 'via686a' + Addresses scanned: ISA in PCI-space encoded address + Datasheet: On request through web form (http://www.via.com.tw/en/support/datasheets/) + +Authors: + Kyösti Mälkki <kmalkki@cc.hut.fi>, + Mark D. Studebaker <mdsxyz123@yahoo.com> + Bob Dougherty <bobd@stanford.edu> + (Some conversion-factor data were contributed by + Jonathan Teh Soon Yew <j.teh@iname.com> + and Alex van Kaam <darkside@chello.nl>.) + +Module Parameters +----------------- + +force_addr=0xaddr Set the I/O base address. Useful for Asus A7V boards + that don't set the address in the BIOS. Does not do a + PCI force; the via686a must still be present in lspci. + Don't use this unless the driver complains that the + base address is not set. + Example: 'modprobe via686a force_addr=0x6000' + +Description +----------- + +The driver does not distinguish between the chips and reports +all as a 686A. + +The Via 686a southbridge has integrated hardware monitor functionality. +It also has an I2C bus, but this driver only supports the hardware monitor. +For the I2C bus driver, see <file:Documentation/i2c/busses/i2c-viapro> + +The Via 686a implements three temperature sensors, two fan rotation speed +sensors, five voltage sensors and alarms. + +Temperatures are measured in degrees Celsius. An alarm is triggered once +when the Overtemperature Shutdown limit is crossed; it is triggered again +as soon as it drops below the hysteresis value. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8) to give +the readings more range or accuracy. Not all RPM values can accurately be +represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. Voltages are internally scalled, so each voltage channel +has a different resolution and range. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.5 seconds since the last update). This means that you can easily +miss once-only alarms. + +The driver only updates its values each 1.5 seconds; reading it more often +will do no harm, but will return 'old' values. diff --git a/Documentation/i2c/chips/w83627hf b/Documentation/i2c/chips/w83627hf new file mode 100644 index 0000000..78f37c2 --- /dev/null +++ b/Documentation/i2c/chips/w83627hf @@ -0,0 +1,66 @@ +Kernel driver w83627hf +====================== + +Supported chips: + * Winbond W83627HF (ISA accesses ONLY) + Prefix: 'w83627hf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf + * Winbond W83627THF + Prefix: 'w83627thf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf + * Winbond W83697HF + Prefix: 'w83697hf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond.com/PDF/sheet/697hf.pdf + * Winbond W83637HF + Prefix: 'w83637hf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf + +Authors: + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com>, + Mark Studebaker <mdsxyz123@yahoo.com>, + Bernhard C. Schrenk <clemy@clemy.org> + +Module Parameters +----------------- + +* force_addr: int + Initialize the ISA address of the sensors +* force_i2c: int + Initialize the I2C address of the sensors +* init: int + (default is 1) + Use 'init=0' to bypass initializing the chip. + Try this if your computer crashes when you load the module. + +Description +----------- + +This driver implements support for ISA accesses *only* for +the Winbond W83627HF, W83627THF, W83697HF and W83637HF Super I/O chips. +We will refer to them collectively as Winbond chips. + +This driver supports ISA accesses, which should be more reliable +than i2c accesses. Also, for Tyan boards which contain both a +Super I/O chip and a second i2c-only Winbond chip (often a W83782D), +using this driver will avoid i2c address conflicts and complex +initialization that were required in the w83781d driver. + +If you really want i2c accesses for these Super I/O chips, +use the w83781d driver. However this is not the preferred method +now that this ISA driver has been developed. + +Technically, the w83627thf does not support a VID reading. However, it's +possible or even likely that your mainboard maker has routed these signals +to a specific set of general purpose IO pins (the Asus P4C800-E is one such +board). The w83627thf driver now interprets these as VID. If the VID on +your board doesn't work, first see doc/vid in the lm_sensors package. If +that still doesn't help, email us at lm-sensors@lm-sensors.org. + +For further information on this driver see the w83781d driver +documentation. + diff --git a/Documentation/i2c/chips/w83781d b/Documentation/i2c/chips/w83781d new file mode 100644 index 0000000..e545933 --- /dev/null +++ b/Documentation/i2c/chips/w83781d @@ -0,0 +1,402 @@ +Kernel driver w83781d +===================== + +Supported chips: + * Winbond W83781D + Prefix: 'w83781d' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83781d.pdf + * Winbond W83782D + Prefix: 'w83782d' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf + * Winbond W83783S + Prefix: 'w83783s' + Addresses scanned: I2C 0x2d + Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83783s.pdf + * Winbond W83627HF + Prefix: 'w83627hf' + Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf + * Asus AS99127F + Prefix: 'as99127f' + Addresses scanned: I2C 0x28 - 0x2f + Datasheet: Unavailable from Asus + +Authors: + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com>, + Mark Studebaker <mdsxyz123@yahoo.com> + +Module parameters +----------------- + +* init int + (default 1) + Use 'init=0' to bypass initializing the chip. + Try this if your computer crashes when you load the module. + +force_subclients=bus,caddr,saddr,saddr + This is used to force the i2c addresses for subclients of + a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b' + to force the subclients of chip 0x2d on bus 0 to i2c addresses + 0x4a and 0x4b. This parameter is useful for certain Tyan boards. + +Description +----------- + +This driver implements support for the Winbond W83781D, W83782D, W83783S, +W83627HF chips, and the Asus AS99127F chips. We will refer to them +collectively as W8378* chips. + +There is quite some difference between these chips, but they are similar +enough that it was sensible to put them together in one driver. +The W83627HF chip is assumed to be identical to the ISA W83782D. +The Asus chips are similar to an I2C-only W83782D. + +Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA +as99127f 7 3 0 3 0x31 0x12c3 yes no +as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no +w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes +w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) +w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes +w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no + +Detection of these chips can sometimes be foiled because they can be in +an internal state that allows no clean access. If you know the address +of the chip, use a 'force' parameter; this will put them into a more +well-behaved state first. + +The W8378* implements temperature sensors (three on the W83781D and W83782D, +two on the W83783S), three fan rotation speed sensors, voltage sensors +(seven on the W83781D, nine on the W83782D and six on the W83783S), VID +lines, alarms with beep warnings, and some miscellaneous stuff. + +Temperatures are measured in degrees Celsius. There is always one main +temperature sensor, and one (W83783S) or two (W83781D and W83782D) other +sensors. An alarm is triggered for the main sensor once when the +Overtemperature Shutdown limit is crossed; it is triggered again as soon as +it drops below the Hysteresis value. A more useful behavior +can be found by setting the Hysteresis value to +127 degrees Celsius; in +this case, alarms are issued during all the time when the actual temperature +is above the Overtemperature Shutdown value. The driver sets the +hysteresis value for temp1 to 127 at initialization. + +For the other temperature sensor(s), an alarm is triggered when the +temperature gets higher then the Overtemperature Shutdown value; it stays +on until the temperature falls below the Hysteresis value. But on the +W83781D, there is only one alarm that functions for both other sensors! +Temperatures are guaranteed within a range of -55 to +125 degrees. The +main temperature sensors has a resolution of 1 degree; the other sensor(s) +of 0.5 degree. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4 or 8 for the +W83781D; 1, 2, 4, 8, 16, 32, 64 or 128 for the others) to give +the readings more range or accuracy. Not all RPM values can accurately +be represented, so some rounding is done. With a divider of 2, the lowest +representable value is around 2600 RPM. + +Voltage sensors (also known as IN sensors) report their values in volts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. Note that minimum in this case always means 'closest to +zero'; this is important for negative voltage measurements. All voltage +inputs can measure voltages between 0 and 4.08 volts, with a resolution +of 0.016 volt. + +The VID lines encode the core voltage value: the voltage level your processor +should work with. This is hardcoded by the mainboard and/or processor itself. +It is a value in volts. When it is unconnected, you will often find the +value 3.50 V here. + +The W83782D and W83783S temperature conversion machine understands about +several kinds of temperature probes. You can program the so-called +beta value in the sensor files. '1' is the PII/Celeron diode, '2' is the +TN3904 transistor, and 3435 the default thermistor value. Other values +are (not yet) supported. + +In addition to the alarms described above, there is a CHAS alarm on the +chips which triggers if your computer case is open. + +When an alarm goes off, you can be warned by a beeping signal through +your computer speaker. It is possible to enable all beeping globally, +or only the beeping for some alarms. + +If an alarm triggers, it will remain triggered until the hardware register +is read at least once. This means that the cause for the alarm may +already have disappeared! Note that in the current implementation, all +hardware registers are read whenever any data is read (unless it is less +than 1.5 seconds since the last update). This means that you can easily +miss once-only alarms. + +The chips only update values each 1.5 seconds; reading them more often +will do no harm, but will return 'old' values. + +AS99127F PROBLEMS +----------------- +The as99127f support was developed without the benefit of a datasheet. +In most cases it is treated as a w83781d (although revision 2 of the +AS99127F looks more like a w83782d). +This support will be BETA until a datasheet is released. +One user has reported problems with fans stopping +occasionally. + +Note that the individual beep bits are inverted from the other chips. +The driver now takes care of this so that user-space applications +don't have to know about it. + +Known problems: + - Problems with diode/thermistor settings (supported?) + - One user reports fans stopping under high server load. + - Revision 2 seems to have 2 PWM registers but we don't know + how to handle them. More details below. + +These will not be fixed unless we get a datasheet. +If you have problems, please lobby Asus to release a datasheet. +Unfortunately several others have without success. +Please do not send mail to us asking for better as99127f support. +We have done the best we can without a datasheet. +Please do not send mail to the author or the sensors group asking for +a datasheet or ideas on how to convince Asus. We can't help. + + +NOTES: +----- + 783s has no in1 so that in[2-6] are compatible with the 781d/782d. + + 783s pin is programmable for -5V or temp1; defaults to -5V, + no control in driver so temp1 doesn't work. + + 782d and 783s datasheets differ on which is pwm1 and which is pwm2. + We chose to follow 782d. + + 782d and 783s pin is programmable for fan3 input or pwm2 output; + defaults to fan3 input. + If pwm2 is enabled (with echo 255 1 > pwm2), then + fan3 will report 0. + + 782d has pwm1-2 for ISA, pwm1-4 for i2c. (pwm3-4 share pins with + the ISA pins) + +Data sheet updates: +------------------ + - PWM clock registers: + + 000: master / 512 + 001: master / 1024 + 010: master / 2048 + 011: master / 4096 + 100: master / 8192 + + +Answers from Winbond tech support +--------------------------------- +> +> 1) In the W83781D data sheet section 7.2 last paragraph, it talks about +> reprogramming the R-T table if the Beta of the thermistor is not +> 3435K. The R-T table is described briefly in section 8.20. +> What formulas do I use to program a new R-T table for a given Beta? +> + We are sorry that the calculation for R-T table value is +confidential. If you have another Beta value of thermistor, we can help +to calculate the R-T table for you. But you should give us real R-T +Table which can be gotten by thermistor vendor. Therefore we will calculate +them and obtain 32-byte data, and you can fill the 32-byte data to the +register in Bank0.CR51 of W83781D. + + +> 2) In the W83782D data sheet, it mentions that pins 38, 39, and 40 are +> programmable to be either thermistor or Pentium II diode inputs. +> How do I program them for diode inputs? I can't find any register +> to program these to be diode inputs. + --> You may program Bank0 CR[5Dh] and CR[59h] registers. + + CR[5Dh] bit 1(VTIN1) bit 2(VTIN2) bit 3(VTIN3) + + thermistor 0 0 0 + diode 1 1 1 + + +(error) CR[59h] bit 4(VTIN1) bit 2(VTIN2) bit 3(VTIN3) +(right) CR[59h] bit 4(VTIN1) bit 5(VTIN2) bit 6(VTIN3) + + PII thermal diode 1 1 1 + 2N3904 diode 0 0 0 + + +Asus Clones +----------- + +We have no datasheets for the Asus clones (AS99127F and ASB100 Bach). +Here are some very useful information that were given to us by Alex Van +Kaam about how to detect these chips, and how to read their values. He +also gives advice for another Asus chipset, the Mozart-2 (which we +don't support yet). Thanks Alex! +I reworded some parts and added personal comments. + +# Detection: + +AS99127F rev.1, AS99127F rev.2 and ASB100: +- I2C address range: 0x29 - 0x2F +- If register 0x58 holds 0x31 then we have an Asus (either ASB100 or + AS99127F) +- Which one depends on register 0x4F (manufacturer ID): + 0x06 or 0x94: ASB100 + 0x12 or 0xC3: AS99127F rev.1 + 0x5C or 0xA3: AS99127F rev.2 + Note that 0x5CA3 is Winbond's ID (WEC), which let us think Asus get their + AS99127F rev.2 direct from Winbond. The other codes mean ATT and DVC, + respectively. ATT could stand for Asustek something (although it would be + very badly chosen IMHO), I don't know what DVC could stand for. Maybe + these codes simply aren't meant to be decoded that way. + +Mozart-2: +- I2C address: 0x77 +- If register 0x58 holds 0x56 or 0x10 then we have a Mozart-2 +- Of the Mozart there are 3 types: + 0x58=0x56, 0x4E=0x94, 0x4F=0x36: Asus ASM58 Mozart-2 + 0x58=0x56, 0x4E=0x94, 0x4F=0x06: Asus AS2K129R Mozart-2 + 0x58=0x10, 0x4E=0x5C, 0x4F=0xA3: Asus ??? Mozart-2 + You can handle all 3 the exact same way :) + +# Temperature sensors: + +ASB100: +- sensor 1: register 0x27 +- sensor 2 & 3 are the 2 LM75's on the SMBus +- sensor 4: register 0x17 +Remark: I noticed that on Intel boards sensor 2 is used for the CPU + and 4 is ignored/stuck, on AMD boards sensor 4 is the CPU and sensor 2 is + either ignored or a socket temperature. + +AS99127F (rev.1 and 2 alike): +- sensor 1: register 0x27 +- sensor 2 & 3 are the 2 LM75's on the SMBus +Remark: Register 0x5b is suspected to be temperature type selector. Bit 1 + would control temp1, bit 3 temp2 and bit 5 temp3. + +Mozart-2: +- sensor 1: register 0x27 +- sensor 2: register 0x13 + +# Fan sensors: + +ASB100, AS99127F (rev.1 and 2 alike): +- 3 fans, identical to the W83781D + +Mozart-2: +- 2 fans only, 1350000/RPM/div +- fan 1: register 0x28, divisor on register 0xA1 (bits 4-5) +- fan 2: register 0x29, divisor on register 0xA1 (bits 6-7) + +# Voltages: + +This is where there is a difference between AS99127F rev.1 and 2. +Remark: The difference is similar to the difference between + W83781D and W83782D. + +ASB100: +in0=r(0x20)*0.016 +in1=r(0x21)*0.016 +in2=r(0x22)*0.016 +in3=r(0x23)*0.016*1.68 +in4=r(0x24)*0.016*3.8 +in5=r(0x25)*(-0.016)*3.97 +in6=r(0x26)*(-0.016)*1.666 + +AS99127F rev.1: +in0=r(0x20)*0.016 +in1=r(0x21)*0.016 +in2=r(0x22)*0.016 +in3=r(0x23)*0.016*1.68 +in4=r(0x24)*0.016*3.8 +in5=r(0x25)*(-0.016)*3.97 +in6=r(0x26)*(-0.016)*1.503 + +AS99127F rev.2: +in0=r(0x20)*0.016 +in1=r(0x21)*0.016 +in2=r(0x22)*0.016 +in3=r(0x23)*0.016*1.68 +in4=r(0x24)*0.016*3.8 +in5=(r(0x25)*0.016-3.6)*5.14+3.6 +in6=(r(0x26)*0.016-3.6)*3.14+3.6 + +Mozart-2: +in0=r(0x20)*0.016 +in1=255 +in2=r(0x22)*0.016 +in3=r(0x23)*0.016*1.68 +in4=r(0x24)*0.016*4 +in5=255 +in6=255 + + +# PWM + +Additional info about PWM on the AS99127F (may apply to other Asus +chips as well) by Jean Delvare as of 2004-04-09: + +AS99127F revision 2 seems to have two PWM registers at 0x59 and 0x5A, +and a temperature sensor type selector at 0x5B (which basically means +that they swapped registers 0x59 and 0x5B when you compare with Winbond +chips). +Revision 1 of the chip also has the temperature sensor type selector at +0x5B, but PWM registers have no effect. + +We don't know exactly how the temperature sensor type selection works. +Looks like bits 1-0 are for temp1, bits 3-2 for temp2 and bits 5-4 for +temp3, although it is possible that only the most significant bit matters +each time. So far, values other than 0 always broke the readings. + +PWM registers seem to be split in two parts: bit 7 is a mode selector, +while the other bits seem to define a value or threshold. + +When bit 7 is clear, bits 6-0 seem to hold a threshold value. If the value +is below a given limit, the fan runs at low speed. If the value is above +the limit, the fan runs at full speed. We have no clue as to what the limit +represents. Note that there seem to be some inertia in this mode, speed +changes may need some time to trigger. Also, an hysteresis mechanism is +suspected since walking through all the values increasingly and then +decreasingly led to slightly different limits. + +When bit 7 is set, bits 3-0 seem to hold a threshold value, while bits 6-4 +would not be significant. If the value is below a given limit, the fan runs +at full speed, while if it is above the limit it runs at low speed (so this +is the contrary of the other mode, in a way). Here again, we don't know +what the limit is supposed to represent. + +One remarkable thing is that the fans would only have two or three +different speeds (transitional states left apart), not a whole range as +you usually get with PWM. + +As a conclusion, you can write 0x00 or 0x8F to the PWM registers to make +fans run at low speed, and 0x7F or 0x80 to make them run at full speed. + +Please contact us if you can figure out how it is supposed to work. As +long as we don't know more, the w83781d driver doesn't handle PWM on +AS99127F chips at all. + +Additional info about PWM on the AS99127F rev.1 by Hector Martin: + +I've been fiddling around with the (in)famous 0x59 register and +found out the following values do work as a form of coarse pwm: + +0x80 - seems to turn fans off after some time(1-2 minutes)... might be +some form of auto-fan-control based on temp? hmm (Qfan? this mobo is an +old ASUS, it isn't marketed as Qfan. Maybe some beta pre-attemp at Qfan +that was dropped at the BIOS) +0x81 - off +0x82 - slightly "on-ner" than off, but my fans do not get to move. I can +hear the high-pitched PWM sound that motors give off at too-low-pwm. +0x83 - now they do move. Estimate about 70% speed or so. +0x84-0x8f - full on + +Changing the high nibble doesn't seem to do much except the high bit +(0x80) must be set for PWM to work, else the current pwm doesn't seem to +change. + +My mobo is an ASUS A7V266-E. This behavior is similar to what I got +with speedfan under Windows, where 0-15% would be off, 15-2x% (can't +remember the exact value) would be 70% and higher would be full on. diff --git a/Documentation/i2c/chips/w83l785ts b/Documentation/i2c/chips/w83l785ts new file mode 100644 index 0000000..1841ced --- /dev/null +++ b/Documentation/i2c/chips/w83l785ts @@ -0,0 +1,39 @@ +Kernel driver w83l785ts +======================= + +Supported chips: + * Winbond W83L785TS-S + Prefix: 'w83l785ts' + Addresses scanned: I2C 0x2e + Datasheet: Publicly available at the Winbond USA website + http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf + +Authors: + Jean Delvare <khali@linux-fr.org> + +Description +----------- + +The W83L785TS-S is a digital temperature sensor. It senses the +temperature of a single external diode. The high limit is +theoretically defined as 85 or 100 degrees C through a combination +of external resistors, so the user cannot change it. Values seen so +far suggest that the two possible limits are actually 95 and 110 +degrees C. The datasheet is rather poor and obviously inaccurate +on several points including this one. + +All temperature values are given in degrees Celsius. Resolution +is 1.0 degree. See the datasheet for details. + +The w83l785ts driver will not update its values more frequently than +every other second; reading them more often will do no harm, but will +return 'old' values. + +Known Issues +------------ + +On some systems (Asus), the BIOS is known to interfere with the driver +and cause read errors. The driver will retry a given number of times +(5 by default) and then give up, returning the old value (or 0 if +there is no old value). It seems to work well enough so that you should +not notice anything. Thanks to James Bolt for helping test this feature. diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index 5640491..a7adbdd 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients @@ -57,7 +57,7 @@ Technical changes: Documentation/i2c/sysfs-interface for the individual files. Also convert the units these files read and write to the specified ones. If you need to add a new type of file, please discuss it on the - sensors mailing list <sensors@stimpy.netroedge.com> by providing a + sensors mailing list <lm-sensors@lm-sensors.org> by providing a patch to the Documentation/i2c/sysfs-interface file. * [Attach] For I2C drivers, the attach function should make sure diff --git a/Documentation/i2c/userspace-tools b/Documentation/i2c/userspace-tools new file mode 100644 index 0000000..2622aac --- /dev/null +++ b/Documentation/i2c/userspace-tools @@ -0,0 +1,39 @@ +Introduction +------------ + +Most mainboards have sensor chips to monitor system health (like temperatures, +voltages, fans speed). They are often connected through an I2C bus, but some +are also connected directly through the ISA bus. + +The kernel drivers make the data from the sensor chips available in the /sys +virtual filesystem. Userspace tools are then used to display or set or the +data in a more friendly manner. + +Lm-sensors +---------- + +Core set of utilites that will allow you to obtain health information, +setup monitoring limits etc. You can get them on their homepage +http://www.lm-sensors.nu/ or as a package from your Linux distribution. + +If from website: +Get lmsensors from project web site. Please note, you need only userspace +part, so compile with "make user_install" target. + +General hints to get things working: + +0) get lm-sensors userspace utils +1) compile all drivers in I2C section as modules in your kernel +2) run sensors-detect script, it will tell you what modules you need to load. +3) load them and run "sensors" command, you should see some results. +4) fix sensors.conf, labels, limits, fan divisors +5) if any more problems consult FAQ, or documentation + +Other utilites +-------------- + +If you want some graphical indicators of system health look for applications +like: gkrellm, ksensors, xsensors, wmtemp, wmsensors, wmgtemp, ksysguardd, +hardware-monitor + +If you are server administrator you can try snmpd or mrtgutils. diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index ad27511..f482dae 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -171,45 +171,31 @@ The following lists are used internally: normal_i2c: filled in by the module writer. A list of I2C addresses which should normally be examined. - normal_i2c_range: filled in by the module writer. - A list of pairs of I2C addresses, each pair being an inclusive range of - addresses which should normally be examined. probe: insmod parameter. A list of pairs. The first value is a bus number (-1 for any I2C bus), the second is the address. These addresses are also probed, as if they were in the 'normal' list. - probe_range: insmod parameter. - A list of triples. The first value is a bus number (-1 for any I2C bus), - the second and third are addresses. These form an inclusive range of - addresses that are also probed, as if they were in the 'normal' list. ignore: insmod parameter. A list of pairs. The first value is a bus number (-1 for any I2C bus), the second is the I2C address. These addresses are never probed. This parameter overrules 'normal' and 'probe', but not the 'force' lists. - ignore_range: insmod parameter. - A list of triples. The first value is a bus number (-1 for any I2C bus), - the second and third are addresses. These form an inclusive range of - I2C addresses that are never probed. - This parameter overrules 'normal' and 'probe', but not the 'force' lists. force: insmod parameter. A list of pairs. The first value is a bus number (-1 for any I2C bus), the second is the I2C address. A device is blindly assumed to be on the given address, no probing is done. -Fortunately, as a module writer, you just have to define the `normal' -and/or `normal_range' parameters. The complete declaration could look -like this: +Fortunately, as a module writer, you just have to define the `normal_i2c' +parameter. The complete declaration could look like this: - /* Scan 0x20 to 0x2f, 0x37, and 0x40 to 0x4f */ - static unsigned short normal_i2c[] = { 0x37,I2C_CLIENT_END }; - static unsigned short normal_i2c_range[] = { 0x20, 0x2f, 0x40, 0x4f, - I2C_CLIENT_END }; + /* Scan 0x37, and 0x48 to 0x4f */ + static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; /* Magic definition of all other variables and things */ I2C_CLIENT_INSMOD; -Note that you *have* to call the two defined variables `normal_i2c' and -`normal_i2c_range', without any prefix! +Note that you *have* to call the defined variable `normal_i2c', +without any prefix! Probing classes (sensors) @@ -223,39 +209,17 @@ The following lists are used internally. They are all lists of integers. normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END. A list of I2C addresses which should normally be examined. - normal_i2c_range: filled in by the module writer. Terminated by - SENSORS_I2C_END - A list of pairs of I2C addresses, each pair being an inclusive range of - addresses which should normally be examined. normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END. A list of ISA addresses which should normally be examined. - normal_isa_range: filled in by the module writer. Terminated by - SENSORS_ISA_END - A list of triples. The first two elements are ISA addresses, being an - range of addresses which should normally be examined. The third is the - modulo parameter: only addresses which are 0 module this value relative - to the first address of the range are actually considered. probe: insmod parameter. Initialize this list with SENSORS_I2C_END values. A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for the ISA bus, -1 for any I2C bus), the second is the address. These addresses are also probed, as if they were in the 'normal' list. - probe_range: insmod parameter. Initialize this list with SENSORS_I2C_END - values. - A list of triples. The first value is a bus number (SENSORS_ISA_BUS for - the ISA bus, -1 for any I2C bus), the second and third are addresses. - These form an inclusive range of addresses that are also probed, as - if they were in the 'normal' list. ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values. A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for the ISA bus, -1 for any I2C bus), the second is the I2C address. These addresses are never probed. This parameter overrules 'normal' and 'probe', but not the 'force' lists. - ignore_range: insmod parameter. Initialize this list with SENSORS_I2C_END - values. - A list of triples. The first value is a bus number (SENSORS_ISA_BUS for - the ISA bus, -1 for any I2C bus), the second and third are addresses. - These form an inclusive range of I2C addresses that are never probed. - This parameter overrules 'normal' and 'probe', but not the 'force' lists. Also used is a list of pointers to sensors_force_data structures: force_data: insmod parameters. A list, ending with an element of which @@ -269,16 +233,14 @@ Also used is a list of pointers to sensors_force_data structures: So we have a generic insmod variabled `force', and chip-specific variables `force_CHIPNAME'. -Fortunately, as a module writer, you just have to define the `normal' -and/or `normal_range' parameters, and define what chip names are used. +Fortunately, as a module writer, you just have to define the `normal_i2c' +and `normal_isa' parameters, and define what chip names are used. The complete declaration could look like this: - /* Scan i2c addresses 0x20 to 0x2f, 0x37, and 0x40 to 0x4f - static unsigned short normal_i2c[] = {0x37,SENSORS_I2C_END}; - static unsigned short normal_i2c_range[] = {0x20,0x2f,0x40,0x4f, - SENSORS_I2C_END}; + /* Scan i2c addresses 0x37, and 0x48 to 0x4f */ + static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; /* Scan ISA address 0x290 */ static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END}; - static unsigned int normal_isa_range[] = {SENSORS_ISA_END}; /* Define chips foo and bar, as well as all module parameters and things */ SENSORS_INSMOD_2(foo,bar); diff --git a/MAINTAINERS b/MAINTAINERS index 0f88a70..4d44824 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -194,7 +194,7 @@ S: Maintained ADM1025 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained ADT746X FAN DRIVER @@ -242,7 +242,7 @@ S: Maintained ALI1563 I2C DRIVER P: Rudolf Marek M: r.marek@sh.cvut.cz -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained ALPHA PORT @@ -1002,7 +1002,7 @@ P: Greg Kroah-Hartman M: greg@kroah.com P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org W: http://www.lm-sensors.nu/ S: Maintained @@ -1430,13 +1430,13 @@ S: Supported LM83 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained LM90 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks) @@ -2075,7 +2075,7 @@ S: Maintained SMSC47M1 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Odd Fixes SMB FILESYSTEM @@ -2614,7 +2614,7 @@ S: Orphan W1 DALLAS'S 1-WIRE BUS P: Evgeniy Polyakov M: johnpol@2ka.mipt.ru -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Maintained W83L51xD SD/MMC CARD INTERFACE DRIVER @@ -2627,7 +2627,7 @@ S: Maintained W83L785TS HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org -L: sensors@stimpy.netroedge.com +L: lm-sensors@lm-sensors.org S: Odd Fixes WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c index 86ca5cf..37ece15 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.c +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c @@ -185,6 +185,26 @@ mpc834x_sys_init_IRQ(void) ipic_set_default_priority(); } +#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374) +extern ulong ds1374_get_rtc_time(void); +extern int ds1374_set_rtc_time(ulong); + +static int __init +mpc834x_rtc_hookup(void) +{ + struct timespec tv; + + ppc_md.get_rtc_time = ds1374_get_rtc_time; + ppc_md.set_rtc_time = ds1374_set_rtc_time; + + tv.tv_nsec = 0; + tv.tv_sec = (ppc_md.get_rtc_time)(); + do_settimeofday(&tv); + + return 0; +} +late_initcall(mpc834x_rtc_hookup); +#endif static __inline__ void mpc834x_sys_set_bat(void) { diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c index ad7ae7a..141b4c2 100644 --- a/drivers/acorn/char/pcf8583.c +++ b/drivers/acorn/char/pcf8583.c @@ -26,11 +26,8 @@ static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, - .normal_i2c_range = ignore, .probe = ignore, - .probe_range = ignore, .ignore = ignore, - .ignore_range = ignore, .force = ignore, }; diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index c3d912c..cc3a952 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -49,7 +49,7 @@ static int i2c_debug=0; /* * Generate a start condition on the i2c bus. * - * returns after the start condition has occured + * returns after the start condition has occurred */ static void pca_start(struct i2c_algo_pca_data *adap) { @@ -62,9 +62,9 @@ static void pca_start(struct i2c_algo_pca_data *adap) } /* - * Generate a repeated start condition on the i2c bus + * Generate a repeated start condition on the i2c bus * - * return after the repeated start condition has occured + * return after the repeated start condition has occurred */ static void pca_repeated_start(struct i2c_algo_pca_data *adap) { @@ -82,7 +82,7 @@ static void pca_repeated_start(struct i2c_algo_pca_data *adap) * returns after the stop condition has been generated * * STOPs do not generate an interrupt or set the SI flag, since the - * part returns the the idle state (0xf8). Hence we don't need to + * part returns the idle state (0xf8). Hence we don't need to * pca_wait here. */ static void pca_stop(struct i2c_algo_pca_data *adap) diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c index 35789bb..f278549 100644 --- a/drivers/i2c/algos/i2c-algo-sibyte.c +++ b/drivers/i2c/algos/i2c-algo-sibyte.c @@ -24,7 +24,6 @@ /* Ported for SiByte SOCs by Broadcom Corporation. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a0018de..916ba5e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -7,7 +7,7 @@ menu "I2C Hardware Bus support" config I2C_ALI1535 tristate "ALI 1535" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB @@ -31,7 +31,7 @@ config I2C_ALI1563 config I2C_ALI15X3 tristate "ALI 15x3" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. @@ -41,7 +41,7 @@ config I2C_ALI15X3 config I2C_AMD756 tristate "AMD 756/766/768/8111 and nVidia nForce" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the AMD 756/766/768 mainboard I2C interfaces. The driver also includes @@ -66,7 +66,7 @@ config I2C_AMD756_S4882 config I2C_AMD8111 tristate "AMD 8111" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the second (SMBus 2.0) AMD 8111 mainboard I2C interface. @@ -109,7 +109,7 @@ config I2C_HYDRA config I2C_I801 tristate "Intel 82801 (ICH)" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following @@ -130,7 +130,7 @@ config I2C_I801 config I2C_I810 tristate "Intel 810/815" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the Intel @@ -183,7 +183,7 @@ config I2C_IOP3XX config I2C_ISA tristate "ISA Bus support" - depends on I2C && EXPERIMENTAL + depends on I2C help If you say yes to this option, support will be included for i2c interfaces that are on the ISA bus. @@ -248,12 +248,11 @@ config I2C_MPC will be called i2c-mpc. config I2C_NFORCE2 - tristate "Nvidia Nforce2" - depends on I2C && PCI && EXPERIMENTAL + tristate "Nvidia nForce2, nForce3 and nForce4" + depends on I2C && PCI help If you say yes to this option, support will be included for the Nvidia - Nforce2 family of mainboard I2C interfaces. - This driver also supports the nForce3 Pro 150 MCP. + nForce2, nForce3 and nForce4 families of mainboard I2C interfaces. This driver can also be built as a module. If so, the module will be called i2c-nforce2. @@ -305,7 +304,7 @@ config I2C_PARPORT_LIGHT config I2C_PROSAVAGE tristate "S3/VIA (Pro)Savage" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -388,7 +387,7 @@ config SCx200_ACB config I2C_SIS5595 tristate "SiS 5595" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the SiS5595 SMBus (a subset of I2C) interface. @@ -398,7 +397,7 @@ config I2C_SIS5595 config I2C_SIS630 tristate "SiS 630/730" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the SiS630 and SiS730 SMBus (a subset of I2C) interface. @@ -408,7 +407,7 @@ config I2C_SIS630 config I2C_SIS96X tristate "SiS 96x" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the SiS 96x SMBus (a subset of I2C) interfaces. Specifically, the following @@ -419,6 +418,7 @@ config I2C_SIS96X 648/961 650/961 735 + 745 This driver can also be built as a module. If so, the module will be called i2c-sis96x. @@ -449,7 +449,7 @@ config I2C_VIA config I2C_VIAPRO tristate "VIA 82C596/82C686/823x" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI help If you say yes to this option, support will be included for the VIA 82C596/82C686/823x I2C interfaces. Specifically, the following @@ -467,7 +467,7 @@ config I2C_VIAPRO config I2C_VOODOO3 tristate "Voodoo 3" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index b00cd40..f634a07 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -53,7 +53,6 @@ /* Note: we assume there can only be one ALI1535, with one SMBus interface */ -#include <linux/config.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 5bd6a4a..0f781a1 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -60,7 +60,6 @@ /* Note: we assume there can only be one ALI15X3, with one SMBus interface */ -#include <linux/config.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index eca5ed3..6347ebc 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -37,7 +37,6 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index af22b40..d664448 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -8,7 +8,6 @@ * the Free Software Foundation version 2. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 75831a20..a7ff112 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -27,7 +27,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <linux/config.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 0a77200..6930b66 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -25,7 +25,6 @@ /* Partialy rewriten by Oleg I. Vdovikin for mmapped support of for Alpha Processor Inc. UP-2000(+) boards */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> diff --git a/drivers/i2c/busses/i2c-frodo.c b/drivers/i2c/busses/i2c-frodo.c index e093829..b6f52f5 100644 --- a/drivers/i2c/busses/i2c-frodo.c +++ b/drivers/i2c/busses/i2c-frodo.c @@ -12,7 +12,6 @@ * version 2 as published by the Free Software Foundation. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 59c238c..45e6efb1 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -41,7 +41,6 @@ /* Note: we assume there can only be one I801, with one SMBus interface */ -#include <linux/config.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index ef358bd..0ff7016 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -34,7 +34,6 @@ i815 1132 */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index bb88521..93ca36d 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -695,7 +695,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ dev->irq = iic_force_poll ? -1 : ocp->def->irq; if (dev->irq >= 0){ - /* Disable interrupts until we finish intialization, + /* Disable interrupts until we finish initialization, assumes level-sensitive IRQ setup... */ iic_interrupt_mode(dev, 0); diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h index d819a95..2b3219d 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.h +++ b/drivers/i2c/busses/i2c-ibm_iic.h @@ -22,7 +22,6 @@ #ifndef __I2C_IBM_IIC_H_ #define __I2C_IBM_IIC_H_ -#include <linux/config.h> #include <linux/i2c.h> struct iic_regs { diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index c961ba4..6b682e9 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -85,7 +85,7 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE; /* - * Everytime unit enable is asserted, GPOD needs to be cleared + * Every time unit enable is asserted, GPOD needs to be cleared * on IOP321 to avoid data corruption on the bus. */ #ifdef CONFIG_ARCH_IOP321 diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 0f54a2a..00e7f71 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -24,7 +24,6 @@ the SMBus and the ISA bus very much easier. See lm78.c for an example of this. */ -#include <linux/config.h> #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c index 702e3de..5f5d294 100644 --- a/drivers/i2c/busses/i2c-ite.c +++ b/drivers/i2c/busses/i2c-ite.c @@ -33,7 +33,6 @@ /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even Frodo Looijaard <frodol@dds.nl> */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index 21cd54d..ec943ca 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -26,11 +26,6 @@ * 'enabled' to drive the GPIOs. */ -#include <linux/config.h> -#ifdef CONFIG_I2C_DEBUG_BUS -#define DEBUG 1 -#endif - #include <linux/kernel.h> #include <linux/init.h> #include <linux/device.h> diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 8c55eaf..f6f5ca3 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -26,11 +26,6 @@ * that is passed as the platform_data to this driver. */ -#include <linux/config.h> -#ifdef CONFIG_I2C_DEBUG_BUS -#define DEBUG 1 -#endif - #include <linux/kernel.h> #include <linux/init.h> #include <linux/device.h> diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index 867d443..363e545 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -46,7 +46,6 @@ sound driver to be happy */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/ioport.h> diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 6f33496..d41ca31 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -325,7 +325,7 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) if (i2c->irq != OCP_IRQ_NA) { if ((result = request_irq(ocp->def->irq, mpc_i2c_isr, - 0, "i2c-mpc", i2c)) < 0) { + SA_SHIRQ, "i2c-mpc", i2c)) < 0) { printk(KERN_ERR "i2c-mpc - failed to attach interrupt\n"); goto fail_irq; @@ -333,6 +333,9 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) } else i2c->irq = 0; + mpc_i2c_setclock(i2c); + ocp_set_drvdata(ocp, i2c); + i2c->adap = mpc_ops; i2c_set_adapdata(&i2c->adap, i2c); @@ -341,8 +344,6 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) goto fail_add; } - mpc_i2c_setclock(i2c); - ocp_set_drvdata(ocp, i2c); return result; fail_add: @@ -358,8 +359,8 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp) static void __devexit mpc_i2c_remove(struct ocp_device *ocp) { struct mpc_i2c *i2c = ocp_get_drvdata(ocp); - ocp_set_drvdata(ocp, NULL); i2c_del_adapter(&i2c->adap); + ocp_set_drvdata(ocp, NULL); if (ocp->def->irq != OCP_IRQ_NA) free_irq(i2c->irq, i2c); @@ -424,12 +425,15 @@ static int fsl_i2c_probe(struct device *device) if (i2c->irq != 0) if ((result = request_irq(i2c->irq, mpc_i2c_isr, - 0, "fsl-i2c", i2c)) < 0) { + SA_SHIRQ, "i2c-mpc", i2c)) < 0) { printk(KERN_ERR "i2c-mpc - failed to attach interrupt\n"); goto fail_irq; } + mpc_i2c_setclock(i2c); + dev_set_drvdata(device, i2c); + i2c->adap = mpc_ops; i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent = &pdev->dev; @@ -438,8 +442,6 @@ static int fsl_i2c_probe(struct device *device) goto fail_add; } - mpc_i2c_setclock(i2c); - dev_set_drvdata(device, i2c); return result; fail_add: @@ -456,8 +458,8 @@ static int fsl_i2c_remove(struct device *device) { struct mpc_i2c *i2c = dev_get_drvdata(device); - dev_set_drvdata(device, NULL); i2c_del_adapter(&i2c->adap); + dev_set_drvdata(device, NULL); if (i2c->irq != 0) free_irq(i2c->irq, i2c); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 6d13127..74eb89a 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -37,7 +37,6 @@ /* Note: we assume there can only be one nForce2, with two SMBus interfaces */ -#include <linux/config.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index cb5e722..3e5eba9 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -24,7 +24,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ------------------------------------------------------------------------ */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index e9560ba..71a2502 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -24,7 +24,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ------------------------------------------------------------------------ */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -131,7 +130,7 @@ static int parport_getsda(void *data) /* Encapsulate the functions above in the correct structure. Note that this is only a template, from which the real structures are copied. The attaching code will set getscl to NULL for adapters that - cannot read SCL back, and will also make the the data field point to + cannot read SCL back, and will also make the data field point to the parallel port structure. */ static struct i2c_algo_bit_data parport_algo_data = { .setsda = parport_setsda, diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index 9c61113..d9b4ddb 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -17,7 +17,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 646381b..1f80ba9 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -28,7 +28,6 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/pci.h> diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c index 13d6628..83fd16d 100644 --- a/drivers/i2c/busses/i2c-prosavage.c +++ b/drivers/i2c/busses/i2c-prosavage.c @@ -54,7 +54,6 @@ * (Additional documentation needed :( */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c index 9497b1b..0ebec3c 100644 --- a/drivers/i2c/busses/i2c-rpx.c +++ b/drivers/i2c/busses/i2c-rpx.c @@ -11,7 +11,6 @@ * changed to eliminate RPXLite references. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index fcfa51c..a3b3825 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -20,6 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> @@ -533,7 +534,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int /* s3c24xx_i2c_xfer * * first port of call from the i2c bus code when an message needs - * transfering across the i2c bus. + * transferring across the i2c bus. */ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 092d032..0c85182 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -29,7 +29,6 @@ it easier to add later. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index e5dd90b..1c99536 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -17,7 +17,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/i2c-algo-sibyte.h> #include <asm/sibyte/sb1250_regs.h> diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 425733b..2b5911c 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -55,7 +55,6 @@ * Add adapter resets */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 58df63d..f58455e 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -48,7 +48,6 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 3cac6d4..6484792 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -32,7 +32,6 @@ We assume there can only be one SiS96x with one SMBus interface. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index 19c805e..00d94e8 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -21,7 +21,6 @@ #define DEBUG 1 -#include <linux/config.h> #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 2cbc4cd..040b8ab 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -21,7 +21,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 0bb60a6..6b50080 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -33,7 +33,6 @@ Note: we assume there can only be one device, with one SMBus interface. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/pci.h> diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 3edf0e3..b675773 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -27,7 +27,6 @@ /* This interfaces to the I2C bus of the Voodoo3 to gain access to the BT869 and possibly other I2C devices. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 1c4159a..a18bdd9 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -24,7 +24,6 @@ */ -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 74d23cf..a0982da 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -1,5 +1,5 @@ # -# I2C Sensor device configuration +# I2C Sensor and "other" chip configuration # menu "Hardware Sensors Chip support" @@ -11,7 +11,7 @@ config I2C_SENSOR config SENSORS_ADM1021 tristate "Analog Devices ADM1021 and compatibles" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for Analog Devices ADM1021 @@ -29,6 +29,7 @@ config SENSORS_ADM1025 help If you say yes here you get support for Analog Devices ADM1025 and Philips NE1619 sensor chips. + This driver can also be built as a module. If so, the module will be called adm1025. @@ -38,6 +39,8 @@ config SENSORS_ADM1026 select I2C_SENSOR help If you say yes here you get support for Analog Devices ADM1026 + sensor chip. + This driver can also be built as a module. If so, the module will be called adm1026. @@ -48,9 +51,21 @@ config SENSORS_ADM1031 help If you say yes here you get support for Analog Devices ADM1031 and ADM1030 sensor chips. + This driver can also be built as a module. If so, the module will be called adm1031. +config SENSORS_ADM9240 + tristate "Analog Devices ADM9240 and compatibles" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM9240, + Dallas DS1780, National Semiconductor LM81 sensor chips. + + This driver can also be built as a module. If so, the module + will be called adm9240. + config SENSORS_ASB100 tristate "Asus ASB100 Bach" depends on I2C && EXPERIMENTAL @@ -62,6 +77,19 @@ config SENSORS_ASB100 This driver can also be built as a module. If so, the module will be called asb100. +config SENSORS_ATXP1 + tristate "Attansic ATXP1 VID controller" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Attansic ATXP1 VID + controller. + + If your board have such a chip, you are able to control your CPU + core and other voltages. + + This driver can also be built as a module. If so, the module + will be called atxp1. + config SENSORS_DS1621 tristate "Dallas Semiconductor DS1621 and DS1625" depends on I2C && EXPERIMENTAL @@ -97,7 +125,7 @@ config SENSORS_FSCPOS config SENSORS_GL518SM tristate "Genesys Logic GL518SM" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for Genesys Logic GL518SM @@ -119,7 +147,7 @@ config SENSORS_GL520SM config SENSORS_IT87 tristate "ITE IT87xx and compatibles" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for ITE IT87xx sensor chips @@ -143,7 +171,7 @@ config SENSORS_LM63 config SENSORS_LM75 tristate "National Semiconductor LM75 and compatibles" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for National Semiconductor LM75 @@ -174,8 +202,7 @@ config SENSORS_LM78 select I2C_SENSOR help If you say yes here you get support for National Semiconductor LM78, - LM78-J and LM79. This can also be built as a module which can be - inserted and removed while the kernel is running. + LM78-J and LM79. This driver can also be built as a module. If so, the module will be called lm78. @@ -208,7 +235,7 @@ config SENSORS_LM85 select I2C_SENSOR help If you say yes here you get support for National Semiconductor LM85 - sensor chips and clones: ADT7463 and ADM1027. + sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027. This driver can also be built as a module. If so, the module will be called lm85. @@ -307,14 +334,14 @@ config SENSORS_SMSC47M1 help If you say yes here you get support for the integrated fan monitoring and control capabilities of the SMSC LPC47B27x, - LPC47M10x, LPC47M13x and LPC47M14x chips. + LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips. This driver can also be built as a module. If so, the module will be called smsc47m1. config SENSORS_VIA686A tristate "VIA686A" - depends on I2C && PCI && EXPERIMENTAL + depends on I2C && PCI select I2C_SENSOR select I2C_ISA help @@ -326,7 +353,7 @@ config SENSORS_VIA686A config SENSORS_W83781D tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" - depends on I2C && EXPERIMENTAL + depends on I2C select I2C_SENSOR help If you say yes here you get support for the Winbond W8378x series @@ -360,22 +387,47 @@ config SENSORS_W83627HF This driver can also be built as a module. If so, the module will be called w83627hf. +config SENSORS_W83627EHF + tristate "Winbond W83627EHF" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get preliminary support for the hardware + monitoring functionality of the Winbond W83627EHF Super-I/O chip. + Only fan and temperature inputs are supported at the moment, while + the chip does much more than that. + + This driver can also be built as a module. If so, the module + will be called w83627ehf. + endmenu menu "Other I2C Chip support" depends on I2C config SENSORS_DS1337 - tristate "Dallas Semiconductor DS1337 Real Time Clock" + tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock" depends on I2C && EXPERIMENTAL select I2C_SENSOR help If you say yes here you get support for Dallas Semiconductor - DS1337 real-time clock chips. + DS1337 and DS1339 real-time clock chips. This driver can also be built as a module. If so, the module will be called ds1337. +config SENSORS_DS1374 + tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Dallas Semiconductor + DS1374 real-time clock chips. + + This driver can also be built as a module. If so, the module + will be called ds1374. + config SENSORS_EEPROM tristate "EEPROM reader" depends on I2C && EXPERIMENTAL @@ -399,6 +451,16 @@ config SENSORS_PCF8574 This driver can also be built as a module. If so, the module will be called pcf8574. +config SENSORS_PCA9539 + tristate "Philips PCA9539 16-bit I/O port" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Philips PCA9539 + 16-bit I/O port. + + This driver can also be built as a module. If so, the module + will be called pca9539. + config SENSORS_PCF8591 tristate "Philips PCF8591" depends on I2C && EXPERIMENTAL @@ -431,6 +493,23 @@ config ISP1301_OMAP This driver can also be built as a module. If so, the module will be called isp1301_omap. +# NOTE: This isn't really OMAP-specific, except for the current +# interface location in <include/asm-arm/arch-omap/tps65010.h> +# and having mostly OMAP-specific board support +config TPS65010 + tristate "TPS6501x Power Management chips" + depends on I2C && ARCH_OMAP + default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK + help + If you say yes here you get support for the TPS6501x series of + Power Management chips. These include voltage regulators, + lithium ion/polymer battery charging, and other features that + are often used in portable devices like cell phones and cameras. + + This driver can also be built as a module. If so, the module + will be called tps65010. + + config SENSORS_M41T00 tristate "ST M41T00 RTC chip" depends on I2C && PPC32 @@ -440,4 +519,16 @@ config SENSORS_M41T00 This driver can also be built as a module. If so, the module will be called m41t00. +config SENSORS_MAX6875 + tristate "MAXIM MAX6875 Power supply supervisor" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the MAX6875 + EEPROM-Programmable, Hex/Quad, Power-Suppy Sequencers/Supervisors. + + This provides a interface to program the EEPROM and reset the chip. + + This driver can also be built as a module. If so, the module + will be called max6875. + endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 6559916..b5e6d2f 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the kernel hardware sensors chip drivers. +# Makefile for sensor and "other" I2C chip drivers. # # asb100, then w83781d go first, as they can override other drivers' addresses. @@ -11,7 +11,10 @@ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o +obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o +obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_DS1337) += ds1337.o +obj-$(CONFIG_SENSORS_DS1374) += ds1374.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o obj-$(CONFIG_SENSORS_FSCHER) += fscher.o @@ -30,8 +33,10 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o obj-$(CONFIG_SENSORS_LM90) += lm90.o obj-$(CONFIG_SENSORS_LM92) += lm92.o obj-$(CONFIG_SENSORS_MAX1619) += max1619.o +obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_M41T00) += m41t00.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o +obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o @@ -39,8 +44,11 @@ obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o +obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o + obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o +obj-$(CONFIG_TPS65010) += tps65010.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index 9058c39..d2c774c 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -19,7 +19,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -103,8 +102,6 @@ struct adm1021_data { u8 remote_temp_hyst; u8 remote_temp_input; u8 alarms; - /* special values for ADM1021 only */ - u8 die_code; /* Special values for ADM1023 only */ u8 remote_temp_prec; u8 remote_temp_os_prec; @@ -156,7 +153,6 @@ static ssize_t show_##value(struct device *dev, struct device_attribute *attr, c return sprintf(buf, "%d\n", data->value); \ } show2(alarms); -show2(die_code); #define set(value, reg) \ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ @@ -183,7 +179,6 @@ static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remot static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static DEVICE_ATTR(die_code, S_IRUGO, show_die_code, NULL); static int adm1021_attach_adapter(struct i2c_adapter *adapter) @@ -307,8 +302,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &dev_attr_temp2_min); device_create_file(&new_client->dev, &dev_attr_temp2_input); device_create_file(&new_client->dev, &dev_attr_alarms); - if (data->type == adm1021) - device_create_file(&new_client->dev, &dev_attr_die_code); return 0; @@ -371,8 +364,6 @@ static struct adm1021_data *adm1021_update_device(struct device *dev) data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; - if (data->type == adm1021) - data->die_code = adm1021_read_value(client, ADM1021_REG_DIE_CODE); if (data->type == adm1023) { data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); diff --git a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c index 111f0c8..e452d0d 100644 --- a/drivers/i2c/chips/adm1025.c +++ b/drivers/i2c/chips/adm1025.c @@ -45,7 +45,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -287,7 +286,9 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } +/* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */ static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { @@ -437,7 +438,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &dev_attr_temp1_max); device_create_file(&new_client->dev, &dev_attr_temp2_max); device_create_file(&new_client->dev, &dev_attr_alarms); + /* in1_ref is deprecated, remove after 2005-11-11 */ device_create_file(&new_client->dev, &dev_attr_in1_ref); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); device_create_file(&new_client->dev, &dev_attr_vrm); /* Pin 11 is either in4 (+12V) or VID4 */ diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c index b15fafe..3c85fe1 100644 --- a/drivers/i2c/chips/adm1026.c +++ b/drivers/i2c/chips/adm1026.c @@ -23,15 +23,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/i2c-sensor.h> -#include <linux/i2c-sysfs.h> #include <linux/i2c-vid.h> +#include <linux/hwmon-sysfs.h> /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; @@ -1225,8 +1224,9 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, c struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); } - +/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL); +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) { @@ -1666,7 +1666,9 @@ int adm1026_detect(struct i2c_adapter *adapter, int address, device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); + /* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ device_create_file(&new_client->dev, &dev_attr_vid); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); device_create_file(&new_client->dev, &dev_attr_vrm); device_create_file(&new_client->dev, &dev_attr_alarms); device_create_file(&new_client->dev, &dev_attr_alarm_mask); diff --git a/drivers/i2c/chips/adm1031.c b/drivers/i2c/chips/adm1031.c index 2163dba..9168e98 100644 --- a/drivers/i2c/chips/adm1031.c +++ b/drivers/i2c/chips/adm1031.c @@ -440,7 +440,7 @@ pwm_reg(2); /* * That function checks the cases where the fan reading is not - * relevent. It is used to provide 0 as fan reading when the fan is + * relevant. It is used to provide 0 as fan reading when the fan is * not supposed to run */ static int trust_fan_readings(struct adm1031_data *data, int chan) diff --git a/drivers/i2c/chips/adm9240.c b/drivers/i2c/chips/adm9240.c new file mode 100644 index 0000000..5c68e9c --- /dev/null +++ b/drivers/i2c/chips/adm9240.c @@ -0,0 +1,791 @@ +/* + * adm9240.c Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * + * Copyright (C) 1999 Frodo Looijaard <frodol@dds.nl> + * Philip Edelbrock <phil@netroedge.com> + * Copyright (C) 2003 Michiel Rook <michiel@grendelproject.nl> + * Copyright (C) 2005 Grant Coady <gcoady@gmail.com> with valuable + * guidance from Jean Delvare + * + * Driver supports Analog Devices ADM9240 + * Dallas Semiconductor DS1780 + * National Semiconductor LM81 + * + * ADM9240 is the reference, DS1780 and LM81 are register compatibles + * + * Voltage Six inputs are scaled by chip, VID also reported + * Temperature Chip temperature to 0.5'C, maximum and max_hysteris + * Fans 2 fans, low speed alarm, automatic fan clock divider + * Alarms 16-bit map of active alarms + * Analog Out 0..1250 mV output + * + * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear' + * + * Test hardware: Intel SE440BX-2 desktop motherboard --Grant + * + * LM81 extended temp reading not implemented + * + * 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/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/i2c-sensor.h> +#include <linux/i2c-vid.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, + I2C_CLIENT_END }; + +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_3(adm9240, ds1780, lm81); + +/* ADM9240 registers */ +#define ADM9240_REG_MAN_ID 0x3e +#define ADM9240_REG_DIE_REV 0x3f +#define ADM9240_REG_CONFIG 0x40 + +#define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */ +#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */ +#define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr)) +#define ADM9240_REG_INT(nr) (0x41 + (nr)) +#define ADM9240_REG_INT_MASK(nr) (0x43 + (nr)) +#define ADM9240_REG_TEMP 0x27 +#define ADM9240_REG_TEMP_HIGH 0x39 +#define ADM9240_REG_TEMP_HYST 0x3a +#define ADM9240_REG_ANALOG_OUT 0x19 +#define ADM9240_REG_CHASSIS_CLEAR 0x46 +#define ADM9240_REG_VID_FAN_DIV 0x47 +#define ADM9240_REG_I2C_ADDR 0x48 +#define ADM9240_REG_VID4 0x49 +#define ADM9240_REG_TEMP_CONF 0x4b + +/* generalised scaling with integer rounding */ +static inline int SCALE(long val, int mul, int div) +{ + if (val < 0) + return (val * mul - div / 2) / div; + else + return (val * mul + div / 2) / div; +} + +/* adm9240 internally scales voltage measurements */ +static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 }; + +static inline unsigned int IN_FROM_REG(u8 reg, int n) +{ + return SCALE(reg, nom_mv[n], 192); +} + +static inline u8 IN_TO_REG(unsigned long val, int n) +{ + return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); +} + +/* temperature range: -40..125, 127 disables temperature alarm */ +static inline s8 TEMP_TO_REG(long val) +{ + return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127); +} + +/* two fans, each with low fan speed limit */ +static inline unsigned int FAN_FROM_REG(u8 reg, u8 div) +{ + if (!reg) /* error */ + return -1; + + if (reg == 255) + return 0; + + return SCALE(1350000, 1, reg * div); +} + +/* analog out 0..1250mV */ +static inline u8 AOUT_TO_REG(unsigned long val) +{ + return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255); +} + +static inline unsigned int AOUT_FROM_REG(u8 reg) +{ + return SCALE(reg, 1250, 255); +} + +static int adm9240_attach_adapter(struct i2c_adapter *adapter); +static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm9240_init_client(struct i2c_client *client); +static int adm9240_detach_client(struct i2c_client *client); +static struct adm9240_data *adm9240_update_device(struct device *dev); + +/* driver data */ +static struct i2c_driver adm9240_driver = { + .owner = THIS_MODULE, + .name = "adm9240", + .id = I2C_DRIVERID_ADM9240, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm9240_attach_adapter, + .detach_client = adm9240_detach_client, +}; + +/* per client data */ +struct adm9240_data { + enum chips type; + struct i2c_client client; + struct semaphore update_lock; + char valid; + unsigned long last_updated_measure; + unsigned long last_updated_config; + + u8 in[6]; /* ro in0_input */ + u8 in_max[6]; /* rw in0_max */ + u8 in_min[6]; /* rw in0_min */ + u8 fan[2]; /* ro fan1_input */ + u8 fan_min[2]; /* rw fan1_min */ + u8 fan_div[2]; /* rw fan1_div, read-only accessor */ + s16 temp; /* ro temp1_input, 9-bit sign-extended */ + s8 temp_high; /* rw temp1_max */ + s8 temp_hyst; /* rw temp1_max_hyst */ + u16 alarms; /* ro alarms */ + u8 aout; /* rw aout_output */ + u8 vid; /* ro vid */ + u8 vrm; /* -- vrm set on startup, no accessor */ +}; + +/* i2c byte read/write interface */ +static int adm9240_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/*** sysfs accessors ***/ + +/* temperature */ +#define show_temp(value, scale) \ +static ssize_t show_##value(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct adm9240_data *data = adm9240_update_device(dev); \ + return sprintf(buf, "%d\n", data->value * scale); \ +} +show_temp(temp_high, 1000); +show_temp(temp_hyst, 1000); +show_temp(temp, 500); /* 0.5'C per bit */ + +#define set_temp(value, reg) \ +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 adm9240_data *data = adm9240_update_device(dev); \ + long temp = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(temp); \ + adm9240_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp(temp_high, ADM9240_REG_TEMP_HIGH); +set_temp(temp_hyst, ADM9240_REG_TEMP_HYST); + +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_temp_high, set_temp_high); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); + +/* voltage */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val, nr); + adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val, nr); + adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t show_in##offset(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ +static ssize_t show_in##offset##_min(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t \ +set_in##offset##_min(struct device *dev, \ + struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t \ +set_in##offset##_max(struct device *dev, \ + struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); +show_in_offset(5); + +/* fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + 1 << data->fan_div[nr])); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + 1 << data->fan_div[nr])); +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", 1 << data->fan_div[nr]); +} + +/* write new fan div, callers must hold data->update_lock */ +static void adm9240_write_fan_div(struct i2c_client *client, int nr, + u8 fan_div) +{ + u8 reg, old, shift = (nr + 2) * 2; + + reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + old = (reg >> shift) & 3; + reg &= ~(3 << shift); + reg |= (fan_div << shift); + adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg); + dev_dbg(&client->dev, "fan%d clock divider changed from %u " + "to %u\n", nr + 1, 1 << old, 1 << fan_div); +} + +/* + * set fan speed low limit: + * + * - value is zero: disable fan speed low limit alarm + * + * - value is below fan speed measurement range: enable fan speed low + * limit alarm to be asserted while fan speed too slow to measure + * + * - otherwise: select fan clock divider to suit fan speed low limit, + * measurement code may adjust registers to ensure fan speed reading + */ +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + u8 new_div; + + down(&data->update_lock); + + if (!val) { + data->fan_min[nr] = 255; + new_div = data->fan_div[nr]; + + dev_dbg(&client->dev, "fan%u low limit set disabled\n", + nr + 1); + + } else if (val < 1350000 / (8 * 254)) { + new_div = 3; + data->fan_min[nr] = 254; + + dev_dbg(&client->dev, "fan%u low limit set minimum %u\n", + nr + 1, FAN_FROM_REG(254, 1 << new_div)); + + } else { + unsigned int new_min = 1350000 / val; + + new_div = 0; + while (new_min > 192 && new_div < 3) { + new_div++; + new_min /= 2; + } + if (!new_min) /* keep > 0 */ + new_min++; + + data->fan_min[nr] = new_min; + + dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n", + nr + 1, FAN_FROM_REG(new_min, 1 << new_div)); + } + + if (new_div != data->fan_div[nr]) { + data->fan_div[nr] = new_div; + adm9240_write_fan_div(client, nr, new_div); + } + adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr), + data->fan_min[nr]); + + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ +return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ +return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ +return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ +return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan_##offset, NULL); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_fan_##offset##_div, NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +show_fan_offset(1); +show_fan_offset(2); + +/* alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* vid */ +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +/* analog output */ +static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); +} + +static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->aout = AOUT_TO_REG(val); + adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout); + up(&data->update_lock); + return count; +} +static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); + +/* chassis_clear */ +static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long val = simple_strtol(buf, NULL, 10); + + if (val == 1) { + adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); + } + return count; +} +static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); + + +/*** sensor chip detect and driver install ***/ + +static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct adm9240_data *data; + int err = 0; + const char *name = ""; + u8 man_id, die_rev; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct adm9240_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm9240_driver; + new_client->flags = 0; + + if (kind == 0) { + kind = adm9240; + } + + if (kind < 0) { + + /* verify chip: reg address should match i2c address */ + if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR) + != address) { + dev_err(&adapter->dev, "detect fail: address match, " + "0x%02x\n", address); + goto exit_free; + } + + /* check known chip manufacturer */ + man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID); + + if (man_id == 0x23) { + kind = adm9240; + } else if (man_id == 0xda) { + kind = ds1780; + } else if (man_id == 0x01) { + kind = lm81; + } else { + dev_err(&adapter->dev, "detect fail: unknown manuf, " + "0x%02x\n", man_id); + goto exit_free; + } + + /* successful detect, print chip info */ + die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV); + dev_info(&adapter->dev, "found %s revision %u\n", + man_id == 0x23 ? "ADM9240" : + man_id == 0xda ? "DS1780" : "LM81", die_rev); + } + + /* either forced or detected chip kind */ + if (kind == adm9240) { + name = "adm9240"; + } else if (kind == ds1780) { + name = "ds1780"; + } else if (kind == lm81) { + name = "lm81"; + } + + /* fill in the remaining client fields and attach */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->type = kind; + init_MUTEX(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + adm9240_init_client(new_client); + + /* populate sysfs filesystem */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_aout_output); + device_create_file(&new_client->dev, &dev_attr_chassis_clear); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + return 0; +exit_free: + kfree(new_client); +exit: + return err; +} + +static int adm9240_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm9240_detect); +} + +static int adm9240_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static void adm9240_init_client(struct i2c_client *client) +{ + struct adm9240_data *data = i2c_get_clientdata(client); + u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG); + u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3; + + data->vrm = i2c_which_vrm(); /* need this to report vid as mV */ + + dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10, + data->vrm % 10); + + if (conf & 1) { /* measurement cycle running: report state */ + + dev_info(&client->dev, "status: config 0x%02x mode %u\n", + conf, mode); + + } else { /* cold start: open limits before starting chip */ + int i; + + for (i = 0; i < 6; i++) + { + adm9240_write_value(client, + ADM9240_REG_IN_MIN(i), 0); + adm9240_write_value(client, + ADM9240_REG_IN_MAX(i), 255); + } + adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255); + adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255); + adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127); + adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127); + + /* start measurement cycle */ + adm9240_write_value(client, ADM9240_REG_CONFIG, 1); + + dev_info(&client->dev, "cold start: config was 0x%02x " + "mode %u\n", conf, mode); + } +} + +static struct adm9240_data *adm9240_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + /* minimum measurement cycle: 1.75 seconds */ + if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) + || !data->valid) { + + for (i = 0; i < 6; i++) /* read voltages */ + { + data->in[i] = adm9240_read_value(client, + ADM9240_REG_IN(i)); + } + data->alarms = adm9240_read_value(client, + ADM9240_REG_INT(0)) | + adm9240_read_value(client, + ADM9240_REG_INT(1)) << 8; + + /* read temperature: assume temperature changes less than + * 0.5'C per two measurement cycles thus ignore possible + * but unlikely aliasing error on lsb reading. --Grant */ + data->temp = ((adm9240_read_value(client, + ADM9240_REG_TEMP) << 8) | + adm9240_read_value(client, + ADM9240_REG_TEMP_CONF)) / 128; + + for (i = 0; i < 2; i++) /* read fans */ + { + data->fan[i] = adm9240_read_value(client, + ADM9240_REG_FAN(i)); + + /* adjust fan clock divider on overflow */ + if (data->valid && data->fan[i] == 255 && + data->fan_div[i] < 3) { + + adm9240_write_fan_div(client, i, + ++data->fan_div[i]); + + /* adjust fan_min if active, but not to 0 */ + if (data->fan_min[i] < 255 && + data->fan_min[i] >= 2) + data->fan_min[i] /= 2; + } + } + data->last_updated_measure = jiffies; + } + + /* minimum config reading cycle: 300 seconds */ + if (time_after(jiffies, data->last_updated_config + (HZ * 300)) + || !data->valid) { + + for (i = 0; i < 6; i++) + { + data->in_min[i] = adm9240_read_value(client, + ADM9240_REG_IN_MIN(i)); + data->in_max[i] = adm9240_read_value(client, + ADM9240_REG_IN_MAX(i)); + } + for (i = 0; i < 2; i++) + { + data->fan_min[i] = adm9240_read_value(client, + ADM9240_REG_FAN_MIN(i)); + } + data->temp_high = adm9240_read_value(client, + ADM9240_REG_TEMP_HIGH); + data->temp_hyst = adm9240_read_value(client, + ADM9240_REG_TEMP_HYST); + + /* read fan divs and 5-bit VID */ + i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + data->fan_div[0] = (i >> 4) & 3; + data->fan_div[1] = (i >> 6) & 3; + data->vid = i & 0x0f; + data->vid |= (adm9240_read_value(client, + ADM9240_REG_VID4) & 1) << 4; + /* read analog out */ + data->aout = adm9240_read_value(client, + ADM9240_REG_ANALOG_OUT); + + data->last_updated_config = jiffies; + data->valid = 1; + } + up(&data->update_lock); + 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_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, " + "Grant Coady <gcoady@gmail.com> and others"); +MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_adm9240_init); +module_exit(sensors_adm9240_exit); + diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c index 4a47b44..70d996d 100644 --- a/drivers/i2c/chips/asb100.c +++ b/drivers/i2c/chips/asb100.c @@ -42,6 +42,7 @@ #include <linux/i2c-sensor.h> #include <linux/i2c-vid.h> #include <linux/init.h> +#include <linux/jiffies.h> #include "lm75.h" /* @@ -168,8 +169,6 @@ static int ASB100_PWM_FROM_REG(u8 reg) return reg * 16; } -#define ALARMS_FROM_REG(val) (val) - #define DIV_FROM_REG(val) (1 << (val)) /* FAN DIV: 1, 2, 4, or 8 (defaults to 2) @@ -556,7 +555,7 @@ device_create_file(&client->dev, &dev_attr_vrm); static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); diff --git a/drivers/i2c/chips/atxp1.c b/drivers/i2c/chips/atxp1.c new file mode 100644 index 0000000..5c6597a --- /dev/null +++ b/drivers/i2c/chips/atxp1.c @@ -0,0 +1,361 @@ +/* + 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> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/i2c-sensor.h> +#include <linux/i2c-vid.h> + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); +MODULE_VERSION("0.6.2"); +MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>"); + +#define ATXP1_VID 0x00 +#define ATXP1_CVID 0x01 +#define ATXP1_GPIO1 0x06 +#define ATXP1_GPIO2 0x0a +#define ATXP1_VIDENA 0x20 +#define ATXP1_VIDMASK 0x1f +#define ATXP1_GPIO1MASK 0x0f + +static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +SENSORS_INSMOD_1(atxp1); + +static int atxp1_attach_adapter(struct i2c_adapter * adapter); +static int atxp1_detach_client(struct i2c_client * client); +static struct atxp1_data * atxp1_update_device(struct device *dev); +static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind); + +static struct i2c_driver atxp1_driver = { + .owner = THIS_MODULE, + .name = "atxp1", + .flags = I2C_DF_NOTIFY, + .attach_adapter = atxp1_attach_adapter, + .detach_client = atxp1_detach_client, +}; + +struct atxp1_data { + struct i2c_client client; + struct semaphore update_lock; + unsigned long last_updated; + u8 valid; + struct { + u8 vid; /* VID output register */ + u8 cpu_vid; /* VID input from CPU */ + u8 gpio1; /* General purpose I/O register 1 */ + u8 gpio2; /* General purpose I/O register 2 */ + } reg; + u8 vrm; /* Detected CPU VRM */ +}; + +static struct atxp1_data * atxp1_update_device(struct device *dev) +{ + struct i2c_client *client; + struct atxp1_data *data; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ) || + (jiffies < data->last_updated) || + !data->valid) { + + /* 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.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); + data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); + + data->valid = 1; + } + + up(&data->update_lock); + + return(data); +} + +/* sys file functions for cpu0_vid */ +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)); + + return size; +} + +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; + char vid; + char cvid; + unsigned int vcore; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + vcore = simple_strtoul(buf, NULL, 10); + vcore /= 25; + vcore *= 25; + + /* Calculate VID */ + vid = vid_to_reg(vcore, data->vrm); + + if (vid < 0) { + dev_err(dev, "VID calculation failed.\n"); + return -1; + } + + /* If output enabled, use control register value. Otherwise original CPU VID */ + if (data->reg.vid & ATXP1_VIDENA) + cvid = data->reg.vid & ATXP1_VIDMASK; + else + cvid = data->reg.cpu_vid; + + /* Nothing changed, aborting */ + if (vid == cvid) + return count; + + dev_info(dev, "Setting VCore to %d mV (0x%02x)\n", 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); + } + } + + data->valid = 0; + + return count; +} + +/* CPU core reference voltage + unit: millivolt +*/ +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) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK); + + return size; +} + +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; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + value = simple_strtoul(buf, NULL, 16); + + value &= ATXP1_GPIO1MASK; + + if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { + dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + + i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); + + data->valid = 0; + } + + return count; +} + +/* 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) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "0x%02x\n", data->reg.gpio2); + + return size; +} + +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; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + value = simple_strtoul(buf, NULL, 16) & 0xff; + + if (value != data->reg.gpio2) { + dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + + i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); + + data->valid = 0; + } + + return count; +} + +/* GPIO2 data register + unit: Eight bit as hex (e.g. 0xff) +*/ +static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); + + +static int atxp1_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, &atxp1_detect); +}; + +static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client * new_client; + struct atxp1_data * data; + int err = 0; + u8 temp; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(data, 0, sizeof(struct atxp1_data)); + new_client = &data->client; + i2c_set_clientdata(new_client, data); + + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &atxp1_driver; + new_client->flags = 0; + + /* Detect ATXP1, checking if vendor ID registers are all zero */ + if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && + (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && + (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && + (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) { + + /* 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) && + (i2c_smbus_read_byte_data(new_client, 0x11) == temp) )) + goto exit_free; + } + + /* Get VRM */ + data->vrm = i2c_which_vrm(); + + if ((data->vrm != 90) && (data->vrm != 91)) { + dev_err(&new_client->dev, "Not supporting VRM %d.%d\n", + data->vrm / 10, data->vrm % 10); + goto exit_free; + } + + strncpy(new_client->name, "atxp1", I2C_NAME_SIZE); + + data->valid = 0; + + init_MUTEX(&data->update_lock); + + err = i2c_attach_client(new_client); + + if (err) + { + dev_err(&new_client->dev, "Attach client error.\n"); + goto exit_free; + } + + device_create_file(&new_client->dev, &dev_attr_gpio1); + device_create_file(&new_client->dev, &dev_attr_gpio2); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + dev_info(&new_client->dev, "Using VRM: %d.%d\n", + data->vrm / 10, data->vrm % 10); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +}; + +static int atxp1_detach_client(struct i2c_client * client) +{ + int err; + + err = i2c_detach_client(client); + + if (err) + dev_err(&client->dev, "Failed to detach client.\n"); + else + kfree(i2c_get_clientdata(client)); + + return err; +}; + +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); diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 07f16c3..74ece8a 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -3,17 +3,16 @@ * * Copyright (C) 2005 James Chapman <jchapman@katalix.com> * - * based on linux/drivers/acron/char/pcf8583.c + * based on linux/drivers/acorn/char/pcf8583.c * Copyright (C) 2000 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Driver for Dallas Semiconductor DS1337 real time clock chip + * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -69,13 +68,11 @@ static struct i2c_driver ds1337_driver = { struct ds1337_data { struct i2c_client client; struct list_head list; - int id; }; /* * Internal variables */ -static int ds1337_id; static LIST_HEAD(ds1337_clients); static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) @@ -95,7 +92,6 @@ static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) */ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) { - struct ds1337_data *data = i2c_get_clientdata(client); int result; u8 buf[7]; u8 val; @@ -103,9 +99,7 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) u8 offs = 0; if (!dt) { - dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n", - __FUNCTION__); - + dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); return -EINVAL; } @@ -119,98 +113,86 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) msg[1].len = sizeof(buf); msg[1].buf = &buf[0]; - result = client->adapter->algo->master_xfer(client->adapter, - &msg[0], 2); + result = i2c_transfer(client->adapter, msg, 2); - dev_dbg(&client->adapter->dev, - "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", + dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", __FUNCTION__, result, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - if (result >= 0) { - dt->tm_sec = BCD_TO_BIN(buf[0]); - dt->tm_min = BCD_TO_BIN(buf[1]); + if (result == 2) { + dt->tm_sec = BCD2BIN(buf[0]); + dt->tm_min = BCD2BIN(buf[1]); val = buf[2] & 0x3f; - dt->tm_hour = BCD_TO_BIN(val); - dt->tm_wday = BCD_TO_BIN(buf[3]) - 1; - dt->tm_mday = BCD_TO_BIN(buf[4]); + dt->tm_hour = BCD2BIN(val); + dt->tm_wday = BCD2BIN(buf[3]) - 1; + dt->tm_mday = BCD2BIN(buf[4]); val = buf[5] & 0x7f; - dt->tm_mon = BCD_TO_BIN(val); - dt->tm_year = 1900 + BCD_TO_BIN(buf[6]); + dt->tm_mon = BCD2BIN(val) - 1; + dt->tm_year = BCD2BIN(buf[6]); if (buf[5] & 0x80) dt->tm_year += 100; - dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, " + dev_dbg(&client->dev, "%s: secs=%d, mins=%d, " "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, dt->tm_sec, dt->tm_min, dt->tm_hour, dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); - } else { - dev_err(&client->adapter->dev, "ds1337[%d]: error reading " - "data! %d\n", data->id, result); - result = -EIO; + + return 0; } - return result; + dev_err(&client->dev, "error reading data! %d\n", result); + return -EIO; } static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) { - struct ds1337_data *data = i2c_get_clientdata(client); int result; u8 buf[8]; u8 val; struct i2c_msg msg[1]; if (!dt) { - dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n", - __FUNCTION__); - + dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); return -EINVAL; } - dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, hours=%d, " + dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, dt->tm_sec, dt->tm_min, dt->tm_hour, dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); buf[0] = 0; /* reg offset */ - buf[1] = BIN_TO_BCD(dt->tm_sec); - buf[2] = BIN_TO_BCD(dt->tm_min); - buf[3] = BIN_TO_BCD(dt->tm_hour) | (1 << 6); - buf[4] = BIN_TO_BCD(dt->tm_wday) + 1; - buf[5] = BIN_TO_BCD(dt->tm_mday); - buf[6] = BIN_TO_BCD(dt->tm_mon); - if (dt->tm_year >= 2000) { - val = dt->tm_year - 2000; + buf[1] = BIN2BCD(dt->tm_sec); + buf[2] = BIN2BCD(dt->tm_min); + buf[3] = BIN2BCD(dt->tm_hour) | (1 << 6); + buf[4] = BIN2BCD(dt->tm_wday) + 1; + buf[5] = BIN2BCD(dt->tm_mday); + buf[6] = BIN2BCD(dt->tm_mon) + 1; + val = dt->tm_year; + if (val >= 100) { + val -= 100; buf[6] |= (1 << 7); - } else { - val = dt->tm_year - 1900; } - buf[7] = BIN_TO_BCD(val); + buf[7] = BIN2BCD(val); msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = sizeof(buf); msg[0].buf = &buf[0]; - result = client->adapter->algo->master_xfer(client->adapter, - &msg[0], 1); - if (result < 0) { - dev_err(&client->adapter->dev, "ds1337[%d]: error " - "writing data! %d\n", data->id, result); - result = -EIO; - } else { - result = 0; - } + result = i2c_transfer(client->adapter, msg, 1); + if (result == 1) + return 0; - return result; + dev_err(&client->dev, "error writing data! %d\n", result); + return -EIO; } static int ds1337_command(struct i2c_client *client, unsigned int cmd, void *arg) { - dev_dbg(&client->adapter->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); + dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); switch (cmd) { case DS1337_GET_DATE: @@ -228,7 +210,7 @@ static int ds1337_command(struct i2c_client *client, unsigned int cmd, * Public API for access to specific device. Useful for low-level * RTC access from kernel code. */ -int ds1337_do_command(int id, int cmd, void *arg) +int ds1337_do_command(int bus, int cmd, void *arg) { struct list_head *walk; struct list_head *tmp; @@ -236,7 +218,7 @@ int ds1337_do_command(int id, int cmd, void *arg) list_for_each_safe(walk, tmp, &ds1337_clients) { data = list_entry(walk, struct ds1337_data, list); - if (data->id == id) + if (data->client.adapter->nr == bus) return ds1337_command(&data->client, cmd, arg); } @@ -346,7 +328,6 @@ static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind) ds1337_init_client(new_client); /* Add client to local list */ - data->id = ds1337_id++; list_add(&data->list, &ds1337_clients); return 0; @@ -398,5 +379,7 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); MODULE_DESCRIPTION("DS1337 RTC driver"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL_GPL(ds1337_do_command); + module_init(ds1337_init); module_exit(ds1337_exit); diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c new file mode 100644 index 0000000..a445736 --- /dev/null +++ b/drivers/i2c/chips/ds1374.c @@ -0,0 +1,260 @@ +/* + * drivers/i2c/chips/ds1374.c + * + * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock + * + * Author: Randy Vinson <rvinson@mvista.com> + * + * Based on the m41t00.c by Mark Greer <mgreer@mvista.com> + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +/* + * This i2c client/driver wedges between the drivers/char/genrtc.c RTC + * interface and the SMBus interface of the i2c subsystem. + * It would be more efficient to use i2c msgs/i2c_transfer directly but, as + * recommened in .../Documentation/i2c/writing-clients section + * "Sending and receiving", using SMBus level communication is preferred. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/rtc.h> +#include <linux/bcd.h> + +#define DS1374_REG_TOD0 0x00 +#define DS1374_REG_TOD1 0x01 +#define DS1374_REG_TOD2 0x02 +#define DS1374_REG_TOD3 0x03 +#define DS1374_REG_WDALM0 0x04 +#define DS1374_REG_WDALM1 0x05 +#define DS1374_REG_WDALM2 0x06 +#define DS1374_REG_CR 0x07 +#define DS1374_REG_SR 0x08 +#define DS1374_REG_SR_OSF 0x80 +#define DS1374_REG_TCR 0x09 + +#define DS1374_DRV_NAME "ds1374" + +static DECLARE_MUTEX(ds1374_mutex); + +static struct i2c_driver ds1374_driver; +static struct i2c_client *save_client; + +static unsigned short ignore[] = { I2C_CLIENT_END }; +static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + .normal_i2c = normal_addr, + .probe = ignore, + .ignore = ignore, + .force = ignore, +}; + +static ulong ds1374_read_rtc(void) +{ + ulong time = 0; + int reg = DS1374_REG_WDALM0; + + while (reg--) { + s32 tmp; + if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) { + dev_warn(&save_client->dev, + "can't read from rtc chip\n"); + return 0; + } + time = (time << 8) | (tmp & 0xff); + } + return time; +} + +static void ds1374_write_rtc(ulong time) +{ + int reg; + + for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) { + if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff) + < 0) { + dev_warn(&save_client->dev, + "can't write to rtc chip\n"); + break; + } + time = time >> 8; + } +} + +static void ds1374_check_rtc_status(void) +{ + s32 tmp; + + tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR); + if (tmp < 0) { + dev_warn(&save_client->dev, + "can't read status from rtc chip\n"); + return; + } + if (tmp & DS1374_REG_SR_OSF) { + dev_warn(&save_client->dev, + "oscillator discontinuity flagged, time unreliable\n"); + tmp &= ~DS1374_REG_SR_OSF; + tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR, + tmp & 0xff); + if (tmp < 0) + dev_warn(&save_client->dev, + "can't clear discontinuity notification\n"); + } +} + +ulong ds1374_get_rtc_time(void) +{ + ulong t1, t2; + int limit = 10; /* arbitrary retry limit */ + + down(&ds1374_mutex); + + /* + * Since the reads are being performed one byte at a time using + * the SMBus vs a 4-byte i2c transfer, there is a chance that a + * carry will occur during the read. To detect this, 2 reads are + * performed and compared. + */ + do { + t1 = ds1374_read_rtc(); + t2 = ds1374_read_rtc(); + } while (t1 != t2 && limit--); + + up(&ds1374_mutex); + + if (t1 != t2) { + dev_warn(&save_client->dev, + "can't get consistent time from rtc chip\n"); + t1 = 0; + } + + return t1; +} + +static void ds1374_set_tlet(ulong arg) +{ + ulong t1, t2; + int limit = 10; /* arbitrary retry limit */ + + t1 = *(ulong *) arg; + + down(&ds1374_mutex); + + /* + * Since the writes are being performed one byte at a time using + * the SMBus vs a 4-byte i2c transfer, there is a chance that a + * carry will occur during the write. To detect this, the write + * value is read back and compared. + */ + do { + ds1374_write_rtc(t1); + t2 = ds1374_read_rtc(); + } while (t1 != t2 && limit--); + + up(&ds1374_mutex); + + if (t1 != t2) + dev_warn(&save_client->dev, + "can't confirm time set from rtc chip\n"); +} + +ulong new_time; + +DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time); + +int ds1374_set_rtc_time(ulong nowtime) +{ + new_time = nowtime; + + if (in_interrupt()) + tasklet_schedule(&ds1374_tasklet); + else + ds1374_set_tlet((ulong) & new_time); + + return 0; +} + +/* + ***************************************************************************** + * + * Driver Interface + * + ***************************************************************************** + */ +static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct i2c_client *client; + int rc; + + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + memset(client, 0, sizeof(struct i2c_client)); + strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE); + client->flags = I2C_DF_NOTIFY; + client->addr = addr; + client->adapter = adap; + client->driver = &ds1374_driver; + + if ((rc = i2c_attach_client(client)) != 0) { + kfree(client); + return rc; + } + + save_client = client; + + ds1374_check_rtc_status(); + + return 0; +} + +static int ds1374_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, ds1374_probe); +} + +static int ds1374_detach(struct i2c_client *client) +{ + int rc; + + if ((rc = i2c_detach_client(client)) == 0) { + kfree(i2c_get_clientdata(client)); + tasklet_kill(&ds1374_tasklet); + } + return rc; +} + +static struct i2c_driver ds1374_driver = { + .owner = THIS_MODULE, + .name = DS1374_DRV_NAME, + .id = I2C_DRIVERID_DS1374, + .flags = I2C_DF_NOTIFY, + .attach_adapter = ds1374_attach, + .detach_client = ds1374_detach, +}; + +static int __init ds1374_init(void) +{ + return i2c_add_driver(&ds1374_driver); +} + +static void __exit ds1374_exit(void) +{ + i2c_del_driver(&ds1374_driver); +} + +module_init(ds1374_init); +module_exit(ds1374_exit); + +MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>"); +MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c index 4ae15bd..5360d58 100644 --- a/drivers/i2c/chips/ds1621.c +++ b/drivers/i2c/chips/ds1621.c @@ -121,7 +121,7 @@ static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) static void ds1621_init_client(struct i2c_client *client) { int reg = ds1621_read_value(client, DS1621_REG_CONF); - /* switch to continous conversion mode */ + /* switch to continuous conversion mode */ reg &= ~ DS1621_REG_CONFIG_1SHOT; /* setup output polarity */ @@ -303,7 +303,7 @@ static struct ds1621_data *ds1621_update_client(struct device *dev) data->temp_max = ds1621_read_value(client, DS1621_REG_TEMP_MAX); - /* reset alarms if neccessary */ + /* reset alarms if necessary */ new_conf = data->conf; if (data->temp < data->temp_min) new_conf &= ~DS1621_ALARM_TEMP_LOW; diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index cbdfa2d..addf0ad 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -26,7 +26,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> diff --git a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c index c3f37db..da41174 100644 --- a/drivers/i2c/chips/fscher.c +++ b/drivers/i2c/chips/fscher.c @@ -26,7 +26,6 @@ * and Philip Edelbrock <phil@netroedge.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c index 4316a15..6bedf72 100644 --- a/drivers/i2c/chips/gl518sm.c +++ b/drivers/i2c/chips/gl518sm.c @@ -36,7 +36,6 @@ * 2004-01-31 Code review and approval. (Jean Delvare) */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index 7f29a8a..354a262 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -145,7 +145,6 @@ static inline void notresponding(struct isp1301 *isp) static unsigned short normal_i2c[] = { ISP_BASE, ISP_BASE + 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c index 007bdf9..db20c9e 100644 --- a/drivers/i2c/chips/it87.c +++ b/drivers/i2c/chips/it87.c @@ -31,7 +31,6 @@ type at module load time. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -39,6 +38,7 @@ #include <linux/i2c.h> #include <linux/i2c-sensor.h> #include <linux/i2c-vid.h> +#include <linux/hwmon-sysfs.h> #include <asm/io.h> @@ -173,8 +173,6 @@ static inline u8 FAN_TO_REG(long rpm, int div) ((val)+500)/1000),-128,127)) #define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) -#define ALARMS_FROM_REG(val) (val) - #define PWM_TO_REG(val) ((val) >> 1) #define PWM_FROM_REG(val) (((val)&0x7f) << 1) @@ -241,27 +239,42 @@ static struct i2c_driver it87_driver = { .detach_client = it87_detach_client, }; -static ssize_t show_in(struct device *dev, char *buf, int nr) +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); } -static ssize_t show_in_min(struct device *dev, char *buf, int nr) +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); } -static ssize_t show_in_max(struct device *dev, char *buf, int nr) +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); } -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); @@ -273,9 +286,12 @@ static ssize_t set_in_min(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); @@ -289,38 +305,14 @@ static ssize_t set_in_max(struct device *dev, const char *buf, } #define show_in_offset(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); #define limit_in_offset(offset) \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset); show_in_offset(0); limit_in_offset(0); @@ -341,24 +333,39 @@ limit_in_offset(7); show_in_offset(8); /* 3 temperatures */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); } -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); } -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) +static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); } -static ssize_t set_temp_max(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -369,9 +376,12 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_temp_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -383,42 +393,23 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, return count; } #define show_temp_offset(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t \ -show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t \ -show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); show_temp_offset(1); show_temp_offset(2); show_temp_offset(3); -static ssize_t show_sensor(struct device *dev, char *buf, int nr) +static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, + char *buf) { + 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 */ @@ -428,9 +419,12 @@ static ssize_t show_sensor(struct device *dev, char *buf, int nr) return sprintf(buf, "2\n"); /* thermistor */ return sprintf(buf, "0\n"); /* disabled */ } -static ssize_t set_sensor(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -453,53 +447,67 @@ static ssize_t set_sensor(struct device *dev, const char *buf, return count; } #define show_sensor_offset(offset) \ -static ssize_t show_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_sensor(dev, buf, offset - 1); \ -} \ -static ssize_t set_sensor_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_sensor(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_sensor_##offset, set_sensor_##offset); +static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ + show_sensor, set_sensor, offset - 1); show_sensor_offset(1); show_sensor_offset(2); show_sensor_offset(3); /* 3 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); } -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); } -static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0); } -static ssize_t show_pwm(struct device *dev, char *buf, int nr) +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, + char *buf) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]); } -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -510,9 +518,12 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -550,9 +561,12 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_pwm_enable(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_pwm_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -581,9 +595,12 @@ static ssize_t set_pwm_enable(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_pwm(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); @@ -599,64 +616,23 @@ static ssize_t set_pwm(struct device *dev, const char *buf, return count; } -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div); +#define show_fan_offset(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1); show_fan_offset(1); show_fan_offset(2); show_fan_offset(3); #define show_pwm_offset(offset) \ -static ssize_t show_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_enable(dev, buf, offset - 1); \ -} \ -static ssize_t show_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_enable(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_enable, \ - set_pwm##offset##_enable); \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm##offset , set_pwm##offset ); +static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + show_pwm_enable, set_pwm_enable, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm, set_pwm, offset - 1); show_pwm_offset(1); show_pwm_offset(2); @@ -666,7 +642,7 @@ show_pwm_offset(3); static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); @@ -864,60 +840,60 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind) it87_init_client(new_client, data); /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in7_input); - device_create_file(&new_client->dev, &dev_attr_in8_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in7_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_in7_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp1_type); - device_create_file(&new_client->dev, &dev_attr_temp2_type); - device_create_file(&new_client->dev, &dev_attr_temp3_type); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan3_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan3_div); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); if (enable_pwm_interface) { - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - device_create_file(&new_client->dev, &dev_attr_pwm3_enable); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm3); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); } if (data->type == it8712) { @@ -954,7 +930,7 @@ static int it87_detach_client(struct i2c_client *client) return 0; } -/* The SMBus locks itself, but ISA access must be locked explicitely! +/* 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 IT87 BUSY flag at this moment - it could lead to deadlocks, @@ -974,7 +950,7 @@ static int it87_read_value(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -/* The SMBus locks itself, but ISA access muse be locked explicitely! +/* 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 IT87 BUSY flag at this moment - it could lead to deadlocks, diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c index bc68e03..7c6f9ea 100644 --- a/drivers/i2c/chips/lm63.c +++ b/drivers/i2c/chips/lm63.c @@ -1,7 +1,7 @@ /* * lm63.c - driver for the National Semiconductor LM63 temperature sensor * with integrated fan control - * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org> * Based on the lm90 driver. * * The LM63 is a sensor chip made by National Semiconductor. It measures @@ -37,13 +37,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/i2c-sensor.h> +#include <linux/hwmon-sysfs.h> /* * Addresses to scan @@ -99,9 +99,9 @@ SENSORS_INSMOD_1(lm63); * Conversions and various macros * For tachometer counts, the LM63 uses 16-bit values. * For local temperature and high limit, remote critical limit and hysteresis - * value, it uses signed 8-bit values with LSB = 1 degree Celcius. + * value, it uses signed 8-bit values with LSB = 1 degree Celsius. * For remote temperature, low and high limits, it uses signed 11-bit values - * with LSB = 0.125 degree Celcius, left-justified in 16-bit registers. + * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. */ #define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ @@ -158,16 +158,16 @@ struct lm63_data { /* registers values */ u8 config, config_fan; - u16 fan1_input; - u16 fan1_low; + u16 fan[2]; /* 0: input + 1: low limit */ u8 pwm1_freq; u8 pwm1_value; - s8 temp1_input; - s8 temp1_high; - s16 temp2_input; - s16 temp2_high; - s16 temp2_low; - s8 temp2_crit; + s8 temp8[3]; /* 0: local input + 1: local high limit + 2: remote critical limit */ + s16 temp11[3]; /* 0: remote input + 1: remote low limit + 2: remote high limit */ u8 temp2_crit_hyst; u8 alarms; }; @@ -176,33 +176,33 @@ struct lm63_data { * Sysfs callback functions and files */ -#define show_fan(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm63_data *data = lm63_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value)); \ +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index])); } -show_fan(fan1_input); -show_fan(fan1_low); -static ssize_t set_fan1_low(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->fan1_low = FAN_TO_REG(val); + data->fan[1] = FAN_TO_REG(val); i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, - data->fan1_low & 0xFF); + data->fan[1] & 0xFF); i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB, - data->fan1_low >> 8); + data->fan[1] >> 8); up(&data->update_lock); return count; } -static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, + char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? @@ -210,7 +210,8 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char (2 * data->pwm1_freq)); } -static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); @@ -229,77 +230,83 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const return count; } -static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, + char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); } -#define show_temp8(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm63_data *data = lm63_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->value)); \ +static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])); } -#define show_temp11(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm63_data *data = lm63_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->value)); \ + +static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp8[1] = TEMP8_TO_REG(val); + i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); + up(&data->update_lock); + return count; } -show_temp8(temp1_input); -show_temp8(temp1_high); -show_temp11(temp2_input); -show_temp11(temp2_high); -show_temp11(temp2_low); -show_temp8(temp2_crit); - -#define set_temp8(value, reg) \ -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 lm63_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP8_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])); } -#define set_temp11(value, reg_msb, reg_lsb) \ -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 lm63_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP11_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg_msb, data->value >> 8); \ - i2c_smbus_write_byte_data(client, reg_lsb, data->value & 0xff); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM63_REG_REMOTE_LOW_MSB, + LM63_REG_REMOTE_LOW_LSB, + LM63_REG_REMOTE_HIGH_MSB, + LM63_REG_REMOTE_HIGH_LSB, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + data->temp11[nr] = TEMP11_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], + data->temp11[nr] >> 8); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], + data->temp11[nr] & 0xff); + up(&data->update_lock); + return count; } -set_temp8(temp1_high, LM63_REG_LOCAL_HIGH); -set_temp11(temp2_high, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB); -set_temp11(temp2_low, LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB); /* Hysteresis register holds a relative value, while we want to present an absolute to user-space */ -static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, + char *buf) { struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp2_crit) + return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) - TEMP8_FROM_REG(data->temp2_crit_hyst)); } /* And now the other way around, user-space provides an absolute hysteresis value and we have to store a relative one */ -static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); @@ -307,36 +314,37 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute * long hyst; down(&data->update_lock); - hyst = TEMP8_FROM_REG(data->temp2_crit) - val; + hyst = TEMP8_FROM_REG(data->temp8[2]) - val; i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, HYST_TO_REG(hyst)); up(&data->update_lock); 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 *dummy, + char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan1_input, NULL); -static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan1_low, - set_fan1_low); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, + set_fan, 1); static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_high, - set_temp1_high); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 1); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp2_input, NULL); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp2_low, - set_temp2_low); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp2_high, - set_temp2_high); -static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp2_crit, NULL); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 1); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 2); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, set_temp2_crit_hyst); @@ -430,17 +438,25 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) /* Register sysfs hooks */ if (data->config & 0x04) { /* tachometer enabled */ - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min.dev_attr); } device_create_file(&new_client->dev, &dev_attr_pwm1); device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); device_create_file(&new_client->dev, &dev_attr_alarms); @@ -511,14 +527,14 @@ static struct lm63_data *lm63_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { if (data->config & 0x04) { /* tachometer enabled */ /* order matters for fan1_input */ - data->fan1_input = i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_LSB) & 0xFC; - data->fan1_input |= i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_MSB) << 8; - data->fan1_low = (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_LSB) & 0xFC) - | (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_MSB) << 8); + data->fan[0] = i2c_smbus_read_byte_data(client, + LM63_REG_TACH_COUNT_LSB) & 0xFC; + data->fan[0] |= i2c_smbus_read_byte_data(client, + LM63_REG_TACH_COUNT_MSB) << 8; + data->fan[1] = (i2c_smbus_read_byte_data(client, + LM63_REG_TACH_LIMIT_LSB) & 0xFC) + | (i2c_smbus_read_byte_data(client, + LM63_REG_TACH_LIMIT_MSB) << 8); } data->pwm1_freq = i2c_smbus_read_byte_data(client, @@ -528,26 +544,26 @@ static struct lm63_data *lm63_update_device(struct device *dev) data->pwm1_value = i2c_smbus_read_byte_data(client, LM63_REG_PWM_VALUE); - data->temp1_input = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_TEMP); - data->temp1_high = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_HIGH); + data->temp8[0] = i2c_smbus_read_byte_data(client, + LM63_REG_LOCAL_TEMP); + data->temp8[1] = i2c_smbus_read_byte_data(client, + LM63_REG_LOCAL_HIGH); /* order matters for temp2_input */ - data->temp2_input = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_MSB) << 8; - data->temp2_input |= i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_LSB); - data->temp2_high = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_LSB); - data->temp2_low = (i2c_smbus_read_byte_data(client, + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TEMP_MSB) << 8; + data->temp11[0] |= i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TEMP_LSB); + data->temp11[1] = (i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_LOW_MSB) << 8) | i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_LOW_LSB); - data->temp2_crit = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT); + data->temp11[2] = (i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_HIGH_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_HIGH_LSB); + data->temp8[2] = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TCRIT); data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST); diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c index 57c51ac..5be164e 100644 --- a/drivers/i2c/chips/lm75.c +++ b/drivers/i2c/chips/lm75.c @@ -18,7 +18,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/drivers/i2c/chips/lm77.c b/drivers/i2c/chips/lm77.c index 9d15cd5..b98f449 100644 --- a/drivers/i2c/chips/lm77.c +++ b/drivers/i2c/chips/lm77.c @@ -25,7 +25,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c index 21b195f..2924146 100644 --- a/drivers/i2c/chips/lm78.c +++ b/drivers/i2c/chips/lm78.c @@ -18,7 +18,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -671,7 +670,7 @@ static int lm78_detach_client(struct i2c_client *client) return 0; } -/* The SMBus locks itself, but ISA access must be locked explicitely! +/* 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, @@ -690,7 +689,7 @@ static int lm78_read_value(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -/* The SMBus locks itself, but ISA access muse be locked explicitely! +/* 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, diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c index 404057b..8100595 100644 --- a/drivers/i2c/chips/lm80.c +++ b/drivers/i2c/chips/lm80.c @@ -21,7 +21,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c index 4d6d7d2..a49008b 100644 --- a/drivers/i2c/chips/lm83.c +++ b/drivers/i2c/chips/lm83.c @@ -1,7 +1,7 @@ /* * lm83.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring - * Copyright (C) 2003 Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org> * * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is * a sensor chip made by National Semiconductor. It reports up to four @@ -27,13 +27,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/i2c-sensor.h> +#include <linux/hwmon-sysfs.h> /* * Addresses to scan @@ -81,7 +81,7 @@ SENSORS_INSMOD_1(lm83); /* * Conversions and various macros - * The LM83 uses signed 8-bit values with LSB = 1 degree Celcius. + * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius. */ #define TEMP_FROM_REG(val) ((val) * 1000) @@ -94,21 +94,20 @@ static const u8 LM83_REG_R_TEMP[] = { LM83_REG_R_LOCAL_TEMP, LM83_REG_R_REMOTE1_TEMP, LM83_REG_R_REMOTE2_TEMP, - LM83_REG_R_REMOTE3_TEMP -}; - -static const u8 LM83_REG_R_HIGH[] = { + LM83_REG_R_REMOTE3_TEMP, LM83_REG_R_LOCAL_HIGH, LM83_REG_R_REMOTE1_HIGH, LM83_REG_R_REMOTE2_HIGH, - LM83_REG_R_REMOTE3_HIGH + LM83_REG_R_REMOTE3_HIGH, + LM83_REG_R_TCRIT, }; static const u8 LM83_REG_W_HIGH[] = { LM83_REG_W_LOCAL_HIGH, LM83_REG_W_REMOTE1_HIGH, LM83_REG_W_REMOTE2_HIGH, - LM83_REG_W_REMOTE3_HIGH + LM83_REG_W_REMOTE3_HIGH, + LM83_REG_W_TCRIT, }; /* @@ -144,9 +143,9 @@ struct lm83_data { unsigned long last_updated; /* in jiffies */ /* registers values */ - s8 temp_input[4]; - s8 temp_high[4]; - s8 temp_crit; + s8 temp[9]; /* 0..3: input 1-4, + 4..7: high limit 1-4, + 8 : critical limit */ u16 alarms; /* bitvector, combined */ }; @@ -154,65 +153,55 @@ struct lm83_data { * Sysfs stuff */ -#define show_temp(suffix, value) \ -static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm83_data *data = lm83_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm83_data *data = lm83_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -show_temp(input1, temp_input[0]); -show_temp(input2, temp_input[1]); -show_temp(input3, temp_input[2]); -show_temp(input4, temp_input[3]); -show_temp(high1, temp_high[0]); -show_temp(high2, temp_high[1]); -show_temp(high3, temp_high[2]); -show_temp(high4, temp_high[3]); -show_temp(crit, temp_crit); - -#define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm83_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + 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); + int nr = attr->index; + + down(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4], + data->temp[nr]); + up(&data->update_lock); + return count; } -set_temp(high1, temp_high[0], LM83_REG_W_LOCAL_HIGH); -set_temp(high2, temp_high[1], LM83_REG_W_REMOTE1_HIGH); -set_temp(high3, temp_high[2], LM83_REG_W_REMOTE2_HIGH); -set_temp(high4, temp_high[3], LM83_REG_W_REMOTE3_HIGH); -set_temp(crit, temp_crit, LM83_REG_W_TCRIT); -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 *dummy, + char *buf) { struct lm83_data *data = lm83_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); -static DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input3, NULL); -static DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input4, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1, - set_temp_high1); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, - set_temp_high2); -static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_high3, - set_temp_high3); -static DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_high4, - set_temp_high4); -static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL); -static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL); -static DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp_crit, - set_temp_crit); -static DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 4); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 5); +static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 6); +static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 7); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp, + set_temp, 8); +static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* @@ -323,18 +312,30 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) */ /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp4_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp4_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); - device_create_file(&new_client->dev, &dev_attr_temp4_crit); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_crit.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); return 0; @@ -370,16 +371,11 @@ static struct lm83_data *lm83_update_device(struct device *dev) int nr; dev_dbg(&client->dev, "Updating lm83 data.\n"); - for (nr = 0; nr < 4 ; nr++) { - data->temp_input[nr] = + for (nr = 0; nr < 9; nr++) { + data->temp[nr] = i2c_smbus_read_byte_data(client, LM83_REG_R_TEMP[nr]); - data->temp_high[nr] = - i2c_smbus_read_byte_data(client, - LM83_REG_R_HIGH[nr]); } - data->temp_crit = - i2c_smbus_read_byte_data(client, LM83_REG_R_TCRIT); data->alarms = i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index b197677..b4d7fd4 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c @@ -23,7 +23,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -285,8 +284,6 @@ static int ZONE_TO_REG( int zone ) /* i2c-vid.h defines vid_from_reg() */ #define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm))) -#define ALARMS_FROM_REG(val) (val) - /* Unlike some other drivers we DO NOT set initial limits. Use * the config file to set limits. Some users have reported * motherboards shutting down when we set limits in a previous @@ -481,7 +478,7 @@ 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) { struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); diff --git a/drivers/i2c/chips/lm87.c b/drivers/i2c/chips/lm87.c index 4372b61..1921ed1 100644 --- a/drivers/i2c/chips/lm87.c +++ b/drivers/i2c/chips/lm87.c @@ -52,7 +52,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c index 9b127a0..a67dcad 100644 --- a/drivers/i2c/chips/lm90.c +++ b/drivers/i2c/chips/lm90.c @@ -1,7 +1,7 @@ /* * lm90.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring - * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org> * * Based on the lm83 driver. The LM90 is a sensor chip made by National * Semiconductor. It reports up to two temperatures (its own plus up to @@ -19,7 +19,7 @@ * Complete datasheets can be obtained from National's website at: * http://www.national.com/pf/LM/LM89.html * http://www.national.com/pf/LM/LM99.html - * Note that there is no way to differenciate between both chips. + * Note that there is no way to differentiate between both chips. * * This driver also supports the LM86, another sensor chip made by * National Semiconductor. It is exactly similar to the LM90 except it @@ -39,7 +39,7 @@ * chips made by Maxim. These chips are similar to the LM86. Complete * datasheet can be obtained at Maxim's website at: * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - * Note that there is no easy way to differenciate between the three + * Note that there is no easy way to differentiate between the three * variants. The extra address and features of the MAX6659 are not * supported by this driver. * @@ -70,13 +70,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/i2c-sensor.h> +#include <linux/hwmon-sysfs.h> /* * Addresses to scan @@ -139,9 +139,9 @@ SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461); /* * Conversions and various macros * For local temperatures and limits, critical limits and the hysteresis - * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celcius. + * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. * For remote temperatures and limits, it uses signed 11-bit values with - * LSB = 0.125 degree Celcius, left-justified in 16-bit registers. + * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. */ #define TEMP1_FROM_REG(val) ((val) * 1000) @@ -206,9 +206,14 @@ struct lm90_data { int kind; /* registers values */ - s8 temp_input1, temp_low1, temp_high1; /* local */ - s16 temp_input2, temp_low2, temp_high2; /* remote, combined */ - s8 temp_crit1, temp_crit2; + s8 temp8[5]; /* 0: local input + 1: local low limit + 2: local high limit + 3: local critical limit + 4: remote critical limit */ + s16 temp11[3]; /* 0: remote input + 1: remote low limit + 2: remote high limit */ u8 temp_hyst; u8 alarms; /* bitvector */ }; @@ -217,75 +222,88 @@ struct lm90_data { * Sysfs stuff */ -#define show_temp(value, converter) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm90_data *data = lm90_update_device(dev); \ - return sprintf(buf, "%d\n", converter(data->value)); \ +static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])); +} + +static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM90_REG_W_LOCAL_LOW, + LM90_REG_W_LOCAL_HIGH, + LM90_REG_W_LOCAL_CRIT, + LM90_REG_W_REMOTE_CRIT, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + if (data->kind == adt7461) + data->temp8[nr] = TEMP1_TO_REG_ADT7461(val); + else + data->temp8[nr] = TEMP1_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]); + up(&data->update_lock); + return count; } -show_temp(temp_input1, TEMP1_FROM_REG); -show_temp(temp_input2, TEMP2_FROM_REG); -show_temp(temp_low1, TEMP1_FROM_REG); -show_temp(temp_low2, TEMP2_FROM_REG); -show_temp(temp_high1, TEMP1_FROM_REG); -show_temp(temp_high2, TEMP2_FROM_REG); -show_temp(temp_crit1, TEMP1_FROM_REG); -show_temp(temp_crit2, TEMP1_FROM_REG); - -#define set_temp1(value, reg) \ -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 lm90_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - if (data->kind == adt7461) \ - data->value = TEMP1_TO_REG_ADT7461(val); \ - else \ - data->value = TEMP1_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index])); } -#define set_temp2(value, regh, regl) \ -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 lm90_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - if (data->kind == adt7461) \ - data->value = TEMP2_TO_REG_ADT7461(val); \ - else \ - data->value = TEMP2_TO_REG(val); \ - i2c_smbus_write_byte_data(client, regh, data->value >> 8); \ - i2c_smbus_write_byte_data(client, regl, data->value & 0xff); \ - up(&data->update_lock); \ - return count; \ + +static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM90_REG_W_REMOTE_LOWH, + LM90_REG_W_REMOTE_LOWL, + LM90_REG_W_REMOTE_HIGHH, + LM90_REG_W_REMOTE_HIGHL, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + if (data->kind == adt7461) + data->temp11[nr] = TEMP2_TO_REG_ADT7461(val); + else + data->temp11[nr] = TEMP2_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], + data->temp11[nr] >> 8); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], + data->temp11[nr] & 0xff); + up(&data->update_lock); + return count; } -set_temp1(temp_low1, LM90_REG_W_LOCAL_LOW); -set_temp2(temp_low2, LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL); -set_temp1(temp_high1, LM90_REG_W_LOCAL_HIGH); -set_temp2(temp_high2, LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL); -set_temp1(temp_crit1, LM90_REG_W_LOCAL_CRIT); -set_temp1(temp_crit2, LM90_REG_W_REMOTE_CRIT); - -#define show_temp_hyst(value, basereg) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm90_data *data = lm90_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->basereg) \ - - TEMP1_FROM_REG(data->temp_hyst)); \ + +static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]) + - TEMP1_FROM_REG(data->temp_hyst)); } -show_temp_hyst(temp_hyst1, temp_crit1); -show_temp_hyst(temp_hyst2, temp_crit2); -static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm90_data *data = i2c_get_clientdata(client); @@ -293,36 +311,37 @@ static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, long hyst; down(&data->update_lock); - hyst = TEMP1_FROM_REG(data->temp_crit1) - val; + hyst = TEMP1_FROM_REG(data->temp8[3]) - val; i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, HYST_TO_REG(hyst)); up(&data->update_lock); 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 *dummy, + char *buf) { struct lm90_data *data = lm90_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_low1, - set_temp_low1); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, - set_temp_low2); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1, - set_temp_high1); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, - set_temp_high2); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit1, - set_temp_crit1); -static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, - set_temp_crit2); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst1, - set_temp_hyst1); -static DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_hyst2, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 1); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 1); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 2); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 2); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 3); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 4); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, + set_temphyst, 3); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* @@ -481,16 +500,26 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) lm90_init_client(new_client); /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit_hyst.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); return 0; @@ -541,16 +570,16 @@ static struct lm90_data *lm90_update_device(struct device *dev) u8 oldh, newh; dev_dbg(&client->dev, "Updating lm90 data.\n"); - data->temp_input1 = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_TEMP); - data->temp_high1 = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_HIGH); - data->temp_low1 = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_LOW); - data->temp_crit1 = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_CRIT); - data->temp_crit2 = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_CRIT); + data->temp8[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_TEMP); + data->temp8[1] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_LOW); + data->temp8[2] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_HIGH); + data->temp8[3] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_CRIT); + data->temp8[4] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_CRIT); data->temp_hyst = i2c_smbus_read_byte_data(client, LM90_REG_R_TCRIT_HYST); @@ -570,13 +599,13 @@ static struct lm90_data *lm90_update_device(struct device *dev) */ oldh = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH); - data->temp_input2 = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPL); newh = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH); if (newh != oldh) { - data->temp_input2 = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPL); #ifdef DEBUG oldh = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH); @@ -586,16 +615,16 @@ static struct lm90_data *lm90_update_device(struct device *dev) "wrong.\n"); #endif } - data->temp_input2 |= (newh << 8); + data->temp11[0] |= (newh << 8); - data->temp_high2 = (i2c_smbus_read_byte_data(client, + data->temp11[1] = (i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_LOWH) << 8) + + i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_LOWL); + data->temp11[2] = (i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_HIGHH) << 8) + i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_HIGHL); - data->temp_low2 = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWL); data->alarms = i2c_smbus_read_byte_data(client, LM90_REG_R_STATUS); diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index e771566..5e463c47 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -40,11 +40,8 @@ static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, - .normal_i2c_range = ignore, .probe = ignore, - .probe_range = ignore, .ignore = ignore, - .ignore_range = ignore, .force = ignore, }; diff --git a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c index 30a1961..bf553dc 100644 --- a/drivers/i2c/chips/max1619.c +++ b/drivers/i2c/chips/max1619.c @@ -26,7 +26,6 @@ */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c new file mode 100644 index 0000000..fe6b150 --- /dev/null +++ b/drivers/i2c/chips/max6875.c @@ -0,0 +1,473 @@ +/* + max6875.c - driver for MAX6874/MAX6875 + + Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> + + Based on i2c/chips/eeprom.c + + The MAX6875 has two EEPROM sections: config and user. + At reset, the config EEPROM is read into the registers. + + This driver make 3 binary files available in sysfs: + reg_config - direct access to the registers + eeprom_config - acesses configuration eeprom space + eeprom_user - free for application use + + In our application, we put device serial & model numbers in user eeprom. + + Notes: + 1) The datasheet says that register 0x44 / EEPROM 0x8044 should NOT + be overwritten, so the driver explicitly prevents that. + 2) It's a good idea to keep the config (0x45) locked in config EEPROM. + You can temporarily enable config writes by changing register 0x45. + + 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. +*/ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/i2c-sensor.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = {0x50, 0x52, I2C_CLIENT_END}; +static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; + +/* Insmod parameters */ +SENSORS_INSMOD_1(max6875); + +/* this param will prevent 'accidental' writes to the eeprom */ +static int allow_write = 0; +module_param(allow_write, int, 0); +MODULE_PARM_DESC(allow_write, + "Enable write access:\n" + "*0: Read only\n" + " 1: Read/Write access"); + +/* The MAX6875 can only read/write 16 bytes at a time */ +#define SLICE_SIZE 16 +#define SLICE_BITS 4 + +/* CONFIG EEPROM is at addresses 0x8000 - 0x8045, registers are at 0 - 0x45 */ +#define CONFIG_EEPROM_BASE 0x8000 +#define CONFIG_EEPROM_SIZE 0x0046 +#define CONFIG_EEPROM_SLICES 5 + +/* USER EEPROM is at addresses 0x8100 - 0x82FF */ +#define USER_EEPROM_BASE 0x8100 +#define USER_EEPROM_SIZE 0x0200 +#define USER_EEPROM_SLICES 32 + +/* MAX6875 commands */ +#define MAX6875_CMD_BLOCK_WRITE 0x83 +#define MAX6875_CMD_BLOCK_READ 0x84 +#define MAX6875_CMD_REBOOT 0x88 + +enum max6875_area_type { + max6875_register_config=0, + max6875_eeprom_config, + max6875_eeprom_user, + max6857_max +}; + +struct eeprom_block { + enum max6875_area_type type; + u8 slices; + u32 size; + u32 valid; + u32 base; + unsigned long *updated; + u8 *data; +}; + +/* Each client has this additional data */ +struct max6875_data { + struct i2c_client client; + struct semaphore update_lock; + struct eeprom_block blocks[max6857_max]; + /* the above structs point into the arrays below */ + u8 data[USER_EEPROM_SIZE + (CONFIG_EEPROM_SIZE*2)]; + unsigned long last_updated[USER_EEPROM_SLICES + (CONFIG_EEPROM_SLICES*2)]; +}; + +static int max6875_attach_adapter(struct i2c_adapter *adapter); +static int max6875_detect(struct i2c_adapter *adapter, int address, int kind); +static int max6875_detach_client(struct i2c_client *client); + +/* This is the driver that will be inserted */ +static struct i2c_driver max6875_driver = { + .owner = THIS_MODULE, + .name = "max6875", + .flags = I2C_DF_NOTIFY, + .attach_adapter = max6875_attach_adapter, + .detach_client = max6875_detach_client, +}; + +static int max6875_update_slice(struct i2c_client *client, + struct eeprom_block *blk, + int slice) +{ + struct max6875_data *data = i2c_get_clientdata(client); + int i, j, addr, count; + u8 rdbuf[SLICE_SIZE]; + int retval = 0; + + if (slice >= blk->slices) + return -1; + + down(&data->update_lock); + + if (!(blk->valid & (1 << slice)) || + (jiffies - blk->updated[slice] > 300 * HZ) || + (jiffies < blk->updated[slice])) { + dev_dbg(&client->dev, "Starting eeprom update, slice %u, base %u\n", + slice, blk->base); + + addr = blk->base + (slice << SLICE_BITS); + count = blk->size - (slice << SLICE_BITS); + if (count > SLICE_SIZE) { + count = SLICE_SIZE; + } + + /* Preset the read address */ + if (addr < 0x100) { + /* select the register */ + if (i2c_smbus_write_byte(client, addr & 0xFF)) { + dev_dbg(&client->dev, "max6875 register select has failed!\n"); + retval = -1; + goto exit; + } + } else { + /* select the eeprom */ + if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { + dev_dbg(&client->dev, "max6875 address set has failed!\n"); + retval = -1; + goto exit; + } + } + + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLOCK_READ, + rdbuf) != SLICE_SIZE) + { + retval = -1; + goto exit; + } + + memcpy(&blk->data[slice << SLICE_BITS], rdbuf, count); + } else { + for (i = 0; i < count; i++) { + j = i2c_smbus_read_byte(client); + if (j < 0) + { + retval = -1; + goto exit; + } + blk->data[(slice << SLICE_BITS) + i] = (u8) j; + } + } + blk->updated[slice] = jiffies; + blk->valid |= (1 << slice); + } + exit: + up(&data->update_lock); + return retval; +} + +static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count, + enum max6875_area_type area_type) +{ + struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); + struct max6875_data *data = i2c_get_clientdata(client); + struct eeprom_block *blk; + int slice; + + blk = &data->blocks[area_type]; + + if (off > blk->size) + return 0; + if (off + count > blk->size) + count = blk->size - off; + + /* Only refresh slices which contain requested bytes */ + for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) + max6875_update_slice(client, blk, slice); + + memcpy(buf, &blk->data[off], count); + + return count; +} + +static ssize_t max6875_user_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_read(kobj, buf, off, count, max6875_eeprom_user); +} + +static ssize_t max6875_config_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_read(kobj, buf, off, count, max6875_eeprom_config); +} + +static ssize_t max6875_cfgreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_read(kobj, buf, off, count, max6875_register_config); +} + + +static ssize_t max6875_write(struct kobject *kobj, char *buf, loff_t off, size_t count, + enum max6875_area_type area_type) +{ + struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); + struct max6875_data *data = i2c_get_clientdata(client); + struct eeprom_block *blk; + int slice, addr, retval; + ssize_t sent = 0; + + blk = &data->blocks[area_type]; + + if (off > blk->size) + return 0; + if ((off + count) > blk->size) + count = blk->size - off; + + if (down_interruptible(&data->update_lock)) + return -EAGAIN; + + /* writing to a register is done with i2c_smbus_write_byte_data() */ + if (blk->type == max6875_register_config) { + for (sent = 0; sent < count; sent++) { + addr = off + sent; + if (addr == 0x44) + continue; + + retval = i2c_smbus_write_byte_data(client, addr, buf[sent]); + } + } else { + int cmd, val; + + /* We are writing to EEPROM */ + for (sent = 0; sent < count; sent++) { + addr = blk->base + off + sent; + cmd = addr >> 8; + val = (addr & 0xff) | (buf[sent] << 8); // reversed + + if (addr == 0x8044) + continue; + + retval = i2c_smbus_write_word_data(client, cmd, val); + + if (retval) { + goto error_exit; + } + + /* A write takes up to 11 ms */ + msleep(11); + } + } + + /* Invalidate the scratch buffer */ + for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) + blk->valid &= ~(1 << slice); + + error_exit: + up(&data->update_lock); + + return sent; +} + +static ssize_t max6875_user_write(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_write(kobj, buf, off, count, max6875_eeprom_user); +} + +static ssize_t max6875_config_write(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_write(kobj, buf, off, count, max6875_eeprom_config); +} + +static ssize_t max6875_cfgreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + return max6875_write(kobj, buf, off, count, max6875_register_config); +} + +static struct bin_attribute user_eeprom_attr = { + .attr = { + .name = "eeprom_user", + .mode = S_IRUGO | S_IWUSR | S_IWGRP, + .owner = THIS_MODULE, + }, + .size = USER_EEPROM_SIZE, + .read = max6875_user_read, + .write = max6875_user_write, +}; + +static struct bin_attribute config_eeprom_attr = { + .attr = { + .name = "eeprom_config", + .mode = S_IRUGO | S_IWUSR, + .owner = THIS_MODULE, + }, + .size = CONFIG_EEPROM_SIZE, + .read = max6875_config_read, + .write = max6875_config_write, +}; + +static struct bin_attribute config_register_attr = { + .attr = { + .name = "reg_config", + .mode = S_IRUGO | S_IWUSR, + .owner = THIS_MODULE, + }, + .size = CONFIG_EEPROM_SIZE, + .read = max6875_cfgreg_read, + .write = max6875_cfgreg_write, +}; + +static int max6875_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, max6875_detect); +} + +/* This function is called by i2c_detect */ +static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct max6875_data *data; + int err = 0; + + /* There are three ways we can read the EEPROM data: + (1) I2C block reads (faster, but unsupported by most adapters) + (2) Consecutive byte reads (100% overhead) + (3) Regular byte data reads (200% overhead) + The third method is not implemented by this driver because all + known adapters support at least the second. */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access eeprom_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct max6875_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &max6875_driver; + new_client->flags = 0; + + /* Setup the user section */ + data->blocks[max6875_eeprom_user].type = max6875_eeprom_user; + data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES; + data->blocks[max6875_eeprom_user].size = USER_EEPROM_SIZE; + data->blocks[max6875_eeprom_user].base = USER_EEPROM_BASE; + data->blocks[max6875_eeprom_user].data = data->data; + data->blocks[max6875_eeprom_user].updated = data->last_updated; + + /* Setup the config section */ + data->blocks[max6875_eeprom_config].type = max6875_eeprom_config; + data->blocks[max6875_eeprom_config].slices = CONFIG_EEPROM_SLICES; + data->blocks[max6875_eeprom_config].size = CONFIG_EEPROM_SIZE; + data->blocks[max6875_eeprom_config].base = CONFIG_EEPROM_BASE; + data->blocks[max6875_eeprom_config].data = &data->data[USER_EEPROM_SIZE]; + data->blocks[max6875_eeprom_config].updated = &data->last_updated[USER_EEPROM_SLICES]; + + /* Setup the register section */ + data->blocks[max6875_register_config].type = max6875_register_config; + data->blocks[max6875_register_config].slices = CONFIG_EEPROM_SLICES; + data->blocks[max6875_register_config].size = CONFIG_EEPROM_SIZE; + data->blocks[max6875_register_config].base = 0; + data->blocks[max6875_register_config].data = &data->data[USER_EEPROM_SIZE+CONFIG_EEPROM_SIZE]; + data->blocks[max6875_register_config].updated = &data->last_updated[USER_EEPROM_SLICES+CONFIG_EEPROM_SLICES]; + + /* Init the data */ + memset(data->data, 0xff, sizeof(data->data)); + + /* Fill in the remaining client fields */ + strlcpy(new_client->name, "max6875", I2C_NAME_SIZE); + init_MUTEX(&data->update_lock); + + /* Verify that the chip is really what we think it is */ + if ((max6875_update_slice(new_client, &data->blocks[max6875_eeprom_config], 4) < 0) || + (max6875_update_slice(new_client, &data->blocks[max6875_register_config], 4) < 0)) + goto exit_kfree; + + /* 0x41,0x42 must be zero and 0x40 must match in eeprom and registers */ + if ((data->blocks[max6875_eeprom_config].data[0x41] != 0) || + (data->blocks[max6875_eeprom_config].data[0x42] != 0) || + (data->blocks[max6875_register_config].data[0x41] != 0) || + (data->blocks[max6875_register_config].data[0x42] != 0) || + (data->blocks[max6875_eeprom_config].data[0x40] != + data->blocks[max6875_register_config].data[0x40])) + goto exit_kfree; + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_kfree; + + /* create the sysfs eeprom files with the correct permissions */ + if (allow_write == 0) { + user_eeprom_attr.attr.mode &= ~S_IWUGO; + user_eeprom_attr.write = NULL; + config_eeprom_attr.attr.mode &= ~S_IWUGO; + config_eeprom_attr.write = NULL; + config_register_attr.attr.mode &= ~S_IWUGO; + config_register_attr.write = NULL; + } + sysfs_create_bin_file(&new_client->dev.kobj, &user_eeprom_attr); + sysfs_create_bin_file(&new_client->dev.kobj, &config_eeprom_attr); + sysfs_create_bin_file(&new_client->dev.kobj, &config_register_attr); + + return 0; + +exit_kfree: + kfree(data); +exit: + return err; +} + +static int max6875_detach_client(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) { + dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static int __init max6875_init(void) +{ + return i2c_add_driver(&max6875_driver); +} + +static void __exit max6875_exit(void) +{ + i2c_del_driver(&max6875_driver); +} + + +MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); +MODULE_DESCRIPTION("MAX6875 driver"); +MODULE_LICENSE("GPL"); + +module_init(max6875_init); +module_exit(max6875_exit); diff --git a/drivers/i2c/chips/pc87360.c b/drivers/i2c/chips/pc87360.c index 65637b2..876c68f 100644 --- a/drivers/i2c/chips/pc87360.c +++ b/drivers/i2c/chips/pc87360.c @@ -33,7 +33,6 @@ * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c new file mode 100644 index 0000000..9f3ad45 --- /dev/null +++ b/drivers/i2c/chips/pca9539.c @@ -0,0 +1,192 @@ +/* + pca9539.c - 16-bit I/O port with interrupt and reset + + Copyright (C) 2005 Ben Gardner <bgardner@wabtec.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. +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/hwmon-sysfs.h> +#include <linux/i2c-sensor.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END}; +static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; + +/* Insmod parameters */ +SENSORS_INSMOD_1(pca9539); + +enum pca9539_cmd +{ + PCA9539_INPUT_0 = 0, + PCA9539_INPUT_1 = 1, + PCA9539_OUTPUT_0 = 2, + PCA9539_OUTPUT_1 = 3, + PCA9539_INVERT_0 = 4, + PCA9539_INVERT_1 = 5, + PCA9539_DIRECTION_0 = 6, + PCA9539_DIRECTION_1 = 7, +}; + +static int pca9539_attach_adapter(struct i2c_adapter *adapter); +static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind); +static int pca9539_detach_client(struct i2c_client *client); + +/* This is the driver that will be inserted */ +static struct i2c_driver pca9539_driver = { + .owner = THIS_MODULE, + .name = "pca9539", + .flags = I2C_DF_NOTIFY, + .attach_adapter = pca9539_attach_adapter, + .detach_client = pca9539_detach_client, +}; + +struct pca9539_data { + struct i2c_client client; +}; + +/* following are the sysfs callback functions */ +static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *psa = to_sensor_dev_attr(attr); + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%d\n", i2c_smbus_read_byte_data(client, + psa->index)); +} + +static ssize_t pca9539_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *psa = to_sensor_dev_attr(attr); + struct i2c_client *client = to_i2c_client(dev); + unsigned long val = simple_strtoul(buf, NULL, 0); + if (val > 0xff) + return -EINVAL; + i2c_smbus_write_byte_data(client, psa->index, val); + return count; +} + +/* Define the device attributes */ + +#define PCA9539_ENTRY_RO(name, cmd_idx) \ + static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9539_show, NULL, cmd_idx) + +#define PCA9539_ENTRY_RW(name, cmd_idx) \ + static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9539_show, \ + pca9539_store, cmd_idx) + +PCA9539_ENTRY_RO(input0, PCA9539_INPUT_0); +PCA9539_ENTRY_RO(input1, PCA9539_INPUT_1); +PCA9539_ENTRY_RW(output0, PCA9539_OUTPUT_0); +PCA9539_ENTRY_RW(output1, PCA9539_OUTPUT_1); +PCA9539_ENTRY_RW(invert0, PCA9539_INVERT_0); +PCA9539_ENTRY_RW(invert1, PCA9539_INVERT_1); +PCA9539_ENTRY_RW(direction0, PCA9539_DIRECTION_0); +PCA9539_ENTRY_RW(direction1, PCA9539_DIRECTION_1); + +static struct attribute *pca9539_attributes[] = { + &sensor_dev_attr_input0.dev_attr.attr, + &sensor_dev_attr_input1.dev_attr.attr, + &sensor_dev_attr_output0.dev_attr.attr, + &sensor_dev_attr_output1.dev_attr.attr, + &sensor_dev_attr_invert0.dev_attr.attr, + &sensor_dev_attr_invert1.dev_attr.attr, + &sensor_dev_attr_direction0.dev_attr.attr, + &sensor_dev_attr_direction1.dev_attr.attr, + NULL +}; + +static struct attribute_group pca9539_defattr_group = { + .attrs = pca9539_attributes, +}; + +static int pca9539_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, pca9539_detect); +} + +/* This function is called by i2c_detect */ +static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct pca9539_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. */ + if (!(data = kmalloc(sizeof(struct pca9539_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct pca9539_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &pca9539_driver; + new_client->flags = 0; + + /* Detection: the pca9539 only has 8 registers (0-7). + A read of 7 should succeed, but a read of 8 should fail. */ + if ((i2c_smbus_read_byte_data(new_client, 7) < 0) || + (i2c_smbus_read_byte_data(new_client, 8) >= 0)) + goto exit_kfree; + + strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_kfree; + + /* Register sysfs hooks (don't care about failure) */ + sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group); + + return 0; + +exit_kfree: + kfree(data); +exit: + return err; +} + +static int pca9539_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int __init pca9539_init(void) +{ + return i2c_add_driver(&pca9539_driver); +} + +static void __exit pca9539_exit(void) +{ + i2c_del_driver(&pca9539_driver); +} + +MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); +MODULE_DESCRIPTION("PCA9539 driver"); +MODULE_LICENSE("GPL"); + +module_init(pca9539_init); +module_exit(pca9539_exit); + diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 4956e9e..cfcf646 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -57,7 +57,7 @@ SENSORS_INSMOD_2(pcf8574, pcf8574a); struct pcf8574_data { struct i2c_client client; - u8 read, write; /* Register values */ + u8 write; /* Remember last written value */ }; static int pcf8574_attach_adapter(struct i2c_adapter *adapter); @@ -79,9 +79,7 @@ static struct i2c_driver pcf8574_driver = { static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); - struct pcf8574_data *data = i2c_get_clientdata(client); - data->read = i2c_smbus_read_byte(client); - return sprintf(buf, "%u\n", data->read); + return sprintf(buf, "%u\n", i2c_smbus_read_byte(client)); } static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c index 5a9dedd..588fc22 100644 --- a/drivers/i2c/chips/rtc8564.c +++ b/drivers/i2c/chips/rtc8564.c @@ -19,7 +19,6 @@ #include <linux/string.h> #include <linux/rtc.h> /* get the user-level API */ #include <linux/init.h> -#include <linux/init.h> #include "rtc8564.h" @@ -66,11 +65,8 @@ static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, - .normal_i2c_range = ignore, .probe = ignore, - .probe_range = ignore, .ignore = ignore, - .ignore_range = ignore, .force = ignore, }; diff --git a/drivers/i2c/chips/sis5595.c b/drivers/i2c/chips/sis5595.c index c665072..6bbfc8f 100644 --- a/drivers/i2c/chips/sis5595.c +++ b/drivers/i2c/chips/sis5595.c @@ -57,6 +57,7 @@ #include <linux/i2c.h> #include <linux/i2c-sensor.h> #include <linux/init.h> +#include <linux/jiffies.h> #include <asm/io.h> diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c index 13d6d4a..897117a 100644 --- a/drivers/i2c/chips/smsc47m1.c +++ b/drivers/i2c/chips/smsc47m1.c @@ -372,14 +372,16 @@ static int smsc47m1_find(int *address) * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id * 0x5F) and LPC47B27x (device id 0x51) have fan control. * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" - * can do much more besides (device id 0x60, unsupported). + * can do much more besides (device id 0x60). */ if (val == 0x51) - printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n"); + printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); else if (val == 0x59) - printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n"); + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n"); else if (val == 0x5F) - printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n"); + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); + else if (val == 0x60) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n"); else { superio_exit(); return -ENODEV; diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c new file mode 100644 index 0000000..c0ac01b --- /dev/null +++ b/drivers/i2c/chips/tps65010.c @@ -0,0 +1,1072 @@ +/* + * tps65010 - driver for tps6501x power management chips + * + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2004-2005 David Brownell + * + * 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. + */ +#undef DEBUG + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/workqueue.h> +#include <linux/suspend.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <asm/arch/gpio.h> +#include <asm/arch/mux.h> +#include <asm/arch/tps65010.h> + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_VERSION "2 May 2005" +#define DRIVER_NAME (tps65010_driver.name) + +MODULE_DESCRIPTION("TPS6501x Power Management Driver"); +MODULE_LICENSE("GPL"); + +/* only two addresses possible */ +#define TPS_BASE 0x48 +static unsigned short normal_i2c[] = { + TPS_BASE, + I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; + +static struct i2c_driver tps65010_driver; + +/*-------------------------------------------------------------------------*/ + +/* This driver handles a family of multipurpose chips, which incorporate + * voltage regulators, lithium ion/polymer battery charging, GPIOs, LEDs, + * and other features often needed in portable devices like cell phones + * or digital cameras. + * + * The tps65011 and tps65013 have different voltage settings compared + * to tps65010 and tps65012. The tps65013 has a NO_CHG status/irq. + * All except tps65010 have "wait" mode, possibly defaulted so that + * battery-insert != device-on. + * + * We could distinguish between some models by checking VDCDC1.UVLO or + * other registers, unless they've been changed already after powerup + * as part of board setup by a bootloader. + */ +enum tps_model { + TPS_UNKNOWN = 0, + TPS65010, + TPS65011, + TPS65012, + TPS65013, +}; + +struct tps65010 { + struct i2c_client client; + struct semaphore lock; + int irq; + struct work_struct work; + struct dentry *file; + unsigned charging:1; + unsigned por:1; + unsigned model:8; + u16 vbus; + unsigned long flags; +#define FLAG_VBUS_CHANGED 0 +#define FLAG_IRQ_ENABLE 1 + + /* copies of last register state */ + u8 chgstatus, regstatus, chgconf; + u8 nmask1, nmask2; + + /* plus four GPIOs, probably used to switch power */ +}; + +#define POWER_POLL_DELAY msecs_to_jiffies(800) + +/*-------------------------------------------------------------------------*/ + +#if defined(DEBUG) || defined(CONFIG_DEBUG_FS) + +static void dbg_chgstat(char *buf, size_t len, u8 chgstatus) +{ + snprintf(buf, len, "%02x%s%s%s%s%s%s%s%s\n", + chgstatus, + (chgstatus & TPS_CHG_USB) ? " USB" : "", + (chgstatus & TPS_CHG_AC) ? " AC" : "", + (chgstatus & TPS_CHG_THERM) ? " therm" : "", + (chgstatus & TPS_CHG_TERM) ? " done" : + ((chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) + ? " (charging)" : ""), + (chgstatus & TPS_CHG_TAPER_TMO) ? " taper_tmo" : "", + (chgstatus & TPS_CHG_CHG_TMO) ? " charge_tmo" : "", + (chgstatus & TPS_CHG_PRECHG_TMO) ? " prechg_tmo" : "", + (chgstatus & TPS_CHG_TEMP_ERR) ? " temp_err" : ""); +} + +static void dbg_regstat(char *buf, size_t len, u8 regstatus) +{ + snprintf(buf, len, "%02x %s%s%s%s%s%s%s%s\n", + regstatus, + (regstatus & TPS_REG_ONOFF) ? "off" : "(on)", + (regstatus & TPS_REG_COVER) ? " uncover" : "", + (regstatus & TPS_REG_UVLO) ? " UVLO" : "", + (regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "", + (regstatus & TPS_REG_PG_LD02) ? " ld01_bad" : "", + (regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "", + (regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "", + (regstatus & TPS_REG_PG_CORE) ? " core_bad" : ""); +} + +static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig) +{ + char *hibit; + + if (por) + hibit = (chgconfig & TPS_CHARGE_POR) + ? "POR=69ms" : "POR=1sec"; + else + hibit = (chgconfig & TPS65013_AUA) ? "AUA" : ""; + + snprintf(buf, len, "%02x %s%s%s AC=%d%% USB=%dmA %sCharge\n", + chgconfig, hibit, + (chgconfig & TPS_CHARGE_RESET) ? " reset" : "", + (chgconfig & TPS_CHARGE_FAST) ? " fast" : "", + ({int p; switch ((chgconfig >> 3) & 3) { + case 3: p = 100; break; + case 2: p = 75; break; + case 1: p = 50; break; + default: p = 25; break; + }; p; }), + (chgconfig & TPS_VBUS_CHARGING) + ? ((chgconfig & TPS_VBUS_500MA) ? 500 : 100) + : 0, + (chgconfig & TPS_CHARGE_ENABLE) ? "" : "No"); +} + +#endif + +#ifdef DEBUG + +static void show_chgstatus(const char *label, u8 chgstatus) +{ + char buf [100]; + + dbg_chgstat(buf, sizeof buf, chgstatus); + pr_debug("%s: %s %s", DRIVER_NAME, label, buf); +} + +static void show_regstatus(const char *label, u8 regstatus) +{ + char buf [100]; + + dbg_regstat(buf, sizeof buf, regstatus); + pr_debug("%s: %s %s", DRIVER_NAME, label, buf); +} + +static void show_chgconfig(int por, const char *label, u8 chgconfig) +{ + char buf [100]; + + dbg_chgconf(por, buf, sizeof buf, chgconfig); + pr_debug("%s: %s %s", DRIVER_NAME, label, buf); +} + +#else + +static inline void show_chgstatus(const char *label, u8 chgstatus) { } +static inline void show_regstatus(const char *label, u8 chgstatus) { } +static inline void show_chgconfig(int por, const char *label, u8 chgconfig) { } + +#endif + +#ifdef CONFIG_DEBUG_FS + +static int dbg_show(struct seq_file *s, void *_) +{ + struct tps65010 *tps = s->private; + u8 value, v2; + unsigned i; + char buf[100]; + const char *chip; + + switch (tps->model) { + case TPS65010: chip = "tps65010"; break; + case TPS65011: chip = "tps65011"; break; + case TPS65012: chip = "tps65012"; break; + case TPS65013: chip = "tps65013"; break; + default: chip = NULL; break; + } + seq_printf(s, "driver %s\nversion %s\nchip %s\n\n", + DRIVER_NAME, DRIVER_VERSION, chip); + + down(&tps->lock); + + /* FIXME how can we tell whether a battery is present? + * likely involves a charge gauging chip (like BQ26501). + */ + + seq_printf(s, "%scharging\n\n", tps->charging ? "" : "(not) "); + + + /* registers for monitoring battery charging and status; note + * that reading chgstat and regstat may ack IRQs... + */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + dbg_chgconf(tps->por, buf, sizeof buf, value); + seq_printf(s, "chgconfig %s", buf); + + value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + dbg_chgstat(buf, sizeof buf, value); + seq_printf(s, "chgstat %s", buf); + value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1); + dbg_chgstat(buf, sizeof buf, value); + seq_printf(s, "mask1 %s", buf); + /* ignore ackint1 */ + + value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + dbg_regstat(buf, sizeof buf, value); + seq_printf(s, "regstat %s", buf); + value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2); + dbg_regstat(buf, sizeof buf, value); + seq_printf(s, "mask2 %s\n", buf); + /* ignore ackint2 */ + + (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); + + + /* VMAIN voltage, enable lowpower, etc */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1); + seq_printf(s, "vdcdc1 %02x\n", value); + + /* VCORE voltage, vibrator on/off */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2); + seq_printf(s, "vdcdc2 %02x\n", value); + + /* both LD0s, and their lowpower behavior */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1); + seq_printf(s, "vregs1 %02x\n\n", value); + + + /* LEDs and GPIOs */ + value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON); + v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER); + seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n", + (value & 0x80) + ? ((v2 & 0x80) ? "on" : "off") + : ((v2 & 0x80) ? "blink" : "(nPG)"), + value, v2, + (value & 0x7f) * 10, (v2 & 0x7f) * 100); + + value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON); + v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER); + seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n", + (value & 0x80) + ? ((v2 & 0x80) ? "on" : "off") + : ((v2 & 0x80) ? "blink" : "off"), + value, v2, + (value & 0x7f) * 10, (v2 & 0x7f) * 100); + + value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO); + v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3); + seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2); + + for (i = 0; i < 4; i++) { + if (value & (1 << (4 +i))) + seq_printf(s, " gpio%d-out %s\n", i + 1, + (value & (1 << i)) ? "low" : "hi "); + else + seq_printf(s, " gpio%d-in %s %s %s\n", i + 1, + (value & (1 << i)) ? "hi " : "low", + (v2 & (1 << i)) ? "no-irq" : "irq", + (v2 & (1 << (4 + i))) ? "rising" : "falling"); + } + + up(&tps->lock); + return 0; +} + +static int dbg_tps_open(struct inode *inode, struct file *file) +{ + return single_open(file, dbg_show, inode->u.generic_ip); +} + +static struct file_operations debug_fops = { + .open = dbg_tps_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define DEBUG_FOPS &debug_fops + +#else +#define DEBUG_FOPS NULL +#endif + +/*-------------------------------------------------------------------------*/ + +/* handle IRQS in a task context, so we can use I2C calls */ +static void tps65010_interrupt(struct tps65010 *tps) +{ + u8 tmp = 0, mask, poll; + + /* IRQs won't trigger irqs for certain events, but we can get + * others by polling (normally, with external power applied). + */ + poll = 0; + + /* regstatus irqs */ + if (tps->nmask2) { + tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + mask = tmp ^ tps->regstatus; + tps->regstatus = tmp; + mask &= tps->nmask2; + } else + mask = 0; + if (mask) { + tps->regstatus = tmp; + /* may need to shut something down ... */ + + /* "off" usually means deep sleep */ + if (tmp & TPS_REG_ONOFF) { + pr_info("%s: power off button\n", DRIVER_NAME); +#if 0 + /* REVISIT: this might need its own workqueue + * plus tweaks including deadlock avoidance ... + */ + software_suspend(); +#endif + poll = 1; + } + } + + /* chgstatus irqs */ + if (tps->nmask1) { + tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + mask = tmp ^ tps->chgstatus; + tps->chgstatus = tmp; + mask &= tps->nmask1; + } else + mask = 0; + if (mask) { + unsigned charging = 0; + + show_chgstatus("chg/irq", tmp); + if (tmp & (TPS_CHG_USB|TPS_CHG_AC)) + show_chgconfig(tps->por, "conf", tps->chgconf); + + /* Unless it was turned off or disabled, we charge any + * battery whenever there's power available for it + * and the charger hasn't been disabled. + */ + if (!(tps->chgstatus & ~(TPS_CHG_USB|TPS_CHG_AC)) + && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) + && (tps->chgconf & TPS_CHARGE_ENABLE) + ) { + if (tps->chgstatus & TPS_CHG_USB) { + /* VBUS options are readonly until reconnect */ + if (mask & TPS_CHG_USB) + set_bit(FLAG_VBUS_CHANGED, &tps->flags); + charging = 1; + } else if (tps->chgstatus & TPS_CHG_AC) + charging = 1; + } + if (charging != tps->charging) { + tps->charging = charging; + pr_info("%s: battery %scharging\n", + DRIVER_NAME, charging ? "" : + ((tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)) + ? "NOT " : "dis")); + } + } + + /* always poll to detect (a) power removal, without tps65013 + * NO_CHG IRQ; or (b) restart of charging after stop. + */ + if ((tps->model != TPS65013 || !tps->charging) + && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))) + poll = 1; + if (poll) + (void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); + + /* also potentially gpio-in rise or fall */ +} + +/* handle IRQs and polling using keventd for now */ +static void tps65010_work(void *_tps) +{ + struct tps65010 *tps = _tps; + + down(&tps->lock); + + tps65010_interrupt(tps); + + if (test_and_clear_bit(FLAG_VBUS_CHANGED, &tps->flags)) { + int status; + u8 chgconfig, tmp; + + chgconfig = i2c_smbus_read_byte_data(&tps->client, + TPS_CHGCONFIG); + chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING); + if (tps->vbus == 500) + chgconfig |= TPS_VBUS_500MA | TPS_VBUS_CHARGING; + else if (tps->vbus >= 100) + chgconfig |= TPS_VBUS_CHARGING; + + status = i2c_smbus_write_byte_data(&tps->client, + TPS_CHGCONFIG, chgconfig); + + /* vbus update fails unless VBUS is connected! */ + tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + tps->chgconf = tmp; + show_chgconfig(tps->por, "update vbus", tmp); + } + + if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags)) + enable_irq(tps->irq); + + up(&tps->lock); +} + +static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs) +{ + struct tps65010 *tps = _tps; + + disable_irq_nosync(irq); + set_bit(FLAG_IRQ_ENABLE, &tps->flags); + (void) schedule_work(&tps->work); + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +static struct tps65010 *the_tps; + +static int __exit tps65010_detach_client(struct i2c_client *client) +{ + struct tps65010 *tps; + + tps = container_of(client, struct tps65010, client); +#ifdef CONFIG_ARM + if (machine_is_omap_h2()) + omap_free_gpio(58); + if (machine_is_omap_osk()) + omap_free_gpio(OMAP_MPUIO(1)); +#endif + free_irq(tps->irq, tps); + debugfs_remove(tps->file); + if (i2c_detach_client(client) == 0) + kfree(tps); + the_tps = 0; + return 0; +} + +static int tps65010_noscan(struct i2c_adapter *bus) +{ + /* pure paranoia, in case someone adds another i2c bus + * after our init section's gone... + */ + return -ENODEV; +} + +/* no error returns, they'd just make bus scanning stop */ +static int __init +tps65010_probe(struct i2c_adapter *bus, int address, int kind) +{ + struct tps65010 *tps; + int status; + + if (the_tps) { + dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME); + return 0; + } + + tps = kmalloc(sizeof *tps, GFP_KERNEL); + if (!tps) + return 0; + + memset(tps, 0, sizeof *tps); + init_MUTEX(&tps->lock); + INIT_WORK(&tps->work, tps65010_work, tps); + tps->irq = -1; + tps->client.addr = address; + i2c_set_clientdata(&tps->client, tps); + tps->client.adapter = bus; + tps->client.driver = &tps65010_driver; + strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE); + + status = i2c_attach_client(&tps->client); + if (status < 0) { + dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", + DRIVER_NAME, address, status); +fail1: + kfree(tps); + return 0; + } + +#ifdef CONFIG_ARM + if (machine_is_omap_h2()) { + tps->model = TPS65010; + omap_cfg_reg(W4_GPIO58); + tps->irq = OMAP_GPIO_IRQ(58); + omap_request_gpio(58); + omap_set_gpio_direction(58, 1); + omap_set_gpio_edge_ctrl(58, OMAP_GPIO_FALLING_EDGE); + } + if (machine_is_omap_osk()) { + tps->model = TPS65010; + // omap_cfg_reg(U19_1610_MPUIO1); + tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); + omap_request_gpio(OMAP_MPUIO(1)); + omap_set_gpio_direction(OMAP_MPUIO(1), 1); + omap_set_gpio_edge_ctrl(OMAP_MPUIO(1), OMAP_GPIO_FALLING_EDGE); + } + if (machine_is_omap_h3()) { + tps->model = TPS65013; + + // FIXME set up this board's IRQ ... + } +#else +#define set_irq_type(num,trigger) do{}while(0) +#endif + + if (tps->irq > 0) { + set_irq_type(tps->irq, IRQT_LOW); + status = request_irq(tps->irq, tps65010_irq, + SA_SAMPLE_RANDOM, DRIVER_NAME, tps); + if (status < 0) { + dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n", + tps->irq, status); + i2c_detach_client(&tps->client); + goto fail1; + } +#ifdef CONFIG_ARM + /* annoying race here, ideally we'd have an option + * to claim the irq now and enable it later. + */ + disable_irq(tps->irq); + set_bit(FLAG_IRQ_ENABLE, &tps->flags); +#endif + } else + printk(KERN_WARNING "%s: IRQ not configured!\n", + DRIVER_NAME); + + + switch (tps->model) { + case TPS65010: + case TPS65012: + tps->por = 1; + break; + case TPS_UNKNOWN: + printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME); + break; + /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ + } + tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + show_chgconfig(tps->por, "conf/init", tps->chgconf); + + show_chgstatus("chg/init", + i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS)); + show_regstatus("reg/init", + i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS)); + + pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1), + i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2), + i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1)); + pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO), + i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); + + tps65010_driver.attach_adapter = tps65010_noscan; + the_tps = tps; + +#if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) + /* USB hosts can't draw VBUS. OTG devices could, later + * when OTG infrastructure enables it. USB peripherals + * could be relying on VBUS while booting, though. + */ + tps->vbus = 100; +#endif + + /* unmask the "interesting" irqs, then poll once to + * kickstart monitoring, initialize shadowed status + * registers, and maybe disable VBUS draw. + */ + tps->nmask1 = ~0; + (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1); + + tps->nmask2 = TPS_REG_ONOFF; + if (tps->model == TPS65013) + tps->nmask2 |= TPS_REG_NO_CHG; + (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2); + + (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f + | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); + + tps65010_work(tps); + + tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, + tps, DEBUG_FOPS); + return 0; +} + +static int __init tps65010_scan_bus(struct i2c_adapter *bus) +{ + if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EINVAL; + return i2c_probe(bus, &addr_data, tps65010_probe); +} + +static struct i2c_driver tps65010_driver = { + .owner = THIS_MODULE, + .name = "tps65010", + .id = 888, /* FIXME assign "official" value */ + .flags = I2C_DF_NOTIFY, + .attach_adapter = tps65010_scan_bus, + .detach_client = __exit_p(tps65010_detach_client), +}; + +/*-------------------------------------------------------------------------*/ + +/* Draw from VBUS: + * 0 mA -- DON'T DRAW (might supply power instead) + * 100 mA -- usb unit load (slowest charge rate) + * 500 mA -- usb high power (fast battery charge) + */ +int tps65010_set_vbus_draw(unsigned mA) +{ + unsigned long flags; + + if (!the_tps) + return -ENODEV; + + /* assumes non-SMP */ + local_irq_save(flags); + if (mA >= 500) + mA = 500; + else if (mA >= 100) + mA = 100; + else + mA = 0; + the_tps->vbus = mA; + if ((the_tps->chgstatus & TPS_CHG_USB) + && test_and_set_bit( + FLAG_VBUS_CHANGED, &the_tps->flags)) { + /* gadget drivers call this in_irq() */ + (void) schedule_work(&the_tps->work); + } + local_irq_restore(flags); + + return 0; +} +EXPORT_SYMBOL(tps65010_set_vbus_draw); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_gpio_out_value parameter: + * gpio: GPIO1, GPIO2, GPIO3 or GPIO4 + * value: LOW or HIGH + */ +int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) +{ + int status; + unsigned defgpio; + + if (!the_tps) + return -ENODEV; + if ((gpio < GPIO1) || (gpio > GPIO4)) + return -EINVAL; + + down(&the_tps->lock); + + defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO); + + /* Configure GPIO for output */ + defgpio |= 1 << (gpio + 3); + + /* Writing 1 forces a logic 0 on that GPIO and vice versa */ + switch (value) { + case LOW: + defgpio |= 1 << (gpio - 1); /* set GPIO low by writing 1 */ + break; + /* case HIGH: */ + default: + defgpio &= ~(1 << (gpio - 1)); /* set GPIO high by writing 0 */ + break; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_DEFGPIO, defgpio); + + pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME, + gpio, value ? "high" : "low", + i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO)); + + up(&the_tps->lock); + return status; +} +EXPORT_SYMBOL(tps65010_set_gpio_out_value); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_led parameter: + * led: LED1 or LED2 + * mode: ON, OFF or BLINK + */ +int tps65010_set_led(unsigned led, unsigned mode) +{ + int status; + unsigned led_on, led_per, offs; + + if (!the_tps) + return -ENODEV; + + if(led == LED1) + offs = 0; + else { + offs = 2; + led = LED2; + } + + down(&the_tps->lock); + + dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + + dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + + switch (mode) { + case OFF: + led_on = 1 << 7; + led_per = 0 << 7; + break; + case ON: + led_on = 1 << 7; + led_per = 1 << 7; + break; + case BLINK: + led_on = 0x30 | (0 << 7); + led_per = 0x08 | (1 << 7); + break; + default: + printk(KERN_ERR "%s: Wrong mode parameter for tps65010_set_led()\n", + DRIVER_NAME); + up(&the_tps->lock); + return -EINVAL; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_LED1_ON + offs, led_on); + + if (status != 0) { + printk(KERN_ERR "%s: Failed to write led%i_on register\n", + DRIVER_NAME, led); + up(&the_tps->lock); + return status; + } + + dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_LED1_PER + offs, led_per); + + if (status != 0) { + printk(KERN_ERR "%s: Failed to write led%i_per register\n", + DRIVER_NAME, led); + up(&the_tps->lock); + return status; + } + + dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65010_set_led); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_vib parameter: + * value: ON or OFF + */ +int tps65010_set_vib(unsigned value) +{ + int status; + unsigned vdcdc2; + + if (!the_tps) + return -ENODEV; + + down(&the_tps->lock); + + vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2); + vdcdc2 &= ~(1 << 1); + if (value) + vdcdc2 |= (1 << 1); + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VDCDC2, vdcdc2); + + pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off"); + + up(&the_tps->lock); + return status; +} +EXPORT_SYMBOL(tps65010_set_vib); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_low_pwr parameter: + * mode: ON or OFF + */ +int tps65010_set_low_pwr(unsigned mode) +{ + int status; + unsigned vdcdc1; + + if (!the_tps) + return -ENODEV; + + down(&the_tps->lock); + + pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, + mode ? "enable" : "disable", + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + + switch (mode) { + case OFF: + vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ + break; + /* case ON: */ + default: + vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ + break; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VDCDC1, vdcdc1); + + if (status != 0) + printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", + DRIVER_NAME); + else + pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65010_set_low_pwr); + +/*-------------------------------------------------------------------------*/ +/* tps65010_config_vregs1 parameter: + * value to be written to VREGS1 register + * Note: The complete register is written, set all bits you need + */ +int tps65010_config_vregs1(unsigned value) +{ + int status; + + if (!the_tps) + return -ENODEV; + + down(&the_tps->lock); + + pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VREGS1, value); + + if (status != 0) + printk(KERN_ERR "%s: Failed to write vregs1 register\n", + DRIVER_NAME); + else + pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65010_config_vregs1); + +/*-------------------------------------------------------------------------*/ +/* tps65013_set_low_pwr parameter: + * mode: ON or OFF + */ + +/* FIXME: Assumes AC or USB power is present. Setting AUA bit is not + required if power supply is through a battery */ + +int tps65013_set_low_pwr(unsigned mode) +{ + int status; + unsigned vdcdc1, chgconfig; + + if (!the_tps || the_tps->por) + return -ENODEV; + + down(&the_tps->lock); + + pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", + DRIVER_NAME, + mode ? "enable" : "disable", + i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG), + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); + vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + + switch (mode) { + case OFF: + chgconfig &= ~TPS65013_AUA; /* disable AUA bit */ + vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ + break; + /* case ON: */ + default: + chgconfig |= TPS65013_AUA; /* enable AUA bit */ + vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ + break; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_CHGCONFIG, chgconfig); + if (status != 0) { + printk(KERN_ERR "%s: Failed to write chconfig register\n", + DRIVER_NAME); + up(&the_tps->lock); + return status; + } + + chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); + the_tps->chgconf = chgconfig; + show_chgconfig(0, "chgconf", chgconfig); + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VDCDC1, vdcdc1); + + if (status != 0) + printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", + DRIVER_NAME); + else + pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65013_set_low_pwr); + +/*-------------------------------------------------------------------------*/ + +static int __init tps_init(void) +{ + u32 tries = 3; + int status = -ENODEV; + + printk(KERN_INFO "%s: version %s\n", DRIVER_NAME, DRIVER_VERSION); + + /* some boards have startup glitches */ + while (tries--) { + status = i2c_add_driver(&tps65010_driver); + if (the_tps) + break; + i2c_del_driver(&tps65010_driver); + if (!tries) { + printk(KERN_ERR "%s: no chip?\n", DRIVER_NAME); + return -ENODEV; + } + pr_debug("%s: re-probe ...\n", DRIVER_NAME); + msleep(10); + } + +#if defined(CONFIG_ARM) + if (machine_is_omap_osk()) { + + // FIXME: More should be placed in the initialization code + // of the submodules (DSP, ethernet, power management, + // board-osk.c). Careful: I2C is initialized "late". + + /* Let LED1 (D9) blink */ + tps65010_set_led(LED1, BLINK); + + /* Disable LED 2 (D2) */ + tps65010_set_led(LED2, OFF); + + /* Set GPIO 1 HIGH to disable VBUS power supply; + * OHCI driver powers it up/down as needed. + */ + tps65010_set_gpio_out_value(GPIO1, HIGH); + + /* Set GPIO 2 low to turn on LED D3 */ + tps65010_set_gpio_out_value(GPIO2, HIGH); + + /* Set GPIO 3 low to take ethernet out of reset */ + tps65010_set_gpio_out_value(GPIO3, LOW); + + /* gpio4 for VDD_DSP */ + + /* Enable LOW_PWR */ + tps65010_set_low_pwr(ON); + + /* Switch VLDO2 to 3.0V for AIC23 */ + tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE); + + } else if (machine_is_omap_h2()) { + /* gpio3 for SD, gpio4 for VDD_DSP */ + + /* Enable LOW_PWR */ + tps65010_set_low_pwr(ON); + } else if (machine_is_omap_h3()) { + /* gpio4 for SD, gpio3 for VDD_DSP */ +#ifdef CONFIG_PM + /* Enable LOW_PWR */ + tps65013_set_low_pwr(ON); +#endif + } +#endif + + return status; +} +/* NOTE: this MUST be initialized before the other parts of the system + * that rely on it ... but after the i2c bus on which this relies. + * That is, much earlier than on PC-type systems, which don't often use + * I2C as a core system bus. + */ +subsys_initcall(tps_init); + +static void __exit tps_exit(void) +{ + i2c_del_driver(&tps65010_driver); +} +module_exit(tps_exit); + diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index fefc24a..137d9b7 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -1,12 +1,12 @@ /* via686a.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - + Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki <kmalkki@cc.hut.fi>, Mark Studebaker <mdsxyz123@yahoo.com>, and Bob Dougherty <bobd@stanford.edu> - (Some conversion-factor data were contributed by Jonathan Teh Soon Yew + (Some conversion-factor data were contributed by Jonathan Teh Soon Yew <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.) This program is free software; you can redistribute it and/or modify @@ -30,11 +30,9 @@ Warning - only supports a single device. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/pci.h> -#include <linux/delay.h> #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/i2c-sensor.h> @@ -66,49 +64,46 @@ SENSORS_INSMOD_1(via686a); /* Many VIA686A constants specified below */ /* Length of ISA address segment */ -#define VIA686A_EXTENT 0x80 -#define VIA686A_BASE_REG 0x70 -#define VIA686A_ENABLE_REG 0x74 +#define VIA686A_EXTENT 0x80 +#define VIA686A_BASE_REG 0x70 +#define VIA686A_ENABLE_REG 0x74 /* The VIA686A registers */ /* ins numbered 0-4 */ -#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) -#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) -#define VIA686A_REG_IN(nr) (0x22 + (nr)) +#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) +#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) +#define VIA686A_REG_IN(nr) (0x22 + (nr)) /* fans numbered 1-2 */ -#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VIA686A_REG_FAN(nr) (0x28 + (nr)) - -/* the following values are as speced by VIA: */ -static const u8 regtemp[] = { 0x20, 0x21, 0x1f }; -static const u8 regover[] = { 0x39, 0x3d, 0x1d }; -static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; +#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) +#define VIA686A_REG_FAN(nr) (0x28 + (nr)) /* temps numbered 1-3 */ -#define VIA686A_REG_TEMP(nr) (regtemp[nr]) -#define VIA686A_REG_TEMP_OVER(nr) (regover[nr]) -#define VIA686A_REG_TEMP_HYST(nr) (reghyst[nr]) -#define VIA686A_REG_TEMP_LOW1 0x4b // bits 7-6 -#define VIA686A_REG_TEMP_LOW23 0x49 // 2 = bits 5-4, 3 = bits 7-6 - -#define VIA686A_REG_ALARM1 0x41 -#define VIA686A_REG_ALARM2 0x42 -#define VIA686A_REG_FANDIV 0x47 -#define VIA686A_REG_CONFIG 0x40 -/* The following register sets temp interrupt mode (bits 1-0 for temp1, +static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; +static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; +static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; +/* bits 7-6 */ +#define VIA686A_REG_TEMP_LOW1 0x4b +/* 2 = bits 5-4, 3 = bits 7-6 */ +#define VIA686A_REG_TEMP_LOW23 0x49 + +#define VIA686A_REG_ALARM1 0x41 +#define VIA686A_REG_ALARM2 0x42 +#define VIA686A_REG_FANDIV 0x47 +#define VIA686A_REG_CONFIG 0x40 +/* The following register sets temp interrupt mode (bits 1-0 for temp1, 3-2 for temp2, 5-4 for temp3). Modes are: 00 interrupt stays as long as value is out-of-range 01 interrupt is cleared once register is read (default) 10 comparator mode- like 00, but ignores hysteresis 11 same as 00 */ -#define VIA686A_REG_TEMP_MODE 0x4b +#define VIA686A_REG_TEMP_MODE 0x4b /* We'll just assume that you want to set all 3 simultaneously: */ -#define VIA686A_TEMP_MODE_MASK 0x3F -#define VIA686A_TEMP_MODE_CONTINUOUS (0x00) +#define VIA686A_TEMP_MODE_MASK 0x3F +#define VIA686A_TEMP_MODE_CONTINUOUS 0x00 /* Conversions. Limit checking is only done on the TO_REG - variants. + variants. ********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): @@ -121,7 +116,7 @@ static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; That is: volts = (25*regVal+133)*factor regVal = (volts/factor-133)/25 - (These conversions were contributed by Jonathan Teh Soon Yew + (These conversions were contributed by Jonathan Teh Soon Yew <j.teh@iname.com>) */ static inline u8 IN_TO_REG(long val, int inNum) { @@ -182,55 +177,55 @@ static inline u8 FAN_TO_REG(long rpm, int div) else return double(temp)*0.924-127.33; - A fifth-order polynomial fits the unofficial data (provided by Alex van - Kaam <darkside@chello.nl>) a bit better. It also give more reasonable - numbers on my machine (ie. they agree with what my BIOS tells me). + A fifth-order polynomial fits the unofficial data (provided by Alex van + Kaam <darkside@chello.nl>) a bit better. It also give more reasonable + numbers on my machine (ie. they agree with what my BIOS tells me). Here's the fifth-order fit to the 8-bit data: - temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - + temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. - (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for + (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for finding my typos in this formula!) - Alas, none of the elegant function-fit solutions will work because we - aren't allowed to use floating point in the kernel and doing it with - integers doesn't rpovide enough precision. So we'll do boring old - look-up table stuff. The unofficial data (see below) have effectively - 7-bit resolution (they are rounded to the nearest degree). I'm assuming - that the transfer function of the device is monotonic and smooth, so a - smooth function fit to the data will allow us to get better precision. + Alas, none of the elegant function-fit solutions will work because we + aren't allowed to use floating point in the kernel and doing it with + integers doesn't provide enough precision. So we'll do boring old + look-up table stuff. The unofficial data (see below) have effectively + 7-bit resolution (they are rounded to the nearest degree). I'm assuming + that the transfer function of the device is monotonic and smooth, so a + smooth function fit to the data will allow us to get better precision. I used the 5th-order poly fit described above and solved for - VIA register values 0-255. I *10 before rounding, so we get tenth-degree - precision. (I could have done all 1024 values for our 10-bit readings, - but the function is very linear in the useful range (0-80 deg C), so - we'll just use linear interpolation for 10-bit readings.) So, tempLUT + VIA register values 0-255. I *10 before rounding, so we get tenth-degree + precision. (I could have done all 1024 values for our 10-bit readings, + but the function is very linear in the useful range (0-80 deg C), so + we'll just use linear interpolation for 10-bit readings.) So, tempLUT is the temp at via register values 0-255: */ static const long tempLUT[] = - { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, - -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, - -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, - -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, - -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, - -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, - -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, - 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, - 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, - 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, - 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, - 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, - 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, - 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, - 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, - 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, - 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, - 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, - 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, - 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, - 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, - 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 +{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, + -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, + -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, + -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, + -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, + -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, + -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, + 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, + 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, + 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, + 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, + 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, + 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, + 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, + 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, + 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, + 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, + 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, + 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, + 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, + 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, + 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 }; -/* the original LUT values from Alex van Kaam <darkside@chello.nl> +/* the original LUT values from Alex van Kaam <darkside@chello.nl> (for via register values 12-240): {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, @@ -245,26 +240,26 @@ static const long tempLUT[] = Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed - an extra term for a good fit to these inverse data!) and then - solving for each temp value from -50 to 110 (the useable range for - this chip). Here's the fit: - viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 + an extra term for a good fit to these inverse data!) and then + solving for each temp value from -50 to 110 (the useable range for + this chip). Here's the fit: + viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) Note that n=161: */ static const u8 viaLUT[] = - { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, - 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, - 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, - 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, - 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, - 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, - 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, - 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, - 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, - 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, - 239, 240 +{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, + 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, + 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, + 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, + 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, + 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, + 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, + 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, + 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, + 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, + 239, 240 }; /* Converting temps to (8-bit) hyst and over registers @@ -272,7 +267,7 @@ static const u8 viaLUT[] = The +50 is because the temps start at -50 */ static inline u8 TEMP_TO_REG(long val) { - return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : + return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : (val < 0 ? val - 500 : val + 500) / 1000 + 50]; } @@ -291,11 +286,9 @@ static inline long TEMP_FROM_REG10(u16 val) /* do some linear interpolation */ return (tempLUT[eightBits] * (4 - twoBits) + - tempLUT[eightBits + 1] * twoBits) * 25; + tempLUT[eightBits + 1] * twoBits) * 25; } -#define ALARMS_FROM_REG(val) (val) - #define DIV_FROM_REG(val) (1 << (val)) #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) @@ -358,28 +351,28 @@ static ssize_t show_in_max(struct device *dev, char *buf, int nr) { return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); } -static ssize_t set_in_min(struct device *dev, const char *buf, +static ssize_t set_in_min(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val,nr); - via686a_write_value(client, VIA686A_REG_IN_MIN(nr), + data->in_min[nr] = IN_TO_REG(val, nr); + via686a_write_value(client, VIA686A_REG_IN_MIN(nr), data->in_min[nr]); up(&data->update_lock); return count; } -static ssize_t set_in_max(struct device *dev, const char *buf, +static ssize_t set_in_max(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val,nr); - via686a_write_value(client, VIA686A_REG_IN_MAX(nr), + data->in_max[nr] = IN_TO_REG(val, nr); + via686a_write_value(client, VIA686A_REG_IN_MAX(nr), data->in_max[nr]); up(&data->update_lock); return count; @@ -435,7 +428,7 @@ static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); } -static ssize_t set_temp_over(struct device *dev, const char *buf, +static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); @@ -443,11 +436,12 @@ static ssize_t set_temp_over(struct device *dev, const char *buf, down(&data->update_lock); data->temp_over[nr] = TEMP_TO_REG(val); - via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]); + via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr], + data->temp_over[nr]); up(&data->update_lock); return count; } -static ssize_t set_temp_hyst(struct device *dev, const char *buf, +static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); @@ -455,7 +449,8 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf, down(&data->update_lock); data->temp_hyst[nr] = TEMP_TO_REG(val); - via686a_write_value(client, VIA686A_REG_TEMP_HYST(nr), data->temp_hyst[nr]); + via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr], + data->temp_hyst[nr]); up(&data->update_lock); return count; } @@ -488,7 +483,7 @@ static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\ static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ show_temp_##offset##_over, set_temp_##offset##_over); \ static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_hyst, set_temp_##offset##_hyst); + show_temp_##offset##_hyst, set_temp_##offset##_hyst); show_temp_offset(1); show_temp_offset(2); @@ -497,19 +492,19 @@ show_temp_offset(3); /* 2 Fans */ static ssize_t show_fan(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr])) ); } static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf,"%d\n", + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); } static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf,"%d\n", DIV_FROM_REG(data->fan_div[nr]) ); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); } -static ssize_t set_fan_min(struct device *dev, const char *buf, +static ssize_t set_fan_min(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); @@ -521,7 +516,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, up(&data->update_lock); return count; } -static ssize_t set_fan_div(struct device *dev, const char *buf, +static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); @@ -572,7 +567,7 @@ show_fan_offset(2); /* Alarms */ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); @@ -612,11 +607,12 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) } /* 8231 requires multiple of 256, we enforce that on 686 as well */ - if(force_addr) + if (force_addr) address = force_addr & 0xFF00; - if(force_addr) { - dev_warn(&adapter->dev,"forcing ISA address 0x%04X\n", address); + if (force_addr) { + dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", + address); if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) return -ENODEV; @@ -625,17 +621,17 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) return -ENODEV; if (!(val & 0x0001)) { - dev_warn(&adapter->dev,"enabling sensors\n"); + dev_warn(&adapter->dev, "enabling sensors\n"); if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) + val | 0x0001)) return -ENODEV; } /* Reserve the ISA region */ if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) { - dev_err(&adapter->dev,"region 0x%x already in use!\n", - address); + dev_err(&adapter->dev, "region 0x%x already in use!\n", + address); return -ENODEV; } @@ -660,7 +656,7 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto ERROR3; - + /* Initialize the VIA686A chip */ via686a_init_client(new_client); @@ -699,9 +695,9 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) return 0; - ERROR3: +ERROR3: kfree(data); - ERROR0: +ERROR0: release_region(address, VIA686A_EXTENT); return err; } @@ -732,7 +728,7 @@ static void via686a_init_client(struct i2c_client *client) via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); /* Configure temp interrupt mode for continuous-interrupt operation */ - via686a_write_value(client, VIA686A_REG_TEMP_MODE, + via686a_write_value(client, VIA686A_REG_TEMP_MODE, via686a_read_value(client, VIA686A_REG_TEMP_MODE) & !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); } @@ -764,15 +760,15 @@ static struct via686a_data *via686a_update_device(struct device *dev) } for (i = 0; i <= 2; i++) { data->temp[i] = via686a_read_value(client, - VIA686A_REG_TEMP(i)) << 2; + VIA686A_REG_TEMP[i]) << 2; data->temp_over[i] = via686a_read_value(client, - VIA686A_REG_TEMP_OVER(i)); + VIA686A_REG_TEMP_OVER[i]); data->temp_hyst[i] = via686a_read_value(client, - VIA686A_REG_TEMP_HYST(i)); + VIA686A_REG_TEMP_HYST[i]); } - /* add in lower 2 bits + /* add in lower 2 bits temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 @@ -804,35 +800,36 @@ static struct via686a_data *via686a_update_device(struct device *dev) } static struct pci_device_id via686a_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, - { 0, } + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, + { 0, } }; MODULE_DEVICE_TABLE(pci, via686a_pci_ids); static int __devinit via686a_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) + const struct pci_device_id *id) { - u16 val; - int addr = 0; - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(dev, VIA686A_BASE_REG, &val)) - return -ENODEV; - - addr = val & ~(VIA686A_EXTENT - 1); - if (addr == 0 && force_addr == 0) { - dev_err(&dev->dev,"base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - addr = force_addr; /* so detect will get called */ - - if (!addr) { - dev_err(&dev->dev,"No Via 686A sensors found.\n"); - return -ENODEV; - } - normal_isa[0] = addr; + u16 val; + int addr = 0; + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(dev, VIA686A_BASE_REG, &val)) + return -ENODEV; + + addr = val & ~(VIA686A_EXTENT - 1); + if (addr == 0 && force_addr == 0) { + dev_err(&dev->dev, "base address not set - upgrade BIOS " + "or use force_addr=0xaddr\n"); + return -ENODEV; + } + if (force_addr) + addr = force_addr; /* so detect will get called */ + + if (!addr) { + dev_err(&dev->dev, "No Via 686A sensors found.\n"); + return -ENODEV; + } + normal_isa[0] = addr; s_bridge = pci_dev_get(dev); if (i2c_add_driver(&via686a_driver)) { @@ -848,14 +845,14 @@ static int __devinit via686a_pci_probe(struct pci_dev *dev, } static struct pci_driver via686a_pci_driver = { - .name = "via686a", - .id_table = via686a_pci_ids, - .probe = via686a_pci_probe, + .name = "via686a", + .id_table = via686a_pci_ids, + .probe = via686a_pci_probe, }; static int __init sm_via686a_init(void) { - return pci_register_driver(&via686a_pci_driver); + return pci_register_driver(&via686a_pci_driver); } static void __exit sm_via686a_exit(void) @@ -869,8 +866,8 @@ static void __exit sm_via686a_exit(void) } MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, " - "Mark Studebaker <mdsxyz123@yahoo.com> " - "and Bob Dougherty <bobd@stanford.edu>"); + "Mark Studebaker <mdsxyz123@yahoo.com> " + "and Bob Dougherty <bobd@stanford.edu>"); MODULE_DESCRIPTION("VIA 686A Sensor device"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/chips/w83627ehf.c b/drivers/i2c/chips/w83627ehf.c new file mode 100644 index 0000000..8a40b69 --- /dev/null +++ b/drivers/i2c/chips/w83627ehf.c @@ -0,0 +1,846 @@ +/* + w83627ehf - Driver for the hardware monitoring functionality of + the Winbond W83627EHF Super-I/O chip + Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> + + Shamelessly ripped from the w83627hf driver + Copyright (C) 2003 Mark Studebaker + + Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help + in testing and debugging this driver. + + 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. + + + Supports the following chips: + + Chip #vin #fan #pwm #temp chip_id man_id + w83627ehf - 5 - 3 0x88 0x5ca3 + + This is a preliminary version of the driver, only supporting the + fan and temperature inputs. The chip does much more than that. +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/i2c-sensor.h> +#include <asm/io.h> +#include "lm75.h" + +/* Addresses to scan + The actual ISA address is read from Super-I/O configuration space */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(w83627ehf); + +/* + * Super-I/O constants and functions + */ + +static int REG; /* The register to read/write */ +static int VAL; /* The value to read/write */ + +#define W83627EHF_LD_HWM 0x0b + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ + +#define SIO_W83627EHF_ID 0x8840 +#define SIO_ID_MASK 0xFFC0 + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static inline void +superio_select(int ld) +{ + outb(SIO_REG_LDSEL, REG); + outb(ld, VAL); +} + +static inline void +superio_enter(void) +{ + outb(0x87, REG); + outb(0x87, REG); +} + +static inline void +superio_exit(void) +{ + outb(0x02, REG); + outb(0x02, VAL); +} + +/* + * ISA constants + */ + +#define REGION_LENGTH 8 +#define ADDR_REG_OFFSET 5 +#define DATA_REG_OFFSET 6 + +#define W83627EHF_REG_BANK 0x4E +#define W83627EHF_REG_CONFIG 0x40 +#define W83627EHF_REG_CHIP_ID 0x49 +#define W83627EHF_REG_MAN_ID 0x4F + +static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; +static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; + +#define W83627EHF_REG_TEMP1 0x27 +#define W83627EHF_REG_TEMP1_HYST 0x3a +#define W83627EHF_REG_TEMP1_OVER 0x39 +static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 }; +static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 }; +static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 }; +static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; + +/* Fan clock dividers are spread over the following five registers */ +#define W83627EHF_REG_FANDIV1 0x47 +#define W83627EHF_REG_FANDIV2 0x4B +#define W83627EHF_REG_VBAT 0x5D +#define W83627EHF_REG_DIODE 0x59 +#define W83627EHF_REG_SMI_OVT 0x4C + +/* + * Conversions + */ + +static inline unsigned int +fan_from_reg(u8 reg, unsigned int div) +{ + if (reg == 0 || reg == 255) + return 0; + return 1350000U / (reg * div); +} + +static inline unsigned int +div_from_reg(u8 reg) +{ + return 1 << reg; +} + +static inline int +temp1_from_reg(s8 reg) +{ + return reg * 1000; +} + +static inline s8 +temp1_to_reg(int temp) +{ + if (temp <= -128000) + return -128; + if (temp >= 127000) + return 127; + if (temp < 0) + return (temp - 500) / 1000; + return (temp + 500) / 1000; +} + +/* + * Data structures and manipulation thereof + */ + +struct w83627ehf_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* Register values */ + u8 fan[5]; + u8 fan_min[5]; + u8 fan_div[5]; + u8 has_fan; /* some fan inputs can be disabled */ + s8 temp1; + s8 temp1_max; + s8 temp1_max_hyst; + s16 temp[2]; + s16 temp_max[2]; + s16 temp_max_hyst[2]; +}; + +static inline int is_word_sized(u16 reg) +{ + return (((reg & 0xff00) == 0x100 + || (reg & 0xff00) == 0x200) + && ((reg & 0x00ff) == 0x50 + || (reg & 0x00ff) == 0x53 + || (reg & 0x00ff) == 0x55)); +} + +/* We assume that the default bank is 0, thus the following two functions do + nothing for registers which live in bank 0. For others, they respectively + set the bank register to the correct value (before the register is + accessed), and back to 0 (afterwards). */ +static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); + outb_p(reg >> 8, client->addr + DATA_REG_OFFSET); + } +} + +static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); + outb_p(0, client->addr + DATA_REG_OFFSET); + } +} + +static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int res, word_sized = is_word_sized(reg); + + down(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); + res = inb_p(client->addr + DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + client->addr + ADDR_REG_OFFSET); + res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET); + } + w83627ehf_reset_bank(client, reg); + + up(&data->lock); + + return res; +} + +static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int word_sized = is_word_sized(reg); + + down(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, client->addr + DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + client->addr + ADDR_REG_OFFSET); + } + outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); + w83627ehf_reset_bank(client, reg); + + up(&data->lock); + return 0; +} + +/* This function assumes that the caller holds data->update_lock */ +static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + u8 reg; + + switch (nr) { + case 0: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) + | ((data->fan_div[0] & 0x03) << 4); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) + | ((data->fan_div[0] & 0x04) << 3); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 1: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) + | ((data->fan_div[1] & 0x03) << 6); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) + | ((data->fan_div[1] & 0x04) << 4); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 2: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f) + | ((data->fan_div[2] & 0x03) << 6); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f) + | ((data->fan_div[2] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 3: + reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc) + | (data->fan_div[3] & 0x03); + w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f) + | ((data->fan_div[3] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg); + break; + case 4: + reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73) + | ((data->fan_div[4] & 0x03) << 3) + | ((data->fan_div[4] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); + break; + } +} + +static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) + || !data->valid) { + /* Fan clock dividers */ + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2); + data->fan_div[2] = (i >> 6) & 0x03; + i = w83627ehf_read_value(client, W83627EHF_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + data->fan_div[2] |= (i >> 5) & 0x04; + if (data->has_fan & ((1 << 3) | (1 << 4))) { + i = w83627ehf_read_value(client, W83627EHF_REG_DIODE); + data->fan_div[3] = i & 0x03; + data->fan_div[4] = ((i >> 2) & 0x03) + | ((i >> 5) & 0x04); + } + if (data->has_fan & (1 << 3)) { + i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT); + data->fan_div[3] |= (i >> 5) & 0x04; + } + + /* Measured fan speeds and limits */ + for (i = 0; i < 5; i++) { + if (!(data->has_fan & (1 << i))) + continue; + + data->fan[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN[i]); + data->fan_min[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_MIN[i]); + + /* If we failed to measure the fan speed and clock + divider can be increased, let's try that for next + time */ + if (data->fan[i] == 0xff + && data->fan_div[i] < 0x07) { + dev_dbg(&client->dev, "Increasing fan %d " + "clock divider from %u to %u\n", + i, div_from_reg(data->fan_div[i]), + div_from_reg(data->fan_div[i] + 1)); + data->fan_div[i]++; + w83627ehf_write_fan_div(client, i); + /* Preserve min limit if possible */ + if (data->fan_min[i] >= 2 + && data->fan_min[i] != 255) + w83627ehf_write_value(client, + W83627EHF_REG_FAN_MIN[i], + (data->fan_min[i] /= 2)); + } + } + + /* Measured temperatures and limits */ + data->temp1 = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1); + data->temp1_max = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1_OVER); + data->temp1_max_hyst = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1_HYST); + for (i = 0; i < 2; i++) { + data->temp[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP[i]); + data->temp_max[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_OVER[i]); + data->temp_max_hyst[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_HYST[i]); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + return data; +} + +/* + * Sysfs callback functions + */ + +#define show_fan_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, char *buf, int nr) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", \ + fan_from_reg(data->reg[nr], \ + div_from_reg(data->fan_div[nr]))); \ +} +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +show_fan_div(struct device *dev, char *buf, int nr) +{ + struct w83627ehf_data *data = w83627ehf_update_device(dev); + return sprintf(buf, "%u\n", + div_from_reg(data->fan_div[nr])); +} + +static ssize_t +store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + unsigned int val = simple_strtoul(buf, NULL, 10); + unsigned int reg; + u8 new_div; + + down(&data->update_lock); + if (!val) { + /* No min limit, alarm disabled */ + data->fan_min[nr] = 255; + new_div = data->fan_div[nr]; /* No change */ + dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); + } else if ((reg = 1350000U / val) >= 128 * 255) { + /* Speed below this value cannot possibly be represented, + even with the highest divider (128) */ + data->fan_min[nr] = 254; + new_div = 7; /* 128 == (1 << 7) */ + dev_warn(dev, "fan%u low limit %u below minimum %u, set to " + "minimum\n", nr + 1, val, fan_from_reg(254, 128)); + } else if (!reg) { + /* Speed above this value cannot possibly be represented, + even with the lowest divider (1) */ + data->fan_min[nr] = 1; + new_div = 0; /* 1 == (1 << 0) */ + dev_warn(dev, "fan%u low limit %u above maximum %u, set to " + "maximum\n", nr + 1, val, fan_from_reg(1, 1)); + } else { + /* Automatically pick the best divider, i.e. the one such + that the min limit will correspond to a register value + in the 96..192 range */ + new_div = 0; + while (reg > 192 && new_div < 7) { + reg >>= 1; + new_div++; + } + data->fan_min[nr] = reg; + } + + /* Write both the fan clock divider (if it changed) and the new + fan min (unconditionally) */ + if (new_div != data->fan_div[nr]) { + if (new_div > data->fan_div[nr]) + data->fan[nr] >>= (data->fan_div[nr] - new_div); + else + data->fan[nr] <<= (new_div - data->fan_div[nr]); + + dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", + nr + 1, div_from_reg(data->fan_div[nr]), + div_from_reg(new_div)); + data->fan_div[nr] = new_div; + w83627ehf_write_fan_div(client, nr); + } + w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], + data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define sysfs_fan_offset(offset) \ +static ssize_t \ +show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_fan(dev, buf, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_reg_fan_##offset, NULL); + +#define sysfs_fan_min_offset(offset) \ +static ssize_t \ +show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_fan_min(dev, buf, offset-1); \ +} \ +static ssize_t \ +store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_fan_min(dev, buf, count, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_reg_fan##offset##_min, \ + store_reg_fan##offset##_min); + +#define sysfs_fan_div_offset(offset) \ +static ssize_t \ +show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_reg_fan##offset##_div, NULL); + +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_div_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_div_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); +sysfs_fan_div_offset(3); +sysfs_fan_offset(4); +sysfs_fan_min_offset(4); +sysfs_fan_div_offset(4); +sysfs_fan_offset(5); +sysfs_fan_min_offset(5); +sysfs_fan_div_offset(5); + +#define show_temp1_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \ +} +show_temp1_reg(temp1); +show_temp1_reg(temp1_max); +show_temp1_reg(temp1_max_hyst); + +#define store_temp1_reg(REG, reg) \ +static ssize_t \ +store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp1_##reg = temp1_to_reg(val); \ + w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ + data->temp1_##reg); \ + up(&data->update_lock); \ + return count; \ +} +store_temp1_reg(OVER, max); +store_temp1_reg(HYST, max_hyst); + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR, + show_temp1_max, store_temp1_max); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR, + show_temp1_max_hyst, store_temp1_max_hyst); + +#define show_temp_reg(reg) \ +static ssize_t \ +show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", \ + LM75_TEMP_FROM_REG(data->reg[nr])); \ +} +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_max_hyst); + +#define store_temp_reg(REG, reg) \ +static ssize_t \ +store_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->reg[nr] = LM75_TEMP_TO_REG(val); \ + w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \ + data->reg[nr]); \ + up(&data->update_lock); \ + return count; \ +} +store_temp_reg(OVER, temp_max); +store_temp_reg(HYST, temp_max_hyst); + +#define sysfs_temp_offset(offset) \ +static ssize_t \ +show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp(dev, buf, offset - 2); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_reg_temp##offset, NULL); + +#define sysfs_temp_reg_offset(reg, offset) \ +static ssize_t \ +show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_##reg(dev, buf, offset - 2); \ +} \ +static ssize_t \ +store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_temp_##reg(dev, buf, count, offset - 2); \ +} \ +static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ + show_reg_temp##offset##_##reg, \ + store_reg_temp##offset##_##reg); + +sysfs_temp_offset(2); +sysfs_temp_reg_offset(max, 2); +sysfs_temp_reg_offset(max_hyst, 2); +sysfs_temp_offset(3); +sysfs_temp_reg_offset(max, 3); +sysfs_temp_reg_offset(max_hyst, 3); + +/* + * Driver and client management + */ + +static struct i2c_driver w83627ehf_driver; + +static void w83627ehf_init_client(struct i2c_client *client) +{ + int i; + u8 tmp; + + /* Start monitoring is needed */ + tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG); + if (!(tmp & 0x01)) + w83627ehf_write_value(client, W83627EHF_REG_CONFIG, + tmp | 0x01); + + /* Enable temp2 and temp3 if needed */ + for (i = 0; i < 2; i++) { + tmp = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_CONFIG[i]); + if (tmp & 0x01) + w83627ehf_write_value(client, + W83627EHF_REG_TEMP_CONFIG[i], + tmp & 0xfe); + } +} + +static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct w83627ehf_data *data; + int i, err = 0; + + if (!i2c_is_isa_adapter(adapter)) + return 0; + + if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) { + err = -EBUSY; + goto exit; + } + + if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release; + } + memset(data, 0, sizeof(struct w83627ehf_data)); + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + init_MUTEX(&data->lock); + client->adapter = adapter; + client->driver = &w83627ehf_driver; + client->flags = 0; + + strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the i2c layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto exit_free; + + /* Initialize the chip */ + w83627ehf_init_client(client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 5; i++) + data->fan_min[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_MIN[i]); + + /* It looks like fan4 and fan5 pins can be alternatively used + as fan on/off switches */ + data->has_fan = 0x07; /* fan1, fan2 and fan3 */ + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); + if (i & (1 << 2)) + data->has_fan |= (1 << 3); + if (i & (1 << 0)) + data->has_fan |= (1 << 4); + + /* Register sysfs hooks */ + device_create_file(&client->dev, &dev_attr_fan1_input); + device_create_file(&client->dev, &dev_attr_fan1_min); + device_create_file(&client->dev, &dev_attr_fan1_div); + device_create_file(&client->dev, &dev_attr_fan2_input); + device_create_file(&client->dev, &dev_attr_fan2_min); + device_create_file(&client->dev, &dev_attr_fan2_div); + device_create_file(&client->dev, &dev_attr_fan3_input); + device_create_file(&client->dev, &dev_attr_fan3_min); + device_create_file(&client->dev, &dev_attr_fan3_div); + + if (data->has_fan & (1 << 3)) { + device_create_file(&client->dev, &dev_attr_fan4_input); + device_create_file(&client->dev, &dev_attr_fan4_min); + device_create_file(&client->dev, &dev_attr_fan4_div); + } + if (data->has_fan & (1 << 4)) { + device_create_file(&client->dev, &dev_attr_fan5_input); + device_create_file(&client->dev, &dev_attr_fan5_min); + device_create_file(&client->dev, &dev_attr_fan5_div); + } + + device_create_file(&client->dev, &dev_attr_temp1_input); + device_create_file(&client->dev, &dev_attr_temp1_max); + device_create_file(&client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&client->dev, &dev_attr_temp2_input); + device_create_file(&client->dev, &dev_attr_temp2_max); + device_create_file(&client->dev, &dev_attr_temp2_max_hyst); + device_create_file(&client->dev, &dev_attr_temp3_input); + device_create_file(&client->dev, &dev_attr_temp3_max); + device_create_file(&client->dev, &dev_attr_temp3_max_hyst); + + return 0; + +exit_free: + kfree(data); +exit_release: + release_region(address, REGION_LENGTH); +exit: + return err; +} + +static int w83627ehf_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, w83627ehf_detect); +} + +static int w83627ehf_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + release_region(client->addr, REGION_LENGTH); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static struct i2c_driver w83627ehf_driver = { + .owner = THIS_MODULE, + .name = "w83627ehf", + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83627ehf_attach_adapter, + .detach_client = w83627ehf_detach_client, +}; + +static int __init w83627ehf_find(int sioaddr, int *address) +{ + u16 val; + + REG = sioaddr; + VAL = sioaddr + 1; + superio_enter(); + + val = (superio_inb(SIO_REG_DEVID) << 8) + | superio_inb(SIO_REG_DEVID + 1); + if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) { + superio_exit(); + return -ENODEV; + } + + superio_select(W83627EHF_LD_HWM); + val = (superio_inb(SIO_REG_ADDR) << 8) + | superio_inb(SIO_REG_ADDR + 1); + *address = val & ~(REGION_LENGTH - 1); + if (*address == 0) { + superio_exit(); + return -ENODEV; + } + + /* Activate logical device if needed */ + val = superio_inb(SIO_REG_ENABLE); + if (!(val & 0x01)) + superio_outb(SIO_REG_ENABLE, val | 0x01); + + superio_exit(); + return 0; +} + +static int __init sensors_w83627ehf_init(void) +{ + if (w83627ehf_find(0x2e, &normal_isa[0]) + && w83627ehf_find(0x4e, &normal_isa[0])) + return -ENODEV; + + return i2c_add_driver(&w83627ehf_driver); +} + +static void __exit sensors_w83627ehf_exit(void) +{ + i2c_del_driver(&w83627ehf_driver); +} + +MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); +MODULE_DESCRIPTION("W83627EHF driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83627ehf_init); +module_exit(sensors_w83627ehf_exit); diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c index 4f1bff5..bd87a42 100644 --- a/drivers/i2c/chips/w83627hf.c +++ b/drivers/i2c/chips/w83627hf.c @@ -264,7 +264,7 @@ static inline u8 DIV_TO_REG(long val) { int i; val = SENSORS_LIMIT(val, 1, 128) >> 1; - for (i = 0; i < 6; i++) { + for (i = 0; i < 7; i++) { if (val == 0) break; val >>= 1; diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index c3926d2..0bb131c 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -28,14 +28,11 @@ as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) - w83627thf 9 3 2 3 0x90 0x5ca3 no yes(LPC) w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no - w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -53,7 +50,7 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf); +SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f); I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); @@ -173,7 +170,6 @@ FAN_TO_REG(long rpm, int div) : (val)) / 1000, 0, 0xff)) #define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) -#define ALARMS_FROM_REG(val) (val) #define PWM_FROM_REG(val) (val) #define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) #define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ @@ -193,7 +189,7 @@ DIV_TO_REG(long val, enum chips type) val = SENSORS_LIMIT(val, 1, ((type == w83781d || type == as99127f) ? 8 : 128)) >> 1; - for (i = 0; i < 6; i++) { + for (i = 0; i < 7; i++) { if (val == 0) break; val >>= 1; @@ -524,7 +520,7 @@ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static @@ -1000,13 +996,6 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) err = -EINVAL; goto ERROR0; } - if (!is_isa && kind == w83697hf) { - dev_err(&adapter->dev, - "Cannot force ISA-only chip for I2C address 0x%02x.\n", - address); - err = -EINVAL; - goto ERROR0; - } if (is_isa) if (!request_region(address, W83781D_EXTENT, @@ -1139,12 +1128,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) else if (val1 == 0x40 && vendid == winbond && !is_isa && address == 0x2d) kind = w83783s; - else if ((val1 == 0x21 || val1 == 0x90) && vendid == winbond) + else if (val1 == 0x21 && vendid == winbond) kind = w83627hf; else if (val1 == 0x31 && !is_isa && address >= 0x28) kind = as99127f; - else if (val1 == 0x60 && vendid == winbond && is_isa) - kind = w83697hf; else { if (kind == 0) dev_warn(&new_client->dev, "Ignoring 'force' " @@ -1163,14 +1150,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) } else if (kind == w83783s) { client_name = "w83783s"; } else if (kind == w83627hf) { - if (val1 == 0x90) - client_name = "w83627thf"; - else - client_name = "w83627hf"; + client_name = "w83627hf"; } else if (kind == as99127f) { client_name = "as99127f"; - } else if (kind == w83697hf) { - client_name = "w83697hf"; } /* Fill in the remaining client fields and put into the global list */ @@ -1208,7 +1190,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) /* Register sysfs hooks */ device_create_file_in(new_client, 0); - if (kind != w83783s && kind != w83697hf) + if (kind != w83783s) device_create_file_in(new_client, 1); device_create_file_in(new_client, 2); device_create_file_in(new_client, 3); @@ -1222,24 +1204,19 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file_fan(new_client, 1); device_create_file_fan(new_client, 2); - if (kind != w83697hf) - device_create_file_fan(new_client, 3); + device_create_file_fan(new_client, 3); device_create_file_temp(new_client, 1); device_create_file_temp(new_client, 2); - if (kind != w83783s && kind != w83697hf) + if (kind != w83783s) device_create_file_temp(new_client, 3); - if (kind != w83697hf) - device_create_file_vid(new_client); - - if (kind != w83697hf) - device_create_file_vrm(new_client); + device_create_file_vid(new_client); + device_create_file_vrm(new_client); device_create_file_fan_div(new_client, 1); device_create_file_fan_div(new_client, 2); - if (kind != w83697hf) - device_create_file_fan_div(new_client, 3); + device_create_file_fan_div(new_client, 3); device_create_file_alarms(new_client); @@ -1258,7 +1235,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) if (kind != as99127f && kind != w83781d) { device_create_file_sensor(new_client, 1); device_create_file_sensor(new_client, 2); - if (kind != w83783s && kind != w83697hf) + if (kind != w83783s) device_create_file_sensor(new_client, 3); } @@ -1481,7 +1458,7 @@ w83781d_init_client(struct i2c_client *client) else data->sens[i - 1] = 2; } - if ((type == w83783s || type == w83697hf) && (i == 2)) + if (type == w83783s && i == 2) break; } } @@ -1497,7 +1474,7 @@ w83781d_init_client(struct i2c_client *client) } /* Enable temp3 */ - if (type != w83783s && type != w83697hf) { + if (type != w83783s) { tmp = w83781d_read_value(client, W83781D_REG_TEMP3_CONFIG); if (tmp & 0x01) { @@ -1538,8 +1515,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) dev_dbg(dev, "Starting device update\n"); for (i = 0; i <= 8; i++) { - if ((data->type == w83783s || data->type == w83697hf) - && (i == 1)) + if (data->type == w83783s && i == 1) continue; /* 783S has no in1 */ data->in[i] = w83781d_read_value(client, W83781D_REG_IN(i)); @@ -1547,7 +1523,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) w83781d_read_value(client, W83781D_REG_IN_MIN(i)); data->in_max[i] = w83781d_read_value(client, W83781D_REG_IN_MAX(i)); - if ((data->type != w83782d) && (data->type != w83697hf) + if ((data->type != w83782d) && (data->type != w83627hf) && (i == 6)) break; } @@ -1583,7 +1559,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); data->temp_max_hyst_add[0] = w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); - if (data->type != w83783s && data->type != w83697hf) { + if (data->type != w83783s) { data->temp_add[1] = w83781d_read_value(client, W83781D_REG_TEMP(3)); data->temp_max_add[1] = @@ -1594,26 +1570,18 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) W83781D_REG_TEMP_HYST(3)); } i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); - if (data->type != w83697hf) { - data->vid = i & 0x0f; - data->vid |= - (w83781d_read_value(client, W83781D_REG_CHIPID) & - 0x01) - << 4; - } + data->vid = i & 0x0f; + data->vid |= (w83781d_read_value(client, + W83781D_REG_CHIPID) & 0x01) << 4; data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = (i >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83781d_read_value(client, - W83781D_REG_PIN) - >> 6) & 0x03; - } + data->fan_div[2] = (w83781d_read_value(client, + W83781D_REG_PIN) >> 6) & 0x03; if ((data->type != w83781d) && (data->type != as99127f)) { i = w83781d_read_value(client, W83781D_REG_VBAT); data->fan_div[0] |= (i >> 3) & 0x04; data->fan_div[1] |= (i >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (i >> 5) & 0x04; + data->fan_div[2] |= (i >> 5) & 0x04; } data->alarms = w83781d_read_value(client, diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c index 74d4b58..4469d52 100644 --- a/drivers/i2c/chips/w83l785ts.c +++ b/drivers/i2c/chips/w83l785ts.c @@ -30,7 +30,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/init.h> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a22e53b..51ce268 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -21,7 +21,6 @@ All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -239,7 +238,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) } /* detach any active clients. This must be done first, because - * it can fail; in which case we give upp. */ + * it can fail; in which case we give up. */ list_for_each_safe(item, _n, &adap->clients) { client = list_entry(item, struct i2c_client, list); @@ -612,27 +611,16 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; - if (client->adapter->algo->master_xfer) { - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.len = count; - msg.buf = (char *)buf; + msg.addr = client->addr; + msg.flags = client->flags & I2C_M_TEN; + msg.len = count; + msg.buf = (char *)buf; - dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", - count); - - down(&adap->bus_lock); - ret = adap->algo->master_xfer(adap,&msg,1); - up(&adap->bus_lock); + ret = i2c_transfer(adap, &msg, 1); - /* if everything went ok (i.e. 1 msg transmitted), return #bytes - * transmitted, else error code. - */ - return (ret == 1 )? count : ret; - } else { - dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); - return -ENOSYS; - } + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ + return (ret == 1) ? count : ret; } int i2c_master_recv(struct i2c_client *client, char *buf ,int count) @@ -640,31 +628,18 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; int ret; - if (client->adapter->algo->master_xfer) { - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.flags |= I2C_M_RD; - msg.len = count; - msg.buf = buf; - - dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", - count); - - down(&adap->bus_lock); - ret = adap->algo->master_xfer(adap,&msg,1); - up(&adap->bus_lock); - - dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n", - ret, count, client->addr); - - /* if everything went ok (i.e. 1 msg transmitted), return #bytes - * transmitted, else error code. - */ - return (ret == 1 )? count : ret; - } else { - dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); - return -ENOSYS; - } + + msg.addr = client->addr; + msg.flags = client->flags & I2C_M_TEN; + msg.flags |= I2C_M_RD; + msg.len = count; + msg.buf = buf; + + ret = i2c_transfer(adap, &msg, 1); + + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ + return (ret == 1) ? count : ret; } @@ -742,18 +717,6 @@ int i2c_probe(struct i2c_adapter *adapter, found = 1; } } - for (i = 0; - !found && (address_data->ignore_range[i] != I2C_CLIENT_END); - i += 3) { - if (((adap_id == address_data->ignore_range[i]) || - ((address_data->ignore_range[i]==ANY_I2C_BUS))) && - (addr >= address_data->ignore_range[i+1]) && - (addr <= address_data->ignore_range[i+2])) { - dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, " - "addr %04x\n", adap_id,addr); - found = 1; - } - } if (found) continue; @@ -770,17 +733,6 @@ int i2c_probe(struct i2c_adapter *adapter, } for (i = 0; - !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); - i += 2) { - if ((addr >= address_data->normal_i2c_range[i]) && - (addr <= address_data->normal_i2c_range[i+1])) { - found = 1; - dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, " - "addr %04x\n", adap_id,addr); - } - } - - for (i = 0; !found && (address_data->probe[i] != I2C_CLIENT_END); i += 2) { if (((adap_id == address_data->probe[i]) || @@ -791,18 +743,6 @@ int i2c_probe(struct i2c_adapter *adapter, "addr %04x\n", adap_id,addr); } } - for (i = 0; - !found && (address_data->probe_range[i] != I2C_CLIENT_END); - i += 3) { - if (((adap_id == address_data->probe_range[i]) || - (address_data->probe_range[i] == ANY_I2C_BUS)) && - (addr >= address_data->probe_range[i+1]) && - (addr <= address_data->probe_range[i+2])) { - found = 1; - dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, " - "addr %04x\n", adap_id,addr); - } - } if (!found) continue; diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 86c4d01..bc5d557 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -29,7 +29,6 @@ /* The devfs code is contributed by Philipp Matthias Hahn <pmhahn@titan.lahn.de> */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> @@ -214,7 +213,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, sizeof(rdwr_arg))) return -EFAULT; - /* Put an arbritrary limit on the number of messages that can + /* Put an arbitrary limit on the number of messages that can * be sent at once */ if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) return -EINVAL; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 0bdb47f..61400f0 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -51,8 +51,10 @@ static int do_probe( struct i2c_adapter *adapter, int addr, int kind); /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ -static unsigned short normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, + 0x2c, 0x2d, 0x2e, 0x2f, + I2C_CLIENT_END }; I2C_CLIENT_INSMOD; diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index 80254ca..48989ed 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c @@ -384,22 +384,14 @@ static unsigned short normal_i2c[] = I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_adv7170; diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index 95d0974..f898b65 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -434,22 +434,14 @@ static unsigned short normal_i2c[] = I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_adv7175; diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index cf0db25..8733588 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -500,22 +500,14 @@ static unsigned short normal_i2c[] = { I2C_BT819 >> 1, I2C_CLIENT_END, }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_bt819; diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c index efe605a..07f72f64 100644 --- a/drivers/media/video/bt832.c +++ b/drivers/media/video/bt832.c @@ -39,8 +39,8 @@ MODULE_LICENSE("GPL"); /* Addresses to scan */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_BT832_ALT1>>1,I2C_BT832_ALT2>>1,I2C_CLIENT_END}; +static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1, + I2C_CLIENT_END }; I2C_CLIENT_INSMOD; /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c index 72c7eb0..a5d529c 100644 --- a/drivers/media/video/bt856.c +++ b/drivers/media/video/bt856.c @@ -288,22 +288,14 @@ bt856_command (struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_bt856; diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 7fbb858..09464d6 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -147,7 +147,6 @@ static unsigned short normal_i2c[] = { I2C_MSP3400C_ALT >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index ba69f09..b8054da 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -64,7 +64,6 @@ static struct video_device saa_template; /* Declared near bottom */ /* Addresses to scan */ static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; static struct i2c_client client_template; diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index d74caa1..7ffa2e9 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -132,7 +132,6 @@ static struct video_device saa_template; /* Declared near bottom */ /* Addresses to scan */ static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; I2C_CLIENT_INSMOD; static struct i2c_client client_template; diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c index 64273b4..22d055d 100644 --- a/drivers/media/video/saa7110.c +++ b/drivers/media/video/saa7110.c @@ -463,22 +463,14 @@ static unsigned short normal_i2c[] = { (I2C_SAA7110 >> 1) + 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_saa7110; diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c index 0a87311..fcd8973 100644 --- a/drivers/media/video/saa7111.c +++ b/drivers/media/video/saa7111.c @@ -482,22 +482,14 @@ saa7111_command (struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_saa7111; diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c index e730236..2ba997f 100644 --- a/drivers/media/video/saa7114.c +++ b/drivers/media/video/saa7114.c @@ -820,22 +820,14 @@ saa7114_command (struct i2c_client *client, */ static unsigned short normal_i2c[] = { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_saa7114; diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 1db0226..42c2b56 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -22,7 +22,6 @@ /* Addresses to scan */ static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; I2C_CLIENT_INSMOD; MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c index 5f0b224..108e7a4 100644 --- a/drivers/media/video/saa7185.c +++ b/drivers/media/video/saa7185.c @@ -380,22 +380,14 @@ saa7185_command (struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver i2c_driver_saa7185; diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 376a4a4..07ba6d3 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -74,7 +74,6 @@ static unsigned short normal_i2c[] = { I2C_TDA7432 >> 1, I2C_CLIENT_END, }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; /* Structure of address and subaddresses for the tda7432 */ diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index b5177c6..c29bdfc 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c @@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); /* addresses to scan, found only at 0x42 (7-Bit) */ static unsigned short normal_i2c[] = { I2C_TDA9840, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; /* magic definition of all other variables and things */ I2C_CLIENT_INSMOD; diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 4f1114c..97b113e 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -44,7 +44,6 @@ static unsigned short normal_i2c[] = { I2C_TDA9875 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; I2C_CLIENT_INSMOD; /* This is a superset of the TDA9875 */ diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index debef191..7e6e6dd 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -33,7 +33,6 @@ static unsigned short normal_i2c[] = { 0x96 >>1, I2C_CLIENT_END, }; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; I2C_CLIENT_INSMOD; /* insmod options */ diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index 3ec3955..b44db8a 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c @@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); /* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */ static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; /* magic definition of all other variables and things */ I2C_CLIENT_INSMOD; diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index bd10710..48d4db7 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -40,7 +40,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); /* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */ static unsigned short normal_i2c[] = { I2C_TEA6420_1, I2C_TEA6420_2, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; /* magic definition of all other variables and things */ I2C_CLIENT_INSMOD; diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c index 6b20aa9..51748c6 100644 --- a/drivers/media/video/tuner-3036.c +++ b/drivers/media/video/tuner-3036.c @@ -34,19 +34,14 @@ static int this_adap; static struct i2c_client client_template; /* Addresses to scan */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {0x60, 0x61, I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force + .normal_i2c = normal_i2c, + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 6212388e..81882dd 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -28,10 +28,8 @@ /* standard i2c insmod options */ static unsigned short normal_i2c[] = { 0x4b, /* tda8290 */ - I2C_CLIENT_END -}; -static unsigned short normal_i2c_range[] = { - 0x60, 0x6f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; @@ -225,9 +223,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) static int tuner_probe(struct i2c_adapter *adap) { if (0 != addr) { - normal_i2c[0] = addr; - normal_i2c_range[0] = addr; - normal_i2c_range[1] = addr; + normal_i2c[0] = addr; + normal_i2c[1] = I2C_CLIENT_END; } this_adap = 0; diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 80dc34f..41b635e 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -148,7 +148,6 @@ static unsigned short normal_i2c[] = { I2C_TDA9874 >> 1, I2C_PIC16C54 >> 1, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; static struct i2c_driver driver; diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index e1443a0..3d21697 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -482,7 +482,6 @@ static unsigned short normal_i2c[] = { 0xa0 >> 1, I2C_CLIENT_END, }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; struct i2c_driver i2c_driver_tveeprom; diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 0fd6c9a..5dbd9f6 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -569,22 +569,14 @@ static unsigned short normal_i2c[] = { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; +static unsigned short ignore = I2C_CLIENT_END; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force + .probe = &ignore, + .ignore = &ignore, + .force = &ignore, }; static struct i2c_driver vpx3220_i2c_driver; diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index e529841..67f8534 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -1230,7 +1230,6 @@ static int maven_shutdown_client(struct i2c_client* clnt) { } static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; static struct i2c_driver maven_driver; diff --git a/include/asm-arm/arch-omap/tps65010.h b/include/asm-arm/arch-omap/tps65010.h index 0f97bb2..b9aa2b3 100644 --- a/include/asm-arm/arch-omap/tps65010.h +++ b/include/asm-arm/arch-omap/tps65010.h @@ -30,6 +30,66 @@ /* * ---------------------------------------------------------------------------- + * Registers, all 8 bits + * ---------------------------------------------------------------------------- + */ + +#define TPS_CHGSTATUS 0x01 +# define TPS_CHG_USB (1 << 7) +# define TPS_CHG_AC (1 << 6) +# define TPS_CHG_THERM (1 << 5) +# define TPS_CHG_TERM (1 << 4) +# define TPS_CHG_TAPER_TMO (1 << 3) +# define TPS_CHG_CHG_TMO (1 << 2) +# define TPS_CHG_PRECHG_TMO (1 << 1) +# define TPS_CHG_TEMP_ERR (1 << 0) +#define TPS_REGSTATUS 0x02 +# define TPS_REG_ONOFF (1 << 7) +# define TPS_REG_COVER (1 << 6) +# define TPS_REG_UVLO (1 << 5) +# define TPS_REG_NO_CHG (1 << 4) /* tps65013 */ +# define TPS_REG_PG_LD02 (1 << 3) +# define TPS_REG_PG_LD01 (1 << 2) +# define TPS_REG_PG_MAIN (1 << 1) +# define TPS_REG_PG_CORE (1 << 0) +#define TPS_MASK1 0x03 +#define TPS_MASK2 0x04 +#define TPS_ACKINT1 0x05 +#define TPS_ACKINT2 0x06 +#define TPS_CHGCONFIG 0x07 +# define TPS_CHARGE_POR (1 << 7) /* 65010/65012 */ +# define TPS65013_AUA (1 << 7) /* 65011/65013 */ +# define TPS_CHARGE_RESET (1 << 6) +# define TPS_CHARGE_FAST (1 << 5) +# define TPS_CHARGE_CURRENT (3 << 3) +# define TPS_VBUS_500MA (1 << 2) +# define TPS_VBUS_CHARGING (1 << 1) +# define TPS_CHARGE_ENABLE (1 << 0) +#define TPS_LED1_ON 0x08 +#define TPS_LED1_PER 0x09 +#define TPS_LED2_ON 0x0a +#define TPS_LED2_PER 0x0b +#define TPS_VDCDC1 0x0c +# define TPS_ENABLE_LP (1 << 3) +#define TPS_VDCDC2 0x0d +#define TPS_VREGS1 0x0e +# define TPS_LDO2_ENABLE (1 << 7) +# define TPS_LDO2_OFF (1 << 6) +# define TPS_VLDO2_3_0V (3 << 4) +# define TPS_VLDO2_2_75V (2 << 4) +# define TPS_VLDO2_2_5V (1 << 4) +# define TPS_VLDO2_1_8V (0 << 4) +# define TPS_LDO1_ENABLE (1 << 3) +# define TPS_LDO1_OFF (1 << 2) +# define TPS_VLDO1_3_0V (3 << 0) +# define TPS_VLDO1_2_75V (2 << 0) +# define TPS_VLDO1_2_5V (1 << 0) +# define TPS_VLDO1_ADJ (0 << 0) +#define TPS_MASK3 0x0f +#define TPS_DEFGPIO 0x10 + +/* + * ---------------------------------------------------------------------------- * Macros used by exported functions * ---------------------------------------------------------------------------- */ @@ -71,10 +131,26 @@ extern int tps65010_set_gpio_out_value(unsigned gpio, unsigned value); */ extern int tps65010_set_led(unsigned led, unsigned mode); +/* tps65010_set_vib parameter: + * value: ON or OFF + */ +extern int tps65010_set_vib(unsigned value); + /* tps65010_set_low_pwr parameter: * mode: ON or OFF */ extern int tps65010_set_low_pwr(unsigned mode); +/* tps65010_config_vregs1 parameter: + * value to be written to VREGS1 register + * Note: The complete register is written, set all bits you need + */ +extern int tps65010_config_vregs1(unsigned value); + +/* tps65013_set_low_pwr parameter: + * mode: ON or OFF + */ +extern int tps65013_set_low_pwr(unsigned mode); + #endif /* __ASM_ARCH_TPS65010_H */ diff --git a/include/linux/i2c-sysfs.h b/include/linux/hwmon-sysfs.h index d7bf6ce..1b5018a 100644 --- a/include/linux/i2c-sysfs.h +++ b/include/linux/hwmon-sysfs.h @@ -1,5 +1,5 @@ /* - * i2c-sysfs.h - i2c chip driver sysfs defines + * hwmon-sysfs.h - hardware monitoring chip driver sysfs defines * * Copyright (C) 2005 Yani Ioannou <yani.ioannou@gmail.com> * @@ -17,8 +17,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef _LINUX_I2C_SYSFS_H -#define _LINUX_I2C_SYSFS_H +#ifndef _LINUX_HWMON_SYSFS_H +#define _LINUX_HWMON_SYSFS_H struct sensor_device_attribute{ struct device_attribute dev_attr; @@ -33,4 +33,4 @@ struct sensor_device_attribute sensor_dev_attr_##_name = { \ .index = _index, \ } -#endif /* _LINUX_I2C_SYSFS_H */ +#endif /* _LINUX_HWMON_SYSFS_H */ diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 89270ce..33f0825 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -108,6 +108,7 @@ #define I2C_DRIVERID_TDA7313 62 /* TDA7313 audio processor */ #define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */ #define I2C_DRIVERID_SAA7114H 64 /* video decoder */ +#define I2C_DRIVERID_DS1374 65 /* DS1374 real time clock */ #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ diff --git a/include/linux/i2c-vid.h b/include/linux/i2c-vid.h index 974835e3..41d0635 100644 --- a/include/linux/i2c-vid.h +++ b/include/linux/i2c-vid.h @@ -97,3 +97,15 @@ static inline int vid_from_reg(int val, int vrm) 2050 - (val) * 50); } } + +static inline int vid_to_reg(int val, int vrm) +{ + switch (vrm) { + case 91: /* VRM 9.1 */ + case 90: /* VRM 9.0 */ + return ((val >= 1100) && (val <= 1850) ? + ((18499 - val * 10) / 25 + 5) / 10 : -1); + default: + return -1; + } +} diff --git a/include/linux/i2c.h b/include/linux/i2c.h index ebcd745..be837b1 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -290,11 +290,8 @@ static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data) */ struct i2c_client_address_data { unsigned short *normal_i2c; - unsigned short *normal_i2c_range; unsigned short *probe; - unsigned short *probe_range; unsigned short *ignore; - unsigned short *ignore_range; unsigned short *force; }; @@ -563,24 +560,15 @@ union i2c_smbus_data { #define I2C_CLIENT_INSMOD \ I2C_CLIENT_MODULE_PARM(probe, \ "List of adapter,address pairs to scan additionally"); \ - I2C_CLIENT_MODULE_PARM(probe_range, \ - "List of adapter,start-addr,end-addr triples to scan " \ - "additionally"); \ I2C_CLIENT_MODULE_PARM(ignore, \ "List of adapter,address pairs not to scan"); \ - I2C_CLIENT_MODULE_PARM(ignore_range, \ - "List of adapter,start-addr,end-addr triples not to " \ - "scan"); \ I2C_CLIENT_MODULE_PARM(force, \ "List of adapter,address pairs to boldly assume " \ "to be present"); \ static struct i2c_client_address_data addr_data = { \ .normal_i2c = normal_i2c, \ - .normal_i2c_range = normal_i2c_range, \ .probe = probe, \ - .probe_range = probe_range, \ .ignore = ignore, \ - .ignore_range = ignore_range, \ .force = force, \ } |