aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/pmbus/ltc2978.c
diff options
context:
space:
mode:
authorGuenter Roeck <guenter.roeck@ericsson.com>2011-09-11 23:31:09 -0400
committerGuenter Roeck <guenter.roeck@ericsson.com>2011-10-24 14:09:43 -0400
commitddfb41ca2a33c9f5053126324597510974724a1f (patch)
treed9f13049c8532cc5b0050de61c0ad5d90d6af5fe /drivers/hwmon/pmbus/ltc2978.c
parentc3ff9a674c2313d4f28e38d384b18b561b313eb7 (diff)
hwmon: (pmbus/ltc2978) Add support for LTC3880 to LTC2978 driver
The LTC3880 PMBus command set is comparable to LTC2978. Add support for it to the LTC2978 driver. Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com> Reviewed-by: Robert Coulson <robert.coulson@ericsson.com>
Diffstat (limited to 'drivers/hwmon/pmbus/ltc2978.c')
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c137
1 files changed, 125 insertions, 12 deletions
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index 02b2e49adb31..820fff48910b 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Hardware monitoring driver for LTC2978 2 * Hardware monitoring driver for LTC2978 and LTC3880
3 * 3 *
4 * Copyright (c) 2011 Ericsson AB. 4 * Copyright (c) 2011 Ericsson AB.
5 * 5 *
@@ -26,19 +26,28 @@
26#include <linux/i2c.h> 26#include <linux/i2c.h>
27#include "pmbus.h" 27#include "pmbus.h"
28 28
29enum chips { ltc2978 }; 29enum chips { ltc2978, ltc3880 };
30 30
31/* LTC2978 and LTC3880 */
31#define LTC2978_MFR_VOUT_PEAK 0xdd 32#define LTC2978_MFR_VOUT_PEAK 0xdd
32#define LTC2978_MFR_VIN_PEAK 0xde 33#define LTC2978_MFR_VIN_PEAK 0xde
33#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf 34#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
34#define LTC2978_MFR_SPECIAL_ID 0xe7 35#define LTC2978_MFR_SPECIAL_ID 0xe7
35 36
37/* LTC2978 only */
36#define LTC2978_MFR_VOUT_MIN 0xfb 38#define LTC2978_MFR_VOUT_MIN 0xfb
37#define LTC2978_MFR_VIN_MIN 0xfc 39#define LTC2978_MFR_VIN_MIN 0xfc
38#define LTC2978_MFR_TEMPERATURE_MIN 0xfd 40#define LTC2978_MFR_TEMPERATURE_MIN 0xfd
39 41
42/* LTC3880 only */
43#define LTC3880_MFR_IOUT_PEAK 0xd7
44#define LTC3880_MFR_CLEAR_PEAKS 0xe3
45#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
46
40#define LTC2978_ID_REV1 0x0121 47#define LTC2978_ID_REV1 0x0121
41#define LTC2978_ID_REV2 0x0122 48#define LTC2978_ID_REV2 0x0122
49#define LTC3880_ID 0x4000
50#define LTC3880_ID_MASK 0xff00
42 51
43/* 52/*
44 * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which 53 * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
@@ -52,6 +61,8 @@ struct ltc2978_data {
52 int vin_min, vin_max; 61 int vin_min, vin_max;
53 int temp_min, temp_max; 62 int temp_min, temp_max;
54 int vout_min[8], vout_max[8]; 63 int vout_min[8], vout_max[8];
64 int iout_max[2];
65 int temp2_max[2];
55 struct pmbus_driver_info info; 66 struct pmbus_driver_info info;
56}; 67};
57 68
@@ -70,7 +81,8 @@ static inline int lin11_to_val(int data)
70 return (e < 0 ? m >> -e : m << e); 81 return (e < 0 ? m >> -e : m << e);
71} 82}
72 83
73static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) 84static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
85 int reg)
74{ 86{
75 const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 87 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
76 struct ltc2978_data *data = to_ltc2978_data(info); 88 struct ltc2978_data *data = to_ltc2978_data(info);
@@ -106,6 +118,25 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
106 ret = data->temp_max; 118 ret = data->temp_max;
107 } 119 }
108 break; 120 break;
121 case PMBUS_VIRT_RESET_VOUT_HISTORY:
122 case PMBUS_VIRT_RESET_VIN_HISTORY:
123 case PMBUS_VIRT_RESET_TEMP_HISTORY:
124 ret = 0;
125 break;
126 default:
127 ret = -ENODATA;
128 break;
129 }
130 return ret;
131}
132
133static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
134{
135 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
136 struct ltc2978_data *data = to_ltc2978_data(info);
137 int ret;
138
139 switch (reg) {
109 case PMBUS_VIRT_READ_VIN_MIN: 140 case PMBUS_VIRT_READ_VIN_MIN:
110 ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN); 141 ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN);
111 if (ret >= 0) { 142 if (ret >= 0) {
@@ -140,18 +171,74 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
140 ret = data->temp_min; 171 ret = data->temp_min;
141 } 172 }
142 break; 173 break;
143 case PMBUS_VIRT_RESET_VOUT_HISTORY: 174 case PMBUS_VIRT_READ_IOUT_MAX:
144 case PMBUS_VIRT_RESET_VIN_HISTORY: 175 case PMBUS_VIRT_RESET_IOUT_HISTORY:
145 case PMBUS_VIRT_RESET_TEMP_HISTORY: 176 case PMBUS_VIRT_READ_TEMP2_MAX:
177 case PMBUS_VIRT_RESET_TEMP2_HISTORY:
178 ret = -ENXIO;
179 break;
180 default:
181 ret = ltc2978_read_word_data_common(client, page, reg);
182 break;
183 }
184 return ret;
185}
186
187static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
188{
189 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
190 struct ltc2978_data *data = to_ltc2978_data(info);
191 int ret;
192
193 switch (reg) {
194 case PMBUS_VIRT_READ_IOUT_MAX:
195 ret = pmbus_read_word_data(client, page, LTC3880_MFR_IOUT_PEAK);
196 if (ret >= 0) {
197 if (lin11_to_val(ret)
198 > lin11_to_val(data->iout_max[page]))
199 data->iout_max[page] = ret;
200 ret = data->iout_max[page];
201 }
202 break;
203 case PMBUS_VIRT_READ_TEMP2_MAX:
204 ret = pmbus_read_word_data(client, page,
205 LTC3880_MFR_TEMPERATURE2_PEAK);
206 if (ret >= 0) {
207 if (lin11_to_val(ret)
208 > lin11_to_val(data->temp2_max[page]))
209 data->temp2_max[page] = ret;
210 ret = data->temp2_max[page];
211 }
212 break;
213 case PMBUS_VIRT_READ_VIN_MIN:
214 case PMBUS_VIRT_READ_VOUT_MIN:
215 case PMBUS_VIRT_READ_TEMP_MIN:
216 ret = -ENXIO;
217 break;
218 case PMBUS_VIRT_RESET_IOUT_HISTORY:
219 case PMBUS_VIRT_RESET_TEMP2_HISTORY:
146 ret = 0; 220 ret = 0;
147 break; 221 break;
148 default: 222 default:
149 ret = -ENODATA; 223 ret = ltc2978_read_word_data_common(client, page, reg);
150 break; 224 break;
151 } 225 }
152 return ret; 226 return ret;
153} 227}
154 228
229static int ltc2978_clear_peaks(struct i2c_client *client, int page,
230 enum chips id)
231{
232 int ret;
233
234 if (id == ltc2978)
235 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
236 else
237 ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
238
239 return ret;
240}
241
155static int ltc2978_write_word_data(struct i2c_client *client, int page, 242static int ltc2978_write_word_data(struct i2c_client *client, int page,
156 int reg, u16 word) 243 int reg, u16 word)
157{ 244{
@@ -160,20 +247,28 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
160 int ret; 247 int ret;
161 248
162 switch (reg) { 249 switch (reg) {
250 case PMBUS_VIRT_RESET_IOUT_HISTORY:
251 data->iout_max[page] = 0x7fff;
252 ret = ltc2978_clear_peaks(client, page, data->id);
253 break;
254 case PMBUS_VIRT_RESET_TEMP2_HISTORY:
255 data->temp2_max[page] = 0x7fff;
256 ret = ltc2978_clear_peaks(client, page, data->id);
257 break;
163 case PMBUS_VIRT_RESET_VOUT_HISTORY: 258 case PMBUS_VIRT_RESET_VOUT_HISTORY:
164 data->vout_min[page] = 0xffff; 259 data->vout_min[page] = 0xffff;
165 data->vout_max[page] = 0; 260 data->vout_max[page] = 0;
166 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); 261 ret = ltc2978_clear_peaks(client, page, data->id);
167 break; 262 break;
168 case PMBUS_VIRT_RESET_VIN_HISTORY: 263 case PMBUS_VIRT_RESET_VIN_HISTORY:
169 data->vin_min = 0x7bff; 264 data->vin_min = 0x7bff;
170 data->vin_max = 0; 265 data->vin_max = 0;
171 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); 266 ret = ltc2978_clear_peaks(client, page, data->id);
172 break; 267 break;
173 case PMBUS_VIRT_RESET_TEMP_HISTORY: 268 case PMBUS_VIRT_RESET_TEMP_HISTORY:
174 data->temp_min = 0x7bff; 269 data->temp_min = 0x7bff;
175 data->temp_max = 0x7fff; 270 data->temp_max = 0x7fff;
176 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); 271 ret = ltc2978_clear_peaks(client, page, data->id);
177 break; 272 break;
178 default: 273 default:
179 ret = -ENODATA; 274 ret = -ENODATA;
@@ -184,6 +279,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
184 279
185static const struct i2c_device_id ltc2978_id[] = { 280static const struct i2c_device_id ltc2978_id[] = {
186 {"ltc2978", ltc2978}, 281 {"ltc2978", ltc2978},
282 {"ltc3880", ltc3880},
187 {} 283 {}
188}; 284};
189MODULE_DEVICE_TABLE(i2c, ltc2978_id); 285MODULE_DEVICE_TABLE(i2c, ltc2978_id);
@@ -211,6 +307,8 @@ static int ltc2978_probe(struct i2c_client *client,
211 307
212 if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) { 308 if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
213 data->id = ltc2978; 309 data->id = ltc2978;
310 } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
311 data->id = ltc3880;
214 } else { 312 } else {
215 dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); 313 dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
216 ret = -ENODEV; 314 ret = -ENODEV;
@@ -223,7 +321,6 @@ static int ltc2978_probe(struct i2c_client *client,
223 ltc2978_id[data->id].name); 321 ltc2978_id[data->id].name);
224 322
225 info = &data->info; 323 info = &data->info;
226 info->read_word_data = ltc2978_read_word_data;
227 info->write_word_data = ltc2978_write_word_data; 324 info->write_word_data = ltc2978_write_word_data;
228 325
229 data->vout_min[0] = 0xffff; 326 data->vout_min[0] = 0xffff;
@@ -233,6 +330,7 @@ static int ltc2978_probe(struct i2c_client *client,
233 330
234 switch (id->driver_data) { 331 switch (id->driver_data) {
235 case ltc2978: 332 case ltc2978:
333 info->read_word_data = ltc2978_read_word_data;
236 info->pages = 8; 334 info->pages = 8;
237 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT 335 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
238 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 336 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
@@ -243,6 +341,21 @@ static int ltc2978_probe(struct i2c_client *client,
243 data->vout_min[i] = 0xffff; 341 data->vout_min[i] = 0xffff;
244 } 342 }
245 break; 343 break;
344 case ltc3880:
345 info->read_word_data = ltc3880_read_word_data;
346 info->pages = 2;
347 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
348 | PMBUS_HAVE_STATUS_INPUT
349 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
350 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
351 | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
352 | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
353 info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
354 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
355 | PMBUS_HAVE_POUT
356 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
357 data->vout_min[1] = 0xffff;
358 break;
246 default: 359 default:
247 ret = -ENODEV; 360 ret = -ENODEV;
248 goto err_mem; 361 goto err_mem;
@@ -289,7 +402,7 @@ static void __exit ltc2978_exit(void)
289} 402}
290 403
291MODULE_AUTHOR("Guenter Roeck"); 404MODULE_AUTHOR("Guenter Roeck");
292MODULE_DESCRIPTION("PMBus driver for LTC2978"); 405MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880");
293MODULE_LICENSE("GPL"); 406MODULE_LICENSE("GPL");
294module_init(ltc2978_init); 407module_init(ltc2978_init);
295module_exit(ltc2978_exit); 408module_exit(ltc2978_exit);