drivers/hwmon/pmbus/ina233.c

Source file repositories/reference/linux-study-clean/drivers/hwmon/pmbus/ina233.c

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/pmbus/ina233.c
Extension
.c
Size
5412 bytes
Lines
197
Domain
Driver Families
Bucket
drivers/hwmon
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// 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);
		if (ret < 0)
			return ret;

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

static int ina233_probe(struct i2c_client *client)
{
	struct device *dev = &client->dev;
	const char *propname;
	int ret, m, R;
	u32 rshunt;

Annotation

Implementation Notes