blob: 95ee9e195cb62a849ce2899f6d94f6592b6e2681 [file] [log] [blame]
Guenter Roecka3eeb452011-01-26 20:15:27 -08001/*
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 };
29
Guenter Roeck98591db2011-07-09 13:17:43 -070030#define MAX34440_MFR_VOUT_PEAK 0xd4
31#define MAX34440_MFR_IOUT_PEAK 0xd5
32#define MAX34440_MFR_TEMPERATURE_PEAK 0xd6
Guenter Roeck56aad5d2012-02-24 08:13:31 -080033#define MAX34440_MFR_VOUT_MIN 0xd7
Guenter Roeck98591db2011-07-09 13:17:43 -070034
Guenter Roecka3eeb452011-01-26 20:15:27 -080035#define MAX34440_STATUS_OC_WARN (1 << 0)
36#define MAX34440_STATUS_OC_FAULT (1 << 1)
37#define MAX34440_STATUS_OT_FAULT (1 << 5)
38#define MAX34440_STATUS_OT_WARN (1 << 6)
39
Guenter Roeck98591db2011-07-09 13:17:43 -070040static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
41{
42 int ret;
43
44 switch (reg) {
Guenter Roeck56aad5d2012-02-24 08:13:31 -080045 case PMBUS_VIRT_READ_VOUT_MIN:
46 ret = pmbus_read_word_data(client, page,
47 MAX34440_MFR_VOUT_MIN);
48 break;
Guenter Roeck98591db2011-07-09 13:17:43 -070049 case PMBUS_VIRT_READ_VOUT_MAX:
50 ret = pmbus_read_word_data(client, page,
51 MAX34440_MFR_VOUT_PEAK);
52 break;
53 case PMBUS_VIRT_READ_IOUT_MAX:
54 ret = pmbus_read_word_data(client, page,
55 MAX34440_MFR_IOUT_PEAK);
56 break;
57 case PMBUS_VIRT_READ_TEMP_MAX:
58 ret = pmbus_read_word_data(client, page,
59 MAX34440_MFR_TEMPERATURE_PEAK);
60 break;
61 case PMBUS_VIRT_RESET_VOUT_HISTORY:
62 case PMBUS_VIRT_RESET_IOUT_HISTORY:
63 case PMBUS_VIRT_RESET_TEMP_HISTORY:
64 ret = 0;
65 break;
66 default:
67 ret = -ENODATA;
68 break;
69 }
70 return ret;
71}
72
73static int max34440_write_word_data(struct i2c_client *client, int page,
74 int reg, u16 word)
75{
76 int ret;
77
78 switch (reg) {
79 case PMBUS_VIRT_RESET_VOUT_HISTORY:
80 ret = pmbus_write_word_data(client, page,
Guenter Roeck56aad5d2012-02-24 08:13:31 -080081 MAX34440_MFR_VOUT_MIN, 0x7fff);
82 if (ret)
83 break;
84 ret = pmbus_write_word_data(client, page,
Guenter Roeck98591db2011-07-09 13:17:43 -070085 MAX34440_MFR_VOUT_PEAK, 0);
86 break;
87 case PMBUS_VIRT_RESET_IOUT_HISTORY:
88 ret = pmbus_write_word_data(client, page,
89 MAX34440_MFR_IOUT_PEAK, 0);
90 break;
91 case PMBUS_VIRT_RESET_TEMP_HISTORY:
92 ret = pmbus_write_word_data(client, page,
93 MAX34440_MFR_TEMPERATURE_PEAK,
Guenter Roeckdc91ad82012-02-24 03:44:34 -080094 0x8000);
Guenter Roeck98591db2011-07-09 13:17:43 -070095 break;
96 default:
97 ret = -ENODATA;
98 break;
99 }
100 return ret;
101}
102
Guenter Roeck2cfa6ae2011-03-08 23:00:10 -0800103static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
Guenter Roecka3eeb452011-01-26 20:15:27 -0800104{
Guenter Roeckda8e48a2011-07-29 22:19:39 -0700105 int ret = 0;
Guenter Roecka3eeb452011-01-26 20:15:27 -0800106 int mfg_status;
107
Guenter Roeckda8e48a2011-07-29 22:19:39 -0700108 if (page >= 0) {
109 ret = pmbus_set_page(client, page);
110 if (ret < 0)
111 return ret;
112 }
Guenter Roecka3eeb452011-01-26 20:15:27 -0800113
114 switch (reg) {
115 case PMBUS_STATUS_IOUT:
116 mfg_status = pmbus_read_word_data(client, 0,
117 PMBUS_STATUS_MFR_SPECIFIC);
118 if (mfg_status < 0)
119 return mfg_status;
120 if (mfg_status & MAX34440_STATUS_OC_WARN)
121 ret |= PB_IOUT_OC_WARNING;
122 if (mfg_status & MAX34440_STATUS_OC_FAULT)
123 ret |= PB_IOUT_OC_FAULT;
124 break;
125 case PMBUS_STATUS_TEMPERATURE:
126 mfg_status = pmbus_read_word_data(client, 0,
127 PMBUS_STATUS_MFR_SPECIFIC);
128 if (mfg_status < 0)
129 return mfg_status;
130 if (mfg_status & MAX34440_STATUS_OT_WARN)
131 ret |= PB_TEMP_OT_WARNING;
132 if (mfg_status & MAX34440_STATUS_OT_FAULT)
133 ret |= PB_TEMP_OT_FAULT;
134 break;
135 default:
136 ret = -ENODATA;
137 break;
138 }
139 return ret;
140}
141
142static struct pmbus_driver_info max34440_info[] = {
143 [max34440] = {
144 .pages = 14,
Guenter Roeck1061d852011-06-25 11:21:49 -0700145 .format[PSC_VOLTAGE_IN] = direct,
146 .format[PSC_VOLTAGE_OUT] = direct,
147 .format[PSC_TEMPERATURE] = direct,
148 .format[PSC_CURRENT_OUT] = direct,
Guenter Roecka3eeb452011-01-26 20:15:27 -0800149 .m[PSC_VOLTAGE_IN] = 1,
150 .b[PSC_VOLTAGE_IN] = 0,
151 .R[PSC_VOLTAGE_IN] = 3, /* R = 0 in datasheet reflects mV */
152 .m[PSC_VOLTAGE_OUT] = 1,
153 .b[PSC_VOLTAGE_OUT] = 0,
154 .R[PSC_VOLTAGE_OUT] = 3, /* R = 0 in datasheet reflects mV */
155 .m[PSC_CURRENT_OUT] = 1,
156 .b[PSC_CURRENT_OUT] = 0,
157 .R[PSC_CURRENT_OUT] = 3, /* R = 0 in datasheet reflects mA */
158 .m[PSC_TEMPERATURE] = 1,
159 .b[PSC_TEMPERATURE] = 0,
160 .R[PSC_TEMPERATURE] = 2,
161 .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
162 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
163 .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
164 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
165 .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
166 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
167 .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
168 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
169 .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
170 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
171 .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
172 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
173 .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
174 .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
175 .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
176 .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
177 .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
178 .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
179 .func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
180 .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
Guenter Roeck2cfa6ae2011-03-08 23:00:10 -0800181 .read_byte_data = max34440_read_byte_data,
Guenter Roeck98591db2011-07-09 13:17:43 -0700182 .read_word_data = max34440_read_word_data,
183 .write_word_data = max34440_write_word_data,
Guenter Roecka3eeb452011-01-26 20:15:27 -0800184 },
185 [max34441] = {
186 .pages = 12,
Guenter Roeck1061d852011-06-25 11:21:49 -0700187 .format[PSC_VOLTAGE_IN] = direct,
188 .format[PSC_VOLTAGE_OUT] = direct,
189 .format[PSC_TEMPERATURE] = direct,
190 .format[PSC_CURRENT_OUT] = direct,
191 .format[PSC_FAN] = direct,
Guenter Roecka3eeb452011-01-26 20:15:27 -0800192 .m[PSC_VOLTAGE_IN] = 1,
193 .b[PSC_VOLTAGE_IN] = 0,
194 .R[PSC_VOLTAGE_IN] = 3,
195 .m[PSC_VOLTAGE_OUT] = 1,
196 .b[PSC_VOLTAGE_OUT] = 0,
197 .R[PSC_VOLTAGE_OUT] = 3,
198 .m[PSC_CURRENT_OUT] = 1,
199 .b[PSC_CURRENT_OUT] = 0,
200 .R[PSC_CURRENT_OUT] = 3,
201 .m[PSC_TEMPERATURE] = 1,
202 .b[PSC_TEMPERATURE] = 0,
203 .R[PSC_TEMPERATURE] = 2,
204 .m[PSC_FAN] = 1,
205 .b[PSC_FAN] = 0,
206 .R[PSC_FAN] = 0,
207 .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
208 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
209 .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
210 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
211 .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
212 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
213 .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
214 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
215 .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
216 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
217 .func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
218 .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
219 .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
220 .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
221 .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
222 .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
223 .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
Guenter Roeck2cfa6ae2011-03-08 23:00:10 -0800224 .read_byte_data = max34440_read_byte_data,
Guenter Roeck98591db2011-07-09 13:17:43 -0700225 .read_word_data = max34440_read_word_data,
226 .write_word_data = max34440_write_word_data,
Guenter Roecka3eeb452011-01-26 20:15:27 -0800227 },
228};
229
230static int max34440_probe(struct i2c_client *client,
231 const struct i2c_device_id *id)
232{
233 return pmbus_do_probe(client, id, &max34440_info[id->driver_data]);
234}
235
Guenter Roecka3eeb452011-01-26 20:15:27 -0800236static const struct i2c_device_id max34440_id[] = {
237 {"max34440", max34440},
238 {"max34441", max34441},
239 {}
240};
241
242MODULE_DEVICE_TABLE(i2c, max34440_id);
243
244/* This is the driver that will be inserted */
245static struct i2c_driver max34440_driver = {
246 .driver = {
247 .name = "max34440",
248 },
249 .probe = max34440_probe,
Guenter Roeckdd285ad2012-02-22 08:56:44 -0800250 .remove = pmbus_do_remove,
Guenter Roecka3eeb452011-01-26 20:15:27 -0800251 .id_table = max34440_id,
252};
253
Axel Linf0967ee2012-01-20 15:38:18 +0800254module_i2c_driver(max34440_driver);
Guenter Roecka3eeb452011-01-26 20:15:27 -0800255
256MODULE_AUTHOR("Guenter Roeck");
257MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
258MODULE_LICENSE("GPL");