Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 267276
b: refs/heads/master
c: ddfb41c
h: refs/heads/master
v: v3
  • Loading branch information
Guenter Roeck committed Oct 24, 2011
1 parent d2460fd commit 6b24d82
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 31 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c3ff9a674c2313d4f28e38d384b18b561b313eb7
refs/heads/master: ddfb41ca2a33c9f5053126324597510974724a1f
57 changes: 41 additions & 16 deletions trunk/Documentation/hwmon/ltc2978
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Supported chips:
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>

Expand All @@ -14,7 +18,8 @@ Description
-----------

The LTC2978 is an octal power supply monitor, supervisor, sequencer and
margin controller.
margin controller. The LTC3880 is a dual, PolyPhase DC/DC synchronous
step-down switching regulator controller.


Usage Notes
Expand Down Expand Up @@ -43,12 +48,12 @@ 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.
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]".
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.
Expand All @@ -58,21 +63,41 @@ 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.
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.

temp1_input Measured temperature.
temp1_min Mimimum temperature.
temp1_max Maximum temperature.
temp1_lcrit Critical low temperature.
temp1_crit Critical high temperature.
temp1_min_alarm Chip temperature low alarm.
temp1_max_alarm Chip temperature high alarm.
temp1_lcrit_alarm Chip temperature critical low alarm.
temp1_crit_alarm Chip temperature critical high alarm.
temp1_lowest Lowest measured temperature.
temp1_highest Highest measured temperature.
temp1_reset_history Reset history. Writing into this attribute will reset
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.
4 changes: 2 additions & 2 deletions trunk/drivers/hwmon/pmbus/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ config SENSORS_LM25066
be called lm25066.

config SENSORS_LTC2978
tristate "Linear Technologies LTC2978"
tristate "Linear Technologies LTC2978 and LTC3880"
default n
help
If you say yes here you get hardware monitoring support for Linear
Technology LTC2978.
Technology LTC2978 and LTC3880.

This driver can also be built as a module. If so, the module will
be called ltc2978.
Expand Down
137 changes: 125 additions & 12 deletions trunk/drivers/hwmon/pmbus/ltc2978.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Hardware monitoring driver for LTC2978
* Hardware monitoring driver for LTC2978 and LTC3880
*
* Copyright (c) 2011 Ericsson AB.
*
Expand All @@ -26,19 +26,28 @@
#include <linux/i2c.h>
#include "pmbus.h"

enum chips { ltc2978 };
enum chips { ltc2978, ltc3880 };

/* LTC2978 and LTC3880 */
#define LTC2978_MFR_VOUT_PEAK 0xdd
#define LTC2978_MFR_VIN_PEAK 0xde
#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
#define LTC2978_MFR_SPECIAL_ID 0xe7

/* LTC2978 only */
#define LTC2978_MFR_VOUT_MIN 0xfb
#define LTC2978_MFR_VIN_MIN 0xfc
#define LTC2978_MFR_TEMPERATURE_MIN 0xfd

/* LTC3880 only */
#define LTC3880_MFR_IOUT_PEAK 0xd7
#define LTC3880_MFR_CLEAR_PEAKS 0xe3
#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4

#define LTC2978_ID_REV1 0x0121
#define LTC2978_ID_REV2 0x0122
#define LTC3880_ID 0x4000
#define LTC3880_ID_MASK 0xff00

