drivers/hwmon/pmbus/mp2891.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/pmbus/mp2891.c
Extension
.c
Size
16669 bytes
Lines
601
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

struct mp2891_data {
	struct pmbus_driver_info info;
	int vout_scale[MP2891_PAGE_NUM];
	int iout_scale[MP2891_PAGE_NUM];
};

#define to_mp2891_data(x) container_of(x, struct mp2891_data, info)

/* Converts a LINEAR11 value to DIRECT format */
static u16 mp2891_reg2data_linear11(u16 word)
{
	s16 exponent;
	s32 mantissa;
	s64 val;

	exponent = ((s16)word) >> 11;
	mantissa = ((s16)((word & 0x7ff) << 5)) >> 5;
	val = mantissa;

	if (exponent >= 0)
		val <<= exponent;
	else
		val >>= -exponent;

	return val;
}

static int
mp2891_identify_vout_scale(struct i2c_client *client, struct pmbus_driver_info *info,
			   int page)
{
	struct mp2891_data *data = to_mp2891_data(info);
	int ret;

	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
	if (ret < 0)
		return ret;

	ret = i2c_smbus_read_word_data(client, MFR_VOUT_LOOP_CTRL);
	if (ret < 0)
		return ret;

	/*
	 * The output voltage is equal to the READ_VOUT(0x8B) register value multiplied
	 * by vout_scale.
	 * Obtain vout scale from the register MFR_VOUT_LOOP_CTRL, bits 15-14,bit 13.
	 * If MFR_VOUT_LOOP_CTRL[13] = 1, the vout scale is below:
	 * 2.5mV/LSB
	 * If MFR_VOUT_LOOP_CTRL[13] = 0, the vout scale is decided by
	 * MFR_VOUT_LOOP_CTRL[15:14]:
	 * 00b - 6.25mV/LSB, 01b - 5mV/LSB, 10b - 2mV/LSB, 11b - 1mV
	 */
	if (ret & GENMASK(13, 13)) {
		data->vout_scale[page] = 250;
	} else {
		ret = FIELD_GET(GENMASK(15, 14), ret);
		if (ret == 0)
			data->vout_scale[page] = 625;
		else if (ret == 1)
			data->vout_scale[page] = 500;
		else if (ret == 2)
			data->vout_scale[page] = 200;
		else
			data->vout_scale[page] = 100;
	}

	return 0;
}

static int
mp2891_identify_iout_scale(struct i2c_client *client, struct pmbus_driver_info *info,
			   int page)
{
	struct mp2891_data *data = to_mp2891_data(info);
	int ret;

	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
	if (ret < 0)
		return ret;

	ret = i2c_smbus_read_word_data(client, MFR_SVI3_IOUT_PRT);
	if (ret < 0)
		return ret;

	/*
	 * The output current is equal to the READ_IOUT(0x8C) register value
	 * multiplied by iout_scale.
	 * Obtain iout_scale from the register MFR_SVI3_IOUT_PRT[2:0].
	 * The value is selected as below:
	 * 000b - 1A/LSB, 001b - (1/32)A/LSB, 010b - (1/16)A/LSB,

Annotation

Implementation Notes