blob: d34ba4f10c308e13834c7d5d40707c5129d928e5 [file] [log] [blame]
Guenter Roeck83f76492011-03-17 13:16:01 -07001/*
2 * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller
3 * and Digital Power Monitor
4 *
5 * Copyright (c) 2011 Ericsson AB.
6 *
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
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/err.h>
22#include <linux/slab.h>
23#include <linux/i2c.h>
Guenter Roeck99b41602015-07-04 09:19:48 -070024#include <linux/bitops.h>
Guenter Roeck83f76492011-03-17 13:16:01 -070025#include "pmbus.h"
26
Guenter Roeck92711262012-02-24 03:40:53 -080027enum chips { adm1075, adm1275, adm1276 };
Guenter Roeck5cf231a2011-07-14 11:55:35 -070028
Guenter Roeckc576e302011-07-09 11:17:33 -070029#define ADM1275_PEAK_IOUT 0xd0
30#define ADM1275_PEAK_VIN 0xd1
31#define ADM1275_PEAK_VOUT 0xd2
Guenter Roeck83f76492011-03-17 13:16:01 -070032#define ADM1275_PMON_CONFIG 0xd4
33
Guenter Roeck99b41602015-07-04 09:19:48 -070034#define ADM1275_VIN_VOUT_SELECT BIT(6)
35#define ADM1275_VRANGE BIT(5)
36#define ADM1075_IRANGE_50 BIT(4)
37#define ADM1075_IRANGE_25 BIT(3)
38#define ADM1075_IRANGE_MASK (BIT(3) | BIT(4))
Guenter Roeck83f76492011-03-17 13:16:01 -070039
Guenter Roeckc5e67632011-08-02 11:08:57 -070040#define ADM1275_IOUT_WARN2_LIMIT 0xd7
41#define ADM1275_DEVICE_CONFIG 0xd8
42
Guenter Roeck99b41602015-07-04 09:19:48 -070043#define ADM1275_IOUT_WARN2_SELECT BIT(4)
Guenter Roeckc5e67632011-08-02 11:08:57 -070044
Guenter Roeck5cf231a2011-07-14 11:55:35 -070045#define ADM1276_PEAK_PIN 0xda
46
Guenter Roeck99b41602015-07-04 09:19:48 -070047#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0)
Guenter Roeckc5e67632011-08-02 11:08:57 -070048
Guenter Roeck92711262012-02-24 03:40:53 -080049#define ADM1075_READ_VAUX 0xdd
50#define ADM1075_VAUX_OV_WARN_LIMIT 0xde
51#define ADM1075_VAUX_UV_WARN_LIMIT 0xdf
52#define ADM1075_VAUX_STATUS 0xf6
53
Guenter Roeck99b41602015-07-04 09:19:48 -070054#define ADM1075_VAUX_OV_WARN BIT(7)
55#define ADM1075_VAUX_UV_WARN BIT(6)
Guenter Roeck92711262012-02-24 03:40:53 -080056
Guenter Roeckc5e67632011-08-02 11:08:57 -070057struct adm1275_data {
Guenter Roeck5cf231a2011-07-14 11:55:35 -070058 int id;
Guenter Roeckc5e67632011-08-02 11:08:57 -070059 bool have_oc_fault;
60 struct pmbus_driver_info info;
61};
62
63#define to_adm1275_data(x) container_of(x, struct adm1275_data, info)
64
Guenter Roeckc576e302011-07-09 11:17:33 -070065static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
66{
Guenter Roeckc5e67632011-08-02 11:08:57 -070067 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
68 const struct adm1275_data *data = to_adm1275_data(info);
Guenter Roeck5cf231a2011-07-14 11:55:35 -070069 int ret = 0;
Guenter Roeckc576e302011-07-09 11:17:33 -070070
71 if (page)
Guenter Roeckc5e67632011-08-02 11:08:57 -070072 return -ENXIO;
Guenter Roeckc576e302011-07-09 11:17:33 -070073
74 switch (reg) {
Guenter Roeckc5e67632011-08-02 11:08:57 -070075 case PMBUS_IOUT_UC_FAULT_LIMIT:
76 if (data->have_oc_fault) {
77 ret = -ENXIO;
78 break;
79 }
80 ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
81 break;
82 case PMBUS_IOUT_OC_FAULT_LIMIT:
83 if (!data->have_oc_fault) {
84 ret = -ENXIO;
85 break;
86 }
87 ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
88 break;
Guenter Roeck92711262012-02-24 03:40:53 -080089 case PMBUS_VOUT_OV_WARN_LIMIT:
90 if (data->id != adm1075) {
91 ret = -ENODATA;
92 break;
93 }
94 ret = pmbus_read_word_data(client, 0,
95 ADM1075_VAUX_OV_WARN_LIMIT);
96 break;
97 case PMBUS_VOUT_UV_WARN_LIMIT:
98 if (data->id != adm1075) {
99 ret = -ENODATA;
100 break;
101 }
102 ret = pmbus_read_word_data(client, 0,
103 ADM1075_VAUX_UV_WARN_LIMIT);
104 break;
105 case PMBUS_READ_VOUT:
106 if (data->id != adm1075) {
107 ret = -ENODATA;
108 break;
109 }
110 ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX);
111 break;
Guenter Roeckc576e302011-07-09 11:17:33 -0700112 case PMBUS_VIRT_READ_IOUT_MAX:
113 ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
114 break;
115 case PMBUS_VIRT_READ_VOUT_MAX:
116 ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT);
117 break;
118 case PMBUS_VIRT_READ_VIN_MAX:
119 ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
120 break;
Guenter Roeck5cf231a2011-07-14 11:55:35 -0700121 case PMBUS_VIRT_READ_PIN_MAX:
Guenter Roeck92711262012-02-24 03:40:53 -0800122 if (data->id == adm1275) {
Guenter Roeck5cf231a2011-07-14 11:55:35 -0700123 ret = -ENXIO;
124 break;
125 }
126 ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN);
127 break;
Guenter Roeckc576e302011-07-09 11:17:33 -0700128 case PMBUS_VIRT_RESET_IOUT_HISTORY:
129 case PMBUS_VIRT_RESET_VOUT_HISTORY:
130 case PMBUS_VIRT_RESET_VIN_HISTORY:
Guenter Roeck5cf231a2011-07-14 11:55:35 -0700131 break;
132 case PMBUS_VIRT_RESET_PIN_HISTORY:
Guenter Roeck92711262012-02-24 03:40:53 -0800133 if (data->id == adm1275)
Guenter Roeck5cf231a2011-07-14 11:55:35 -0700134 ret = -ENXIO;
Guenter Roeckc576e302011-07-09 11:17:33 -0700135 break;
136 default:
137 ret = -ENODATA;
138 break;
139 }
140 return ret;
141}
142
143static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
144 u16 word)
145{
146 int ret;
147
148 if (page)
Guenter Roeckc5e67632011-08-02 11:08:57 -0700149 return -ENXIO;
Guenter Roeckc576e302011-07-09 11:17:33 -0700150
151 switch (reg) {
Guenter Roeckc5e67632011-08-02 11:08:57 -0700152 case PMBUS_IOUT_UC_FAULT_LIMIT:
153 case PMBUS_IOUT_OC_FAULT_LIMIT:
154 ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT,
155 word);
156 break;
Guenter Roeckc576e302011-07-09 11:17:33 -0700157 case PMBUS_VIRT_RESET_IOUT_HISTORY:
158 ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
159 break;
160 case PMBUS_VIRT_RESET_VOUT_HISTORY:
161 ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0);
162 break;
163 case PMBUS_VIRT_RESET_VIN_HISTORY:
164 ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0);
165 break;
Guenter Roeck5cf231a2011-07-14 11:55:35 -0700166 case PMBUS_VIRT_RESET_PIN_HISTORY:
167 ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0);
168 break;
Guenter Roeckc576e302011-07-09 11:17:33 -0700169 default:
170 ret = -ENODATA;
171 break;
172 }
173 return ret;
174}
175
Guenter Roeckc5e67632011-08-02 11:08:57 -0700176static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
177{
178 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
179 const struct adm1275_data *data = to_adm1275_data(info);
180 int mfr_status, ret;
181
Guenter Roeckda8e48a2011-07-29 22:19:39 -0700182 if (page > 0)
Guenter Roeckc5e67632011-08-02 11:08:57 -0700183 return -ENXIO;
184
185 switch (reg) {
186 case PMBUS_STATUS_IOUT:
187 ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT);
188 if (ret < 0)
189 break;
190 mfr_status = pmbus_read_byte_data(client, page,
191 PMBUS_STATUS_MFR_SPECIFIC);
192 if (mfr_status < 0) {
193 ret = mfr_status;
194 break;
195 }
196 if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) {
197 ret |= data->have_oc_fault ?
198 PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT;
199 }
200 break;
Guenter Roeck92711262012-02-24 03:40:53 -0800201 case PMBUS_STATUS_VOUT:
202 if (data->id != adm1075) {
203 ret = -ENODATA;
204 break;
205 }
206 ret = 0;
207 mfr_status = pmbus_read_byte_data(client, 0,
208 ADM1075_VAUX_STATUS);
209 if (mfr_status & ADM1075_VAUX_OV_WARN)
210 ret |= PB_VOLTAGE_OV_WARNING;
211 if (mfr_status & ADM1075_VAUX_UV_WARN)
212 ret |= PB_VOLTAGE_UV_WARNING;
213 break;
Guenter Roeckc5e67632011-08-02 11:08:57 -0700214 default:
215 ret = -ENODATA;
216 break;
217 }
218 return ret;
219}
220
Guenter Roeck87102802011-09-30 11:53:25 -0700221static const struct i2c_device_id adm1275_id[] = {
Guenter Roeck92711262012-02-24 03:40:53 -0800222 { "adm1075", adm1075 },
Guenter Roeck87102802011-09-30 11:53:25 -0700223 { "adm1275", adm1275 },
224 { "adm1276", adm1276 },
225 { }
226};
227MODULE_DEVICE_TABLE(i2c, adm1275_id);
228
Guenter Roeck83f76492011-03-17 13:16:01 -0700229static int adm1275_probe(struct i2c_client *client,
230 const struct i2c_device_id *id)
231{
Guenter Roeck87102802011-09-30 11:53:25 -0700232 u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
Guenter Roeckc5e67632011-08-02 11:08:57 -0700233 int config, device_config;
Guenter Roeck3b33ca42011-06-30 02:30:03 -0700234 int ret;
Guenter Roeck83f76492011-03-17 13:16:01 -0700235 struct pmbus_driver_info *info;
Guenter Roeckc5e67632011-08-02 11:08:57 -0700236 struct adm1275_data *data;
Guenter Roeck87102802011-09-30 11:53:25 -0700237 const struct i2c_device_id *mid;
Guenter Roeck83f76492011-03-17 13:16:01 -0700238
239 if (!i2c_check_functionality(client->adapter,
Guenter Roeck87102802011-09-30 11:53:25 -0700240 I2C_FUNC_SMBUS_READ_BYTE_DATA
241 | I2C_FUNC_SMBUS_BLOCK_DATA))
Guenter Roeck83f76492011-03-17 13:16:01 -0700242 return -ENODEV;
243
Guenter Roeck87102802011-09-30 11:53:25 -0700244 ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer);
245 if (ret < 0) {
246 dev_err(&client->dev, "Failed to read Manufacturer ID\n");
247 return ret;
248 }
249 if (ret != 3 || strncmp(block_buffer, "ADI", 3)) {
250 dev_err(&client->dev, "Unsupported Manufacturer ID\n");
251 return -ENODEV;
252 }
253
254 ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer);
255 if (ret < 0) {
256 dev_err(&client->dev, "Failed to read Manufacturer Model\n");
257 return ret;
258 }
259 for (mid = adm1275_id; mid->name[0]; mid++) {
260 if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
261 break;
262 }
263 if (!mid->name[0]) {
264 dev_err(&client->dev, "Unsupported device\n");
265 return -ENODEV;
266 }
267
268 if (id->driver_data != mid->driver_data)
269 dev_notice(&client->dev,
270 "Device mismatch: Configured %s, detected %s\n",
271 id->name, mid->name);
272
273 config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
274 if (config < 0)
275 return config;
276
277 device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG);
278 if (device_config < 0)
279 return device_config;
280
Guenter Roeck8b313ca2012-02-22 08:56:43 -0800281 data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data),
282 GFP_KERNEL);
Guenter Roeckc5e67632011-08-02 11:08:57 -0700283 if (!data)
Guenter Roeck83f76492011-03-17 13:16:01 -0700284 return -ENOMEM;
285
Guenter Roeck87102802011-09-30 11:53:25 -0700286 data->id = mid->driver_data;
Guenter Roeck83f76492011-03-17 13:16:01 -0700287
Guenter Roeckc5e67632011-08-02 11:08:57 -0700288 info = &data->info;
289
Guenter Roeck83f76492011-03-17 13:16:01 -0700290 info->pages = 1;
Guenter Roeck1061d852011-06-25 11:21:49 -0700291 info->format[PSC_VOLTAGE_IN] = direct;
292 info->format[PSC_VOLTAGE_OUT] = direct;
293 info->format[PSC_CURRENT_OUT] = direct;
Guenter Roeck7e97bbb2011-07-14 14:18:03 -0700294 info->m[PSC_CURRENT_OUT] = 807;
Guenter Roeck83f76492011-03-17 13:16:01 -0700295 info->b[PSC_CURRENT_OUT] = 20475;
296 info->R[PSC_CURRENT_OUT] = -1;
297 info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
298
Guenter Roeckc576e302011-07-09 11:17:33 -0700299 info->read_word_data = adm1275_read_word_data;
Guenter Roeckc5e67632011-08-02 11:08:57 -0700300 info->read_byte_data = adm1275_read_byte_data;
Guenter Roeckc576e302011-07-09 11:17:33 -0700301 info->write_word_data = adm1275_write_word_data;
302
Guenter Roeck92711262012-02-24 03:40:53 -0800303 if (data->id == adm1075) {
304 info->m[PSC_VOLTAGE_IN] = 27169;
305 info->b[PSC_VOLTAGE_IN] = 0;
306 info->R[PSC_VOLTAGE_IN] = -1;
307 info->m[PSC_VOLTAGE_OUT] = 27169;
308 info->b[PSC_VOLTAGE_OUT] = 0;
309 info->R[PSC_VOLTAGE_OUT] = -1;
310 } else if (config & ADM1275_VRANGE) {
Guenter Roeck7e97bbb2011-07-14 14:18:03 -0700311 info->m[PSC_VOLTAGE_IN] = 19199;
Guenter Roeck83f76492011-03-17 13:16:01 -0700312 info->b[PSC_VOLTAGE_IN] = 0;
313 info->R[PSC_VOLTAGE_IN] = -2;
Guenter Roeck7e97bbb2011-07-14 14:18:03 -0700314 info->m[PSC_VOLTAGE_OUT] = 19199;
Guenter Roeck83f76492011-03-17 13:16:01 -0700315 info->b[PSC_VOLTAGE_OUT] = 0;
316 info->R[PSC_VOLTAGE_OUT] = -2;
317 } else {
Guenter Roeck7e97bbb2011-07-14 14:18:03 -0700318 info->m[PSC_VOLTAGE_IN] = 6720;
Guenter Roeck83f76492011-03-17 13:16:01 -0700319 info->b[PSC_VOLTAGE_IN] = 0;
320 info->R[PSC_VOLTAGE_IN] = -1;
Guenter Roeck7e97bbb2011-07-14 14:18:03 -0700321 info->m[PSC_VOLTAGE_OUT] = 6720;
Guenter Roeck83f76492011-03-17 13:16:01 -0700322 info->b[PSC_VOLTAGE_OUT] = 0;
323 info->R[PSC_VOLTAGE_OUT] = -1;
324 }
325
Guenter Roeckc5e67632011-08-02 11:08:57 -0700326 if (device_config & ADM1275_IOUT_WARN2_SELECT)
327 data->have_oc_fault = true;
328
Guenter Roeck87102802011-09-30 11:53:25 -0700329 switch (data->id) {
Guenter Roeck92711262012-02-24 03:40:53 -0800330 case adm1075:
331 info->format[PSC_POWER] = direct;
332 info->b[PSC_POWER] = 0;
333 info->R[PSC_POWER] = -1;
334 switch (config & ADM1075_IRANGE_MASK) {
335 case ADM1075_IRANGE_25:
336 info->m[PSC_POWER] = 8549;
337 info->m[PSC_CURRENT_OUT] = 806;
338 break;
339 case ADM1075_IRANGE_50:
340 info->m[PSC_POWER] = 4279;
341 info->m[PSC_CURRENT_OUT] = 404;
342 break;
343 default:
344 dev_err(&client->dev, "Invalid input current range");
345 info->m[PSC_POWER] = 0;
346 info->m[PSC_CURRENT_OUT] = 0;
347 break;
348 }
349 info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
350 | PMBUS_HAVE_STATUS_INPUT;
351 if (config & ADM1275_VIN_VOUT_SELECT)
352 info->func[0] |=
353 PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
354 break;
Guenter Roeck5cf231a2011-07-14 11:55:35 -0700355 case adm1275:
356 if (config & ADM1275_VIN_VOUT_SELECT)
357 info->func[0] |=
358 PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
359 else
360 info->func[0] |=
361 PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
362 break;
363 case adm1276:
364 info->format[PSC_POWER] = direct;
365 info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
366 | PMBUS_HAVE_STATUS_INPUT;
367 if (config & ADM1275_VIN_VOUT_SELECT)
368 info->func[0] |=
369 PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
370 if (config & ADM1275_VRANGE) {
371 info->m[PSC_POWER] = 6043;
372 info->b[PSC_POWER] = 0;
373 info->R[PSC_POWER] = -2;
374 } else {
375 info->m[PSC_POWER] = 2115;
376 info->b[PSC_POWER] = 0;
377 info->R[PSC_POWER] = -1;
378 }
379 break;
380 }
Guenter Roeck83f76492011-03-17 13:16:01 -0700381
Guenter Roeck8b313ca2012-02-22 08:56:43 -0800382 return pmbus_do_probe(client, id, info);
Guenter Roeck83f76492011-03-17 13:16:01 -0700383}
384
Guenter Roeck83f76492011-03-17 13:16:01 -0700385static struct i2c_driver adm1275_driver = {
386 .driver = {
387 .name = "adm1275",
388 },
389 .probe = adm1275_probe,
Guenter Roeckdd285ad2012-02-22 08:56:44 -0800390 .remove = pmbus_do_remove,
Guenter Roeck83f76492011-03-17 13:16:01 -0700391 .id_table = adm1275_id,
392};
393
Axel Linf0967ee2012-01-20 15:38:18 +0800394module_i2c_driver(adm1275_driver);
Guenter Roeck83f76492011-03-17 13:16:01 -0700395
396MODULE_AUTHOR("Guenter Roeck");
Guenter Roeck5cf231a2011-07-14 11:55:35 -0700397MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
Guenter Roeck83f76492011-03-17 13:16:01 -0700398MODULE_LICENSE("GPL");