root/drivers/hwmon/ltc2945.c

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

DEFINITIONS

This source file includes following definitions.
  1. is_power_reg
  2. ltc2945_reg_to_val
  3. ltc2945_val_to_reg
  4. ltc2945_value_show
  5. ltc2945_value_store
  6. ltc2945_history_store
  7. ltc2945_bool_show
  8. ltc2945_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Driver for Linear Technology LTC2945 I2C Power Monitor
   4  *
   5  * Copyright (c) 2014 Guenter Roeck
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/module.h>
  10 #include <linux/err.h>
  11 #include <linux/slab.h>
  12 #include <linux/i2c.h>
  13 #include <linux/hwmon.h>
  14 #include <linux/hwmon-sysfs.h>
  15 #include <linux/jiffies.h>
  16 #include <linux/regmap.h>
  17 
  18 /* chip registers */
  19 #define LTC2945_CONTROL                 0x00
  20 #define LTC2945_ALERT                   0x01
  21 #define LTC2945_STATUS                  0x02
  22 #define LTC2945_FAULT                   0x03
  23 #define LTC2945_POWER_H                 0x05
  24 #define LTC2945_MAX_POWER_H             0x08
  25 #define LTC2945_MIN_POWER_H             0x0b
  26 #define LTC2945_MAX_POWER_THRES_H       0x0e
  27 #define LTC2945_MIN_POWER_THRES_H       0x11
  28 #define LTC2945_SENSE_H                 0x14
  29 #define LTC2945_MAX_SENSE_H             0x16
  30 #define LTC2945_MIN_SENSE_H             0x18
  31 #define LTC2945_MAX_SENSE_THRES_H       0x1a
  32 #define LTC2945_MIN_SENSE_THRES_H       0x1c
  33 #define LTC2945_VIN_H                   0x1e
  34 #define LTC2945_MAX_VIN_H               0x20
  35 #define LTC2945_MIN_VIN_H               0x22
  36 #define LTC2945_MAX_VIN_THRES_H         0x24
  37 #define LTC2945_MIN_VIN_THRES_H         0x26
  38 #define LTC2945_ADIN_H                  0x28
  39 #define LTC2945_MAX_ADIN_H              0x2a
  40 #define LTC2945_MIN_ADIN_H              0x2c
  41 #define LTC2945_MAX_ADIN_THRES_H        0x2e
  42 #define LTC2945_MIN_ADIN_THRES_H        0x30
  43 #define LTC2945_MIN_ADIN_THRES_L        0x31
  44 
  45 /* Fault register bits */
  46 
  47 #define FAULT_ADIN_UV           (1 << 0)
  48 #define FAULT_ADIN_OV           (1 << 1)
  49 #define FAULT_VIN_UV            (1 << 2)
  50 #define FAULT_VIN_OV            (1 << 3)
  51 #define FAULT_SENSE_UV          (1 << 4)
  52 #define FAULT_SENSE_OV          (1 << 5)
  53 #define FAULT_POWER_UV          (1 << 6)
  54 #define FAULT_POWER_OV          (1 << 7)
  55 
  56 /* Control register bits */
  57 
  58 #define CONTROL_MULT_SELECT     (1 << 0)
  59 #define CONTROL_TEST_MODE       (1 << 4)
  60 
  61 static inline bool is_power_reg(u8 reg)
  62 {
  63         return reg < LTC2945_SENSE_H;
  64 }
  65 
  66 /* Return the value from the given register in uW, mV, or mA */
  67 static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
  68 {
  69         struct regmap *regmap = dev_get_drvdata(dev);
  70         unsigned int control;
  71         u8 buf[3];
  72         long long val;
  73         int ret;
  74 
  75         ret = regmap_bulk_read(regmap, reg, buf,
  76                                is_power_reg(reg) ? 3 : 2);
  77         if (ret < 0)
  78                 return ret;
  79 
  80         if (is_power_reg(reg)) {
  81                 /* power */
  82                 val = (buf[0] << 16) + (buf[1] << 8) + buf[2];
  83         } else {
  84                 /* current, voltage */
  85                 val = (buf[0] << 4) + (buf[1] >> 4);
  86         }
  87 
  88         switch (reg) {
  89         case LTC2945_POWER_H:
  90         case LTC2945_MAX_POWER_H:
  91         case LTC2945_MIN_POWER_H:
  92         case LTC2945_MAX_POWER_THRES_H:
  93         case LTC2945_MIN_POWER_THRES_H:
  94                 /*
  95                  * Convert to uW by assuming current is measured with
  96                  * an 1mOhm sense resistor, similar to current
  97                  * measurements.
  98                  * Control register bit 0 selects if voltage at SENSE+/VDD
  99                  * or voltage at ADIN is used to measure power.
 100                  */
 101                 ret = regmap_read(regmap, LTC2945_CONTROL, &control);
 102                 if (ret < 0)
 103                         return ret;
 104                 if (control & CONTROL_MULT_SELECT) {
 105                         /* 25 mV * 25 uV = 0.625 uV resolution. */
 106                         val *= 625LL;
 107                 } else {
 108                         /* 0.5 mV * 25 uV = 0.0125 uV resolution. */
 109                         val = (val * 25LL) >> 1;
 110                 }
 111                 break;
 112         case LTC2945_VIN_H:
 113         case LTC2945_MAX_VIN_H:
 114         case LTC2945_MIN_VIN_H:
 115         case LTC2945_MAX_VIN_THRES_H:
 116         case LTC2945_MIN_VIN_THRES_H:
 117                 /* 25 mV resolution. Convert to mV. */
 118                 val *= 25;
 119                 break;
 120         case LTC2945_ADIN_H:
 121         case LTC2945_MAX_ADIN_H:
 122         case LTC2945_MIN_ADIN_THRES_H:
 123         case LTC2945_MAX_ADIN_THRES_H:
 124         case LTC2945_MIN_ADIN_H:
 125                 /* 0.5mV resolution. Convert to mV. */
 126                 val = val >> 1;
 127                 break;
 128         case LTC2945_SENSE_H:
 129         case LTC2945_MAX_SENSE_H:
 130         case LTC2945_MIN_SENSE_H:
 131         case LTC2945_MAX_SENSE_THRES_H:
 132         case LTC2945_MIN_SENSE_THRES_H:
 133                 /*
 134                  * 25 uV resolution. Convert to current as measured with
 135                  * an 1 mOhm sense resistor, in mA. If a different sense
 136                  * resistor is installed, calculate the actual current by
 137                  * dividing the reported current by the sense resistor value
 138                  * in mOhm.
 139                  */
 140                 val *= 25;
 141                 break;
 142         default:
 143                 return -EINVAL;
 144         }
 145         return val;
 146 }
 147 
 148 static int ltc2945_val_to_reg(struct device *dev, u8 reg,
 149                               unsigned long val)
 150 {
 151         struct regmap *regmap = dev_get_drvdata(dev);
 152         unsigned int control;
 153         int ret;
 154 
 155         switch (reg) {
 156         case LTC2945_POWER_H:
 157         case LTC2945_MAX_POWER_H:
 158         case LTC2945_MIN_POWER_H:
 159         case LTC2945_MAX_POWER_THRES_H:
 160         case LTC2945_MIN_POWER_THRES_H:
 161                 /*
 162                  * Convert to register value by assuming current is measured
 163                  * with an 1mOhm sense resistor, similar to current
 164                  * measurements.
 165                  * Control register bit 0 selects if voltage at SENSE+/VDD
 166                  * or voltage at ADIN is used to measure power, which in turn
 167                  * determines register calculations.
 168                  */
 169                 ret = regmap_read(regmap, LTC2945_CONTROL, &control);
 170                 if (ret < 0)
 171                         return ret;
 172                 if (control & CONTROL_MULT_SELECT) {
 173                         /* 25 mV * 25 uV = 0.625 uV resolution. */
 174                         val = DIV_ROUND_CLOSEST(val, 625);
 175                 } else {
 176                         /*
 177                          * 0.5 mV * 25 uV = 0.0125 uV resolution.
 178                          * Divide first to avoid overflow;
 179                          * accept loss of accuracy.
 180                          */
 181                         val = DIV_ROUND_CLOSEST(val, 25) * 2;
 182                 }
 183                 break;
 184         case LTC2945_VIN_H:
 185         case LTC2945_MAX_VIN_H:
 186         case LTC2945_MIN_VIN_H:
 187         case LTC2945_MAX_VIN_THRES_H:
 188         case LTC2945_MIN_VIN_THRES_H:
 189                 /* 25 mV resolution. */
 190                 val /= 25;
 191                 break;
 192         case LTC2945_ADIN_H:
 193         case LTC2945_MAX_ADIN_H:
 194         case LTC2945_MIN_ADIN_THRES_H:
 195         case LTC2945_MAX_ADIN_THRES_H:
 196         case LTC2945_MIN_ADIN_H:
 197                 /* 0.5mV resolution. */
 198                 val *= 2;
 199                 break;
 200         case LTC2945_SENSE_H:
 201         case LTC2945_MAX_SENSE_H:
 202         case LTC2945_MIN_SENSE_H:
 203         case LTC2945_MAX_SENSE_THRES_H:
 204         case LTC2945_MIN_SENSE_THRES_H:
 205                 /*
 206                  * 25 uV resolution. Convert to current as measured with
 207                  * an 1 mOhm sense resistor, in mA. If a different sense
 208                  * resistor is installed, calculate the actual current by
 209                  * dividing the reported current by the sense resistor value
 210                  * in mOhm.
 211                  */
 212                 val = DIV_ROUND_CLOSEST(val, 25);
 213                 break;
 214         default:
 215                 return -EINVAL;
 216         }
 217         return val;
 218 }
 219 
 220 static ssize_t ltc2945_value_show(struct device *dev,
 221                                   struct device_attribute *da, char *buf)
 222 {
 223         struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 224         long long value;
 225 
 226         value = ltc2945_reg_to_val(dev, attr->index);
 227         if (value < 0)
 228                 return value;
 229         return snprintf(buf, PAGE_SIZE, "%lld\n", value);
 230 }
 231 
 232 static ssize_t ltc2945_value_store(struct device *dev,
 233                                    struct device_attribute *da,
 234                                    const char *buf, size_t count)
 235 {
 236         struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 237         struct regmap *regmap = dev_get_drvdata(dev);
 238         u8 reg = attr->index;
 239         unsigned long val;
 240         u8 regbuf[3];
 241         int num_regs;
 242         int regval;
 243         int ret;
 244 
 245         ret = kstrtoul(buf, 10, &val);
 246         if (ret)
 247                 return ret;
 248 
 249         /* convert to register value, then clamp and write result */
 250         regval = ltc2945_val_to_reg(dev, reg, val);
 251         if (is_power_reg(reg)) {
 252                 regval = clamp_val(regval, 0, 0xffffff);
 253                 regbuf[0] = regval >> 16;
 254                 regbuf[1] = (regval >> 8) & 0xff;
 255                 regbuf[2] = regval;
 256                 num_regs = 3;
 257         } else {
 258                 regval = clamp_val(regval, 0, 0xfff) << 4;
 259                 regbuf[0] = regval >> 8;
 260                 regbuf[1] = regval & 0xff;
 261                 num_regs = 2;
 262         }
 263         ret = regmap_bulk_write(regmap, reg, regbuf, num_regs);
 264         return ret < 0 ? ret : count;
 265 }
 266 
 267 static ssize_t ltc2945_history_store(struct device *dev,
 268                                      struct device_attribute *da,
 269                                      const char *buf, size_t count)
 270 {
 271         struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 272         struct regmap *regmap = dev_get_drvdata(dev);
 273         u8 reg = attr->index;
 274         int num_regs = is_power_reg(reg) ? 3 : 2;
 275         u8 buf_min[3] = { 0xff, 0xff, 0xff };
 276         u8 buf_max[3] = { 0, 0, 0 };
 277         unsigned long val;
 278         int ret;
 279 
 280         ret = kstrtoul(buf, 10, &val);
 281         if (ret)
 282                 return ret;
 283         if (val != 1)
 284                 return -EINVAL;
 285 
 286         ret = regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE,
 287                                  CONTROL_TEST_MODE);
 288 
 289         /* Reset minimum */
 290         ret = regmap_bulk_write(regmap, reg, buf_min, num_regs);
 291         if (ret)
 292                 return ret;
 293 
 294         switch (reg) {
 295         case LTC2945_MIN_POWER_H:
 296                 reg = LTC2945_MAX_POWER_H;
 297                 break;
 298         case LTC2945_MIN_SENSE_H:
 299                 reg = LTC2945_MAX_SENSE_H;
 300                 break;
 301         case LTC2945_MIN_VIN_H:
 302                 reg = LTC2945_MAX_VIN_H;
 303                 break;
 304         case LTC2945_MIN_ADIN_H:
 305                 reg = LTC2945_MAX_ADIN_H;
 306                 break;
 307         default:
 308                 WARN_ONCE(1, "Bad register: 0x%x\n", reg);
 309                 return -EINVAL;
 310         }
 311         /* Reset maximum */
 312         ret = regmap_bulk_write(regmap, reg, buf_max, num_regs);
 313 
 314         /* Try resetting test mode even if there was an error */
 315         regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE, 0);
 316 
 317         return ret ? : count;
 318 }
 319 
 320 static ssize_t ltc2945_bool_show(struct device *dev,
 321                                  struct device_attribute *da, char *buf)
 322 {
 323         struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 324         struct regmap *regmap = dev_get_drvdata(dev);
 325         unsigned int fault;
 326         int ret;
 327 
 328         ret = regmap_read(regmap, LTC2945_FAULT, &fault);
 329         if (ret < 0)
 330                 return ret;
 331 
 332         fault &= attr->index;
 333         if (fault)              /* Clear reported faults in chip register */
 334                 regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0);
 335 
 336         return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
 337 }
 338 
 339 /* Input voltages */
 340 
 341 static SENSOR_DEVICE_ATTR_RO(in1_input, ltc2945_value, LTC2945_VIN_H);
 342 static SENSOR_DEVICE_ATTR_RW(in1_min, ltc2945_value, LTC2945_MIN_VIN_THRES_H);
 343 static SENSOR_DEVICE_ATTR_RW(in1_max, ltc2945_value, LTC2945_MAX_VIN_THRES_H);
 344 static SENSOR_DEVICE_ATTR_RO(in1_lowest, ltc2945_value, LTC2945_MIN_VIN_H);
 345 static SENSOR_DEVICE_ATTR_RO(in1_highest, ltc2945_value, LTC2945_MAX_VIN_H);
 346 static SENSOR_DEVICE_ATTR_WO(in1_reset_history, ltc2945_history,
 347                              LTC2945_MIN_VIN_H);
 348 
 349 static SENSOR_DEVICE_ATTR_RO(in2_input, ltc2945_value, LTC2945_ADIN_H);
 350 static SENSOR_DEVICE_ATTR_RW(in2_min, ltc2945_value, LTC2945_MIN_ADIN_THRES_H);
 351 static SENSOR_DEVICE_ATTR_RW(in2_max, ltc2945_value, LTC2945_MAX_ADIN_THRES_H);
 352 static SENSOR_DEVICE_ATTR_RO(in2_lowest, ltc2945_value, LTC2945_MIN_ADIN_H);
 353 static SENSOR_DEVICE_ATTR_RO(in2_highest, ltc2945_value, LTC2945_MAX_ADIN_H);
 354 static SENSOR_DEVICE_ATTR_WO(in2_reset_history, ltc2945_history,
 355                              LTC2945_MIN_ADIN_H);
 356 
 357 /* Voltage alarms */
 358 
 359 static SENSOR_DEVICE_ATTR_RO(in1_min_alarm, ltc2945_bool, FAULT_VIN_UV);
 360 static SENSOR_DEVICE_ATTR_RO(in1_max_alarm, ltc2945_bool, FAULT_VIN_OV);
 361 static SENSOR_DEVICE_ATTR_RO(in2_min_alarm, ltc2945_bool, FAULT_ADIN_UV);
 362 static SENSOR_DEVICE_ATTR_RO(in2_max_alarm, ltc2945_bool, FAULT_ADIN_OV);
 363 
 364 /* Currents (via sense resistor) */
 365 
 366 static SENSOR_DEVICE_ATTR_RO(curr1_input, ltc2945_value, LTC2945_SENSE_H);
 367 static SENSOR_DEVICE_ATTR_RW(curr1_min, ltc2945_value,
 368                              LTC2945_MIN_SENSE_THRES_H);
 369 static SENSOR_DEVICE_ATTR_RW(curr1_max, ltc2945_value,
 370                              LTC2945_MAX_SENSE_THRES_H);
 371 static SENSOR_DEVICE_ATTR_RO(curr1_lowest, ltc2945_value, LTC2945_MIN_SENSE_H);
 372 static SENSOR_DEVICE_ATTR_RO(curr1_highest, ltc2945_value,
 373                              LTC2945_MAX_SENSE_H);
 374 static SENSOR_DEVICE_ATTR_WO(curr1_reset_history, ltc2945_history,
 375                              LTC2945_MIN_SENSE_H);
 376 
 377 /* Current alarms */
 378 
 379 static SENSOR_DEVICE_ATTR_RO(curr1_min_alarm, ltc2945_bool, FAULT_SENSE_UV);
 380 static SENSOR_DEVICE_ATTR_RO(curr1_max_alarm, ltc2945_bool, FAULT_SENSE_OV);
 381 
 382 /* Power */
 383 
 384 static SENSOR_DEVICE_ATTR_RO(power1_input, ltc2945_value, LTC2945_POWER_H);
 385 static SENSOR_DEVICE_ATTR_RW(power1_min, ltc2945_value,
 386                              LTC2945_MIN_POWER_THRES_H);
 387 static SENSOR_DEVICE_ATTR_RW(power1_max, ltc2945_value,
 388                              LTC2945_MAX_POWER_THRES_H);
 389 static SENSOR_DEVICE_ATTR_RO(power1_input_lowest, ltc2945_value,
 390                              LTC2945_MIN_POWER_H);
 391 static SENSOR_DEVICE_ATTR_RO(power1_input_highest, ltc2945_value,
 392                              LTC2945_MAX_POWER_H);
 393 static SENSOR_DEVICE_ATTR_WO(power1_reset_history, ltc2945_history,
 394                              LTC2945_MIN_POWER_H);
 395 
 396 /* Power alarms */
 397 
 398 static SENSOR_DEVICE_ATTR_RO(power1_min_alarm, ltc2945_bool, FAULT_POWER_UV);
 399 static SENSOR_DEVICE_ATTR_RO(power1_max_alarm, ltc2945_bool, FAULT_POWER_OV);
 400 
 401 static struct attribute *ltc2945_attrs[] = {
 402         &sensor_dev_attr_in1_input.dev_attr.attr,
 403         &sensor_dev_attr_in1_min.dev_attr.attr,
 404         &sensor_dev_attr_in1_max.dev_attr.attr,
 405         &sensor_dev_attr_in1_lowest.dev_attr.attr,
 406         &sensor_dev_attr_in1_highest.dev_attr.attr,
 407         &sensor_dev_attr_in1_reset_history.dev_attr.attr,
 408         &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
 409         &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
 410 
 411         &sensor_dev_attr_in2_input.dev_attr.attr,
 412         &sensor_dev_attr_in2_min.dev_attr.attr,
 413         &sensor_dev_attr_in2_max.dev_attr.attr,
 414         &sensor_dev_attr_in2_lowest.dev_attr.attr,
 415         &sensor_dev_attr_in2_highest.dev_attr.attr,
 416         &sensor_dev_attr_in2_reset_history.dev_attr.attr,
 417         &sensor_dev_attr_in2_min_alarm.dev_attr.attr,
 418         &sensor_dev_attr_in2_max_alarm.dev_attr.attr,
 419 
 420         &sensor_dev_attr_curr1_input.dev_attr.attr,
 421         &sensor_dev_attr_curr1_min.dev_attr.attr,
 422         &sensor_dev_attr_curr1_max.dev_attr.attr,
 423         &sensor_dev_attr_curr1_lowest.dev_attr.attr,
 424         &sensor_dev_attr_curr1_highest.dev_attr.attr,
 425         &sensor_dev_attr_curr1_reset_history.dev_attr.attr,
 426         &sensor_dev_attr_curr1_min_alarm.dev_attr.attr,
 427         &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
 428 
 429         &sensor_dev_attr_power1_input.dev_attr.attr,
 430         &sensor_dev_attr_power1_min.dev_attr.attr,
 431         &sensor_dev_attr_power1_max.dev_attr.attr,
 432         &sensor_dev_attr_power1_input_lowest.dev_attr.attr,
 433         &sensor_dev_attr_power1_input_highest.dev_attr.attr,
 434         &sensor_dev_attr_power1_reset_history.dev_attr.attr,
 435         &sensor_dev_attr_power1_min_alarm.dev_attr.attr,
 436         &sensor_dev_attr_power1_max_alarm.dev_attr.attr,
 437 
 438         NULL,
 439 };
 440 ATTRIBUTE_GROUPS(ltc2945);
 441 
 442 static const struct regmap_config ltc2945_regmap_config = {
 443         .reg_bits = 8,
 444         .val_bits = 8,
 445         .max_register = LTC2945_MIN_ADIN_THRES_L,
 446 };
 447 
 448 static int ltc2945_probe(struct i2c_client *client,
 449                          const struct i2c_device_id *id)
 450 {
 451         struct device *dev = &client->dev;
 452         struct device *hwmon_dev;
 453         struct regmap *regmap;
 454 
 455         regmap = devm_regmap_init_i2c(client, &ltc2945_regmap_config);
 456         if (IS_ERR(regmap)) {
 457                 dev_err(dev, "failed to allocate register map\n");
 458                 return PTR_ERR(regmap);
 459         }
 460 
 461         /* Clear faults */
 462         regmap_write(regmap, LTC2945_FAULT, 0x00);
 463 
 464         hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
 465                                                            regmap,
 466                                                            ltc2945_groups);
 467         return PTR_ERR_OR_ZERO(hwmon_dev);
 468 }
 469 
 470 static const struct i2c_device_id ltc2945_id[] = {
 471         {"ltc2945", 0},
 472         { }
 473 };
 474 
 475 MODULE_DEVICE_TABLE(i2c, ltc2945_id);
 476 
 477 static struct i2c_driver ltc2945_driver = {
 478         .driver = {
 479                    .name = "ltc2945",
 480                    },
 481         .probe = ltc2945_probe,
 482         .id_table = ltc2945_id,
 483 };
 484 
 485 module_i2c_driver(ltc2945_driver);
 486 
 487 MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
 488 MODULE_DESCRIPTION("LTC2945 driver");
 489 MODULE_LICENSE("GPL");

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