root/drivers/hwmon/pmbus/lm25066.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lm25066_read_word_data
  2. lm25056_read_word_data
  3. lm25056_read_byte_data
  4. lm25066_write_word_data
  5. lm25066_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066
   4  *
   5  * Copyright (c) 2011 Ericsson AB.
   6  * Copyright (c) 2013 Guenter Roeck
   7  */
   8 
   9 #include <linux/bitops.h>
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/init.h>
  13 #include <linux/err.h>
  14 #include <linux/slab.h>
  15 #include <linux/i2c.h>
  16 #include <linux/log2.h>
  17 #include "pmbus.h"
  18 
  19 enum chips { lm25056, lm25066, lm5064, lm5066, lm5066i };
  20 
  21 #define LM25066_READ_VAUX               0xd0
  22 #define LM25066_MFR_READ_IIN            0xd1
  23 #define LM25066_MFR_READ_PIN            0xd2
  24 #define LM25066_MFR_IIN_OC_WARN_LIMIT   0xd3
  25 #define LM25066_MFR_PIN_OP_WARN_LIMIT   0xd4
  26 #define LM25066_READ_PIN_PEAK           0xd5
  27 #define LM25066_CLEAR_PIN_PEAK          0xd6
  28 #define LM25066_DEVICE_SETUP            0xd9
  29 #define LM25066_READ_AVG_VIN            0xdc
  30 #define LM25066_SAMPLES_FOR_AVG         0xdb
  31 #define LM25066_READ_AVG_VOUT           0xdd
  32 #define LM25066_READ_AVG_IIN            0xde
  33 #define LM25066_READ_AVG_PIN            0xdf
  34 
  35 #define LM25066_DEV_SETUP_CL            BIT(4)  /* Current limit */
  36 
  37 #define LM25066_SAMPLES_FOR_AVG_MAX     4096
  38 
  39 /* LM25056 only */
  40 
  41 #define LM25056_VAUX_OV_WARN_LIMIT      0xe3
  42 #define LM25056_VAUX_UV_WARN_LIMIT      0xe4
  43 
  44 #define LM25056_MFR_STS_VAUX_OV_WARN    BIT(1)
  45 #define LM25056_MFR_STS_VAUX_UV_WARN    BIT(0)
  46 
  47 struct __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 
  54 static struct __coeff lm25066_coeff[6][PSC_NUM_CLASSES + 2] = {
  55         [lm25056] = {
  56                 [PSC_VOLTAGE_IN] = {
  57                         .m = 16296,
  58                         .R = -2,
  59                 },
  60                 [PSC_CURRENT_IN] = {
  61                         .m = 13797,
  62                         .R = -2,
  63                 },
  64                 [PSC_CURRENT_IN_L] = {
  65                         .m = 6726,
  66                         .R = -2,
  67                 },
  68                 [PSC_POWER] = {
  69                         .m = 5501,
  70                         .R = -3,
  71                 },
  72                 [PSC_POWER_L] = {
  73                         .m = 26882,
  74                         .R = -4,
  75                 },
  76                 [PSC_TEMPERATURE] = {
  77                         .m = 1580,
  78                         .b = -14500,
  79                         .R = -2,
  80                 },
  81         },
  82         [lm25066] = {
  83                 [PSC_VOLTAGE_IN] = {
  84                         .m = 22070,
  85                         .R = -2,
  86                 },
  87                 [PSC_VOLTAGE_OUT] = {
  88                         .m = 22070,
  89                         .R = -2,
  90                 },
  91                 [PSC_CURRENT_IN] = {
  92                         .m = 13661,
  93                         .R = -2,
  94                 },
  95                 [PSC_CURRENT_IN_L] = {
  96                         .m = 6852,
  97                         .R = -2,
  98                 },
  99                 [PSC_POWER] = {
 100                         .m = 736,
 101                         .R = -2,
 102                 },
 103                 [PSC_POWER_L] = {
 104                         .m = 369,
 105                         .R = -2,
 106                 },
 107                 [PSC_TEMPERATURE] = {
 108                         .m = 16,
 109                 },
 110         },
 111         [lm5064] = {
 112                 [PSC_VOLTAGE_IN] = {
 113                         .m = 4611,
 114                         .R = -2,
 115                 },
 116                 [PSC_VOLTAGE_OUT] = {
 117                         .m = 4621,
 118                         .R = -2,
 119                 },
 120                 [PSC_CURRENT_IN] = {
 121                         .m = 10742,
 122                         .R = -2,
 123                 },
 124                 [PSC_CURRENT_IN_L] = {
 125                         .m = 5456,
 126                         .R = -2,
 127                 },
 128                 [PSC_POWER] = {
 129                         .m = 1204,
 130                         .R = -3,
 131                 },
 132                 [PSC_POWER_L] = {
 133                         .m = 612,
 134                         .R = -3,
 135                 },
 136                 [PSC_TEMPERATURE] = {
 137                         .m = 16,
 138                 },
 139         },
 140         [lm5066] = {
 141                 [PSC_VOLTAGE_IN] = {
 142                         .m = 4587,
 143                         .R = -2,
 144                 },
 145                 [PSC_VOLTAGE_OUT] = {
 146                         .m = 4587,
 147                         .R = -2,
 148                 },
 149                 [PSC_CURRENT_IN] = {
 150                         .m = 10753,
 151                         .R = -2,
 152                 },
 153                 [PSC_CURRENT_IN_L] = {
 154                         .m = 5405,
 155                         .R = -2,
 156                 },
 157                 [PSC_POWER] = {
 158                         .m = 1204,
 159                         .R = -3,
 160                 },
 161                 [PSC_POWER_L] = {
 162                         .m = 605,
 163                         .R = -3,
 164                 },
 165                 [PSC_TEMPERATURE] = {
 166                         .m = 16,
 167                 },
 168         },
 169         [lm5066i] = {
 170                 [PSC_VOLTAGE_IN] = {
 171                         .m = 4617,
 172                         .b = -140,
 173                         .R = -2,
 174                 },
 175                 [PSC_VOLTAGE_OUT] = {
 176                         .m = 4602,
 177                         .b = 500,
 178                         .R = -2,
 179                 },
 180                 [PSC_CURRENT_IN] = {
 181                         .m = 15076,
 182                         .b = -504,
 183                         .R = -2,
 184                 },
 185                 [PSC_CURRENT_IN_L] = {
 186                         .m = 7645,
 187                         .b = 100,
 188                         .R = -2,
 189                 },
 190                 [PSC_POWER] = {
 191                         .m = 1701,
 192                         .b = -4000,
 193                         .R = -3,
 194                 },
 195                 [PSC_POWER_L] = {
 196                         .m = 861,
 197                         .b = -965,
 198                         .R = -3,
 199                 },
 200                 [PSC_TEMPERATURE] = {
 201                         .m = 16,
 202                 },
 203         },
 204 };
 205 
 206 struct lm25066_data {
 207         int id;
 208         u16 rlimit;                     /* Maximum register value */
 209         struct pmbus_driver_info info;
 210 };
 211 
 212 #define to_lm25066_data(x)  container_of(x, struct lm25066_data, info)
 213 
 214 static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
 215 {
 216         const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 217         const struct lm25066_data *data = to_lm25066_data(info);
 218         int ret;
 219 
 220         switch (reg) {
 221         case PMBUS_VIRT_READ_VMON:
 222                 ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
 223                 if (ret < 0)
 224                         break;
 225                 /* Adjust returned value to match VIN coefficients */
 226                 switch (data->id) {
 227                 case lm25056:
 228                         /* VIN: 6.14 mV VAUX: 293 uV LSB */
 229                         ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
 230                         break;
 231                 case lm25066:
 232                         /* VIN: 4.54 mV VAUX: 283.2 uV LSB */
 233                         ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
 234                         break;
 235                 case lm5064:
 236                         /* VIN: 4.53 mV VAUX: 700 uV LSB */
 237                         ret = DIV_ROUND_CLOSEST(ret * 70, 453);
 238                         break;
 239                 case lm5066:
 240                 case lm5066i:
 241                         /* VIN: 2.18 mV VAUX: 725 uV LSB */
 242                         ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
 243                         break;
 244                 }
 245                 break;
 246         case PMBUS_READ_IIN:
 247                 ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
 248                 break;
 249         case PMBUS_READ_PIN:
 250                 ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN);
 251                 break;
 252         case PMBUS_IIN_OC_WARN_LIMIT:
 253                 ret = pmbus_read_word_data(client, 0,
 254                                            LM25066_MFR_IIN_OC_WARN_LIMIT);
 255                 break;
 256         case PMBUS_PIN_OP_WARN_LIMIT:
 257                 ret = pmbus_read_word_data(client, 0,
 258                                            LM25066_MFR_PIN_OP_WARN_LIMIT);
 259                 break;
 260         case PMBUS_VIRT_READ_VIN_AVG:
 261                 ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN);
 262                 break;
 263         case PMBUS_VIRT_READ_VOUT_AVG:
 264                 ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT);
 265                 break;
 266         case PMBUS_VIRT_READ_IIN_AVG:
 267                 ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN);
 268                 break;
 269         case PMBUS_VIRT_READ_PIN_AVG:
 270                 ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN);
 271                 break;
 272         case PMBUS_VIRT_READ_PIN_MAX:
 273                 ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK);
 274                 break;
 275         case PMBUS_VIRT_RESET_PIN_HISTORY:
 276                 ret = 0;
 277                 break;
 278         case PMBUS_VIRT_SAMPLES:
 279                 ret = pmbus_read_byte_data(client, 0, LM25066_SAMPLES_FOR_AVG);
 280                 if (ret < 0)
 281                         break;
 282                 ret = 1 << ret;
 283                 break;
 284         default:
 285                 ret = -ENODATA;
 286                 break;
 287         }
 288         return ret;
 289 }
 290 
 291 static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
 292 {
 293         int ret;
 294 
 295         switch (reg) {
 296         case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
 297                 ret = pmbus_read_word_data(client, 0,
 298                                            LM25056_VAUX_UV_WARN_LIMIT);
 299                 if (ret < 0)
 300                         break;
 301                 /* Adjust returned value to match VIN coefficients */
 302                 ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
 303                 break;
 304         case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
 305                 ret = pmbus_read_word_data(client, 0,
 306                                            LM25056_VAUX_OV_WARN_LIMIT);
 307                 if (ret < 0)
 308                         break;
 309                 /* Adjust returned value to match VIN coefficients */
 310                 ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
 311                 break;
 312         default:
 313                 ret = lm25066_read_word_data(client, page, reg);
 314                 break;
 315         }
 316         return ret;
 317 }
 318 
 319 static int lm25056_read_byte_data(struct i2c_client *client, int page, int reg)
 320 {
 321         int ret, s;
 322 
 323         switch (reg) {
 324         case PMBUS_VIRT_STATUS_VMON:
 325                 ret = pmbus_read_byte_data(client, 0,
 326                                            PMBUS_STATUS_MFR_SPECIFIC);
 327                 if (ret < 0)
 328                         break;
 329                 s = 0;
 330                 if (ret & LM25056_MFR_STS_VAUX_UV_WARN)
 331                         s |= PB_VOLTAGE_UV_WARNING;
 332                 if (ret & LM25056_MFR_STS_VAUX_OV_WARN)
 333                         s |= PB_VOLTAGE_OV_WARNING;
 334                 ret = s;
 335                 break;
 336         default:
 337                 ret = -ENODATA;
 338                 break;
 339         }
 340         return ret;
 341 }
 342 
 343 static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
 344                                    u16 word)
 345 {
 346         const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 347         const struct lm25066_data *data = to_lm25066_data(info);
 348         int ret;
 349 
 350         switch (reg) {
 351         case PMBUS_POUT_OP_FAULT_LIMIT:
 352         case PMBUS_POUT_OP_WARN_LIMIT:
 353         case PMBUS_VOUT_UV_WARN_LIMIT:
 354         case PMBUS_OT_FAULT_LIMIT:
 355         case PMBUS_OT_WARN_LIMIT:
 356         case PMBUS_IIN_OC_FAULT_LIMIT:
 357         case PMBUS_VIN_UV_WARN_LIMIT:
 358         case PMBUS_VIN_UV_FAULT_LIMIT:
 359         case PMBUS_VIN_OV_FAULT_LIMIT:
 360         case PMBUS_VIN_OV_WARN_LIMIT:
 361                 word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
 362                 ret = pmbus_write_word_data(client, 0, reg, word);
 363                 pmbus_clear_cache(client);
 364                 break;
 365         case PMBUS_IIN_OC_WARN_LIMIT:
 366                 word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
 367                 ret = pmbus_write_word_data(client, 0,
 368                                             LM25066_MFR_IIN_OC_WARN_LIMIT,
 369                                             word);
 370                 pmbus_clear_cache(client);
 371                 break;
 372         case PMBUS_PIN_OP_WARN_LIMIT:
 373                 word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
 374                 ret = pmbus_write_word_data(client, 0,
 375                                             LM25066_MFR_PIN_OP_WARN_LIMIT,
 376                                             word);
 377                 pmbus_clear_cache(client);
 378                 break;
 379         case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
 380                 /* Adjust from VIN coefficients (for LM25056) */
 381                 word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
 382                 word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
 383                 ret = pmbus_write_word_data(client, 0,
 384                                             LM25056_VAUX_UV_WARN_LIMIT, word);
 385                 pmbus_clear_cache(client);
 386                 break;
 387         case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
 388                 /* Adjust from VIN coefficients (for LM25056) */
 389                 word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
 390                 word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);
 391                 ret = pmbus_write_word_data(client, 0,
 392                                             LM25056_VAUX_OV_WARN_LIMIT, word);
 393                 pmbus_clear_cache(client);
 394                 break;
 395         case PMBUS_VIRT_RESET_PIN_HISTORY:
 396                 ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
 397                 break;
 398         case PMBUS_VIRT_SAMPLES:
 399                 word = clamp_val(word, 1, LM25066_SAMPLES_FOR_AVG_MAX);
 400                 ret = pmbus_write_byte_data(client, 0, LM25066_SAMPLES_FOR_AVG,
 401                                             ilog2(word));
 402                 break;
 403         default:
 404                 ret = -ENODATA;
 405                 break;
 406         }
 407         return ret;
 408 }
 409 
 410 static int lm25066_probe(struct i2c_client *client,
 411                           const struct i2c_device_id *id)
 412 {
 413         int config;
 414         struct lm25066_data *data;
 415         struct pmbus_driver_info *info;
 416         struct __coeff *coeff;
 417 
 418         if (!i2c_check_functionality(client->adapter,
 419                                      I2C_FUNC_SMBUS_READ_BYTE_DATA))
 420                 return -ENODEV;
 421 
 422         data = devm_kzalloc(&client->dev, sizeof(struct lm25066_data),
 423                             GFP_KERNEL);
 424         if (!data)
 425                 return -ENOMEM;
 426 
 427         config = i2c_smbus_read_byte_data(client, LM25066_DEVICE_SETUP);
 428         if (config < 0)
 429                 return config;
 430 
 431         data->id = id->driver_data;
 432         info = &data->info;
 433 
 434         info->pages = 1;
 435         info->format[PSC_VOLTAGE_IN] = direct;
 436         info->format[PSC_VOLTAGE_OUT] = direct;
 437         info->format[PSC_CURRENT_IN] = direct;
 438         info->format[PSC_TEMPERATURE] = direct;
 439         info->format[PSC_POWER] = direct;
 440 
 441         info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON
 442           | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT
 443           | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_SAMPLES;
 444 
 445         if (data->id == lm25056) {
 446                 info->func[0] |= PMBUS_HAVE_STATUS_VMON;
 447                 info->read_word_data = lm25056_read_word_data;
 448                 info->read_byte_data = lm25056_read_byte_data;
 449                 data->rlimit = 0x0fff;
 450         } else {
 451                 info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
 452                 info->read_word_data = lm25066_read_word_data;
 453                 data->rlimit = 0x0fff;
 454         }
 455         info->write_word_data = lm25066_write_word_data;
 456 
 457         coeff = &lm25066_coeff[data->id][0];
 458         info->m[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].m;
 459         info->b[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].b;
 460         info->R[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].R;
 461         info->m[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].m;
 462         info->b[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].b;
 463         info->R[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].R;
 464         info->m[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].m;
 465         info->b[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].b;
 466         info->R[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].R;
 467         info->R[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].R;
 468         info->R[PSC_POWER] = coeff[PSC_POWER].R;
 469         if (config & LM25066_DEV_SETUP_CL) {
 470                 info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN_L].m;
 471                 info->b[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN_L].b;
 472                 info->m[PSC_POWER] = coeff[PSC_POWER_L].m;
 473                 info->b[PSC_POWER] = coeff[PSC_POWER_L].b;
 474         } else {
 475                 info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].m;
 476                 info->b[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].b;
 477                 info->m[PSC_POWER] = coeff[PSC_POWER].m;
 478                 info->b[PSC_POWER] = coeff[PSC_POWER].b;
 479         }
 480 
 481         return pmbus_do_probe(client, id, info);
 482 }
 483 
 484 static const struct i2c_device_id lm25066_id[] = {
 485         {"lm25056", lm25056},
 486         {"lm25066", lm25066},
 487         {"lm5064", lm5064},
 488         {"lm5066", lm5066},
 489         {"lm5066i", lm5066i},
 490         { }
 491 };
 492 
 493 MODULE_DEVICE_TABLE(i2c, lm25066_id);
 494 
 495 /* This is the driver that will be inserted */
 496 static struct i2c_driver lm25066_driver = {
 497         .driver = {
 498                    .name = "lm25066",
 499                    },
 500         .probe = lm25066_probe,
 501         .remove = pmbus_do_remove,
 502         .id_table = lm25066_id,
 503 };
 504 
 505 module_i2c_driver(lm25066_driver);
 506 
 507 MODULE_AUTHOR("Guenter Roeck");
 508 MODULE_DESCRIPTION("PMBus driver for LM25066 and compatible chips");
 509 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */