Commit 3cb60328 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'hwmon-for-linus' of...

Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (26 commits)
  hwmon: (w83627ehf) Better fix for negative temperature values
  hwmon: (w83627ehf) Uninline is_word_sized
  hwmon: (lm75) Document why clones are not detected
  hwmon: (w83627ehf) Move fan pins check to a separate function
  hwmon: (w83627ehf) Skip reading unused voltage registers
  hwmon: (lm75) Add support for Analog Devices ADT75
  hwmon: (pmbus_core) Simplify sign extensions
  hwmon: (pmbus) Add support for Lineage Power DC-DC converters
  hwmon: (pmbus/ltc2978) Add support for LTC3880 to LTC2978 driver
  hwmon: (pmbus/ltc2978) Explicit driver for LTC2978
  hwmon: (pmbus) Add support for TEMP2 peak attributes
  hwmon: AD7314 driver (ported from IIO)
  hwmon: (pmbus) Add support for Intersil power management chips
  hwmon: (pmbus) Always call _pmbus_read_byte in core driver
  hwmon: (pmbus) Replace EINVAL return codes with more appropriate errors
  hwmon: (pmbus) Provide more documentation
  hwmon/f71882fg: Make the decision wether to register fan attr. per fan
  hwmon/f71882fg: Add a f71882fg_create_fan_sysfs_files helper function
  hwmon/f71882fg: Make all fan/pwm attr tables 2 dimensional
  hwmon: (exynos4_tmu) Remove IRQF_DISABLED
  ...