/*
* LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
Expand All @@ -52,6 +61,8 @@ struct ltc2978_data {
int vin_min, vin_max;
int temp_min, temp_max;
int vout_min[8], vout_max[8];
int iout_max[2];
int temp2_max[2];
struct pmbus_driver_info info;
};

Expand All @@ -70,7 +81,8 @@ static inline int lin11_to_val(int data)
return (e < 0 ? m >> -e : m << e);
}

static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct ltc2978_data *data = to_ltc2978_data(info);
Expand Down Expand Up @@ -106,6 +118,25 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
ret = data->temp_max;
}
break;
case PMBUS_VIRT_RESET_VOUT_HISTORY:
case PMBUS_VIRT_RESET_VIN_HISTORY:
case PMBUS_VIRT_RESET_TEMP_HISTORY:
ret = 0;
break;
default:
ret = -ENODATA;
break;
}
return ret;
}

static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct ltc2978_data *data = to_ltc2978_data(info);
int ret;

switch (reg) {
case PMBUS_VIRT_READ_VIN_MIN:
ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN);
if (ret >= 0) {
Expand Down Expand Up @@ -140,18 +171,74 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
ret = data->temp_min;
}
break;
case PMBUS_VIRT_RESET_VOUT_HISTORY:
case PMBUS_VIRT_RESET_VIN_HISTORY:
case PMBUS_VIRT_RESET_TEMP_HISTORY:
case PMBUS_VIRT_READ_IOUT_MAX:
case PMBUS_VIRT_RESET_IOUT_HISTORY:
case PMBUS_VIRT_READ_TEMP2_MAX:
case PMBUS_VIRT_RESET_TEMP2_HISTORY:
ret = -ENXIO;
break;
default:
ret = ltc2978_read_word_data_common(client, page, reg);
break;
}
return ret;
}

static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct ltc2978_data *data = to_ltc2978_data(info);
int ret;

switch (reg) {
case PMBUS_VIRT_READ_IOUT_MAX:
ret = pmbus_read_word_data(client, page, LTC3880_MFR_IOUT_PEAK);
if (ret >= 0) {
if (lin11_to_val(ret)
> lin11_to_val(data->iout_max[page]))
data->iout_max[page] = ret;
ret = data->iout_max[page];
}
break;
case PMBUS_VIRT_READ_TEMP2_MAX:
ret = pmbus_read_word_data(client, page,
LTC3880_MFR_TEMPERATURE2_PEAK);
if (ret >= 0) {
if (lin11_to_val(ret)
> lin11_to_val(data->temp2_max[page]))
data->temp2_max[page] = ret;
ret = data->temp2_max[page];
}
break;
case PMBUS_VIRT_READ_VIN_MIN:
case PMBUS_VIRT_READ_VOUT_MIN:
case PMBUS_VIRT_READ_TEMP_MIN:
ret = -ENXIO;
break;
case PMBUS_VIRT_RESET_IOUT_HISTORY:
case PMBUS_VIRT_RESET_TEMP2_HISTORY:
ret = 0;
break;
default:
ret = -ENODATA;
ret = ltc2978_read_word_data_common(client, page, reg);
break;
}
return ret;
}

static int ltc2978_clear_peaks(struct i2c_client *client, int page,
enum chips id)
{
int ret;

if (id == ltc2978)
ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
else
ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);

return ret;
}

static int ltc2978_write_word_data(struct i2c_client *client, int page,
int reg, u16 word)
{
Expand All @@ -160,20 +247,28 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
int ret;

switch (reg) {
case PMBUS_VIRT_RESET_IOUT_HISTORY:
data->iout_max[page] = 0x7fff;
ret = ltc2978_clear_peaks(client, page, data->id);
break;
case PMBUS_VIRT_RESET_TEMP2_HISTORY:
data->temp2_max[page] = 0x7fff;
ret = ltc2978_clear_peaks(client, page, data->id);
break;
case PMBUS_VIRT_RESET_VOUT_HISTORY:
data->vout_min[page] = 0xffff;
data->vout_max[page] = 0;
ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
ret = ltc2978_clear_peaks(client, page, data->id);
break;
case PMBUS_VIRT_RESET_VIN_HISTORY:
data->vin_min = 0x7bff;
data->vin_max = 0;
ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
ret = ltc2978_clear_peaks(client, page, data->id);
break;
case PMBUS_VIRT_RESET_TEMP_HISTORY:
data->temp_min = 0x7bff;
data->temp_max = 0x7fff;
ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
ret = ltc2978_clear_peaks(client, page, data->id);
break;
default:
ret = -ENODATA;
Expand All @@ -184,6 +279,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,

static const struct i2c_device_id ltc2978_id[] = {
{"ltc2978", ltc2978},
{"ltc3880", ltc3880},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
Expand Down Expand Up @@ -211,6 +307,8 @@ static int ltc2978_probe(struct i2c_client *client,

if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
data->id = ltc2978;
} else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
data->id = ltc3880;
} else {
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
ret = -ENODEV;
Expand All @@ -223,7 +321,6 @@ static int ltc2978_probe(struct i2c_client *client,
ltc2978_id[data->id].name);

info = &data->info;
info->read_word_data = ltc2978_read_word_data;
info->write_word_data = ltc2978_write_word_data;

data->vout_min[0] = 0xffff;
Expand All @@ -233,6 +330,7 @@ static int ltc2978_probe(struct i2c_client *client,

switch (id->driver_data) {
case ltc2978:
info->read_word_data = ltc2978_read_word_data;
info->pages = 8;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
Expand All @@ -243,6 +341,21 @@ static int ltc2978_probe(struct i2c_client *client,
data->vout_min[i] = 0xffff;
}
break;
case ltc3880:
info->read_word_data = ltc3880_read_word_data;
info->pages = 2;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
| PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_POUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
data->vout_min[1] = 0xffff;
break;
default:
ret = -ENODEV;
goto err_mem;
Expand Down Expand Up @@ -289,7 +402,7 @@ static void __exit ltc2978_exit(void)
}

MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for LTC2978");
MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880");
MODULE_LICENSE("GPL");
module_init(ltc2978_init);
module_exit(ltc2978_exit);

0 comments on commit 6b24d82

Please sign in to comment.