1c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck/*
2c24c407e963e73d3ad18b9bc0af32cf23f37a7b0Guenter Roeck * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880,
3f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeck * LTC3883, and LTM4676
4c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck *
5c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * Copyright (c) 2011 Ericsson AB.
6f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeck * Copyright (c) 2013, 2014 Guenter Roeck
7c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck *
8c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * This program is free software; you can redistribute it and/or modify
9c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * it under the terms of the GNU General Public License as published by
10c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * the Free Software Foundation; either version 2 of the License, or
11c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * (at your option) any later version.
12c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck *
13c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * This program is distributed in the hope that it will be useful,
14c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * GNU General Public License for more details.
17c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck */
18c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
19c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/kernel.h>
20c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/module.h>
21c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/init.h>
22c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/err.h>
23c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/slab.h>
24c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/i2c.h>
25c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include "pmbus.h"
26c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
27f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeckenum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 };
28c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
29fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck/* Common for all chips */
30c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_VOUT_PEAK		0xdd
31c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_VIN_PEAK		0xde
32c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_TEMPERATURE_PEAK	0xdf
33c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_SPECIAL_ID		0xe7
34c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
35c24c407e963e73d3ad18b9bc0af32cf23f37a7b0Guenter Roeck/* LTC2974, LCT2977, and LTC2978 */
36c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_VOUT_MIN		0xfb
37c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_VIN_MIN		0xfc
38c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_TEMPERATURE_MIN	0xfd
39c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
40fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck/* LTC2974 only */
41fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck#define LTC2974_MFR_IOUT_PEAK		0xd7
42fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck#define LTC2974_MFR_IOUT_MIN		0xd8
43fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck
44f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeck/* LTC3880, LTC3883, and LTM4676 */
45ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_MFR_IOUT_PEAK		0xd7
46ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_MFR_CLEAR_PEAKS		0xe3
47ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_MFR_TEMPERATURE2_PEAK	0xf4
48ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck
49fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck/* LTC3883 only */
50fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck#define LTC3883_MFR_IIN_PEAK		0xe1
51fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck
52a2e151074366487dcde943fdc08d88acfe476f9dGuenter Roeck#define LTC2974_ID_REV1			0x0212
53a2e151074366487dcde943fdc08d88acfe476f9dGuenter Roeck#define LTC2974_ID_REV2			0x0213
54c24c407e963e73d3ad18b9bc0af32cf23f37a7b0Guenter Roeck#define LTC2977_ID			0x0130
55c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_ID_REV1			0x0121
56c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_ID_REV2			0x0122
573f08d7f49f8365d5c9050522ee733951a503e955Guenter Roeck#define LTC2978A_ID			0x0124
58ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_ID			0x4000
59ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_ID_MASK			0xff00
60fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck#define LTC3883_ID			0x4300
61fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck#define LTC3883_ID_MASK			0xff00
62f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeck#define LTM4676_ID			0x4480	/* datasheet claims 0x440X */
63f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeck#define LTM4676_ID_MASK			0xfff0
64c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
65fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck#define LTC2974_NUM_PAGES		4
663d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck#define LTC2978_NUM_PAGES		8
673d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck#define LTC3880_NUM_PAGES		2
68fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck#define LTC3883_NUM_PAGES		1
693d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck
70c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck/*
71c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
72c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * happens pretty much each time chip data is updated. Raw peak data therefore
73c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * does not provide much value. To be able to provide useful peak data, keep an
74c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * internal cache of measured peak data, which is only cleared if an explicit
75c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * "clear peak" command is executed for the sensor in question.
76c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck */
773d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck
78c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstruct ltc2978_data {
79c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	enum chips id;
803d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck	u16 vin_min, vin_max;
81fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES];
823d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck	u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES];
83fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES];
84fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	u16 iin_max;
853d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck	u16 temp2_max;
86c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	struct pmbus_driver_info info;
87c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck};
88c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
89c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define to_ltc2978_data(x)  container_of(x, struct ltc2978_data, info)
90c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
91c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic inline int lin11_to_val(int data)
92c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck{
93c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	s16 e = ((s16)data) >> 11;
94c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	s32 m = (((s16)(data << 5)) >> 5);
95c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
96c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	/*
97c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	 * mantissa is 10 bit + sign, exponent adds up to 15 bit.
98c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	 * Add 6 bit to exponent for maximum accuracy (10 + 15 + 6 = 31).
99c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	 */
100c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	e += 6;
101c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	return (e < 0 ? m >> -e : m << e);
102c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck}
103c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
104ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeckstatic int ltc2978_read_word_data_common(struct i2c_client *client, int page,
105ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck					 int reg)
106c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck{
107c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
108c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	struct ltc2978_data *data = to_ltc2978_data(info);
109c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	int ret;
110c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
111c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	switch (reg) {
112c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case PMBUS_VIRT_READ_VIN_MAX:
113c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_PEAK);
114c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		if (ret >= 0) {
115c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			if (lin11_to_val(ret) > lin11_to_val(data->vin_max))
116c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck				data->vin_max = ret;
117c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			ret = data->vin_max;
118c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		}
119c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
120c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case PMBUS_VIRT_READ_VOUT_MAX:
121c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK);
122c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		if (ret >= 0) {
123c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			/*
124c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 * VOUT is 16 bit unsigned with fixed exponent,
125c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 * so we can compare it directly
126c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 */
127c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			if (ret > data->vout_max[page])
128c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck				data->vout_max[page] = ret;
129c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			ret = data->vout_max[page];
130c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		}
131c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
132c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case PMBUS_VIRT_READ_TEMP_MAX:
133c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		ret = pmbus_read_word_data(client, page,
134c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck					   LTC2978_MFR_TEMPERATURE_PEAK);
135c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		if (ret >= 0) {
1368c958c703ef8804093437959221951eaf0e1e664Guenter Roeck			if (lin11_to_val(ret)
1378c958c703ef8804093437959221951eaf0e1e664Guenter Roeck			    > lin11_to_val(data->temp_max[page]))
1388c958c703ef8804093437959221951eaf0e1e664Guenter Roeck				data->temp_max[page] = ret;
1398c958c703ef8804093437959221951eaf0e1e664Guenter Roeck			ret = data->temp_max[page];
140c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		}
141c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
142ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_RESET_VOUT_HISTORY:
143ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_RESET_VIN_HISTORY:
144ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_RESET_TEMP_HISTORY:
145ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = 0;
146ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
147ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	default:
148ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = -ENODATA;
149ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
150ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	}
151ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	return ret;
152ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck}
153ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck
154ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeckstatic int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
155ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck{
156ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
157ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	struct ltc2978_data *data = to_ltc2978_data(info);
158ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	int ret;
159ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck
160ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	switch (reg) {
161c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case PMBUS_VIRT_READ_VIN_MIN:
162c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN);
163c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		if (ret >= 0) {
164c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			if (lin11_to_val(ret) < lin11_to_val(data->vin_min))
165c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck				data->vin_min = ret;
166c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			ret = data->vin_min;
167c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		}
168c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
169c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case PMBUS_VIRT_READ_VOUT_MIN:
170c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_MIN);
171c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		if (ret >= 0) {
172c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			/*
173c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 * VOUT_MIN is known to not be supported on some lots
174c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 * of LTC2978 revision 1, and will return the maximum
175c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 * possible voltage if read. If VOUT_MAX is valid and
176c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 * lower than the reading of VOUT_MIN, use it instead.
177c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 */
178c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			if (data->vout_max[page] && ret > data->vout_max[page])
179c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck				ret = data->vout_max[page];
180c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			if (ret < data->vout_min[page])
181c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck				data->vout_min[page] = ret;
182c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			ret = data->vout_min[page];
183c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		}
184c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
185c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case PMBUS_VIRT_READ_TEMP_MIN:
186c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		ret = pmbus_read_word_data(client, page,
187c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck					   LTC2978_MFR_TEMPERATURE_MIN);
188c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		if (ret >= 0) {
189c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			if (lin11_to_val(ret)
190fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			    < lin11_to_val(data->temp_min[page]))
191fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck				data->temp_min[page] = ret;
192fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			ret = data->temp_min[page];
193c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		}
194c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
195ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_READ_IOUT_MAX:
196ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_RESET_IOUT_HISTORY:
197ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_READ_TEMP2_MAX:
198ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
199ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = -ENXIO;
200ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
201ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	default:
202ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = ltc2978_read_word_data_common(client, page, reg);
203ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
204ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	}
205ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	return ret;
206ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck}
207ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck
208fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeckstatic int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
209fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck{
210fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
211fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	struct ltc2978_data *data = to_ltc2978_data(info);
212fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	int ret;
213fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck
214fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	switch (reg) {
215fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	case PMBUS_VIRT_READ_IOUT_MAX:
216fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_PEAK);
217fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		if (ret >= 0) {
218fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			if (lin11_to_val(ret)
219fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			    > lin11_to_val(data->iout_max[page]))
220fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck				data->iout_max[page] = ret;
221fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			ret = data->iout_max[page];
222fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		}
223fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
224fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	case PMBUS_VIRT_READ_IOUT_MIN:
225fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_MIN);
226fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		if (ret >= 0) {
227fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			if (lin11_to_val(ret)
228fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			    < lin11_to_val(data->iout_min[page]))
229fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck				data->iout_min[page] = ret;
230fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			ret = data->iout_min[page];
231fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		}
232fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
233fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	case PMBUS_VIRT_RESET_IOUT_HISTORY:
234fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		ret = 0;
235fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
236fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	default:
237fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		ret = ltc2978_read_word_data(client, page, reg);
238fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
239fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	}
240fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	return ret;
241fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck}
242fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck
243ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeckstatic int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
244ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck{
245ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
246ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	struct ltc2978_data *data = to_ltc2978_data(info);
247ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	int ret;
248ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck
249ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	switch (reg) {
250ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_READ_IOUT_MAX:
251ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = pmbus_read_word_data(client, page, LTC3880_MFR_IOUT_PEAK);
252ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		if (ret >= 0) {
253ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck			if (lin11_to_val(ret)
254ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck			    > lin11_to_val(data->iout_max[page]))
255ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck				data->iout_max[page] = ret;
256ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck			ret = data->iout_max[page];
257ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		}
258ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
259ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_READ_TEMP2_MAX:
260ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = pmbus_read_word_data(client, page,
261ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck					   LTC3880_MFR_TEMPERATURE2_PEAK);
262ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		if (ret >= 0) {
263dbd712c2272764a536e29ad6841dba74989a39d9Guenter Roeck			if (lin11_to_val(ret) > lin11_to_val(data->temp2_max))
264dbd712c2272764a536e29ad6841dba74989a39d9Guenter Roeck				data->temp2_max = ret;
265dbd712c2272764a536e29ad6841dba74989a39d9Guenter Roeck			ret = data->temp2_max;
266ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		}
267ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
268ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_READ_VIN_MIN:
269ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_READ_VOUT_MIN:
270ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_READ_TEMP_MIN:
271ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = -ENXIO;
272ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
273ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_RESET_IOUT_HISTORY:
274ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
275c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		ret = 0;
276c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
277c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	default:
278ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = ltc2978_read_word_data_common(client, page, reg);
279c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
280c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	}
281c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	return ret;
282c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck}
283c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
284fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeckstatic int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
285fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck{
286fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
287fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	struct ltc2978_data *data = to_ltc2978_data(info);
288fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	int ret;
289fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck
290fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	switch (reg) {
291fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	case PMBUS_VIRT_READ_IIN_MAX:
292fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		ret = pmbus_read_word_data(client, page, LTC3883_MFR_IIN_PEAK);
293fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		if (ret >= 0) {
294fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			if (lin11_to_val(ret)
295fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			    > lin11_to_val(data->iin_max))
296fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck				data->iin_max = ret;
297fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			ret = data->iin_max;
298fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		}
299fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
300fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	case PMBUS_VIRT_RESET_IIN_HISTORY:
301fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		ret = 0;
302fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
303fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	default:
304fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		ret = ltc3880_read_word_data(client, page, reg);
305fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
306fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	}
307fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	return ret;
308fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck}
309fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck
310ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeckstatic int ltc2978_clear_peaks(struct i2c_client *client, int page,
311ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck			       enum chips id)
312ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck{
313ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	int ret;
314ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck
315fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	if (id == ltc3880 || id == ltc3883)
316ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
317fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	else
318fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
319ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck
320ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	return ret;
321ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck}
322ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck
323c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic int ltc2978_write_word_data(struct i2c_client *client, int page,
324c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck				    int reg, u16 word)
325c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck{
326c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
327c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	struct ltc2978_data *data = to_ltc2978_data(info);
328c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	int ret;
329c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
330c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	switch (reg) {
331fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	case PMBUS_VIRT_RESET_IIN_HISTORY:
332fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		data->iin_max = 0x7c00;
333fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		ret = ltc2978_clear_peaks(client, page, data->id);
334fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
335ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_RESET_IOUT_HISTORY:
336dbd712c2272764a536e29ad6841dba74989a39d9Guenter Roeck		data->iout_max[page] = 0x7c00;
337fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		data->iout_min[page] = 0xfbff;
338ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = ltc2978_clear_peaks(client, page, data->id);
339ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
340ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
341dbd712c2272764a536e29ad6841dba74989a39d9Guenter Roeck		data->temp2_max = 0x7c00;
342ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = ltc2978_clear_peaks(client, page, data->id);
343ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
344c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case PMBUS_VIRT_RESET_VOUT_HISTORY:
345c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		data->vout_min[page] = 0xffff;
346c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		data->vout_max[page] = 0;
347ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = ltc2978_clear_peaks(client, page, data->id);
348c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
349c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case PMBUS_VIRT_RESET_VIN_HISTORY:
350c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		data->vin_min = 0x7bff;
351dbd712c2272764a536e29ad6841dba74989a39d9Guenter Roeck		data->vin_max = 0x7c00;
352ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = ltc2978_clear_peaks(client, page, data->id);
353c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
354c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case PMBUS_VIRT_RESET_TEMP_HISTORY:
355fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		data->temp_min[page] = 0x7bff;
3568c958c703ef8804093437959221951eaf0e1e664Guenter Roeck		data->temp_max[page] = 0x7c00;
357ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		ret = ltc2978_clear_peaks(client, page, data->id);
358c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
359c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	default:
360c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		ret = -ENODATA;
361c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
362c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	}
363c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	return ret;
364c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck}
365c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
366c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic const struct i2c_device_id ltc2978_id[] = {
367fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	{"ltc2974", ltc2974},
368c24c407e963e73d3ad18b9bc0af32cf23f37a7b0Guenter Roeck	{"ltc2977", ltc2977},
369c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	{"ltc2978", ltc2978},
370ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	{"ltc3880", ltc3880},
371fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	{"ltc3883", ltc3883},
372f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeck	{"ltm4676", ltm4676},
373c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	{}
374c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck};
375c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter RoeckMODULE_DEVICE_TABLE(i2c, ltc2978_id);
376c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
377c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic int ltc2978_probe(struct i2c_client *client,
378c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 const struct i2c_device_id *id)
379c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck{
3808b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck	int chip_id, i;
381c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	struct ltc2978_data *data;
382c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	struct pmbus_driver_info *info;
383c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
384c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	if (!i2c_check_functionality(client->adapter,
385c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck				     I2C_FUNC_SMBUS_READ_WORD_DATA))
386c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		return -ENODEV;
387c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
3888b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck	data = devm_kzalloc(&client->dev, sizeof(struct ltc2978_data),
3898b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck			    GFP_KERNEL);
390c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	if (!data)
391c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		return -ENOMEM;
392c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
393c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID);
3948b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck	if (chip_id < 0)
3958b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck		return chip_id;
396c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
397a2e151074366487dcde943fdc08d88acfe476f9dGuenter Roeck	if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) {
398fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		data->id = ltc2974;
399c24c407e963e73d3ad18b9bc0af32cf23f37a7b0Guenter Roeck	} else if (chip_id == LTC2977_ID) {
400c24c407e963e73d3ad18b9bc0af32cf23f37a7b0Guenter Roeck		data->id = ltc2977;
4013f08d7f49f8365d5c9050522ee733951a503e955Guenter Roeck	} else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 ||
4023f08d7f49f8365d5c9050522ee733951a503e955Guenter Roeck		   chip_id == LTC2978A_ID) {
403c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		data->id = ltc2978;
404ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	} else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
405ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		data->id = ltc3880;
406fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	} else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
407fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		data->id = ltc3883;
408f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeck	} else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) {
409f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeck		data->id = ltm4676;
410c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	} else {
411c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
4128b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck		return -ENODEV;
413c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	}
414c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	if (data->id != id->driver_data)
415c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		dev_warn(&client->dev,
416c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 "Device mismatch: Configured %s, detected %s\n",
417c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 id->name,
418c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			 ltc2978_id[data->id].name);
419c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
420c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	info = &data->info;
421c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	info->write_word_data = ltc2978_write_word_data;
422c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
423c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	data->vin_min = 0x7bff;
424dbd712c2272764a536e29ad6841dba74989a39d9Guenter Roeck	data->vin_max = 0x7c00;
4253d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck	for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
4263d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck		data->vout_min[i] = 0xffff;
427fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	for (i = 0; i < ARRAY_SIZE(data->iout_min); i++)
428fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		data->iout_min[i] = 0xfbff;
429fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	for (i = 0; i < ARRAY_SIZE(data->iout_max); i++)
430fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		data->iout_max[i] = 0x7c00;
431fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	for (i = 0; i < ARRAY_SIZE(data->temp_min); i++)
432fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		data->temp_min[i] = 0x7bff;
4338c958c703ef8804093437959221951eaf0e1e664Guenter Roeck	for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
4348c958c703ef8804093437959221951eaf0e1e664Guenter Roeck		data->temp_max[i] = 0x7c00;
435dbd712c2272764a536e29ad6841dba74989a39d9Guenter Roeck	data->temp2_max = 0x7c00;
436c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
437f366fccd0809f13ba20d64cae3c83f7338c88af7Guenter Roeck	switch (data->id) {
438fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	case ltc2974:
439fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		info->read_word_data = ltc2974_read_word_data;
440fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		info->pages = LTC2974_NUM_PAGES;
441fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
442fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		  | PMBUS_HAVE_TEMP2;
443fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		for (i = 0; i < info->pages; i++) {
444fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			info->func[i] |= PMBUS_HAVE_VOUT
445fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			  | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
446fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
447fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck			  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
448fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		}
449fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
450c24c407e963e73d3ad18b9bc0af32cf23f37a7b0Guenter Roeck	case ltc2977:
451c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	case ltc2978:
452ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		info->read_word_data = ltc2978_read_word_data;
4533d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck		info->pages = LTC2978_NUM_PAGES;
454c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
455c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
456c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
4573d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck		for (i = 1; i < LTC2978_NUM_PAGES; i++) {
458c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			info->func[i] = PMBUS_HAVE_VOUT
459c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck			  | PMBUS_HAVE_STATUS_VOUT;
460c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		}
461c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		break;
462ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck	case ltc3880:
463f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter Roeck	case ltm4676:
464ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		info->read_word_data = ltc3880_read_word_data;
4653d0d2839937778bd19bf505b38093d829a1cdf69Guenter Roeck		info->pages = LTC3880_NUM_PAGES;
466ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
467ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		  | PMBUS_HAVE_STATUS_INPUT
468ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
469ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
470ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		  | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
471ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
472ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
473ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
474ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		  | PMBUS_HAVE_POUT
475ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
476fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		break;
477fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck	case ltc3883:
478fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		info->read_word_data = ltc3883_read_word_data;
479fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		info->pages = LTC3883_NUM_PAGES;
480fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
481fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		  | PMBUS_HAVE_STATUS_INPUT
482fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
483fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
484fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		  | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
485fd9175d2f603509e7ddf14e7b60633f6e88fb0e7Guenter Roeck		  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
486ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck		break;
487c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	default:
4888b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck		return -ENODEV;
489c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	}
4908b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck	return pmbus_do_probe(client, id, info);
491c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck}
492c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
493c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck/* This is the driver that will be inserted */
494c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic struct i2c_driver ltc2978_driver = {
495c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	.driver = {
496c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		   .name = "ltc2978",
497c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck		   },
498c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	.probe = ltc2978_probe,
499dd285ad7373bf5d21cceacb3b7a5eb8b72d37085Guenter Roeck	.remove = pmbus_do_remove,
500c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck	.id_table = ltc2978_id,
501c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck};
502c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
503f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(ltc2978_driver);
504c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck
505c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter RoeckMODULE_AUTHOR("Guenter Roeck");
506f76992b00a4111fc4679b0b2d49fe75f05c2b04dGuenter RoeckMODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676");
507c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter RoeckMODULE_LICENSE("GPL");
508