parents 2355e429 c5794cfa
Kernel driver ad7314
====================
Supported chips:
* Analog Devices AD7314
Prefix: 'ad7314'
Datasheet: Publicly available at Analog Devices website.
* Analog Devices ADT7301
Prefix: 'adt7301'
Datasheet: Publicly available at Analog Devices website.
* Analog Devices ADT7302
Prefix: 'adt7302'
Datasheet: Publicly available at Analog Devices website.
Description
-----------
Driver supports the above parts. The ad7314 has a 10 bit
sensor with 1lsb = 0.25 degrees centigrade. The adt7301 and
adt7302 have 14 bit sensors with 1lsb = 0.03125 degrees centigrade.
Notes
-----
Currently power down mode is not supported.
......@@ -6,6 +6,10 @@ Supported chips:
Prefix: 'adm1275'
Addresses scanned: -
Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1275.pdf
* Analog Devices ADM1276
Prefix: 'adm1276'
Addresses scanned: -
Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1276.pdf
Author: Guenter Roeck <guenter.roeck@ericsson.com>
......@@ -13,13 +17,13 @@ Author: Guenter Roeck <guenter.roeck@ericsson.com>
Description
-----------
This driver supports hardware montoring for Analog Devices ADM1275 Hot-Swap
Controller and Digital Power Monitor.
This driver supports hardware montoring for Analog Devices ADM1275 and ADM1276
Hot-Swap Controller and Digital Power Monitor.
The ADM1275 is a hot-swap controller that allows a circuit board to be removed
from or inserted into a live backplane. It also features current and voltage
readback via an integrated 12-bit analog-to-digital converter (ADC), accessed
using a PMBus. interface.
ADM1275 and ADM1276 are hot-swap controllers that allow a circuit board to be
removed from or inserted into a live backplane. They also feature current and
voltage readback via an integrated 12-bit analog-to-digital converter (ADC),
accessed using a PMBus interface.
The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus for details on PMBus client drivers.
......@@ -48,17 +52,25 @@ attributes are write-only, all other attributes are read-only.
in1_label "vin1" or "vout1" depending on chip variant and
configuration.
in1_input Measured voltage. From READ_VOUT register.
in1_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
in1_max Maximum voltage. From VOUT_OV_WARN_LIMIT register.
in1_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status.
in1_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status.
in1_input Measured voltage.
in1_min Minumum Voltage.
in1_max Maximum voltage.
in1_min_alarm Voltage low alarm.
in1_max_alarm Voltage high alarm.
in1_highest Historical maximum voltage.
in1_reset_history Write any value to reset history.
curr1_label "iout1"
curr1_input Measured current. From READ_IOUT register.
curr1_max Maximum current. From IOUT_OC_WARN_LIMIT register.
curr1_max_alarm Current high alarm. From IOUT_OC_WARN_LIMIT register.
curr1_input Measured current.
curr1_max Maximum current.
curr1_max_alarm Current high alarm.
curr1_lcrit Critical minimum current. Depending on the chip
configuration, either curr1_lcrit or curr1_crit is
supported, but not both.
curr1_lcrit_alarm Critical current low alarm.
curr1_crit Critical maximum current. Depending on the chip
configuration, either curr1_lcrit or curr1_crit is
supported, but not both.
curr1_crit_alarm Critical current high alarm.
curr1_highest Historical maximum current.
curr1_reset_history Write any value to reset history.
Kernel driver exynos4_tmu
=================
Supported chips:
* ARM SAMSUNG EXYNOS4 series of SoC
Prefix: 'exynos4-tmu'
Datasheet: Not publicly available
Authors: Donggeun Kim <dg77.kim@samsung.com>
Description
-----------
This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
The chip only exposes the measured 8-bit temperature code value
through a register.
Temperature can be taken from the temperature code.
There are three equations converting from temperature to temperature code.
The three equations are:
1. Two point trimming
Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
2. One point trimming
Tc = T + TI1 - 25
3. No trimming
Tc = T + 50
Tc: Temperature code, T: Temperature,
TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
Temperature code measured at 25 degree Celsius which is unchanged
TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register)
Temperature code measured at 85 degree Celsius which is unchanged
TMU(Thermal Management Unit) in EXYNOS4 generates interrupt
when temperature exceeds pre-defined levels.
The maximum number of configurable threshold is four.
The threshold levels are defined as follows:
Level_0: current temperature > trigger_level_0 + threshold
Level_1: current temperature > trigger_level_1 + threshold
Level_2: current temperature > trigger_level_2 + threshold
Level_3: current temperature > trigger_level_3 + threshold
The threshold and each trigger_level are set
through the corresponding registers.
When an interrupt occurs, this driver notify user space of
one of four threshold levels for the interrupt
through kobject_uevent_env and sysfs_notify functions.
Although an interrupt condition for level_0 can be set,
it is not notified to user space through sysfs_notify function.
Sysfs Interface
---------------
name name of the temperature sensor
RO
temp1_input temperature
RO
temp1_max temperature for level_1 interrupt
RO
temp1_crit temperature for level_2 interrupt
RO
temp1_emergency temperature for level_3 interrupt
RO
temp1_max_alarm alarm for level_1 interrupt
RO
temp1_crit_alarm
alarm for level_2 interrupt
RO
temp1_emergency_alarm
alarm for level_3 interrupt
RO
......@@ -12,26 +12,46 @@ Supported chips:
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
* Dallas Semiconductor DS75, DS1775
Prefixes: 'ds75', 'ds1775'
Addresses scanned: none
Datasheet: Publicly available at the Dallas Semiconductor website
http://www.maxim-ic.com/
* Maxim MAX6625, MAX6626
Prefix: 'lm75'
Addresses scanned: I2C 0x48 - 0x4b
Prefixes: 'max6625', 'max6626'
Addresses scanned: none
Datasheet: Publicly available at the Maxim website
http://www.maxim-ic.com/
* Microchip (TelCom) TCN75
Prefix: 'lm75'
Addresses scanned: I2C 0x48 - 0x4f
Addresses scanned: none
Datasheet: Publicly available at the Microchip website
http://www.microchip.com/
* Microchip MCP9800, MCP9801, MCP9802, MCP9803
Prefix: 'mcp980x'
Addresses scanned: none
Datasheet: Publicly available at the Microchip website
http://www.microchip.com/
* Analog Devices ADT75
Prefix: 'adt75'
Addresses scanned: none
Datasheet: Publicly available at the Analog Devices website
http://www.analog.com/adt75
* ST Microelectronics STDS75
Prefix: 'stds75'
Addresses scanned: none
Datasheet: Publicly available at the ST website
http://www.st.com/internet/analog/product/121769.jsp
* Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175, TMP275
Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp175', 'tmp75', 'tmp275'
Addresses scanned: none
Datasheet: Publicly available at the Texas Instruments website
http://www.ti.com/product/tmp100
http://www.ti.com/product/tmp101
http://www.ti.com/product/tmp105
http://www.ti.com/product/tmp75
http://www.ti.com/product/tmp175
http://www.ti.com/product/tmp275
Author: Frodo Looijaard <frodol@dds.nl>
......@@ -50,21 +70,16 @@ 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 original LM75 was typically used in combination with LM78-like chips
on PC motherboards, to measure the temperature of the processor(s). Clones
are now used in various embedded designs.
The LM75 is essentially an industry standard; there may be other
LM75 clones not listed here, with or without various enhancements,
that are supported.
that are supported. The clones are not detected by the driver, unless
they reproduce the exact register tricks of the original LM75, and must
therefore be instantiated explicitly. The specific enhancements (such as
higher resolution) are not currently supported by the driver.
The LM77 is not supported, contrary to what we pretended for a long time.
Both chips are simply not compatible, value encoding differs.
Kernel driver ltc2978
=====================
Supported chips:
* Linear Technology LTC2978
Prefix: 'ltc2978'
Addresses scanned: -
Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf
* Linear Technology LTC3880
Prefix: 'ltc3880'
Addresses scanned: -
Datasheet: http://cds.linear.com/docs/Datasheet/3880f.pdf
Author: Guenter Roeck <guenter.roeck@ericsson.com>
Description
-----------
The LTC2978 is an octal power supply monitor, supervisor, sequencer and
margin controller. The LTC3880 is a dual, PolyPhase DC/DC synchronous
step-down switching regulator controller.
Usage Notes
-----------
This driver does not probe for PMBus devices. You will have to instantiate
devices explicitly.
Example: the following commands will load the driver for an LTC2978 at address
0x60 on I2C bus #1:
# modprobe ltc2978
# echo ltc2978 0x60 > /sys/bus/i2c/devices/i2c-1/new_device
Sysfs attributes
----------------
in1_label "vin"
in1_input Measured input voltage.
in1_min Minimum input voltage.
in1_max Maximum input voltage.
in1_lcrit Critical minimum input voltage.
in1_crit Critical maximum input voltage.
in1_min_alarm Input voltage low alarm.
in1_max_alarm Input voltage high alarm.
in1_lcrit_alarm Input voltage critical low alarm.
in1_crit_alarm Input voltage critical high alarm.
in1_lowest Lowest input voltage. LTC2978 only.
in1_highest Highest input voltage.
in1_reset_history Reset history. Writing into this attribute will reset
history for all attributes.
in[2-9]_label "vout[1-8]". Channels 3 to 9 on LTC2978 only.
in[2-9]_input Measured output voltage.
in[2-9]_min Minimum output voltage.
in[2-9]_max Maximum output voltage.
in[2-9]_lcrit Critical minimum output voltage.
in[2-9]_crit Critical maximum output voltage.
in[2-9]_min_alarm Output voltage low alarm.
in[2-9]_max_alarm Output voltage high alarm.
in[2-9]_lcrit_alarm Output voltage critical low alarm.
in[2-9]_crit_alarm Output voltage critical high alarm.
in[2-9]_lowest Lowest output voltage. LTC2978 only.
in[2-9]_highest Lowest output voltage.
in[2-9]_reset_history Reset history. Writing into this attribute will reset
history for all attributes.
temp[1-3]_input Measured temperature.
On LTC2978, only one temperature measurement is
supported and reflects the internal temperature.
On LTC3880, temp1 and temp2 report external
temperatures, and temp3 reports the internal
temperature.
temp[1-3]_min Mimimum temperature.
temp[1-3]_max Maximum temperature.
temp[1-3]_lcrit Critical low temperature.
temp[1-3]_crit Critical high temperature.
temp[1-3]_min_alarm Chip temperature low alarm.
temp[1-3]_max_alarm Chip temperature high alarm.
temp[1-3]_lcrit_alarm Chip temperature critical low alarm.
temp[1-3]_crit_alarm Chip temperature critical high alarm.
temp[1-3]_lowest Lowest measured temperature. LTC2978 only.
temp[1-3]_highest Highest measured temperature.
temp[1-3]_reset_history Reset history. Writing into this attribute will reset
history for all attributes.
power[1-2]_label "pout[1-2]". LTC3880 only.
power[1-2]_input Measured power.
curr1_label "iin". LTC3880 only.
curr1_input Measured input current.
curr1_max Maximum input current.
curr1_max_alarm Input current high alarm.
curr[2-3]_label "iout[1-2]". LTC3880 only.
curr[2-3]_input Measured input current.
curr[2-3]_max Maximum input current.
curr[2-3]_crit Critical input current.
curr[2-3]_max_alarm Input current high alarm.
curr[2-3]_crit_alarm Input current critical high alarm.
......@@ -8,11 +8,6 @@ Supported chips:
Addresses scanned: -
Datasheet:
http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146395
* Linear Technology LTC2978
Octal PMBus Power Supply Monitor and Controller
Prefix: 'ltc2978'
Addresses scanned: -
Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf
* ON Semiconductor ADP4000, NCP4200, NCP4208
Prefixes: 'adp4000', 'ncp4200', 'ncp4208'
Addresses scanned: -
......@@ -20,6 +15,14 @@ Supported chips:
http://www.onsemi.com/pub_link/Collateral/ADP4000-D.PDF
http://www.onsemi.com/pub_link/Collateral/NCP4200-D.PDF
http://www.onsemi.com/pub_link/Collateral/JUNE%202009-%20REV.%200.PDF
* Lineage Power
Prefixes: 'pdt003', 'pdt006', 'pdt012', 'udt020'
Addresses scanned: -
Datasheets:
http://www.lineagepower.com/oem/pdf/PDT003A0X.pdf
http://www.lineagepower.com/oem/pdf/PDT006A0X.pdf
http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf
http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf
* Generic PMBus devices
Prefix: 'pmbus'
Addresses scanned: -
......
This diff is collapsed.
Kernel driver zl6100
====================
Supported chips:
* Intersil / Zilker Labs ZL2004
Prefix: 'zl2004'
Addresses scanned: -
Datasheet: http://www.intersil.com/data/fn/fn6847.pdf
* Intersil / Zilker Labs ZL2006
Prefix: 'zl2006'
Addresses scanned: -
Datasheet: http://www.intersil.com/data/fn/fn6850.pdf
* Intersil / Zilker Labs ZL2008
Prefix: 'zl2008'
Addresses scanned: -
Datasheet: http://www.intersil.com/data/fn/fn6859.pdf
* Intersil / Zilker Labs ZL2105
Prefix: 'zl2105'
Addresses scanned: -
Datasheet: http://www.intersil.com/data/fn/fn6851.pdf
* Intersil / Zilker Labs ZL2106
Prefix: 'zl2106'
Addresses scanned: -
Datasheet: http://www.intersil.com/data/fn/fn6852.pdf
* Intersil / Zilker Labs ZL6100
Prefix: 'zl6100'
Addresses scanned: -
Datasheet: http://www.intersil.com/data/fn/fn6876.pdf
* Intersil / Zilker Labs ZL6105
Prefix: 'zl6105'
Addresses scanned: -
Datasheet: http://www.intersil.com/data/fn/fn6906.pdf
Author: Guenter Roeck <guenter.roeck@ericsson.com>
Description
-----------
This driver supports hardware montoring for Intersil / Zilker Labs ZL6100 and
compatible digital DC-DC controllers.
The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus and Documentation.hwmon/pmbus-core for details
on PMBus client drivers.
Usage Notes
-----------
This driver does not auto-detect devices. You will have to instantiate the
devices explicitly. Please see Documentation/i2c/instantiating-devices for
details.
WARNING: Do not access chip registers using the i2cdump command, and do not use
any of the i2ctools commands on a command register used to save and restore
configuration data (0x11, 0x12, 0x15, 0x16, and 0xf4). The chips supported by
this driver interpret any access to those command registers (including read
commands) as request to execute the command in question. Unless write accesses
to those registers are protected, this may result in power loss, board resets,
and/or Flash corruption. Worst case, your board may turn into a brick.
Platform data support
---------------------
The driver supports standard PMBus driver platform data.
Module parameters
-----------------
delay
-----
Some Intersil/Zilker Labs DC-DC controllers require a minimum interval between
I2C bus accesses. According to Intersil, the minimum interval is 2 ms, though
1 ms appears to be sufficient and has not caused any problems in testing.
The problem is known to affect ZL6100, ZL2105, and ZL2008. It is known not to
affect ZL2004 and ZL6105. The driver automatically sets the interval to 1 ms
except for ZL2004 and ZL6105. To enable manual override, the driver provides a
writeable module parameter, 'delay', which can be used to set the interval to
a value between 0 and 65,535 microseconds.
Sysfs entries
-------------
The following attributes are supported. Limits are read-write; all other
attributes are read-only.
in1_label "vin"
in1_input Measured input voltage.
in1_min Minimum input voltage.
in1_max Maximum input voltage.
in1_lcrit Critical minumum input voltage.
in1_crit Critical maximum input voltage.
in1_min_alarm Input voltage low alarm.
in1_max_alarm Input voltage high alarm.
in1_lcrit_alarm Input voltage critical low alarm.
in1_crit_alarm Input voltage critical high alarm.
in2_label "vout1"
in2_input Measured output voltage.
in2_lcrit Critical minumum output Voltage.
in2_crit Critical maximum output voltage.
in2_lcrit_alarm Critical output voltage critical low alarm.
in2_crit_alarm Critical output voltage critical high alarm.
curr1_label "iout1"
curr1_input Measured output current.
curr1_lcrit Critical minimum output current.
curr1_crit Critical maximum output current.
curr1_lcrit_alarm Output current critical low alarm.
curr1_crit_alarm Output current critical high alarm.
temp[12]_input Measured temperature.
temp[12]_min Minimum temperature.
temp[12]_max Maximum temperature.
temp[12]_lcrit Critical low temperature.
temp[12]_crit Critical high temperature.
temp[12]_min_alarm Chip temperature low alarm.
temp[12]_max_alarm Chip temperature high alarm.
temp[12]_lcrit_alarm Chip temperature critical low alarm.
temp[12]_crit_alarm Chip temperature critical high alarm.
......@@ -68,6 +68,16 @@ config SENSORS_ABITUGURU3
This driver can also be built as a module. If so, the module
will be called abituguru3.
config SENSORS_AD7314
tristate "Analog Devices AD7314 and compatibles"
depends on SPI && EXPERIMENTAL
help
If you say yes here you get support for the Analog Devices
AD7314, ADT7301 and ADT7302 temperature sensors.
This driver can also be built as a module. If so, the module
will be called ad7314.
config SENSORS_AD7414
tristate "Analog Devices AD7414"
depends on I2C && EXPERIMENTAL
......@@ -303,6 +313,16 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module
will be called ds1621.
config SENSORS_EXYNOS4_TMU
tristate "Temperature sensor on Samsung EXYNOS4"
depends on EXYNOS4_DEV_TMU
help
If you say yes here you get support for TMU (Thermal Managment
Unit) on SAMSUNG EXYNOS4 series of SoC.
This driver can also be built as a module. If so, the module
will be called exynos4-tmu.
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI && EXPERIMENTAL
......@@ -531,6 +551,7 @@ config SENSORS_LM75
If you say yes here you get support for one common type of
temperature sensor chip, with models including:
- Analog Devices ADT75
- Dallas Semiconductor DS75 and DS1775
- Maxim MAX6625 and MAX6626
- Microchip MCP980x
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7314) += ad7314.o
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o
......@@ -47,6 +48,7 @@ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o
obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_tmu.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
......
/*
* AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*
* Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk>
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
/*
* AD7314 power mode
*/
#define AD7314_PD 0x2000
/*
* AD7314 temperature masks
*/
#define AD7314_TEMP_SIGN 0x200
#define AD7314_TEMP_MASK 0x7FE0
#define AD7314_TEMP_OFFSET 5
/*
* ADT7301 and ADT7302 temperature masks
*/
#define ADT7301_TEMP_SIGN 0x2000
#define ADT7301_TEMP_MASK 0x3FFF
enum ad7314_variant {
adt7301,
adt7302,
ad7314,
};
struct ad7314_data {
struct spi_device *spi_dev;
struct device *hwmon_dev;
u16 rx ____cacheline_aligned;
};
static int ad7314_spi_read(struct ad7314_data *chip, s16 *data)
{
int ret;
ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx));
if (ret < 0) {
dev_err(&chip->spi_dev->dev, "SPI read error\n");
return ret;
}
*data = be16_to_cpu(chip->rx);
return ret;
}
static ssize_t ad7314_show_temperature(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ad7314_data *chip = dev_get_drvdata(dev);
s16 data;
int ret;
ret = ad7314_spi_read(chip, &data);
if (ret < 0)
return ret;
switch (spi_get_device_id(chip->spi_dev)->driver_data) {
case ad7314:
data = (data & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET;
data = (data << 6) >> 6;
return sprintf(buf, "%d\n", 250 * data);
case adt7301:
case adt7302:
/*
* Documented as a 13 bit twos complement register
* with a sign bit - which is a 14 bit 2's complement
* register. 1lsb - 31.25 milli degrees centigrade
*/
data &= ADT7301_TEMP_MASK;
data = (data << 2) >> 2;
return sprintf(buf, "%d\n",
DIV_ROUND_CLOSEST(data * 3125, 100));
default:
return -EINVAL;
}
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
ad7314_show_temperature, NULL, 0);
static struct attribute *ad7314_attributes[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
NULL,
};
static const struct attribute_group ad7314_group = {
.attrs = ad7314_attributes,
};
static int __devinit ad7314_probe(struct spi_device *spi_dev)
{
int ret;
struct ad7314_data *chip;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL) {
ret = -ENOMEM;
goto error_ret;
}
dev_set_drvdata(&spi_dev->dev, chip);
ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
if (ret < 0)
goto error_free_chip;
chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
if (IS_ERR(chip->hwmon_dev)) {
ret = PTR_ERR(chip->hwmon_dev);
goto error_remove_group;
}
return 0;
error_remove_group:
sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
error_free_chip:
kfree(chip);
error_ret:
return ret;
}
static int __devexit ad7314_remove(struct spi_device *spi_dev)
{
struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev);
hwmon_device_unregister(chip->hwmon_dev);
sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
kfree(chip);
return 0;
}
static const struct spi_device_id ad7314_id[] = {
{ "adt7301", adt7301 },
{ "adt7302", adt7302 },
{ "ad7314", ad7314 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7314_id);
static struct spi_driver ad7314_driver = {
.driver = {
.name = "ad7314",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = ad7314_probe,
.remove = __devexit_p(ad7314_remove),
.id_table = ad7314_id,
};
static __init int ad7314_init(void)
{
return spi_register_driver(&ad7314_driver);
}
module_init(ad7314_init);
static __exit void ad7314_exit(void)
{
spi_unregister_driver(&ad7314_driver);
}
module_exit(ad7314_exit);
MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
" temperature sensor driver");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
This diff is collapsed.
......@@ -35,6 +35,7 @@
*/
enum lm75_type { /* keep sorted in alphabetical order */
adt75,
ds1775,
ds75,
lm75,
......@@ -213,6 +214,7 @@ static int lm75_remove(struct i2c_client *client)
}
static const struct i2c_device_id lm75_ids[] = {
{ "adt75", adt75, },
{ "ds1775", ds1775, },
{ "ds75", ds75, },
{ "lm75", lm75, },
......@@ -247,19 +249,30 @@ static int lm75_detect(struct i2c_client *new_client,
I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
/* Now, we do the remaining detection. There is no identification-
dedicated register so we have to rely on several tricks:
unused bits, registers cycling over 8-address boundaries,
addresses 0x04-0x07 returning the last read value.
The cycling+unused addresses combination is not tested,
since it would significantly slow the detection down and would
hardly add any value.
The National Semiconductor LM75A is different than earlier
LM75s. It has an ID byte of 0xaX (where X is the chip
revision, with 1 being the only revision in existence) in
register 7, and unused registers return 0xff rather than the
last read value. */
/*
* Now, we do the remaining detection. There is no identification-
* dedicated register so we have to rely on several tricks:
* unused bits, registers cycling over 8-address boundaries,
* addresses 0x04-0x07 returning the last read value.
* The cycling+unused addresses combination is not tested,
* since it would significantly slow the detection down and would
* hardly add any value.
*
* The National Semiconductor LM75A is different than earlier
* LM75s. It has an ID byte of 0xaX (where X is the chip
* revision, with 1 being the only revision in existence) in
* register 7, and unused registers return 0xff rather than the
* last read value.
*
* Note that this function only detects the original National
* Semiconductor LM75 and the LM75A. Clones from other vendors
* aren't detected, on purpose, because they are typically never
* found on PC hardware. They are found on embedded designs where
* they can be instantiated explicitly so detection is not needed.
* The absence of identification registers on all these clones
* would make their exhaustive detection very difficult and weak,
* and odds are that the driver would bind to unsupported devices.
*/
/* Unused bits */
conf = i2c_smbus_read_byte_data(new_client, 1);
......
......@@ -20,17 +20,18 @@ config SENSORS_PMBUS
help
If you say yes here you get hardware monitoring support for generic
PMBus devices, including but not limited to ADP4000, BMR450, BMR451,
BMR453, BMR454, LTC2978, NCP4200, and NCP4208.
BMR453, BMR454, NCP4200, and NCP4208.
This driver can also be built as a module. If so, the module will
be called pmbus.
config SENSORS_ADM1275
tristate "Analog Devices ADM1275"
tristate "Analog Devices ADM1275 and compatibles"
default n
help
If you say yes here you get hardware monitoring support for Analog
Devices ADM1275 Hot-Swap Controller and Digital Power Monitor.
Devices ADM1275 and ADM1276 Hot-Swap Controller and Digital Power
Monitor.
This driver can also be built as a module. If so, the module will
be called adm1275.
......@@ -45,6 +46,16 @@ config SENSORS_LM25066
This driver can also be built as a module. If so, the module will
be called lm25066.
config SENSORS_LTC2978
tristate "Linear Technologies LTC2978 and LTC3880"
default n
help
If you say yes here you get hardware monitoring support for Linear
Technology LTC2978 and LTC3880.
This driver can also be built as a module. If so, the module will
be called ltc2978.
config SENSORS_MAX16064
tristate "Maxim MAX16064"
default n
......@@ -97,4 +108,15 @@ config SENSORS_UCD9200
This driver can also be built as a module. If so, the module will
be called ucd9200.
config SENSORS_ZL6100
tristate "Intersil ZL6100 and compatibles"
default n
help
If you say yes here you get hardware monitoring support for Intersil
ZL2004, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105 Digital
DC/DC Controllers.
This driver can also be built as a module. If so, the module will
be called zl6100.
endif # PMBUS
......@@ -6,8 +6,10 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o
obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o
......@@ -23,6 +23,8 @@
#include <linux/i2c.h>
#include "pmbus.h"
enum chips { adm1275, adm1276 };
#define ADM1275_PEAK_IOUT 0xd0
#define ADM1275_PEAK_VIN 0xd1
#define ADM1275_PEAK_VOUT 0xd2
......@@ -31,14 +33,47 @@
#define ADM1275_VIN_VOUT_SELECT (1 << 6)
#define ADM1275_VRANGE (1 << 5)
#define ADM1275_IOUT_WARN2_LIMIT 0xd7
#define ADM1275_DEVICE_CONFIG 0xd8
#define ADM1275_IOUT_WARN2_SELECT (1 << 4)
#define ADM1276_PEAK_PIN 0xda
#define ADM1275_MFR_STATUS_IOUT_WARN2 (1 << 0)
struct adm1275_data {
int id;
bool have_oc_fault;
struct pmbus_driver_info info;
};
#define to_adm1275_data(x) container_of(x, struct adm1275_data, info)
static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
{
int ret;
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
const struct adm1275_data *data = to_adm1275_data(info);
int ret = 0;
if (page)
return -EINVAL;
return -ENXIO;
switch (reg) {
case PMBUS_IOUT_UC_FAULT_LIMIT:
if (data->have_oc_fault) {
ret = -ENXIO;
break;
}
ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
break;
case PMBUS_IOUT_OC_FAULT_LIMIT:
if (!data->have_oc_fault) {
ret = -ENXIO;
break;
}
ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
break;
case PMBUS_VIRT_READ_IOUT_MAX:
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
break;
......@@ -48,10 +83,20 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
case PMBUS_VIRT_READ_VIN_MAX:
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
break;
case PMBUS_VIRT_READ_PIN_MAX:
if (data->id != adm1276) {
ret = -ENXIO;
break;
}
ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN);
break;
case PMBUS_VIRT_RESET_IOUT_HISTORY:
case PMBUS_VIRT_RESET_VOUT_HISTORY:
case PMBUS_VIRT_RESET_VIN_HISTORY:
ret = 0;
break;
case PMBUS_VIRT_RESET_PIN_HISTORY:
if (data->id != adm1276)
ret = -ENXIO;
break;
default:
ret = -ENODATA;
......@@ -66,9 +111,14 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
int ret;
if (page)
return -EINVAL;
return -ENXIO;
switch (reg) {
case PMBUS_IOUT_UC_FAULT_LIMIT:
case PMBUS_IOUT_OC_FAULT_LIMIT:
ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT,
word);
break;
case PMBUS_VIRT_RESET_IOUT_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
break;
......@@ -78,6 +128,41 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
case PMBUS_VIRT_RESET_VIN_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0);
break;
case PMBUS_VIRT_RESET_PIN_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0);
break;
default:
ret = -ENODATA;
break;
}
return ret;
}
static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
const struct adm1275_data *data = to_adm1275_data(info);
int mfr_status, ret;
if (page > 0)
return -ENXIO;
switch (reg) {
case PMBUS_STATUS_IOUT:
ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT);
if (ret < 0)
break;
mfr_status = pmbus_read_byte_data(client, page,
PMBUS_STATUS_MFR_SPECIFIC);
if (mfr_status < 0) {
ret = mfr_status;
break;
}
if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) {
ret |= data->have_oc_fault ?
PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT;
}
break;
default:
ret = -ENODATA;
break;
......@@ -88,16 +173,17 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
static int adm1275_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int config;
int config, device_config;
int ret;
struct pmbus_driver_info *info;
struct adm1275_data *data;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA))
return -ENODEV;
info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
if (!info)
data = kzalloc(sizeof(struct adm1275_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
......@@ -106,6 +192,15 @@ static int adm1275_probe(struct i2c_client *client,
goto err_mem;
}
device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG);
if (device_config < 0) {
ret = device_config;
goto err_mem;
}
data->id = id->driver_data;
info = &data->info;
info->pages = 1;
info->format[PSC_VOLTAGE_IN] = direct;
info->format[PSC_VOLTAGE_OUT] = direct;
......@@ -116,6 +211,7 @@ static int adm1275_probe(struct i2c_client *client,
info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
info->read_word_data = adm1275_read_word_data;
info->read_byte_data = adm1275_read_byte_data;
info->write_word_data = adm1275_write_word_data;
if (config & ADM1275_VRANGE) {
......@@ -134,10 +230,36 @@ static int adm1275_probe(struct i2c_client *client,
info->R[PSC_VOLTAGE_OUT] = -1;
}
if (config & ADM1275_VIN_VOUT_SELECT)
info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
else
info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
if (device_config & ADM1275_IOUT_WARN2_SELECT)
data->have_oc_fault = true;
switch (id->driver_data) {
case adm1275:
if (config & ADM1275_VIN_VOUT_SELECT)
info->func[0] |=
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
else
info->func[0] |=
PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
break;
case adm1276:
info->format[PSC_POWER] = direct;
info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
| PMBUS_HAVE_STATUS_INPUT;
if (config & ADM1275_VIN_VOUT_SELECT)
info->func[0] |=
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
if (config & ADM1275_VRANGE) {
info->m[PSC_POWER] = 6043;
info->b[PSC_POWER] = 0;
info->R[PSC_POWER] = -2;
} else {
info->m[PSC_POWER] = 2115;
info->b[PSC_POWER] = 0;
info->R[PSC_POWER] = -1;
}
break;
}
ret = pmbus_do_probe(client, id, info);
if (ret)
......@@ -145,22 +267,23 @@ static int adm1275_probe(struct i2c_client *client,
return 0;
err_mem:
kfree(info);
kfree(data);
return ret;
}
static int adm1275_remove(struct i2c_client *client)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
int ret;
const struct adm1275_data *data = to_adm1275_data(info);
ret = pmbus_do_remove(client);
kfree(info);
return ret;
pmbus_do_remove(client);
kfree(data);
return 0;
}
static const struct i2c_device_id adm1275_id[] = {
{"adm1275", 0},
{ "adm1275", adm1275 },
{ "adm1276", adm1276 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adm1275_id);
......@@ -185,7 +308,7 @@ static void __exit adm1275_exit(void)
}
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275");
MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
MODULE_LICENSE("GPL");
module_init(adm1275_init);
module_exit(adm1275_exit);
......@@ -57,7 +57,7 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
int ret;
if (page > 1)
return -EINVAL;
return -ENXIO;
/* Map READ_VAUX into READ_VOUT register on page 1 */
if (page == 1) {
......@@ -85,7 +85,7 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
break;
default:
/* No other valid registers on page 1 */
ret = -EINVAL;
ret = -ENXIO;
break;
}
goto done;
......@@ -138,7 +138,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
int ret;
if (page > 1)
return -EINVAL;
return -ENXIO;
switch (reg) {
case PMBUS_IIN_OC_WARN_LIMIT:
......@@ -164,10 +164,10 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
static int lm25066_write_byte(struct i2c_client *client, int page, u8 value)
{
if (page > 1)
return -EINVAL;
return -ENXIO;
if (page == 0)
return pmbus_write_byte(client, 0, value);
if (page <= 0)
return pmbus_write_byte(client, page, value);
return 0;
}
......@@ -309,11 +309,10 @@ static int lm25066_remove(struct i2c_client *client)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
const struct lm25066_data *data = to_lm25066_data(info);
int ret;
ret = pmbus_do_remove(client);
pmbus_do_remove(client);
kfree(data);
return ret;
return 0;
}
static const struct i2c_device_id lm25066_id[] = {
......
This diff is collapsed.
......@@ -105,7 +105,8 @@ static int max16064_probe(struct i2c_client *client,
static int max16064_remove(struct i2c_client *client)
{
return pmbus_do_remove(client);
pmbus_do_remove(client);
return 0;
}
static const struct i2c_device_id max16064_id[] = {
......
......@@ -93,12 +93,14 @@ static int max34440_write_word_data(struct i2c_client *client, int page,
static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
{
int ret;
int ret = 0;
int mfg_status;
ret = pmbus_set_page(client, page);
if (ret < 0)
return ret;
if (page >= 0) {
ret = pmbus_set_page(client, page);
if (ret < 0)
return ret;
}
switch (reg) {
case PMBUS_STATUS_IOUT:
......@@ -224,7 +226,8 @@ static int max34440_probe(struct i2c_client *client,
static int max34440_remove(struct i2c_client *client)
{
return pmbus_do_remove(client);
pmbus_do_remove(client);
return 0;
}
static const struct i2c_device_id max34440_id[] = {
......
......@@ -45,7 +45,7 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
int ret;
if (page)
return -EINVAL;
return -ENXIO;
switch (reg) {
case PMBUS_VIRT_READ_VOUT_MAX:
......@@ -101,8 +101,8 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
int ret = 0;
int mfg_status;
if (page)
return -EINVAL;
if (page > 0)
return -ENXIO;
switch (reg) {
case PMBUS_STATUS_VOUT:
......@@ -182,7 +182,8 @@ static int max8688_probe(struct i2c_client *client,
static int max8688_remove(struct i2c_client *client)
{
return pmbus_do_remove(client);
pmbus_do_remove(client);
return 0;
}
static const struct i2c_device_id max8688_id[] = {
......
......@@ -187,13 +187,12 @@ static int pmbus_probe(struct i2c_client *client,
static int pmbus_remove(struct i2c_client *client)
{
int ret;
const struct pmbus_driver_info *info;
info = pmbus_get_driver_info(client);
ret = pmbus_do_remove(client);
pmbus_do_remove(client);
kfree(info);
return ret;
return 0;
}
/*
......@@ -205,10 +204,13 @@ static const struct i2c_device_id pmbus_id[] = {
{"bmr451", 1},
{"bmr453", 1},
{"bmr454", 1},
{"ltc2978", 8},
{"ncp4200", 1},
{"ncp4208", 1},
{"pdt003", 1},
{"pdt006", 1},
{"pdt012", 1},
{"pmbus", 0},
{"udt020", 1},
{}
};
......
......@@ -134,8 +134,16 @@
* Semantics:
* Virtual registers are all word size.
* READ registers are read-only; writes are either ignored or return an error.
* RESET registers are read/write. Reading returns zero (used for detection),
* writing any value causes the associated history to be reset.
* RESET registers are read/write. Reading reset registers returns zero
* (used for detection), writing any value causes the associated history to be
* reset.
* Virtual registers have to be handled in device specific driver code. Chip
* driver code returns non-negative register values if a virtual register is
* supported, or a negative error code if not. The chip driver may return
* -ENODATA or any other error code in this case, though an error code other
* than -ENODATA is handled more efficiently and thus preferred. Either case,
* the calling PMBus core code will abort if the chip driver returns an error
* code when reading or writing virtual registers.
*/
#define PMBUS_VIRT_BASE 0x100
#define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 0)
......@@ -160,6 +168,9 @@
#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 19)
#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 20)
#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 21)
#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 22)
#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 23)
#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 24)
/*
* CAPABILITY
......@@ -320,6 +331,12 @@ struct pmbus_driver_info {
* The following functions map manufacturing specific register values
* to PMBus standard register values. Specify only if mapping is
* necessary.
* Functions return the register value (read) or zero (write) if
* successful. A return value of -ENODATA indicates that there is no
* manufacturer specific register, but that a standard PMBus register
* may exist. Any other negative return value indicates that the
* register does not exist, and that no attempt should be made to read
* the standard register.
*/
int (*read_byte_data)(struct i2c_client *client, int page, int reg);
int (*read_word_data)(struct i2c_client *client, int page, int reg);
......@@ -347,7 +364,7 @@ bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
struct pmbus_driver_info *info);
int pmbus_do_remove(struct i2c_client *client);
void pmbus_do_remove(struct i2c_client *client);
const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
*client);
......
......@@ -160,7 +160,7 @@ int pmbus_set_page(struct i2c_client *client, u8 page)
rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
if (newpage != page)
rv = -EINVAL;
rv = -EIO;
else
data->currpage = page;
}
......@@ -229,7 +229,7 @@ static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg,
return status;
}
if (reg >= PMBUS_VIRT_BASE)
return -EINVAL;
return -ENXIO;
return pmbus_write_word_data(client, page, reg, word);
}
......@@ -261,7 +261,7 @@ static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg)
return status;
}
if (reg >= PMBUS_VIRT_BASE)
return -EINVAL;
return -ENXIO;
return pmbus_read_word_data(client, page, reg);
}
......@@ -316,11 +316,11 @@ static int pmbus_check_status_cml(struct i2c_client *client)
{
int status, status2;
status = pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
if (status < 0 || (status & PB_STATUS_CML)) {
status2 = pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
return -EINVAL;
return -EIO;
}
return 0;
}
......@@ -371,8 +371,8 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
for (i = 0; i < info->pages; i++)
data->status[PB_STATUS_BASE + i]
= pmbus_read_byte_data(client, i,
PMBUS_STATUS_BYTE);
= _pmbus_read_byte_data(client, i,
PMBUS_STATUS_BYTE);
for (i = 0; i < info->pages; i++) {
if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
continue;
......@@ -445,13 +445,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
exponent = data->exponent;
mantissa = (u16) sensor->data;
} else { /* LINEAR11 */
exponent = (sensor->data >> 11) & 0x001f;
mantissa = sensor->data & 0x07ff;
if (exponent > 0x0f)
exponent |= 0xffe0; /* sign extend exponent */
if (mantissa > 0x03ff)
mantissa |= 0xfffff800; /* sign extend mantissa */
exponent = ((s16)sensor->data) >> 11;
mantissa = ((s16)((sensor->data & 0x7ff) << 5)) >> 5;
}
val = mantissa;
......@@ -1401,7 +1396,42 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = {
}
};
static const struct pmbus_limit_attr temp_limit_attrs23[] = {
static const struct pmbus_limit_attr temp_limit_attrs2[] = {
{
.reg = PMBUS_UT_WARN_LIMIT,
.low = true,
.attr = "min",
.alarm = "min_alarm",
.sbit = PB_TEMP_UT_WARNING,
}, {
.reg = PMBUS_UT_FAULT_LIMIT,
.low = true,
.attr = "lcrit",
.alarm = "lcrit_alarm",
.sbit = PB_TEMP_UT_FAULT,
}, {
.reg = PMBUS_OT_WARN_LIMIT,
.attr = "max",
.alarm = "max_alarm",
.sbit = PB_TEMP_OT_WARNING,
}, {
.reg = PMBUS_OT_FAULT_LIMIT,
.attr = "crit",
.alarm = "crit_alarm",
.sbit = PB_TEMP_OT_FAULT,
}, {
.reg = PMBUS_VIRT_READ_TEMP2_MIN,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_TEMP2_MAX,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_TEMP2_HISTORY,
.attr = "reset_history",
}
};
static const struct pmbus_limit_attr temp_limit_attrs3[] = {
{
.reg = PMBUS_UT_WARN_LIMIT,
.low = true,
......@@ -1450,8 +1480,8 @@ static const struct pmbus_sensor_attr temp_attributes[] = {
.sfunc = PMBUS_HAVE_STATUS_TEMP,
.sbase = PB_STATUS_TEMP_BASE,
.gbit = PB_STATUS_TEMPERATURE,
.limit = temp_limit_attrs23,
.nlimit = ARRAY_SIZE(temp_limit_attrs23),
.limit = temp_limit_attrs2,
.nlimit = ARRAY_SIZE(temp_limit_attrs2),
}, {
.reg = PMBUS_READ_TEMPERATURE_3,
.class = PSC_TEMPERATURE,
......@@ -1462,8 +1492,8 @@ static const struct pmbus_sensor_attr temp_attributes[] = {
.sfunc = PMBUS_HAVE_STATUS_TEMP,
.sbase = PB_STATUS_TEMP_BASE,
.gbit = PB_STATUS_TEMPERATURE,
.limit = temp_limit_attrs23,
.nlimit = ARRAY_SIZE(temp_limit_attrs23),
.limit = temp_limit_attrs3,
.nlimit = ARRAY_SIZE(temp_limit_attrs3),
}
};
......@@ -1593,10 +1623,10 @@ static void pmbus_find_attributes(struct i2c_client *client,
static int pmbus_identify_common(struct i2c_client *client,
struct pmbus_data *data)
{
int vout_mode = -1, exponent;
int vout_mode = -1;
if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE))
vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
vout_mode = _pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
if (vout_mode >= 0 && vout_mode != 0xff) {
/*
* Not all chips support the VOUT_MODE command,
......@@ -1607,11 +1637,7 @@ static int pmbus_identify_common(struct i2c_client *client,
if (data->info->format[PSC_VOLTAGE_OUT] != linear)
return -ENODEV;
exponent = vout_mode & 0x1f;
/* and sign-extend it */
if (exponent & 0x10)
exponent |= ~0x1f;
data->exponent = exponent;
data->exponent = ((s8)(vout_mode << 3)) >> 3;
break;
case 1: /* VID mode */
if (data->info->format[PSC_VOLTAGE_OUT] != vid)
......@@ -1682,7 +1708,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
dev_err(&client->dev, "Bad number of PMBus pages: %d\n",
info->pages);
ret = -EINVAL;
ret = -ENODEV;
goto out_data;
}
......@@ -1764,7 +1790,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
}
EXPORT_SYMBOL_GPL(pmbus_do_probe);
int pmbus_do_remove(struct i2c_client *client)
void pmbus_do_remove(struct i2c_client *client)
{
struct pmbus_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
......@@ -1774,7 +1800,6 @@ int pmbus_do_remove(struct i2c_client *client)
kfree(data->booleans);
kfree(data->sensors);
kfree(data);
return 0;
}
EXPORT_SYMBOL_GPL(pmbus_do_remove);
......
......@@ -74,8 +74,8 @@ static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg)
switch (reg) {
case PMBUS_FAN_CONFIG_12:
if (page)
return -EINVAL;
if (page > 0)
return -ENXIO;
ret = ucd9000_get_fan_config(client, 0);
if (ret < 0)
......@@ -88,8 +88,8 @@ static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg)
ret = fan_config;
break;
case PMBUS_FAN_CONFIG_34:
if (page)
return -EINVAL;
if (page > 0)
return -ENXIO;
ret = ucd9000_get_fan_config(client, 2);
if (ret < 0)
......@@ -239,13 +239,12 @@ static int ucd9000_probe(struct i2c_client *client,
static int ucd9000_remove(struct i2c_client *client)
{
int ret;
struct ucd9000_data *data;
data = to_ucd9000_data(pmbus_get_driver_info(client));
ret = pmbus_do_remove(client);
pmbus_do_remove(client);
kfree(data);
return ret;
return 0;
}
......
......@@ -171,13 +171,12 @@ static int ucd9200_probe(struct i2c_client *client,
static int ucd9200_remove(struct i2c_client *client)
{
int ret;
const struct pmbus_driver_info *info;
info = pmbus_get_driver_info(client);
ret = pmbus_do_remove(client);
pmbus_do_remove(client);
kfree(info);
return ret;
return 0;
}
......
/*
* Hardware monitoring driver for ZL6100 and compatibles
*
* Copyright (c) 2011 Ericsson AB.
*
* 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/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/ktime.h>
#include <linux/delay.h>
#include "pmbus.h"
enum chips { zl2004, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 };
struct zl6100_data {
int id;
ktime_t access; /* chip access time */
struct pmbus_driver_info info;
};
#define to_zl6100_data(x) container_of(x, struct zl6100_data, info)
#define ZL6100_DEVICE_ID 0xe4
#define ZL6100_WAIT_TIME 1000 /* uS */
static ushort delay = ZL6100_WAIT_TIME;
module_param(delay, ushort, 0644);
MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
/* Some chips need a delay between accesses */
static inline void zl6100_wait(const struct zl6100_data *data)
{
if (delay) {
s64 delta = ktime_us_delta(ktime_get(), data->access);
if (delta < delay)
udelay(delay - delta);
}
}
static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct zl6100_data *data = to_zl6100_data(info);
int ret;
if (page || reg >= PMBUS_VIRT_BASE)
return -ENXIO;
zl6100_wait(data);
ret = pmbus_read_word_data(client, page, reg);
data->access = ktime_get();
return ret;
}
static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct zl6100_data *data = to_zl6100_data(info);
int ret;
if (page > 0)
return -ENXIO;
zl6100_wait(data);
ret = pmbus_read_byte_data(client, page, reg);
data->access = ktime_get();
return ret;
}
static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
u16 word)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct zl6100_data *data = to_zl6100_data(info);
int ret;
if (page || reg >= PMBUS_VIRT_BASE)
return -ENXIO;
zl6100_wait(data);
ret = pmbus_write_word_data(client, page, reg, word);
data->access = ktime_get();
return ret;
}
static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct zl6100_data *data = to_zl6100_data(info);
int ret;
if (page > 0)
return -ENXIO;
zl6100_wait(data);
ret = pmbus_write_byte(client, page, value);
data->access = ktime_get();
return ret;
}
static const struct i2c_device_id zl6100_id[] = {
{"zl2004", zl2004},
{"zl2006", zl2006},
{"zl2008", zl2008},
{"zl2105", zl2105},
{"zl2106", zl2106},
{"zl6100", zl6100},
{"zl6105", zl6105},
{ }
};
MODULE_DEVICE_TABLE(i2c, zl6100_id);
static int zl6100_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct zl6100_data *data;
struct pmbus_driver_info *info;
u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
const struct i2c_device_id *mid;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA
| I2C_FUNC_SMBUS_READ_BLOCK_DATA))
return -ENODEV;
ret = i2c_smbus_read_block_data(client, ZL6100_DEVICE_ID,
device_id);
if (ret < 0) {
dev_err(&client->dev, "Failed to read device ID\n");
return ret;
}
device_id[ret] = '\0';
dev_info(&client->dev, "Device ID %s\n", device_id);
mid = NULL;
for (mid = zl6100_id; mid->name[0]; mid++) {
if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
break;
}
if (!mid->name[0]) {
dev_err(&client->dev, "Unsupported device\n");
return -ENODEV;
}
if (id->driver_data != mid->driver_data)
dev_notice(&client->dev,
"Device mismatch: Configured %s, detected %s\n",
id->name, mid->name);
data = kzalloc(sizeof(struct zl6100_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->id = mid->driver_data;
/*
* ZL2008, ZL2105, and ZL6100 are known to require a wait time
* between I2C accesses. ZL2004 and ZL6105 are known to be safe.
*
* Only clear the wait time for chips known to be safe. The wait time
* can be cleared later for additional chips if tests show that it
* is not needed (in other words, better be safe than sorry).
*/
if (data->id == zl2004 || data->id == zl6105)
delay = 0;
/*
* Since there was a direct I2C device access above, wait before
* accessing the chip again.
* Set the timestamp, wait, then set it again. This should provide
* enough buffer time to be safe.
*/
data->access = ktime_get();
zl6100_wait(data);
data->access = ktime_get();
info = &data->info;
info->pages = 1;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
info->read_word_data = zl6100_read_word_data;
info->read_byte_data = zl6100_read_byte_data;
info->write_word_data = zl6100_write_word_data;
info->write_byte = zl6100_write_byte;
ret = pmbus_do_probe(client, mid, info);
if (ret)
goto err_mem;
return 0;
err_mem:
kfree(data);
return ret;
}
static int zl6100_remove(struct i2c_client *client)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
const struct zl6100_data *data = to_zl6100_data(info);
pmbus_do_remove(client);
kfree(data);
return 0;
}
static struct i2c_driver zl6100_driver = {
.driver = {
.name = "zl6100",
},
.probe = zl6100_probe,
.remove = zl6100_remove,
.id_table = zl6100_id,
};
static int __init zl6100_init(void)
{
return i2c_add_driver(&zl6100_driver);
}
static void __exit zl6100_exit(void)
{
i2c_del_driver(&zl6100_driver);
}
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
MODULE_LICENSE("GPL");
module_init(zl6100_init);
module_exit(zl6100_exit);
This diff is collapsed.
/*
* exynos4_tmu.h - Samsung EXYNOS4 TMU (Thermal Management Unit)
*
* Copyright (C) 2011 Samsung Electronics
* Donggeun Kim <dg77.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LINUX_EXYNOS4_TMU_H
#define _LINUX_EXYNOS4_TMU_H
enum calibration_type {
TYPE_ONE_POINT_TRIMMING,
TYPE_TWO_POINT_TRIMMING,
TYPE_NONE,
};
/**
* struct exynos4_tmu_platform_data
* @threshold: basic temperature for generating interrupt
* 25 <= threshold <= 125 [unit: degree Celsius]
* @trigger_levels: array for each interrupt levels
* [unit: degree Celsius]
* 0: temperature for trigger_level0 interrupt
* condition for trigger_level0 interrupt:
* current temperature > threshold + trigger_levels[0]
* 1: temperature for trigger_level1 interrupt
* condition for trigger_level1 interrupt:
* current temperature > threshold + trigger_levels[1]
* 2: temperature for trigger_level2 interrupt
* condition for trigger_level2 interrupt:
* current temperature > threshold + trigger_levels[2]
* 3: temperature for trigger_level3 interrupt
* condition for trigger_level3 interrupt:
* current temperature > threshold + trigger_levels[3]
* @trigger_level0_en:
* 1 = enable trigger_level0 interrupt,
* 0 = disable trigger_level0 interrupt
* @trigger_level1_en:
* 1 = enable trigger_level1 interrupt,
* 0 = disable trigger_level1 interrupt
* @trigger_level2_en:
* 1 = enable trigger_level2 interrupt,
* 0 = disable trigger_level2 interrupt
* @trigger_level3_en:
* 1 = enable trigger_level3 interrupt,
* 0 = disable trigger_level3 interrupt
* @gain: gain of amplifier in the positive-TC generator block
* 0 <= gain <= 15
* @reference_voltage: reference voltage of amplifier
* in the positive-TC generator block
* 0 <= reference_voltage <= 31
* @cal_type: calibration type for temperature
*
* This structure is required for configuration of exynos4_tmu driver.
*/
struct exynos4_tmu_platform_data {
u8 threshold;
u8 trigger_levels[4];
bool trigger_level0_en;
bool trigger_level1_en;
bool trigger_level2_en;
bool trigger_level3_en;
u8 gain;
u8 reference_voltage;
enum calibration_type cal_type;
};
#endif /* _LINUX_EXYNOS4_TMU_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment