blob: 08267149dc6324f92dce4cc6866bbd03ad6310d3 [file] [log] [blame]
Guenter Roeck03e9bd82011-07-08 10:43:57 -07001/*
2 * Hardware monitoring driver for LM25066 / LM5064 / LM5066
3 *
4 * Copyright (c) 2011 Ericsson AB.
Guenter Roecka7c69112013-02-06 09:55:37 -08005 * Copyright (c) 2013 Guenter Roeck
Guenter Roeck03e9bd82011-07-08 10:43:57 -07006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/err.h>
26#include <linux/slab.h>
27#include <linux/i2c.h>
28#include "pmbus.h"
29
30enum chips { lm25066, lm5064, lm5066 };
31
32#define LM25066_READ_VAUX 0xd0
33#define LM25066_MFR_READ_IIN 0xd1
34#define LM25066_MFR_READ_PIN 0xd2
35#define LM25066_MFR_IIN_OC_WARN_LIMIT 0xd3
36#define LM25066_MFR_PIN_OP_WARN_LIMIT 0xd4
37#define LM25066_READ_PIN_PEAK 0xd5
38#define LM25066_CLEAR_PIN_PEAK 0xd6
39#define LM25066_DEVICE_SETUP 0xd9
40#define LM25066_READ_AVG_VIN 0xdc
41#define LM25066_READ_AVG_VOUT 0xdd
42#define LM25066_READ_AVG_IIN 0xde
43#define LM25066_READ_AVG_PIN 0xdf
44
45#define LM25066_DEV_SETUP_CL (1 << 4) /* Current limit */
46
Guenter Roecke53e6492013-02-09 14:26:51 -080047struct __coeff {
48 short m, b, R;
49};
50
51#define PSC_CURRENT_IN_L (PSC_NUM_CLASSES)
52#define PSC_POWER_L (PSC_NUM_CLASSES + 1)
53
54static struct __coeff lm25066_coeff[3][PSC_NUM_CLASSES + 2] = {
55 [lm25066] = {
56 [PSC_VOLTAGE_IN] = {
57 .m = 22070,
58 .R = -2,
59 },
60 [PSC_VOLTAGE_OUT] = {
61 .m = 22070,
62 .R = -2,
63 },
64 [PSC_CURRENT_IN] = {
65 .m = 13661,
66 .R = -2,
67 },
68 [PSC_CURRENT_IN_L] = {
69 .m = 6852,
70 .R = -2,
71 },
72 [PSC_POWER] = {
73 .m = 736,
74 .R = -2,
75 },
76 [PSC_POWER_L] = {
77 .m = 369,
78 .R = -2,
79 },
80 [PSC_TEMPERATURE] = {
81 .m = 16,
82 },
83 },
84 [lm5064] = {
85 [PSC_VOLTAGE_IN] = {
86 .m = 4611,
87 .R = -2,
88 },
89 [PSC_VOLTAGE_OUT] = {
90 .m = 4621,
91 .R = -2,
92 },
93 [PSC_CURRENT_IN] = {
94 .m = 10742,
95 .R = -2,
96 },
97 [PSC_CURRENT_IN_L] = {
98 .m = 5456,
99 .R = -2,
100 },
101 [PSC_POWER] = {
102 .m = 1204,
103 .R = -3,
104 },
105 [PSC_POWER_L] = {
106 .m = 612,
107 .R = -3,
108 },
109 [PSC_TEMPERATURE] = {
110 .m = 16,
111 },
112 },
113 [lm5066] = {
114 [PSC_VOLTAGE_IN] = {
115 .m = 4587,
116 .R = -2,
117 },
118 [PSC_VOLTAGE_OUT] = {
119 .m = 4587,
120 .R = -2,
121 },
122 [PSC_CURRENT_IN] = {
123 .m = 10753,
124 .R = -2,
125 },
126 [PSC_CURRENT_IN_L] = {
127 .m = 5405,
128 .R = -2,
129 },
130 [PSC_POWER] = {
131 .m = 1204,
132 .R = -3,
133 },
134 [PSC_POWER_L] = {
135 .m = 605,
136 .R = -3,
137 },
138 [PSC_TEMPERATURE] = {
139 .m = 16,
140 },
141 },
142};
143
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700144struct lm25066_data {
145 int id;
146 struct pmbus_driver_info info;
147};
148
149#define to_lm25066_data(x) container_of(x, struct lm25066_data, info)
150
151static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
152{
153 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
154 const struct lm25066_data *data = to_lm25066_data(info);
155 int ret;
156
Guenter Roecka7c69112013-02-06 09:55:37 -0800157 switch (reg) {
158 case PMBUS_VIRT_READ_VMON:
159 ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
160 if (ret < 0)
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700161 break;
Guenter Roecka7c69112013-02-06 09:55:37 -0800162 /* Adjust returned value to match VIN coefficients */
163 switch (data->id) {
164 case lm25066:
165 /* VIN: 4.54 mV VAUX: 283.2 uV LSB */
166 ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
167 break;
168 case lm5064:
169 /* VIN: 4.53 mV VAUX: 700 uV LSB */
170 ret = DIV_ROUND_CLOSEST(ret * 70, 453);
171 break;
172 case lm5066:
173 /* VIN: 2.18 mV VAUX: 725 uV LSB */
174 ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700175 break;
176 }
Guenter Roecka7c69112013-02-06 09:55:37 -0800177 break;
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700178 case PMBUS_READ_IIN:
179 ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
180 break;
181 case PMBUS_READ_PIN:
182 ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN);
183 break;
184 case PMBUS_IIN_OC_WARN_LIMIT:
185 ret = pmbus_read_word_data(client, 0,
186 LM25066_MFR_IIN_OC_WARN_LIMIT);
187 break;
188 case PMBUS_PIN_OP_WARN_LIMIT:
189 ret = pmbus_read_word_data(client, 0,
190 LM25066_MFR_PIN_OP_WARN_LIMIT);
191 break;
192 case PMBUS_VIRT_READ_VIN_AVG:
193 ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN);
194 break;
195 case PMBUS_VIRT_READ_VOUT_AVG:
196 ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT);
197 break;
198 case PMBUS_VIRT_READ_IIN_AVG:
199 ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN);
200 break;
201 case PMBUS_VIRT_READ_PIN_AVG:
202 ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN);
203 break;
204 case PMBUS_VIRT_READ_PIN_MAX:
205 ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK);
206 break;
207 case PMBUS_VIRT_RESET_PIN_HISTORY:
208 ret = 0;
209 break;
210 default:
211 ret = -ENODATA;
212 break;
213 }
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700214 return ret;
215}
216
217static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
218 u16 word)
219{
220 int ret;
221
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700222 switch (reg) {
Guenter Roeck2507abb2013-02-06 20:49:12 -0800223 case PMBUS_VOUT_UV_WARN_LIMIT:
224 case PMBUS_OT_FAULT_LIMIT:
225 case PMBUS_OT_WARN_LIMIT:
226 case PMBUS_VIN_UV_WARN_LIMIT:
227 case PMBUS_VIN_OV_WARN_LIMIT:
228 word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
229 ret = pmbus_write_word_data(client, 0, reg, word);
230 pmbus_clear_cache(client);
231 break;
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700232 case PMBUS_IIN_OC_WARN_LIMIT:
Guenter Roeck2507abb2013-02-06 20:49:12 -0800233 word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700234 ret = pmbus_write_word_data(client, 0,
235 LM25066_MFR_IIN_OC_WARN_LIMIT,
236 word);
Guenter Roeck2507abb2013-02-06 20:49:12 -0800237 pmbus_clear_cache(client);
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700238 break;
239 case PMBUS_PIN_OP_WARN_LIMIT:
Guenter Roeck2507abb2013-02-06 20:49:12 -0800240 word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700241 ret = pmbus_write_word_data(client, 0,
242 LM25066_MFR_PIN_OP_WARN_LIMIT,
243 word);
Guenter Roeck2507abb2013-02-06 20:49:12 -0800244 pmbus_clear_cache(client);
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700245 break;
246 case PMBUS_VIRT_RESET_PIN_HISTORY:
247 ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
248 break;
249 default:
250 ret = -ENODATA;
251 break;
252 }
253 return ret;
254}
255
256static int lm25066_probe(struct i2c_client *client,
257 const struct i2c_device_id *id)
258{
259 int config;
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700260 struct lm25066_data *data;
261 struct pmbus_driver_info *info;
Guenter Roecke53e6492013-02-09 14:26:51 -0800262 struct __coeff *coeff;
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700263
264 if (!i2c_check_functionality(client->adapter,
265 I2C_FUNC_SMBUS_READ_BYTE_DATA))
266 return -ENODEV;
267
Guenter Roeck8b313ca2012-02-22 08:56:43 -0800268 data = devm_kzalloc(&client->dev, sizeof(struct lm25066_data),
269 GFP_KERNEL);
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700270 if (!data)
271 return -ENOMEM;
272
273 config = i2c_smbus_read_byte_data(client, LM25066_DEVICE_SETUP);
Guenter Roeck8b313ca2012-02-22 08:56:43 -0800274 if (config < 0)
275 return config;
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700276
277 data->id = id->driver_data;
278 info = &data->info;
279
Guenter Roecka7c69112013-02-06 09:55:37 -0800280 info->pages = 1;
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700281 info->format[PSC_VOLTAGE_IN] = direct;
282 info->format[PSC_VOLTAGE_OUT] = direct;
283 info->format[PSC_CURRENT_IN] = direct;
284 info->format[PSC_TEMPERATURE] = direct;
285 info->format[PSC_POWER] = direct;
286
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700287
Guenter Roecka7c69112013-02-06 09:55:37 -0800288 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON | PMBUS_HAVE_VOUT
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700289 | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN
290 | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700291
292 info->read_word_data = lm25066_read_word_data;
293 info->write_word_data = lm25066_write_word_data;
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700294
Guenter Roecke53e6492013-02-09 14:26:51 -0800295 coeff = &lm25066_coeff[data->id][0];
296 info->m[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].m;
297 info->b[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].b;
298 info->R[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].R;
299 info->m[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].m;
300 info->b[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].b;
301 info->R[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].R;
302 info->m[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].m;
303 info->b[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].b;
304 info->R[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].R;
305 info->b[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].b;
306 info->R[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].R;
307 info->b[PSC_POWER] = coeff[PSC_POWER].b;
308 info->R[PSC_POWER] = coeff[PSC_POWER].R;
309 if (config & LM25066_DEV_SETUP_CL) {
310 info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN_L].m;
311 info->m[PSC_POWER] = coeff[PSC_POWER_L].m;
312 } else {
313 info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].m;
314 info->m[PSC_POWER] = coeff[PSC_POWER].m;
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700315 }
316
Guenter Roeck8b313ca2012-02-22 08:56:43 -0800317 return pmbus_do_probe(client, id, info);
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700318}
319
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700320static const struct i2c_device_id lm25066_id[] = {
321 {"lm25066", lm25066},
322 {"lm5064", lm5064},
323 {"lm5066", lm5066},
324 { }
325};
326
327MODULE_DEVICE_TABLE(i2c, lm25066_id);
328
329/* This is the driver that will be inserted */
330static struct i2c_driver lm25066_driver = {
331 .driver = {
332 .name = "lm25066",
333 },
334 .probe = lm25066_probe,
Guenter Roeckdd285ad2012-02-22 08:56:44 -0800335 .remove = pmbus_do_remove,
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700336 .id_table = lm25066_id,
337};
338
Axel Linf0967ee2012-01-20 15:38:18 +0800339module_i2c_driver(lm25066_driver);
Guenter Roeck03e9bd82011-07-08 10:43:57 -0700340
341MODULE_AUTHOR("Guenter Roeck");
342MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066");
343MODULE_LICENSE("GPL");