1/*
2 * Hardware monitoring driver for Maxim MAX34440/MAX34441
3 *
4 * Copyright (c) 2011 Ericsson AB.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/err.h>
25#include <linux/i2c.h>
26#include "pmbus.h"
27
28enum chips { max34440, max34441, max34446 };
29
30#define MAX34440_MFR_VOUT_PEAK		0xd4
31#define MAX34440_MFR_IOUT_PEAK		0xd5
32#define MAX34440_MFR_TEMPERATURE_PEAK	0xd6
33#define MAX34440_MFR_VOUT_MIN		0xd7
34
35#define MAX34446_MFR_POUT_PEAK		0xe0
36#define MAX34446_MFR_POUT_AVG		0xe1
37#define MAX34446_MFR_IOUT_AVG		0xe2
38#define MAX34446_MFR_TEMPERATURE_AVG	0xe3
39
40#define MAX34440_STATUS_OC_WARN		(1 << 0)
41#define MAX34440_STATUS_OC_FAULT	(1 << 1)
42#define MAX34440_STATUS_OT_FAULT	(1 << 5)
43#define MAX34440_STATUS_OT_WARN		(1 << 6)
44
45struct max34440_data {
46	int id;
47	struct pmbus_driver_info info;
48};
49
50#define to_max34440_data(x)  container_of(x, struct max34440_data, info)
51
52static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
53{
54	int ret;
55	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
56	const struct max34440_data *data = to_max34440_data(info);
57
58	switch (reg) {
59	case PMBUS_VIRT_READ_VOUT_MIN:
60		ret = pmbus_read_word_data(client, page,
61					   MAX34440_MFR_VOUT_MIN);
62		break;
63	case PMBUS_VIRT_READ_VOUT_MAX:
64		ret = pmbus_read_word_data(client, page,
65					   MAX34440_MFR_VOUT_PEAK);
66		break;
67	case PMBUS_VIRT_READ_IOUT_AVG:
68		if (data->id != max34446)
69			return -ENXIO;
70		ret = pmbus_read_word_data(client, page,
71					   MAX34446_MFR_IOUT_AVG);
72		break;
73	case PMBUS_VIRT_READ_IOUT_MAX:
74		ret = pmbus_read_word_data(client, page,
75					   MAX34440_MFR_IOUT_PEAK);
76		break;
77	case PMBUS_VIRT_READ_POUT_AVG:
78		if (data->id != max34446)
79			return -ENXIO;
80		ret = pmbus_read_word_data(client, page,
81					   MAX34446_MFR_POUT_AVG);
82		break;
83	case PMBUS_VIRT_READ_POUT_MAX:
84		if (data->id != max34446)
85			return -ENXIO;
86		ret = pmbus_read_word_data(client, page,
87					   MAX34446_MFR_POUT_PEAK);
88		break;
89	case PMBUS_VIRT_READ_TEMP_AVG:
90		if (data->id != max34446)
91			return -ENXIO;
92		ret = pmbus_read_word_data(client, page,
93					   MAX34446_MFR_TEMPERATURE_AVG);
94		break;
95	case PMBUS_VIRT_READ_TEMP_MAX:
96		ret = pmbus_read_word_data(client, page,
97					   MAX34440_MFR_TEMPERATURE_PEAK);
98		break;
99	case PMBUS_VIRT_RESET_POUT_HISTORY:
100		if (data->id != max34446)
101			return -ENXIO;
102		ret = 0;
103		break;
104	case PMBUS_VIRT_RESET_VOUT_HISTORY:
105	case PMBUS_VIRT_RESET_IOUT_HISTORY:
106	case PMBUS_VIRT_RESET_TEMP_HISTORY:
107		ret = 0;
108		break;
109	default:
110		ret = -ENODATA;
111		break;
112	}
113	return ret;
114}
115
116static int max34440_write_word_data(struct i2c_client *client, int page,
117				    int reg, u16 word)
118{
119	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
120	const struct max34440_data *data = to_max34440_data(info);
121	int ret;
122
123	switch (reg) {
124	case PMBUS_VIRT_RESET_POUT_HISTORY:
125		ret = pmbus_write_word_data(client, page,
126					    MAX34446_MFR_POUT_PEAK, 0);
127		if (ret)
128			break;
129		ret = pmbus_write_word_data(client, page,
130					    MAX34446_MFR_POUT_AVG, 0);
131		break;
132	case PMBUS_VIRT_RESET_VOUT_HISTORY:
133		ret = pmbus_write_word_data(client, page,
134					    MAX34440_MFR_VOUT_MIN, 0x7fff);
135		if (ret)
136			break;
137		ret = pmbus_write_word_data(client, page,
138					    MAX34440_MFR_VOUT_PEAK, 0);
139		break;
140	case PMBUS_VIRT_RESET_IOUT_HISTORY:
141		ret = pmbus_write_word_data(client, page,
142					    MAX34440_MFR_IOUT_PEAK, 0);
143		if (!ret && data->id == max34446)
144			ret = pmbus_write_word_data(client, page,
145					MAX34446_MFR_IOUT_AVG, 0);
146
147		break;
148	case PMBUS_VIRT_RESET_TEMP_HISTORY:
149		ret = pmbus_write_word_data(client, page,
150					    MAX34440_MFR_TEMPERATURE_PEAK,
151					    0x8000);
152		if (!ret && data->id == max34446)
153			ret = pmbus_write_word_data(client, page,
154					MAX34446_MFR_TEMPERATURE_AVG, 0);
155		break;
156	default:
157		ret = -ENODATA;
158		break;
159	}
160	return ret;
161}
162
163static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
164{
165	int ret = 0;
166	int mfg_status;
167
168	if (page >= 0) {
169		ret = pmbus_set_page(client, page);
170		if (ret < 0)
171			return ret;
172	}
173
174	switch (reg) {
175	case PMBUS_STATUS_IOUT:
176		mfg_status = pmbus_read_word_data(client, 0,
177						  PMBUS_STATUS_MFR_SPECIFIC);
178		if (mfg_status < 0)
179			return mfg_status;
180		if (mfg_status & MAX34440_STATUS_OC_WARN)
181			ret |= PB_IOUT_OC_WARNING;
182		if (mfg_status & MAX34440_STATUS_OC_FAULT)
183			ret |= PB_IOUT_OC_FAULT;
184		break;
185	case PMBUS_STATUS_TEMPERATURE:
186		mfg_status = pmbus_read_word_data(client, 0,
187						  PMBUS_STATUS_MFR_SPECIFIC);
188		if (mfg_status < 0)
189			return mfg_status;
190		if (mfg_status & MAX34440_STATUS_OT_WARN)
191			ret |= PB_TEMP_OT_WARNING;
192		if (mfg_status & MAX34440_STATUS_OT_FAULT)
193			ret |= PB_TEMP_OT_FAULT;
194		break;
195	default:
196		ret = -ENODATA;
197		break;
198	}
199	return ret;
200}
201
202static struct pmbus_driver_info max34440_info[] = {
203	[max34440] = {
204		.pages = 14,
205		.format[PSC_VOLTAGE_IN] = direct,
206		.format[PSC_VOLTAGE_OUT] = direct,
207		.format[PSC_TEMPERATURE] = direct,
208		.format[PSC_CURRENT_OUT] = direct,
209		.m[PSC_VOLTAGE_IN] = 1,
210		.b[PSC_VOLTAGE_IN] = 0,
211		.R[PSC_VOLTAGE_IN] = 3,	    /* R = 0 in datasheet reflects mV */
212		.m[PSC_VOLTAGE_OUT] = 1,
213		.b[PSC_VOLTAGE_OUT] = 0,
214		.R[PSC_VOLTAGE_OUT] = 3,    /* R = 0 in datasheet reflects mV */
215		.m[PSC_CURRENT_OUT] = 1,
216		.b[PSC_CURRENT_OUT] = 0,
217		.R[PSC_CURRENT_OUT] = 3,    /* R = 0 in datasheet reflects mA */
218		.m[PSC_TEMPERATURE] = 1,
219		.b[PSC_TEMPERATURE] = 0,
220		.R[PSC_TEMPERATURE] = 2,
221		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
222		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
223		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
224		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
225		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
226		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
227		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
228		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
229		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
230		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
231		.func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
232		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
233		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
234		.func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
235		.func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
236		.func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
237		.func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
238		.func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
239		.func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
240		.func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
241		.read_byte_data = max34440_read_byte_data,
242		.read_word_data = max34440_read_word_data,
243		.write_word_data = max34440_write_word_data,
244	},
245	[max34441] = {
246		.pages = 12,
247		.format[PSC_VOLTAGE_IN] = direct,
248		.format[PSC_VOLTAGE_OUT] = direct,
249		.format[PSC_TEMPERATURE] = direct,
250		.format[PSC_CURRENT_OUT] = direct,
251		.format[PSC_FAN] = direct,
252		.m[PSC_VOLTAGE_IN] = 1,
253		.b[PSC_VOLTAGE_IN] = 0,
254		.R[PSC_VOLTAGE_IN] = 3,
255		.m[PSC_VOLTAGE_OUT] = 1,
256		.b[PSC_VOLTAGE_OUT] = 0,
257		.R[PSC_VOLTAGE_OUT] = 3,
258		.m[PSC_CURRENT_OUT] = 1,
259		.b[PSC_CURRENT_OUT] = 0,
260		.R[PSC_CURRENT_OUT] = 3,
261		.m[PSC_TEMPERATURE] = 1,
262		.b[PSC_TEMPERATURE] = 0,
263		.R[PSC_TEMPERATURE] = 2,
264		.m[PSC_FAN] = 1,
265		.b[PSC_FAN] = 0,
266		.R[PSC_FAN] = 0,
267		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
268		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
269		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
270		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
271		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
272		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
273		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
274		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
275		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
276		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
277		.func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
278		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
279		.func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
280		.func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
281		.func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
282		.func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
283		.func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
284		.read_byte_data = max34440_read_byte_data,
285		.read_word_data = max34440_read_word_data,
286		.write_word_data = max34440_write_word_data,
287	},
288	[max34446] = {
289		.pages = 7,
290		.format[PSC_VOLTAGE_IN] = direct,
291		.format[PSC_VOLTAGE_OUT] = direct,
292		.format[PSC_TEMPERATURE] = direct,
293		.format[PSC_CURRENT_OUT] = direct,
294		.format[PSC_POWER] = direct,
295		.m[PSC_VOLTAGE_IN] = 1,
296		.b[PSC_VOLTAGE_IN] = 0,
297		.R[PSC_VOLTAGE_IN] = 3,
298		.m[PSC_VOLTAGE_OUT] = 1,
299		.b[PSC_VOLTAGE_OUT] = 0,
300		.R[PSC_VOLTAGE_OUT] = 3,
301		.m[PSC_CURRENT_OUT] = 1,
302		.b[PSC_CURRENT_OUT] = 0,
303		.R[PSC_CURRENT_OUT] = 3,
304		.m[PSC_POWER] = 1,
305		.b[PSC_POWER] = 0,
306		.R[PSC_POWER] = 3,
307		.m[PSC_TEMPERATURE] = 1,
308		.b[PSC_TEMPERATURE] = 0,
309		.R[PSC_TEMPERATURE] = 2,
310		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
311		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
312		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
313		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
314		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
315		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
316		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
317		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
318		.func[4] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
319		.func[5] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
320		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
321		.read_byte_data = max34440_read_byte_data,
322		.read_word_data = max34440_read_word_data,
323		.write_word_data = max34440_write_word_data,
324	},
325};
326
327static int max34440_probe(struct i2c_client *client,
328			  const struct i2c_device_id *id)
329{
330	struct max34440_data *data;
331
332	data = devm_kzalloc(&client->dev, sizeof(struct max34440_data),
333			    GFP_KERNEL);
334	if (!data)
335		return -ENOMEM;
336	data->id = id->driver_data;
337	data->info = max34440_info[id->driver_data];
338
339	return pmbus_do_probe(client, id, &data->info);
340}
341
342static const struct i2c_device_id max34440_id[] = {
343	{"max34440", max34440},
344	{"max34441", max34441},
345	{"max34446", max34446},
346	{}
347};
348MODULE_DEVICE_TABLE(i2c, max34440_id);
349
350/* This is the driver that will be inserted */
351static struct i2c_driver max34440_driver = {
352	.driver = {
353		   .name = "max34440",
354		   },
355	.probe = max34440_probe,
356	.remove = pmbus_do_remove,
357	.id_table = max34440_id,
358};
359
360module_i2c_driver(max34440_driver);
361
362MODULE_AUTHOR("Guenter Roeck");
363MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
364MODULE_LICENSE("GPL");
365