162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Hardware monitoring driver for Maxim MAX34440/MAX34441
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2011 Ericsson AB.
662306a36Sopenharmony_ci * Copyright (c) 2012 Guenter Roeck
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bitops.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/i2c.h>
1562306a36Sopenharmony_ci#include "pmbus.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cienum chips { max34440, max34441, max34446, max34451, max34460, max34461 };
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define MAX34440_MFR_VOUT_PEAK		0xd4
2062306a36Sopenharmony_ci#define MAX34440_MFR_IOUT_PEAK		0xd5
2162306a36Sopenharmony_ci#define MAX34440_MFR_TEMPERATURE_PEAK	0xd6
2262306a36Sopenharmony_ci#define MAX34440_MFR_VOUT_MIN		0xd7
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define MAX34446_MFR_POUT_PEAK		0xe0
2562306a36Sopenharmony_ci#define MAX34446_MFR_POUT_AVG		0xe1
2662306a36Sopenharmony_ci#define MAX34446_MFR_IOUT_AVG		0xe2
2762306a36Sopenharmony_ci#define MAX34446_MFR_TEMPERATURE_AVG	0xe3
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define MAX34440_STATUS_OC_WARN		BIT(0)
3062306a36Sopenharmony_ci#define MAX34440_STATUS_OC_FAULT	BIT(1)
3162306a36Sopenharmony_ci#define MAX34440_STATUS_OT_FAULT	BIT(5)
3262306a36Sopenharmony_ci#define MAX34440_STATUS_OT_WARN		BIT(6)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * The whole max344* family have IOUT_OC_WARN_LIMIT and IOUT_OC_FAULT_LIMIT
3662306a36Sopenharmony_ci * swapped from the standard pmbus spec addresses.
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_ci#define MAX34440_IOUT_OC_WARN_LIMIT	0x46
3962306a36Sopenharmony_ci#define MAX34440_IOUT_OC_FAULT_LIMIT	0x4A
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define MAX34451_MFR_CHANNEL_CONFIG	0xe4
4262306a36Sopenharmony_ci#define MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK	0x3f
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct max34440_data {
4562306a36Sopenharmony_ci	int id;
4662306a36Sopenharmony_ci	struct pmbus_driver_info info;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define to_max34440_data(x)  container_of(x, struct max34440_data, info)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const struct i2c_device_id max34440_id[];
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int max34440_read_word_data(struct i2c_client *client, int page,
5462306a36Sopenharmony_ci				   int phase, int reg)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	int ret;
5762306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
5862306a36Sopenharmony_ci	const struct max34440_data *data = to_max34440_data(info);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	switch (reg) {
6162306a36Sopenharmony_ci	case PMBUS_IOUT_OC_FAULT_LIMIT:
6262306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
6362306a36Sopenharmony_ci					   MAX34440_IOUT_OC_FAULT_LIMIT);
6462306a36Sopenharmony_ci		break;
6562306a36Sopenharmony_ci	case PMBUS_IOUT_OC_WARN_LIMIT:
6662306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
6762306a36Sopenharmony_ci					   MAX34440_IOUT_OC_WARN_LIMIT);
6862306a36Sopenharmony_ci		break;
6962306a36Sopenharmony_ci	case PMBUS_VIRT_READ_VOUT_MIN:
7062306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
7162306a36Sopenharmony_ci					   MAX34440_MFR_VOUT_MIN);
7262306a36Sopenharmony_ci		break;
7362306a36Sopenharmony_ci	case PMBUS_VIRT_READ_VOUT_MAX:
7462306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
7562306a36Sopenharmony_ci					   MAX34440_MFR_VOUT_PEAK);
7662306a36Sopenharmony_ci		break;
7762306a36Sopenharmony_ci	case PMBUS_VIRT_READ_IOUT_AVG:
7862306a36Sopenharmony_ci		if (data->id != max34446 && data->id != max34451)
7962306a36Sopenharmony_ci			return -ENXIO;
8062306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
8162306a36Sopenharmony_ci					   MAX34446_MFR_IOUT_AVG);
8262306a36Sopenharmony_ci		break;
8362306a36Sopenharmony_ci	case PMBUS_VIRT_READ_IOUT_MAX:
8462306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
8562306a36Sopenharmony_ci					   MAX34440_MFR_IOUT_PEAK);
8662306a36Sopenharmony_ci		break;
8762306a36Sopenharmony_ci	case PMBUS_VIRT_READ_POUT_AVG:
8862306a36Sopenharmony_ci		if (data->id != max34446)
8962306a36Sopenharmony_ci			return -ENXIO;
9062306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
9162306a36Sopenharmony_ci					   MAX34446_MFR_POUT_AVG);
9262306a36Sopenharmony_ci		break;
9362306a36Sopenharmony_ci	case PMBUS_VIRT_READ_POUT_MAX:
9462306a36Sopenharmony_ci		if (data->id != max34446)
9562306a36Sopenharmony_ci			return -ENXIO;
9662306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
9762306a36Sopenharmony_ci					   MAX34446_MFR_POUT_PEAK);
9862306a36Sopenharmony_ci		break;
9962306a36Sopenharmony_ci	case PMBUS_VIRT_READ_TEMP_AVG:
10062306a36Sopenharmony_ci		if (data->id != max34446 && data->id != max34460 &&
10162306a36Sopenharmony_ci		    data->id != max34461)
10262306a36Sopenharmony_ci			return -ENXIO;
10362306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
10462306a36Sopenharmony_ci					   MAX34446_MFR_TEMPERATURE_AVG);
10562306a36Sopenharmony_ci		break;
10662306a36Sopenharmony_ci	case PMBUS_VIRT_READ_TEMP_MAX:
10762306a36Sopenharmony_ci		ret = pmbus_read_word_data(client, page, phase,
10862306a36Sopenharmony_ci					   MAX34440_MFR_TEMPERATURE_PEAK);
10962306a36Sopenharmony_ci		break;
11062306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_POUT_HISTORY:
11162306a36Sopenharmony_ci		if (data->id != max34446)
11262306a36Sopenharmony_ci			return -ENXIO;
11362306a36Sopenharmony_ci		ret = 0;
11462306a36Sopenharmony_ci		break;
11562306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_VOUT_HISTORY:
11662306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_IOUT_HISTORY:
11762306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_TEMP_HISTORY:
11862306a36Sopenharmony_ci		ret = 0;
11962306a36Sopenharmony_ci		break;
12062306a36Sopenharmony_ci	default:
12162306a36Sopenharmony_ci		ret = -ENODATA;
12262306a36Sopenharmony_ci		break;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci	return ret;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int max34440_write_word_data(struct i2c_client *client, int page,
12862306a36Sopenharmony_ci				    int reg, u16 word)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
13162306a36Sopenharmony_ci	const struct max34440_data *data = to_max34440_data(info);
13262306a36Sopenharmony_ci	int ret;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	switch (reg) {
13562306a36Sopenharmony_ci	case PMBUS_IOUT_OC_FAULT_LIMIT:
13662306a36Sopenharmony_ci		ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_FAULT_LIMIT,
13762306a36Sopenharmony_ci					    word);
13862306a36Sopenharmony_ci		break;
13962306a36Sopenharmony_ci	case PMBUS_IOUT_OC_WARN_LIMIT:
14062306a36Sopenharmony_ci		ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_WARN_LIMIT,
14162306a36Sopenharmony_ci					    word);
14262306a36Sopenharmony_ci		break;
14362306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_POUT_HISTORY:
14462306a36Sopenharmony_ci		ret = pmbus_write_word_data(client, page,
14562306a36Sopenharmony_ci					    MAX34446_MFR_POUT_PEAK, 0);
14662306a36Sopenharmony_ci		if (ret)
14762306a36Sopenharmony_ci			break;
14862306a36Sopenharmony_ci		ret = pmbus_write_word_data(client, page,
14962306a36Sopenharmony_ci					    MAX34446_MFR_POUT_AVG, 0);
15062306a36Sopenharmony_ci		break;
15162306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_VOUT_HISTORY:
15262306a36Sopenharmony_ci		ret = pmbus_write_word_data(client, page,
15362306a36Sopenharmony_ci					    MAX34440_MFR_VOUT_MIN, 0x7fff);
15462306a36Sopenharmony_ci		if (ret)
15562306a36Sopenharmony_ci			break;
15662306a36Sopenharmony_ci		ret = pmbus_write_word_data(client, page,
15762306a36Sopenharmony_ci					    MAX34440_MFR_VOUT_PEAK, 0);
15862306a36Sopenharmony_ci		break;
15962306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_IOUT_HISTORY:
16062306a36Sopenharmony_ci		ret = pmbus_write_word_data(client, page,
16162306a36Sopenharmony_ci					    MAX34440_MFR_IOUT_PEAK, 0);
16262306a36Sopenharmony_ci		if (!ret && (data->id == max34446 || data->id == max34451))
16362306a36Sopenharmony_ci			ret = pmbus_write_word_data(client, page,
16462306a36Sopenharmony_ci					MAX34446_MFR_IOUT_AVG, 0);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_TEMP_HISTORY:
16862306a36Sopenharmony_ci		ret = pmbus_write_word_data(client, page,
16962306a36Sopenharmony_ci					    MAX34440_MFR_TEMPERATURE_PEAK,
17062306a36Sopenharmony_ci					    0x8000);
17162306a36Sopenharmony_ci		if (!ret && data->id == max34446)
17262306a36Sopenharmony_ci			ret = pmbus_write_word_data(client, page,
17362306a36Sopenharmony_ci					MAX34446_MFR_TEMPERATURE_AVG, 0);
17462306a36Sopenharmony_ci		break;
17562306a36Sopenharmony_ci	default:
17662306a36Sopenharmony_ci		ret = -ENODATA;
17762306a36Sopenharmony_ci		break;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci	return ret;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	int ret = 0;
18562306a36Sopenharmony_ci	int mfg_status;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (page >= 0) {
18862306a36Sopenharmony_ci		ret = pmbus_set_page(client, page, 0xff);
18962306a36Sopenharmony_ci		if (ret < 0)
19062306a36Sopenharmony_ci			return ret;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	switch (reg) {
19462306a36Sopenharmony_ci	case PMBUS_STATUS_IOUT:
19562306a36Sopenharmony_ci		mfg_status = pmbus_read_word_data(client, 0, 0xff,
19662306a36Sopenharmony_ci						  PMBUS_STATUS_MFR_SPECIFIC);
19762306a36Sopenharmony_ci		if (mfg_status < 0)
19862306a36Sopenharmony_ci			return mfg_status;
19962306a36Sopenharmony_ci		if (mfg_status & MAX34440_STATUS_OC_WARN)
20062306a36Sopenharmony_ci			ret |= PB_IOUT_OC_WARNING;
20162306a36Sopenharmony_ci		if (mfg_status & MAX34440_STATUS_OC_FAULT)
20262306a36Sopenharmony_ci			ret |= PB_IOUT_OC_FAULT;
20362306a36Sopenharmony_ci		break;
20462306a36Sopenharmony_ci	case PMBUS_STATUS_TEMPERATURE:
20562306a36Sopenharmony_ci		mfg_status = pmbus_read_word_data(client, 0, 0xff,
20662306a36Sopenharmony_ci						  PMBUS_STATUS_MFR_SPECIFIC);
20762306a36Sopenharmony_ci		if (mfg_status < 0)
20862306a36Sopenharmony_ci			return mfg_status;
20962306a36Sopenharmony_ci		if (mfg_status & MAX34440_STATUS_OT_WARN)
21062306a36Sopenharmony_ci			ret |= PB_TEMP_OT_WARNING;
21162306a36Sopenharmony_ci		if (mfg_status & MAX34440_STATUS_OT_FAULT)
21262306a36Sopenharmony_ci			ret |= PB_TEMP_OT_FAULT;
21362306a36Sopenharmony_ci		break;
21462306a36Sopenharmony_ci	default:
21562306a36Sopenharmony_ci		ret = -ENODATA;
21662306a36Sopenharmony_ci		break;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci	return ret;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int max34451_set_supported_funcs(struct i2c_client *client,
22262306a36Sopenharmony_ci					 struct max34440_data *data)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	/*
22562306a36Sopenharmony_ci	 * Each of the channel 0-15 can be configured to monitor the following
22662306a36Sopenharmony_ci	 * functions based on MFR_CHANNEL_CONFIG[5:0]
22762306a36Sopenharmony_ci	 * 0x10: Sequencing + voltage monitoring (only valid for PAGES 0–11)
22862306a36Sopenharmony_ci	 * 0x20: Voltage monitoring (no sequencing)
22962306a36Sopenharmony_ci	 * 0x21: Voltage read only
23062306a36Sopenharmony_ci	 * 0x22: Current monitoring
23162306a36Sopenharmony_ci	 * 0x23: Current read only
23262306a36Sopenharmony_ci	 * 0x30: General-purpose input active low
23362306a36Sopenharmony_ci	 * 0x34: General-purpose input active high
23462306a36Sopenharmony_ci	 * 0x00:  Disabled
23562306a36Sopenharmony_ci	 */
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	int page, rv;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	for (page = 0; page < 16; page++) {
24062306a36Sopenharmony_ci		rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
24162306a36Sopenharmony_ci		if (rv < 0)
24262306a36Sopenharmony_ci			return rv;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci		rv = i2c_smbus_read_word_data(client,
24562306a36Sopenharmony_ci					      MAX34451_MFR_CHANNEL_CONFIG);
24662306a36Sopenharmony_ci		if (rv < 0)
24762306a36Sopenharmony_ci			return rv;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		switch (rv & MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK) {
25062306a36Sopenharmony_ci		case 0x10:
25162306a36Sopenharmony_ci		case 0x20:
25262306a36Sopenharmony_ci			data->info.func[page] = PMBUS_HAVE_VOUT |
25362306a36Sopenharmony_ci				PMBUS_HAVE_STATUS_VOUT;
25462306a36Sopenharmony_ci			break;
25562306a36Sopenharmony_ci		case 0x21:
25662306a36Sopenharmony_ci			data->info.func[page] = PMBUS_HAVE_VOUT;
25762306a36Sopenharmony_ci			break;
25862306a36Sopenharmony_ci		case 0x22:
25962306a36Sopenharmony_ci			data->info.func[page] = PMBUS_HAVE_IOUT |
26062306a36Sopenharmony_ci				PMBUS_HAVE_STATUS_IOUT;
26162306a36Sopenharmony_ci			break;
26262306a36Sopenharmony_ci		case 0x23:
26362306a36Sopenharmony_ci			data->info.func[page] = PMBUS_HAVE_IOUT;
26462306a36Sopenharmony_ci			break;
26562306a36Sopenharmony_ci		default:
26662306a36Sopenharmony_ci			break;
26762306a36Sopenharmony_ci		}
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	return 0;
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic struct pmbus_driver_info max34440_info[] = {
27462306a36Sopenharmony_ci	[max34440] = {
27562306a36Sopenharmony_ci		.pages = 14,
27662306a36Sopenharmony_ci		.format[PSC_VOLTAGE_IN] = direct,
27762306a36Sopenharmony_ci		.format[PSC_VOLTAGE_OUT] = direct,
27862306a36Sopenharmony_ci		.format[PSC_TEMPERATURE] = direct,
27962306a36Sopenharmony_ci		.format[PSC_CURRENT_OUT] = direct,
28062306a36Sopenharmony_ci		.m[PSC_VOLTAGE_IN] = 1,
28162306a36Sopenharmony_ci		.b[PSC_VOLTAGE_IN] = 0,
28262306a36Sopenharmony_ci		.R[PSC_VOLTAGE_IN] = 3,	    /* R = 0 in datasheet reflects mV */
28362306a36Sopenharmony_ci		.m[PSC_VOLTAGE_OUT] = 1,
28462306a36Sopenharmony_ci		.b[PSC_VOLTAGE_OUT] = 0,
28562306a36Sopenharmony_ci		.R[PSC_VOLTAGE_OUT] = 3,    /* R = 0 in datasheet reflects mV */
28662306a36Sopenharmony_ci		.m[PSC_CURRENT_OUT] = 1,
28762306a36Sopenharmony_ci		.b[PSC_CURRENT_OUT] = 0,
28862306a36Sopenharmony_ci		.R[PSC_CURRENT_OUT] = 3,    /* R = 0 in datasheet reflects mA */
28962306a36Sopenharmony_ci		.m[PSC_TEMPERATURE] = 1,
29062306a36Sopenharmony_ci		.b[PSC_TEMPERATURE] = 0,
29162306a36Sopenharmony_ci		.R[PSC_TEMPERATURE] = 2,
29262306a36Sopenharmony_ci		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
29362306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
29462306a36Sopenharmony_ci		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
29562306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
29662306a36Sopenharmony_ci		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
29762306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
29862306a36Sopenharmony_ci		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
29962306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
30062306a36Sopenharmony_ci		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
30162306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
30262306a36Sopenharmony_ci		.func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
30362306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
30462306a36Sopenharmony_ci		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
30562306a36Sopenharmony_ci		.func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
30662306a36Sopenharmony_ci		.func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
30762306a36Sopenharmony_ci		.func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
30862306a36Sopenharmony_ci		.func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
30962306a36Sopenharmony_ci		.func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
31062306a36Sopenharmony_ci		.func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
31162306a36Sopenharmony_ci		.func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
31262306a36Sopenharmony_ci		.read_byte_data = max34440_read_byte_data,
31362306a36Sopenharmony_ci		.read_word_data = max34440_read_word_data,
31462306a36Sopenharmony_ci		.write_word_data = max34440_write_word_data,
31562306a36Sopenharmony_ci	},
31662306a36Sopenharmony_ci	[max34441] = {
31762306a36Sopenharmony_ci		.pages = 12,
31862306a36Sopenharmony_ci		.format[PSC_VOLTAGE_IN] = direct,
31962306a36Sopenharmony_ci		.format[PSC_VOLTAGE_OUT] = direct,
32062306a36Sopenharmony_ci		.format[PSC_TEMPERATURE] = direct,
32162306a36Sopenharmony_ci		.format[PSC_CURRENT_OUT] = direct,
32262306a36Sopenharmony_ci		.format[PSC_FAN] = direct,
32362306a36Sopenharmony_ci		.m[PSC_VOLTAGE_IN] = 1,
32462306a36Sopenharmony_ci		.b[PSC_VOLTAGE_IN] = 0,
32562306a36Sopenharmony_ci		.R[PSC_VOLTAGE_IN] = 3,
32662306a36Sopenharmony_ci		.m[PSC_VOLTAGE_OUT] = 1,
32762306a36Sopenharmony_ci		.b[PSC_VOLTAGE_OUT] = 0,
32862306a36Sopenharmony_ci		.R[PSC_VOLTAGE_OUT] = 3,
32962306a36Sopenharmony_ci		.m[PSC_CURRENT_OUT] = 1,
33062306a36Sopenharmony_ci		.b[PSC_CURRENT_OUT] = 0,
33162306a36Sopenharmony_ci		.R[PSC_CURRENT_OUT] = 3,
33262306a36Sopenharmony_ci		.m[PSC_TEMPERATURE] = 1,
33362306a36Sopenharmony_ci		.b[PSC_TEMPERATURE] = 0,
33462306a36Sopenharmony_ci		.R[PSC_TEMPERATURE] = 2,
33562306a36Sopenharmony_ci		.m[PSC_FAN] = 1,
33662306a36Sopenharmony_ci		.b[PSC_FAN] = 0,
33762306a36Sopenharmony_ci		.R[PSC_FAN] = 0,
33862306a36Sopenharmony_ci		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
33962306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
34062306a36Sopenharmony_ci		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
34162306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
34262306a36Sopenharmony_ci		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
34362306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
34462306a36Sopenharmony_ci		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
34562306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
34662306a36Sopenharmony_ci		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
34762306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
34862306a36Sopenharmony_ci		.func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
34962306a36Sopenharmony_ci		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
35062306a36Sopenharmony_ci		.func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
35162306a36Sopenharmony_ci		.func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
35262306a36Sopenharmony_ci		.func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
35362306a36Sopenharmony_ci		.func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
35462306a36Sopenharmony_ci		.func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
35562306a36Sopenharmony_ci		.read_byte_data = max34440_read_byte_data,
35662306a36Sopenharmony_ci		.read_word_data = max34440_read_word_data,
35762306a36Sopenharmony_ci		.write_word_data = max34440_write_word_data,
35862306a36Sopenharmony_ci	},
35962306a36Sopenharmony_ci	[max34446] = {
36062306a36Sopenharmony_ci		.pages = 7,
36162306a36Sopenharmony_ci		.format[PSC_VOLTAGE_IN] = direct,
36262306a36Sopenharmony_ci		.format[PSC_VOLTAGE_OUT] = direct,
36362306a36Sopenharmony_ci		.format[PSC_TEMPERATURE] = direct,
36462306a36Sopenharmony_ci		.format[PSC_CURRENT_OUT] = direct,
36562306a36Sopenharmony_ci		.format[PSC_POWER] = direct,
36662306a36Sopenharmony_ci		.m[PSC_VOLTAGE_IN] = 1,
36762306a36Sopenharmony_ci		.b[PSC_VOLTAGE_IN] = 0,
36862306a36Sopenharmony_ci		.R[PSC_VOLTAGE_IN] = 3,
36962306a36Sopenharmony_ci		.m[PSC_VOLTAGE_OUT] = 1,
37062306a36Sopenharmony_ci		.b[PSC_VOLTAGE_OUT] = 0,
37162306a36Sopenharmony_ci		.R[PSC_VOLTAGE_OUT] = 3,
37262306a36Sopenharmony_ci		.m[PSC_CURRENT_OUT] = 1,
37362306a36Sopenharmony_ci		.b[PSC_CURRENT_OUT] = 0,
37462306a36Sopenharmony_ci		.R[PSC_CURRENT_OUT] = 3,
37562306a36Sopenharmony_ci		.m[PSC_POWER] = 1,
37662306a36Sopenharmony_ci		.b[PSC_POWER] = 0,
37762306a36Sopenharmony_ci		.R[PSC_POWER] = 3,
37862306a36Sopenharmony_ci		.m[PSC_TEMPERATURE] = 1,
37962306a36Sopenharmony_ci		.b[PSC_TEMPERATURE] = 0,
38062306a36Sopenharmony_ci		.R[PSC_TEMPERATURE] = 2,
38162306a36Sopenharmony_ci		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
38262306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
38362306a36Sopenharmony_ci		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
38462306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
38562306a36Sopenharmony_ci		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
38662306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
38762306a36Sopenharmony_ci		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
38862306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
38962306a36Sopenharmony_ci		.func[4] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
39062306a36Sopenharmony_ci		.func[5] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
39162306a36Sopenharmony_ci		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
39262306a36Sopenharmony_ci		.read_byte_data = max34440_read_byte_data,
39362306a36Sopenharmony_ci		.read_word_data = max34440_read_word_data,
39462306a36Sopenharmony_ci		.write_word_data = max34440_write_word_data,
39562306a36Sopenharmony_ci	},
39662306a36Sopenharmony_ci	[max34451] = {
39762306a36Sopenharmony_ci		.pages = 21,
39862306a36Sopenharmony_ci		.format[PSC_VOLTAGE_OUT] = direct,
39962306a36Sopenharmony_ci		.format[PSC_TEMPERATURE] = direct,
40062306a36Sopenharmony_ci		.format[PSC_CURRENT_OUT] = direct,
40162306a36Sopenharmony_ci		.m[PSC_VOLTAGE_OUT] = 1,
40262306a36Sopenharmony_ci		.b[PSC_VOLTAGE_OUT] = 0,
40362306a36Sopenharmony_ci		.R[PSC_VOLTAGE_OUT] = 3,
40462306a36Sopenharmony_ci		.m[PSC_CURRENT_OUT] = 1,
40562306a36Sopenharmony_ci		.b[PSC_CURRENT_OUT] = 0,
40662306a36Sopenharmony_ci		.R[PSC_CURRENT_OUT] = 2,
40762306a36Sopenharmony_ci		.m[PSC_TEMPERATURE] = 1,
40862306a36Sopenharmony_ci		.b[PSC_TEMPERATURE] = 0,
40962306a36Sopenharmony_ci		.R[PSC_TEMPERATURE] = 2,
41062306a36Sopenharmony_ci		/* func 0-15 is set dynamically before probing */
41162306a36Sopenharmony_ci		.func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
41262306a36Sopenharmony_ci		.func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
41362306a36Sopenharmony_ci		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
41462306a36Sopenharmony_ci		.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
41562306a36Sopenharmony_ci		.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
41662306a36Sopenharmony_ci		.read_word_data = max34440_read_word_data,
41762306a36Sopenharmony_ci		.write_word_data = max34440_write_word_data,
41862306a36Sopenharmony_ci	},
41962306a36Sopenharmony_ci	[max34460] = {
42062306a36Sopenharmony_ci		.pages = 18,
42162306a36Sopenharmony_ci		.format[PSC_VOLTAGE_OUT] = direct,
42262306a36Sopenharmony_ci		.format[PSC_TEMPERATURE] = direct,
42362306a36Sopenharmony_ci		.m[PSC_VOLTAGE_OUT] = 1,
42462306a36Sopenharmony_ci		.b[PSC_VOLTAGE_OUT] = 0,
42562306a36Sopenharmony_ci		.R[PSC_VOLTAGE_OUT] = 3,
42662306a36Sopenharmony_ci		.m[PSC_TEMPERATURE] = 1,
42762306a36Sopenharmony_ci		.b[PSC_TEMPERATURE] = 0,
42862306a36Sopenharmony_ci		.R[PSC_TEMPERATURE] = 2,
42962306a36Sopenharmony_ci		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43062306a36Sopenharmony_ci		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43162306a36Sopenharmony_ci		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43262306a36Sopenharmony_ci		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43362306a36Sopenharmony_ci		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43462306a36Sopenharmony_ci		.func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43562306a36Sopenharmony_ci		.func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43662306a36Sopenharmony_ci		.func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43762306a36Sopenharmony_ci		.func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43862306a36Sopenharmony_ci		.func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
43962306a36Sopenharmony_ci		.func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
44062306a36Sopenharmony_ci		.func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
44162306a36Sopenharmony_ci		.func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
44262306a36Sopenharmony_ci		.func[14] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
44362306a36Sopenharmony_ci		.func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
44462306a36Sopenharmony_ci		.func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
44562306a36Sopenharmony_ci		.func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
44662306a36Sopenharmony_ci		.read_word_data = max34440_read_word_data,
44762306a36Sopenharmony_ci		.write_word_data = max34440_write_word_data,
44862306a36Sopenharmony_ci	},
44962306a36Sopenharmony_ci	[max34461] = {
45062306a36Sopenharmony_ci		.pages = 23,
45162306a36Sopenharmony_ci		.format[PSC_VOLTAGE_OUT] = direct,
45262306a36Sopenharmony_ci		.format[PSC_TEMPERATURE] = direct,
45362306a36Sopenharmony_ci		.m[PSC_VOLTAGE_OUT] = 1,
45462306a36Sopenharmony_ci		.b[PSC_VOLTAGE_OUT] = 0,
45562306a36Sopenharmony_ci		.R[PSC_VOLTAGE_OUT] = 3,
45662306a36Sopenharmony_ci		.m[PSC_TEMPERATURE] = 1,
45762306a36Sopenharmony_ci		.b[PSC_TEMPERATURE] = 0,
45862306a36Sopenharmony_ci		.R[PSC_TEMPERATURE] = 2,
45962306a36Sopenharmony_ci		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46062306a36Sopenharmony_ci		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46162306a36Sopenharmony_ci		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46262306a36Sopenharmony_ci		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46362306a36Sopenharmony_ci		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46462306a36Sopenharmony_ci		.func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46562306a36Sopenharmony_ci		.func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46662306a36Sopenharmony_ci		.func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46762306a36Sopenharmony_ci		.func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46862306a36Sopenharmony_ci		.func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
46962306a36Sopenharmony_ci		.func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
47062306a36Sopenharmony_ci		.func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
47162306a36Sopenharmony_ci		.func[12] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
47262306a36Sopenharmony_ci		.func[13] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
47362306a36Sopenharmony_ci		.func[14] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
47462306a36Sopenharmony_ci		.func[15] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
47562306a36Sopenharmony_ci		/* page 16 is reserved */
47662306a36Sopenharmony_ci		.func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
47762306a36Sopenharmony_ci		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
47862306a36Sopenharmony_ci		.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
47962306a36Sopenharmony_ci		.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
48062306a36Sopenharmony_ci		.func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
48162306a36Sopenharmony_ci		.read_word_data = max34440_read_word_data,
48262306a36Sopenharmony_ci		.write_word_data = max34440_write_word_data,
48362306a36Sopenharmony_ci	},
48462306a36Sopenharmony_ci};
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic int max34440_probe(struct i2c_client *client)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct max34440_data *data;
48962306a36Sopenharmony_ci	int rv;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	data = devm_kzalloc(&client->dev, sizeof(struct max34440_data),
49262306a36Sopenharmony_ci			    GFP_KERNEL);
49362306a36Sopenharmony_ci	if (!data)
49462306a36Sopenharmony_ci		return -ENOMEM;
49562306a36Sopenharmony_ci	data->id = i2c_match_id(max34440_id, client)->driver_data;
49662306a36Sopenharmony_ci	data->info = max34440_info[data->id];
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (data->id == max34451) {
49962306a36Sopenharmony_ci		rv = max34451_set_supported_funcs(client, data);
50062306a36Sopenharmony_ci		if (rv)
50162306a36Sopenharmony_ci			return rv;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	return pmbus_do_probe(client, &data->info);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic const struct i2c_device_id max34440_id[] = {
50862306a36Sopenharmony_ci	{"max34440", max34440},
50962306a36Sopenharmony_ci	{"max34441", max34441},
51062306a36Sopenharmony_ci	{"max34446", max34446},
51162306a36Sopenharmony_ci	{"max34451", max34451},
51262306a36Sopenharmony_ci	{"max34460", max34460},
51362306a36Sopenharmony_ci	{"max34461", max34461},
51462306a36Sopenharmony_ci	{}
51562306a36Sopenharmony_ci};
51662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max34440_id);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci/* This is the driver that will be inserted */
51962306a36Sopenharmony_cistatic struct i2c_driver max34440_driver = {
52062306a36Sopenharmony_ci	.driver = {
52162306a36Sopenharmony_ci		   .name = "max34440",
52262306a36Sopenharmony_ci		   },
52362306a36Sopenharmony_ci	.probe = max34440_probe,
52462306a36Sopenharmony_ci	.id_table = max34440_id,
52562306a36Sopenharmony_ci};
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cimodule_i2c_driver(max34440_driver);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ciMODULE_AUTHOR("Guenter Roeck");
53062306a36Sopenharmony_ciMODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
53162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
53262306a36Sopenharmony_ciMODULE_IMPORT_NS(PMBUS);
533