drivers/hwmon/pmbus/mp9945.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/pmbus/mp9945.c
Extension
.c
Size
5541 bytes
Lines
244
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 mp9945_data {
	struct pmbus_driver_info info;
	enum mp9945_vout_mode vout_mode;
	int vid_resolution;
	int vid_offset;
};

#define to_mp9945_data(x) container_of(x, struct mp9945_data, info)

static int mp9945_read_vout(struct i2c_client *client, struct mp9945_data *data)
{
	int ret;

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

	ret &= GENMASK(11, 0);

	switch (data->vout_mode) {
	case MP9945_VOUT_MODE_VID:
		if (ret > 0)
			ret = (ret + data->vid_offset) * data->vid_resolution;
		break;
	case MP9945_VOUT_MODE_DIRECT:
		break;
	case MP9945_VOUT_MODE_LINEAR16:
		/* LSB: 1000 * 2^-9 (mV) */
		ret = DIV_ROUND_CLOSEST(ret * 125, 64);
		break;
	default:
		return -ENODEV;
	}

	return ret;
}

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

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

	switch (reg) {
	case PMBUS_VOUT_MODE:
		/*
		 * Override VOUT_MODE to DIRECT as the driver handles custom
		 * VOUT format conversions internally.
		 */
		return PB_VOUT_MODE_DIRECT;
	default:
		return -ENODATA;
	}
}

static int mp9945_read_word_data(struct i2c_client *client, int page, int phase,
				 int reg)
{
	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
	struct mp9945_data *data = to_mp9945_data(info);
	int ret;

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

	switch (reg) {
	case PMBUS_READ_VOUT:
		ret = mp9945_read_vout(client, data);
		break;
	case PMBUS_VOUT_OV_FAULT_LIMIT:
	case PMBUS_VOUT_UV_FAULT_LIMIT:
		ret = i2c_smbus_read_word_data(client, reg);
		if (ret < 0)
			return ret;

		/* LSB: 1.95 (mV) */
		ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * 39, 20);
		break;
	case PMBUS_VOUT_UV_WARN_LIMIT:
		ret = i2c_smbus_read_word_data(client, reg);
		if (ret < 0)
			return ret;

		ret &= GENMASK(9, 0);
		if (ret > 0)
			ret = (ret + data->vid_offset) * data->vid_resolution;
		break;

Annotation

Implementation Notes