Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/hwmon/pmbus/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 5 kB image not shown  

Quelle  ina233.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Hardware monitoring driver for ina233
 *
 * Copyright (c) 2025 Leo Yang
 */


#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "pmbus.h"

#define MFR_READ_VSHUNT 0xd1
#define MFR_CALIBRATION 0xd4

#define INA233_MAX_CURRENT_DEFAULT 32768000 /* uA */
#define INA233_RSHUNT_DEFAULT  2000 /* uOhm */

#define MAX_M_VAL 32767

static void calculate_coef(int *m, int *R, u32 current_lsb, int power_coef)
{
 u64 scaled_m;
 int scale_factor = 0;
 int scale_coef = 1;

 /*
 * 1000000 from Current_LSB A->uA .
 * scale_coef is for scaling up to minimize rounding errors,
 * If there is no decimal information, no need to scale.
 */

 if (1000000 % current_lsb) {
  /* Scaling to keep integer precision */
  scale_factor = -3;
  scale_coef = 1000;
 }

 /*
 * Unit Conversion (Current_LSB A->uA) and use scaling(scale_factor)
 * to keep integer precision.
 * Formulae referenced from spec.
 */

 scaled_m = div64_u64(1000000 * scale_coef, (u64)current_lsb * power_coef);

 /* Maximize while keeping it bounded.*/
 while (scaled_m > MAX_M_VAL) {
  scaled_m = div_u64(scaled_m, 10);
  scale_factor++;
 }
 /* Scale up only if fractional part exists. */
 while (scaled_m * 10 < MAX_M_VAL && scale_coef != 1) {
  scaled_m *= 10;
  scale_factor--;
 }

 *m = scaled_m;
 *R = scale_factor;
}

static int ina233_read_word_data(struct i2c_client *client, int page,
     int phase, int reg)
{
 int ret;

 switch (reg) {
 case PMBUS_VIRT_READ_VMON:
  ret = pmbus_read_word_data(client, 0, 0xff, MFR_READ_VSHUNT);

  /* Adjust returned value to match VIN coefficients */
  /* VIN: 1.25 mV VSHUNT: 2.5 uV LSB */
  ret = DIV_ROUND_CLOSEST(ret * 25, 12500);
  break;
 default:
  ret = -ENODATA;
  break;
 }
 return ret;
}

static int ina233_probe(struct i2c_client *client)
{
 struct device *dev = &client->dev;
 int ret, m, R;
 u32 rshunt;
 u32 max_current;
 u32 current_lsb;
 u16 calibration;
 struct pmbus_driver_info *info;

 info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info),
       GFP_KERNEL);
 if (!info)
  return -ENOMEM;

 info->pages = 1;
 info->format[PSC_VOLTAGE_IN] = direct;
 info->format[PSC_VOLTAGE_OUT] = direct;
 info->format[PSC_CURRENT_OUT] = direct;
 info->format[PSC_POWER] = direct;
 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_INPUT
  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
  | PMBUS_HAVE_POUT
  | PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
 info->m[PSC_VOLTAGE_IN] = 8;
 info->R[PSC_VOLTAGE_IN] = 2;
 info->m[PSC_VOLTAGE_OUT] = 8;
 info->R[PSC_VOLTAGE_OUT] = 2;
 info->read_word_data = ina233_read_word_data;

 /* If INA233 skips current/power, shunt-resistor and current-lsb aren't needed. */
 /* read rshunt value (uOhm) */
 ret = device_property_read_u32(dev, "shunt-resistor", &rshunt);
 if (ret) {
  if (ret != -EINVAL)
   return dev_err_probe(dev, ret, "Shunt resistor property read fail.\n");
  rshunt = INA233_RSHUNT_DEFAULT;
 }
 if (!rshunt)
  return dev_err_probe(dev, -EINVAL,
         "Shunt resistor cannot be zero.\n");

 /* read Maximum expected current value (uA) */
 ret = device_property_read_u32(dev, "ti,maximum-expected-current-microamp", &max_current);
 if (ret) {
  if (ret != -EINVAL)
   return dev_err_probe(dev, ret,
          "Maximum expected current property read fail.\n");
  max_current = INA233_MAX_CURRENT_DEFAULT;
 }
 if (max_current < 32768)
  return dev_err_probe(dev, -EINVAL,
         "Maximum expected current cannot less then 32768.\n");

 /* Calculate Current_LSB according to the spec formula */
 current_lsb = max_current / 32768;

 /* calculate current coefficient */
 calculate_coef(&m, &R, current_lsb, 1);
 info->m[PSC_CURRENT_OUT] = m;
 info->R[PSC_CURRENT_OUT] = R;

 /* calculate power coefficient */
 calculate_coef(&m, &R, current_lsb, 25);
 info->m[PSC_POWER] = m;
 info->R[PSC_POWER] = R;

 /* write MFR_CALIBRATION register, Apply formula from spec with unit scaling. */
 calibration = div64_u64(5120000000ULL, (u64)rshunt * current_lsb);
 if (calibration > 0x7FFF)
  return dev_err_probe(dev, -EINVAL,
         "Product of Current_LSB %u and shunt resistor %u too small, MFR_CALIBRATION reg exceeds 0x7FFF.\n",
         current_lsb, rshunt);
 ret = i2c_smbus_write_word_data(client, MFR_CALIBRATION, calibration);
 if (ret < 0)
  return dev_err_probe(dev, ret, "Unable to write calibration.\n");

 dev_dbg(dev, "power monitor %s (Rshunt = %u uOhm, Current_LSB = %u uA/bit)\n",
  client->name, rshunt, current_lsb);

 return pmbus_do_probe(client, info);
}

static const struct i2c_device_id ina233_id[] = {
 {"ina233", 0},
 {}
};
MODULE_DEVICE_TABLE(i2c, ina233_id);

static const struct of_device_id __maybe_unused ina233_of_match[] = {
 { .compatible = "ti,ina233" },
 {}
};
MODULE_DEVICE_TABLE(of, ina233_of_match);

static struct i2c_driver ina233_driver = {
 .driver = {
     .name = "ina233",
     .of_match_table = of_match_ptr(ina233_of_match),
 },
 .probe = ina233_probe,
 .id_table = ina233_id,
};

module_i2c_driver(ina233_driver);

MODULE_AUTHOR("Leo Yang ");
MODULE_DESCRIPTION("PMBus driver for INA233 and compatible chips");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("PMBUS");

Messung V0.5
C=96 H=94 G=94

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.