| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066 |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2011 Ericsson AB. |
|---|
| 5 | 6 | * Copyright (c) 2013 Guenter Roeck |
|---|
| 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 | | - * 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 | 7 | */ |
|---|
| 21 | 8 | |
|---|
| 22 | 9 | #include <linux/bitops.h> |
|---|
| .. | .. |
|---|
| 26 | 13 | #include <linux/err.h> |
|---|
| 27 | 14 | #include <linux/slab.h> |
|---|
| 28 | 15 | #include <linux/i2c.h> |
|---|
| 16 | +#include <linux/log2.h> |
|---|
| 29 | 17 | #include "pmbus.h" |
|---|
| 30 | 18 | |
|---|
| 31 | 19 | enum chips { lm25056, lm25066, lm5064, lm5066, lm5066i }; |
|---|
| .. | .. |
|---|
| 39 | 27 | #define LM25066_CLEAR_PIN_PEAK 0xd6 |
|---|
| 40 | 28 | #define LM25066_DEVICE_SETUP 0xd9 |
|---|
| 41 | 29 | #define LM25066_READ_AVG_VIN 0xdc |
|---|
| 30 | +#define LM25066_SAMPLES_FOR_AVG 0xdb |
|---|
| 42 | 31 | #define LM25066_READ_AVG_VOUT 0xdd |
|---|
| 43 | 32 | #define LM25066_READ_AVG_IIN 0xde |
|---|
| 44 | 33 | #define LM25066_READ_AVG_PIN 0xdf |
|---|
| 45 | 34 | |
|---|
| 46 | 35 | #define LM25066_DEV_SETUP_CL BIT(4) /* Current limit */ |
|---|
| 36 | + |
|---|
| 37 | +#define LM25066_SAMPLES_FOR_AVG_MAX 4096 |
|---|
| 47 | 38 | |
|---|
| 48 | 39 | /* LM25056 only */ |
|---|
| 49 | 40 | |
|---|
| .. | .. |
|---|
| 243 | 234 | |
|---|
| 244 | 235 | #define to_lm25066_data(x) container_of(x, struct lm25066_data, info) |
|---|
| 245 | 236 | |
|---|
| 246 | | -static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) |
|---|
| 237 | +static const struct i2c_device_id lm25066_id[]; |
|---|
| 238 | + |
|---|
| 239 | +static int lm25066_read_word_data(struct i2c_client *client, int page, |
|---|
| 240 | + int phase, int reg) |
|---|
| 247 | 241 | { |
|---|
| 248 | 242 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
|---|
| 249 | 243 | const struct lm25066_data *data = to_lm25066_data(info); |
|---|
| .. | .. |
|---|
| 251 | 245 | |
|---|
| 252 | 246 | switch (reg) { |
|---|
| 253 | 247 | case PMBUS_VIRT_READ_VMON: |
|---|
| 254 | | - ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX); |
|---|
| 248 | + ret = pmbus_read_word_data(client, 0, 0xff, LM25066_READ_VAUX); |
|---|
| 255 | 249 | if (ret < 0) |
|---|
| 256 | 250 | break; |
|---|
| 257 | 251 | /* Adjust returned value to match VIN coefficients */ |
|---|
| .. | .. |
|---|
| 276 | 270 | } |
|---|
| 277 | 271 | break; |
|---|
| 278 | 272 | case PMBUS_READ_IIN: |
|---|
| 279 | | - ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN); |
|---|
| 273 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 274 | + LM25066_MFR_READ_IIN); |
|---|
| 280 | 275 | break; |
|---|
| 281 | 276 | case PMBUS_READ_PIN: |
|---|
| 282 | | - ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN); |
|---|
| 277 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 278 | + LM25066_MFR_READ_PIN); |
|---|
| 283 | 279 | break; |
|---|
| 284 | 280 | case PMBUS_IIN_OC_WARN_LIMIT: |
|---|
| 285 | | - ret = pmbus_read_word_data(client, 0, |
|---|
| 281 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 286 | 282 | LM25066_MFR_IIN_OC_WARN_LIMIT); |
|---|
| 287 | 283 | break; |
|---|
| 288 | 284 | case PMBUS_PIN_OP_WARN_LIMIT: |
|---|
| 289 | | - ret = pmbus_read_word_data(client, 0, |
|---|
| 285 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 290 | 286 | LM25066_MFR_PIN_OP_WARN_LIMIT); |
|---|
| 291 | 287 | break; |
|---|
| 292 | 288 | case PMBUS_VIRT_READ_VIN_AVG: |
|---|
| 293 | | - ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN); |
|---|
| 289 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 290 | + LM25066_READ_AVG_VIN); |
|---|
| 294 | 291 | break; |
|---|
| 295 | 292 | case PMBUS_VIRT_READ_VOUT_AVG: |
|---|
| 296 | | - ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT); |
|---|
| 293 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 294 | + LM25066_READ_AVG_VOUT); |
|---|
| 297 | 295 | break; |
|---|
| 298 | 296 | case PMBUS_VIRT_READ_IIN_AVG: |
|---|
| 299 | | - ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN); |
|---|
| 297 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 298 | + LM25066_READ_AVG_IIN); |
|---|
| 300 | 299 | break; |
|---|
| 301 | 300 | case PMBUS_VIRT_READ_PIN_AVG: |
|---|
| 302 | | - ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN); |
|---|
| 301 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 302 | + LM25066_READ_AVG_PIN); |
|---|
| 303 | 303 | break; |
|---|
| 304 | 304 | case PMBUS_VIRT_READ_PIN_MAX: |
|---|
| 305 | | - ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK); |
|---|
| 305 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 306 | + LM25066_READ_PIN_PEAK); |
|---|
| 306 | 307 | break; |
|---|
| 307 | 308 | case PMBUS_VIRT_RESET_PIN_HISTORY: |
|---|
| 308 | 309 | ret = 0; |
|---|
| 310 | + break; |
|---|
| 311 | + case PMBUS_VIRT_SAMPLES: |
|---|
| 312 | + ret = pmbus_read_byte_data(client, 0, LM25066_SAMPLES_FOR_AVG); |
|---|
| 313 | + if (ret < 0) |
|---|
| 314 | + break; |
|---|
| 315 | + ret = 1 << ret; |
|---|
| 309 | 316 | break; |
|---|
| 310 | 317 | default: |
|---|
| 311 | 318 | ret = -ENODATA; |
|---|
| .. | .. |
|---|
| 314 | 321 | return ret; |
|---|
| 315 | 322 | } |
|---|
| 316 | 323 | |
|---|
| 317 | | -static int lm25056_read_word_data(struct i2c_client *client, int page, int reg) |
|---|
| 324 | +static int lm25056_read_word_data(struct i2c_client *client, int page, |
|---|
| 325 | + int phase, int reg) |
|---|
| 318 | 326 | { |
|---|
| 319 | 327 | int ret; |
|---|
| 320 | 328 | |
|---|
| 321 | 329 | switch (reg) { |
|---|
| 322 | 330 | case PMBUS_VIRT_VMON_UV_WARN_LIMIT: |
|---|
| 323 | | - ret = pmbus_read_word_data(client, 0, |
|---|
| 331 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 324 | 332 | LM25056_VAUX_UV_WARN_LIMIT); |
|---|
| 325 | 333 | if (ret < 0) |
|---|
| 326 | 334 | break; |
|---|
| .. | .. |
|---|
| 328 | 336 | ret = DIV_ROUND_CLOSEST(ret * 293, 6140); |
|---|
| 329 | 337 | break; |
|---|
| 330 | 338 | case PMBUS_VIRT_VMON_OV_WARN_LIMIT: |
|---|
| 331 | | - ret = pmbus_read_word_data(client, 0, |
|---|
| 339 | + ret = pmbus_read_word_data(client, 0, 0xff, |
|---|
| 332 | 340 | LM25056_VAUX_OV_WARN_LIMIT); |
|---|
| 333 | 341 | if (ret < 0) |
|---|
| 334 | 342 | break; |
|---|
| .. | .. |
|---|
| 336 | 344 | ret = DIV_ROUND_CLOSEST(ret * 293, 6140); |
|---|
| 337 | 345 | break; |
|---|
| 338 | 346 | default: |
|---|
| 339 | | - ret = lm25066_read_word_data(client, page, reg); |
|---|
| 347 | + ret = lm25066_read_word_data(client, page, phase, reg); |
|---|
| 340 | 348 | break; |
|---|
| 341 | 349 | } |
|---|
| 342 | 350 | return ret; |
|---|
| .. | .. |
|---|
| 421 | 429 | case PMBUS_VIRT_RESET_PIN_HISTORY: |
|---|
| 422 | 430 | ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK); |
|---|
| 423 | 431 | break; |
|---|
| 432 | + case PMBUS_VIRT_SAMPLES: |
|---|
| 433 | + word = clamp_val(word, 1, LM25066_SAMPLES_FOR_AVG_MAX); |
|---|
| 434 | + ret = pmbus_write_byte_data(client, 0, LM25066_SAMPLES_FOR_AVG, |
|---|
| 435 | + ilog2(word)); |
|---|
| 436 | + break; |
|---|
| 424 | 437 | default: |
|---|
| 425 | 438 | ret = -ENODATA; |
|---|
| 426 | 439 | break; |
|---|
| .. | .. |
|---|
| 428 | 441 | return ret; |
|---|
| 429 | 442 | } |
|---|
| 430 | 443 | |
|---|
| 431 | | -static int lm25066_probe(struct i2c_client *client, |
|---|
| 432 | | - const struct i2c_device_id *id) |
|---|
| 444 | +static int lm25066_probe(struct i2c_client *client) |
|---|
| 433 | 445 | { |
|---|
| 434 | 446 | int config; |
|---|
| 435 | 447 | struct lm25066_data *data; |
|---|
| .. | .. |
|---|
| 449 | 461 | if (config < 0) |
|---|
| 450 | 462 | return config; |
|---|
| 451 | 463 | |
|---|
| 452 | | - data->id = id->driver_data; |
|---|
| 464 | + data->id = i2c_match_id(lm25066_id, client)->driver_data; |
|---|
| 453 | 465 | info = &data->info; |
|---|
| 454 | 466 | |
|---|
| 455 | 467 | info->pages = 1; |
|---|
| .. | .. |
|---|
| 461 | 473 | |
|---|
| 462 | 474 | info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON |
|---|
| 463 | 475 | | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT |
|---|
| 464 | | - | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; |
|---|
| 476 | + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_SAMPLES; |
|---|
| 465 | 477 | |
|---|
| 466 | 478 | if (data->id == lm25056) { |
|---|
| 467 | 479 | info->func[0] |= PMBUS_HAVE_STATUS_VMON; |
|---|
| .. | .. |
|---|
| 499 | 511 | info->b[PSC_POWER] = coeff[PSC_POWER].b; |
|---|
| 500 | 512 | } |
|---|
| 501 | 513 | |
|---|
| 502 | | - return pmbus_do_probe(client, id, info); |
|---|
| 514 | + return pmbus_do_probe(client, info); |
|---|
| 503 | 515 | } |
|---|
| 504 | 516 | |
|---|
| 505 | 517 | static const struct i2c_device_id lm25066_id[] = { |
|---|
| .. | .. |
|---|
| 518 | 530 | .driver = { |
|---|
| 519 | 531 | .name = "lm25066", |
|---|
| 520 | 532 | }, |
|---|
| 521 | | - .probe = lm25066_probe, |
|---|
| 533 | + .probe_new = lm25066_probe, |
|---|
| 522 | 534 | .remove = pmbus_do_remove, |
|---|
| 523 | 535 | .id_table = lm25066_id, |
|---|
| 524 | 536 | }; |
|---|