blob: 771802d7e20dba19d62e9ebe2299c4ce5d02ba4c [file] [log] [blame]
Guenter Roeck200855e2011-07-29 22:21:53 -07001/*
2 * Hardware monitoring driver for ZL6100 and compatibles
3 *
4 * Copyright (c) 2011 Ericsson AB.
Guenter Roeck1640eae2012-03-07 03:54:50 -08005 * Copyright (c) 2012 Guenter Roeck
Guenter Roeck200855e2011-07-29 22:21:53 -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
Guenter Roeck2c052d422015-08-17 16:17:24 -070022#include <linux/bitops.h>
Guenter Roeck200855e2011-07-29 22:21:53 -070023#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/err.h>
27#include <linux/slab.h>
28#include <linux/i2c.h>
29#include <linux/ktime.h>
30#include <linux/delay.h>
31#include "pmbus.h"
32
Guenter Roeck3360a102012-02-28 13:18:47 -080033enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105,
34 zl9101, zl9117 };
Guenter Roeck200855e2011-07-29 22:21:53 -070035
36struct zl6100_data {
37 int id;
38 ktime_t access; /* chip access time */
Guenter Roeck7ad63072012-03-07 03:58:55 -080039 int delay; /* Delay between chip accesses in uS */
Guenter Roeck200855e2011-07-29 22:21:53 -070040 struct pmbus_driver_info info;
41};
42
43#define to_zl6100_data(x) container_of(x, struct zl6100_data, info)
44
Guenter Roeck56badac2011-10-04 17:26:04 -070045#define ZL6100_MFR_CONFIG 0xd0
Guenter Roeck200855e2011-07-29 22:21:53 -070046#define ZL6100_DEVICE_ID 0xe4
47
Guenter Roeck2c052d422015-08-17 16:17:24 -070048#define ZL6100_MFR_XTEMP_ENABLE BIT(7)
Guenter Roeck56badac2011-10-04 17:26:04 -070049
Guenter Roeck1640eae2012-03-07 03:54:50 -080050#define MFR_VMON_OV_FAULT_LIMIT 0xf5
51#define MFR_VMON_UV_FAULT_LIMIT 0xf6
52#define MFR_READ_VMON 0xf7
53
Guenter Roeck2c052d422015-08-17 16:17:24 -070054#define VMON_UV_WARNING BIT(5)
55#define VMON_OV_WARNING BIT(4)
56#define VMON_UV_FAULT BIT(1)
57#define VMON_OV_FAULT BIT(0)
Guenter Roeck1640eae2012-03-07 03:54:50 -080058
Guenter Roeck200855e2011-07-29 22:21:53 -070059#define ZL6100_WAIT_TIME 1000 /* uS */
60
61static ushort delay = ZL6100_WAIT_TIME;
62module_param(delay, ushort, 0644);
63MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
64
Guenter Roeck1640eae2012-03-07 03:54:50 -080065/* Convert linear sensor value to milli-units */
66static long zl6100_l2d(s16 l)
67{
68 s16 exponent;
69 s32 mantissa;
70 long val;
71
72 exponent = l >> 11;
73 mantissa = ((s16)((l & 0x7ff) << 5)) >> 5;
74
75 val = mantissa;
76
77 /* scale result to milli-units */
78 val = val * 1000L;
79
80 if (exponent >= 0)
81 val <<= exponent;
82 else
83 val >>= -exponent;
84
85 return val;
86}
87
88#define MAX_MANTISSA (1023 * 1000)
89#define MIN_MANTISSA (511 * 1000)
90
91static u16 zl6100_d2l(long val)
92{
93 s16 exponent = 0, mantissa;
94 bool negative = false;
95
96 /* simple case */
97 if (val == 0)
98 return 0;
99
100 if (val < 0) {
101 negative = true;
102 val = -val;
103 }
104
105 /* Reduce large mantissa until it fits into 10 bit */
106 while (val >= MAX_MANTISSA && exponent < 15) {
107 exponent++;
108 val >>= 1;
109 }
110 /* Increase small mantissa to improve precision */
111 while (val < MIN_MANTISSA && exponent > -15) {
112 exponent--;
113 val <<= 1;
114 }
115
116 /* Convert mantissa from milli-units to units */
117 mantissa = DIV_ROUND_CLOSEST(val, 1000);
118
119 /* Ensure that resulting number is within range */
120 if (mantissa > 0x3ff)
121 mantissa = 0x3ff;
122
123 /* restore sign */
124 if (negative)
125 mantissa = -mantissa;
126
127 /* Convert to 5 bit exponent, 11 bit mantissa */
128 return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
129}
130
Guenter Roeck200855e2011-07-29 22:21:53 -0700131/* Some chips need a delay between accesses */
132static inline void zl6100_wait(const struct zl6100_data *data)
133{
Guenter Roeck7ad63072012-03-07 03:58:55 -0800134 if (data->delay) {
Guenter Roeck200855e2011-07-29 22:21:53 -0700135 s64 delta = ktime_us_delta(ktime_get(), data->access);
Guenter Roeck7ad63072012-03-07 03:58:55 -0800136 if (delta < data->delay)
137 udelay(data->delay - delta);
Guenter Roeck200855e2011-07-29 22:21:53 -0700138 }
139}
140
141static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
142{
143 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
144 struct zl6100_data *data = to_zl6100_data(info);
Guenter Roeck1640eae2012-03-07 03:54:50 -0800145 int ret, vreg;
Guenter Roeck200855e2011-07-29 22:21:53 -0700146
Guenter Roeck1640eae2012-03-07 03:54:50 -0800147 if (page > 0)
Guenter Roeck200855e2011-07-29 22:21:53 -0700148 return -ENXIO;
149
Guenter Roeckbc581e62011-10-01 16:50:36 -0700150 if (data->id == zl2005) {
151 /*
152 * Limit register detection is not reliable on ZL2005.
153 * Make sure registers are not erroneously detected.
154 */
155 switch (reg) {
156 case PMBUS_VOUT_OV_WARN_LIMIT:
157 case PMBUS_VOUT_UV_WARN_LIMIT:
158 case PMBUS_IOUT_OC_WARN_LIMIT:
159 return -ENXIO;
160 }
161 }
162
Guenter Roeck1640eae2012-03-07 03:54:50 -0800163 switch (reg) {
164 case PMBUS_VIRT_READ_VMON:
165 vreg = MFR_READ_VMON;
166 break;
167 case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
168 case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
169 vreg = MFR_VMON_OV_FAULT_LIMIT;
170 break;
171 case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
172 case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
173 vreg = MFR_VMON_UV_FAULT_LIMIT;
174 break;
175 default:
176 if (reg >= PMBUS_VIRT_BASE)
177 return -ENXIO;
178 vreg = reg;
179 break;
180 }
181
Guenter Roeck200855e2011-07-29 22:21:53 -0700182 zl6100_wait(data);
Guenter Roeck1640eae2012-03-07 03:54:50 -0800183 ret = pmbus_read_word_data(client, page, vreg);
Guenter Roeck200855e2011-07-29 22:21:53 -0700184 data->access = ktime_get();
Guenter Roeck1640eae2012-03-07 03:54:50 -0800185 if (ret < 0)
186 return ret;
187
188 switch (reg) {
189 case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
190 ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 9, 10));
191 break;
192 case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
193 ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 11, 10));
194 break;
195 }
Guenter Roeck200855e2011-07-29 22:21:53 -0700196
197 return ret;
198}
199
200static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
201{
202 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
203 struct zl6100_data *data = to_zl6100_data(info);
Guenter Roeck1640eae2012-03-07 03:54:50 -0800204 int ret, status;
Guenter Roeck200855e2011-07-29 22:21:53 -0700205
206 if (page > 0)
207 return -ENXIO;
208
209 zl6100_wait(data);
Guenter Roeck1640eae2012-03-07 03:54:50 -0800210
211 switch (reg) {
212 case PMBUS_VIRT_STATUS_VMON:
213 ret = pmbus_read_byte_data(client, 0,
214 PMBUS_STATUS_MFR_SPECIFIC);
215 if (ret < 0)
216 break;
217
218 status = 0;
219 if (ret & VMON_UV_WARNING)
220 status |= PB_VOLTAGE_UV_WARNING;
221 if (ret & VMON_OV_WARNING)
222 status |= PB_VOLTAGE_OV_WARNING;
223 if (ret & VMON_UV_FAULT)
224 status |= PB_VOLTAGE_UV_FAULT;
225 if (ret & VMON_OV_FAULT)
226 status |= PB_VOLTAGE_OV_FAULT;
227 ret = status;
228 break;
229 default:
230 ret = pmbus_read_byte_data(client, page, reg);
231 break;
232 }
Guenter Roeck200855e2011-07-29 22:21:53 -0700233 data->access = ktime_get();
234
235 return ret;
236}
237
238static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
239 u16 word)
240{
241 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
242 struct zl6100_data *data = to_zl6100_data(info);
Guenter Roeck1640eae2012-03-07 03:54:50 -0800243 int ret, vreg;
Guenter Roeck200855e2011-07-29 22:21:53 -0700244
Guenter Roeck1640eae2012-03-07 03:54:50 -0800245 if (page > 0)
Guenter Roeck200855e2011-07-29 22:21:53 -0700246 return -ENXIO;
247
Guenter Roeck1640eae2012-03-07 03:54:50 -0800248 switch (reg) {
249 case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
250 word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 9));
251 vreg = MFR_VMON_OV_FAULT_LIMIT;
252 pmbus_clear_cache(client);
253 break;
254 case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
255 vreg = MFR_VMON_OV_FAULT_LIMIT;
256 pmbus_clear_cache(client);
257 break;
258 case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
259 word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 11));
260 vreg = MFR_VMON_UV_FAULT_LIMIT;
261 pmbus_clear_cache(client);
262 break;
263 case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
264 vreg = MFR_VMON_UV_FAULT_LIMIT;
265 pmbus_clear_cache(client);
266 break;
267 default:
268 if (reg >= PMBUS_VIRT_BASE)
269 return -ENXIO;
270 vreg = reg;
271 }
272
Guenter Roeck200855e2011-07-29 22:21:53 -0700273 zl6100_wait(data);
Guenter Roeck1640eae2012-03-07 03:54:50 -0800274 ret = pmbus_write_word_data(client, page, vreg, word);
Guenter Roeck200855e2011-07-29 22:21:53 -0700275 data->access = ktime_get();
276
277 return ret;
278}
279
280static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
281{
282 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
283 struct zl6100_data *data = to_zl6100_data(info);
284 int ret;
285
286 if (page > 0)
287 return -ENXIO;
288
289 zl6100_wait(data);
290 ret = pmbus_write_byte(client, page, value);
291 data->access = ktime_get();
292
293 return ret;
294}
295
296static const struct i2c_device_id zl6100_id[] = {
Guenter Roeck443830f2011-10-01 17:35:44 -0700297 {"bmr450", zl2005},
298 {"bmr451", zl2005},
299 {"bmr462", zl2008},
300 {"bmr463", zl2008},
301 {"bmr464", zl2008},
Guenter Roeck200855e2011-07-29 22:21:53 -0700302 {"zl2004", zl2004},
Guenter Roeckbc581e62011-10-01 16:50:36 -0700303 {"zl2005", zl2005},
Guenter Roeck200855e2011-07-29 22:21:53 -0700304 {"zl2006", zl2006},
305 {"zl2008", zl2008},
306 {"zl2105", zl2105},
307 {"zl2106", zl2106},
308 {"zl6100", zl6100},
309 {"zl6105", zl6105},
Guenter Roeck3360a102012-02-28 13:18:47 -0800310 {"zl9101", zl9101},
311 {"zl9117", zl9117},
Guenter Roeck200855e2011-07-29 22:21:53 -0700312 { }
313};
314MODULE_DEVICE_TABLE(i2c, zl6100_id);
315
316static int zl6100_probe(struct i2c_client *client,
317 const struct i2c_device_id *id)
318{
319 int ret;
320 struct zl6100_data *data;
321 struct pmbus_driver_info *info;
322 u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
323 const struct i2c_device_id *mid;
324
325 if (!i2c_check_functionality(client->adapter,
Guenter Roeck56badac2011-10-04 17:26:04 -0700326 I2C_FUNC_SMBUS_READ_WORD_DATA
Guenter Roeck200855e2011-07-29 22:21:53 -0700327 | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
328 return -ENODEV;
329
330 ret = i2c_smbus_read_block_data(client, ZL6100_DEVICE_ID,
331 device_id);
332 if (ret < 0) {
333 dev_err(&client->dev, "Failed to read device ID\n");
334 return ret;
335 }
336 device_id[ret] = '\0';
337 dev_info(&client->dev, "Device ID %s\n", device_id);
338
339 mid = NULL;
340 for (mid = zl6100_id; mid->name[0]; mid++) {
341 if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
342 break;
343 }
344 if (!mid->name[0]) {
345 dev_err(&client->dev, "Unsupported device\n");
346 return -ENODEV;
347 }
348 if (id->driver_data != mid->driver_data)
349 dev_notice(&client->dev,
350 "Device mismatch: Configured %s, detected %s\n",
351 id->name, mid->name);
352
Guenter Roeck8b313ca2012-02-22 08:56:43 -0800353 data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data),
354 GFP_KERNEL);
Guenter Roeck200855e2011-07-29 22:21:53 -0700355 if (!data)
356 return -ENOMEM;
357
358 data->id = mid->driver_data;
359
360 /*
Guenter Roeckfecfb642012-03-13 09:05:14 -0700361 * According to information from the chip vendor, all currently
362 * supported chips are known to require a wait time between I2C
363 * accesses.
Guenter Roeck200855e2011-07-29 22:21:53 -0700364 */
Guenter Roeck7ad63072012-03-07 03:58:55 -0800365 data->delay = delay;
Guenter Roeck200855e2011-07-29 22:21:53 -0700366
367 /*
368 * Since there was a direct I2C device access above, wait before
369 * accessing the chip again.
Guenter Roeck200855e2011-07-29 22:21:53 -0700370 */
371 data->access = ktime_get();
372 zl6100_wait(data);
Guenter Roeck200855e2011-07-29 22:21:53 -0700373
374 info = &data->info;
375
376 info->pages = 1;
377 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
378 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
379 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
Guenter Roeck56badac2011-10-04 17:26:04 -0700380 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
381
Guenter Roeck1640eae2012-03-07 03:54:50 -0800382 /*
383 * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage
384 * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon.
385 */
386 if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117)
387 info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
388
Guenter Roeck56badac2011-10-04 17:26:04 -0700389 ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
390 if (ret < 0)
Guenter Roeck8b313ca2012-02-22 08:56:43 -0800391 return ret;
392
Guenter Roeck56badac2011-10-04 17:26:04 -0700393 if (ret & ZL6100_MFR_XTEMP_ENABLE)
394 info->func[0] |= PMBUS_HAVE_TEMP2;
395
396 data->access = ktime_get();
397 zl6100_wait(data);
Guenter Roeck200855e2011-07-29 22:21:53 -0700398
399 info->read_word_data = zl6100_read_word_data;
400 info->read_byte_data = zl6100_read_byte_data;
401 info->write_word_data = zl6100_write_word_data;
402 info->write_byte = zl6100_write_byte;
403
Guenter Roeck8b313ca2012-02-22 08:56:43 -0800404 return pmbus_do_probe(client, mid, info);
Guenter Roeck200855e2011-07-29 22:21:53 -0700405}
406
Guenter Roeck200855e2011-07-29 22:21:53 -0700407static struct i2c_driver zl6100_driver = {
408 .driver = {
409 .name = "zl6100",
410 },
411 .probe = zl6100_probe,
Guenter Roeckdd285ad2012-02-22 08:56:44 -0800412 .remove = pmbus_do_remove,
Guenter Roeck200855e2011-07-29 22:21:53 -0700413 .id_table = zl6100_id,
414};
415
Axel Linf0967ee2012-01-20 15:38:18 +0800416module_i2c_driver(zl6100_driver);
Guenter Roeck200855e2011-07-29 22:21:53 -0700417
418MODULE_AUTHOR("Guenter Roeck");
419MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
420MODULE_LICENSE("GPL");