Commit 7a001dba authored by Kun Yi's avatar Kun Yi Committed by Guenter Roeck
Browse files

hwmon: (pmbus/max34440) Add support for MAX34451.



MAX34451 is a 16-Channel Voltage/Current Monitor and 12-Channel
Sequencer.

Signed-off-by: default avatarKun Yi <kunyi@google.com>
Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
parent fb41a710
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@ Supported chips:
    Prefixes: 'max34446'
    Addresses scanned: -
    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX34446.pdf
  * Maxim MAX34451
    PMBus 16-Channel V/I Monitor and 12-Channel Sequencer/Marginer
    Prefixes: 'max34451'
    Addresses scanned: -
    Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX34451.pdf
  * Maxim MAX34460
    PMBus 12-Channel Voltage Monitor & Sequencer
    Prefix: 'max34460'
@@ -36,9 +41,10 @@ Description
This driver supports hardware monitoring for Maxim MAX34440 PMBus 6-Channel
Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply Manager
and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data Logger.
It also supports the MAX34460 and MAX34461 PMBus Voltage Monitor & Sequencers.
The MAX34460 supports 12 voltage channels, and the MAX34461 supports 16 voltage
channels.
It also supports the MAX34451, MAX34460, and MAX34461 PMBus Voltage Monitor &
Sequencers. The MAX34451 supports monitoring voltage or current of 12 channels
based on GIN pins. The MAX34460 supports 12 voltage channels, and the MAX34461
supports 16 voltage channels.

The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus for details on PMBus client drivers.
@@ -93,7 +99,7 @@ curr[1-6]_max Maximum current. From IOUT_OC_WARN_LIMIT register.
curr[1-6]_crit		Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
curr[1-6]_max_alarm	Current high alarm. From IOUT_OC_WARNING status.
curr[1-6]_crit_alarm	Current critical high alarm. From IOUT_OC_FAULT status.
curr[1-4]_average	Historical average current (MAX34446 only).
curr[1-4]_average	Historical average current (MAX34446/34451 only).
curr[1-6]_highest	Historical maximum current.
curr[1-6]_reset_history	Write any value to reset history.

@@ -123,5 +129,7 @@ temp[1-8]_reset_history Write any value to reset history.
			temp7 and temp8 attributes only exist for MAX34440.
			MAX34446 only supports temp[1-3].

MAX34451 supports attribute groups in[1-16] (or curr[1-16] based on input pins)
and temp[1-5].
MAX34460 supports attribute groups in[1-12] and temp[1-5].
MAX34461 supports attribute groups in[1-16] and temp[1-5].
+1 −1
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ config SENSORS_MAX34440
	default n
	help
	  If you say yes here you get hardware monitoring support for Maxim
	  MAX34440, MAX34441, MAX34446, MAX34460, and MAX34461.
	  MAX34440, MAX34441, MAX34446, MAX34451, MAX34460, and MAX34461.

	  This driver can also be built as a module. If so, the module will
	  be called max34440.
+90 −3
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@
#include <linux/i2c.h>
#include "pmbus.h"

enum chips { max34440, max34441, max34446, max34460, max34461 };
enum chips { max34440, max34441, max34446, max34451, max34460, max34461 };

#define MAX34440_MFR_VOUT_PEAK		0xd4
#define MAX34440_MFR_IOUT_PEAK		0xd5
@@ -44,6 +44,9 @@ enum chips { max34440, max34441, max34446, max34460, max34461 };
#define MAX34440_STATUS_OT_FAULT	BIT(5)
#define MAX34440_STATUS_OT_WARN		BIT(6)

#define MAX34451_MFR_CHANNEL_CONFIG	0xe4
#define MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK	0x3f

struct max34440_data {
	int id;
	struct pmbus_driver_info info;
@@ -67,7 +70,7 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
					   MAX34440_MFR_VOUT_PEAK);
		break;
	case PMBUS_VIRT_READ_IOUT_AVG:
		if (data->id != max34446)
		if (data->id != max34446 && data->id != max34451)
			return -ENXIO;
		ret = pmbus_read_word_data(client, page,
					   MAX34446_MFR_IOUT_AVG);
@@ -143,7 +146,7 @@ static int max34440_write_word_data(struct i2c_client *client, int page,
	case PMBUS_VIRT_RESET_IOUT_HISTORY:
		ret = pmbus_write_word_data(client, page,
					    MAX34440_MFR_IOUT_PEAK, 0);
		if (!ret && data->id == max34446)
		if (!ret && (data->id == max34446 || data->id == max34451))
			ret = pmbus_write_word_data(client, page,
					MAX34446_MFR_IOUT_AVG, 0);

@@ -202,6 +205,58 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
	return ret;
}

static int max34451_set_supported_funcs(struct i2c_client *client,
					 struct max34440_data *data)
{
	/*
	 * Each of the channel 0-15 can be configured to monitor the following
	 * functions based on MFR_CHANNEL_CONFIG[5:0]
	 * 0x10: Sequencing + voltage monitoring (only valid for PAGES 0–11)
	 * 0x20: Voltage monitoring (no sequencing)
	 * 0x21: Voltage read only
	 * 0x22: Current monitoring
	 * 0x23: Current read only
	 * 0x30: General-purpose input active low
	 * 0x34: General-purpose input active high
	 * 0x00:  Disabled
	 */

	int page, rv;

	for (page = 0; page < 16; page++) {
		rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
		if (rv < 0)
			return rv;

		rv = i2c_smbus_read_word_data(client,
					      MAX34451_MFR_CHANNEL_CONFIG);
		if (rv < 0)
			return rv;

		switch (rv & MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK) {
		case 0x10:
		case 0x20:
			data->info.func[page] = PMBUS_HAVE_VOUT |
				PMBUS_HAVE_STATUS_VOUT;
			break;
		case 0x21:
			data->info.func[page] = PMBUS_HAVE_VOUT;
			break;
		case 0x22:
			data->info.func[page] = PMBUS_HAVE_IOUT |
				PMBUS_HAVE_STATUS_IOUT;
			break;
		case 0x23:
			data->info.func[page] = PMBUS_HAVE_IOUT;
			break;
		default:
			break;
		}
	}

	return 0;
}

static struct pmbus_driver_info max34440_info[] = {
	[max34440] = {
		.pages = 14,
@@ -325,6 +380,30 @@ static struct pmbus_driver_info max34440_info[] = {
		.read_word_data = max34440_read_word_data,
		.write_word_data = max34440_write_word_data,
	},
	[max34451] = {
		.pages = 21,
		.format[PSC_VOLTAGE_OUT] = direct,
		.format[PSC_TEMPERATURE] = direct,
		.format[PSC_CURRENT_OUT] = direct,
		.m[PSC_VOLTAGE_OUT] = 1,
		.b[PSC_VOLTAGE_OUT] = 0,
		.R[PSC_VOLTAGE_OUT] = 3,
		.m[PSC_CURRENT_OUT] = 1,
		.b[PSC_CURRENT_OUT] = 0,
		.R[PSC_CURRENT_OUT] = 2,
		.m[PSC_TEMPERATURE] = 1,
		.b[PSC_TEMPERATURE] = 0,
		.R[PSC_TEMPERATURE] = 2,
		/* func 0-15 is set dynamically before probing */
		.func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
		.func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
		.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
		.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
		.read_byte_data = max34440_read_byte_data,
		.read_word_data = max34440_read_word_data,
		.write_word_data = max34440_write_word_data,
	},
	[max34460] = {
		.pages = 18,
		.format[PSC_VOLTAGE_OUT] = direct,
@@ -398,6 +477,7 @@ static int max34440_probe(struct i2c_client *client,
			  const struct i2c_device_id *id)
{
	struct max34440_data *data;
	int rv;

	data = devm_kzalloc(&client->dev, sizeof(struct max34440_data),
			    GFP_KERNEL);
@@ -406,6 +486,12 @@ static int max34440_probe(struct i2c_client *client,
	data->id = id->driver_data;
	data->info = max34440_info[id->driver_data];

	if (data->id == max34451) {
		rv = max34451_set_supported_funcs(client, data);
		if (rv)
			return rv;
	}

	return pmbus_do_probe(client, id, &data->info);
}

@@ -413,6 +499,7 @@ static const struct i2c_device_id max34440_id[] = {
	{"max34440", max34440},
	{"max34441", max34441},
	{"max34446", max34446},
	{"max34451", max34451},
	{"max34460", max34460},
	{"max34461", max34461},
	{}