drivers/hwmon/max16065.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/max16065.c
Extension
.c
Size
19717 bytes
Lines
620
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 max16065_data {
	enum chips chip;
	struct i2c_client *client;
	const struct attribute_group *groups[4];
	struct mutex update_lock;
	bool valid;
	unsigned long last_updated; /* in jiffies */
	int num_adc;
	bool have_current;
	int curr_gain;
	/* limits are in mV */
	int limit[MAX16065_NUM_LIMIT][MAX16065_NUM_ADC];
	int range[MAX16065_NUM_ADC + 1];/* voltage range */
	int adc[MAX16065_NUM_ADC + 1];	/* adc values (raw) including csp_adc */
	int curr_sense;
	int fault[2];
};

static const int max16065_adc_range[] = { 5560, 2780, 1390, 0 };
static const int max16065_csp_adc_range[] = { 7000, 14000 };

/* ADC registers have 10 bit resolution. */
static inline int ADC_TO_MV(int adc, int range)
{
	return (adc * range) / 1024;
}

/*
 * Limit registers have 8 bit resolution and match upper 8 bits of ADC
 * registers.
 */
static inline int LIMIT_TO_MV(int limit, int range)
{
	return limit * range / 256;
}

static inline int MV_TO_LIMIT(unsigned long mv, int range)
{
	mv = clamp_val(mv, 0, ULONG_MAX / 256);
	return DIV_ROUND_CLOSEST(clamp_val(mv * 256, 0, range * 255), range);
}

static inline int ADC_TO_CURR(int adc, int gain)
{
	return adc * 1400000 / (gain * 255);
}

/*
 * max16065_read_adc()
 *
 * Read 16 bit value from <reg>, <reg+1>.
 * Upper 8 bits are in <reg>, lower 2 bits are in bits 7:6 of <reg+1>.
 */
static int max16065_read_adc(struct i2c_client *client, int reg)
{
	int rv;

	rv = i2c_smbus_read_word_swapped(client, reg);
	if (unlikely(rv < 0))
		return rv;
	return rv >> 6;
}

static struct max16065_data *max16065_update_device(struct device *dev)
{
	struct max16065_data *data = dev_get_drvdata(dev);
	struct i2c_client *client = data->client;

	mutex_lock(&data->update_lock);
	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
		int i;

		for (i = 0; i < data->num_adc; i++)
			WRITE_ONCE(data->adc[i],
				   max16065_read_adc(client, MAX16065_ADC(i)));

		if (data->have_current) {
			WRITE_ONCE(data->adc[MAX16065_NUM_ADC],
				   max16065_read_adc(client, MAX16065_CSP_ADC));
			WRITE_ONCE(data->curr_sense,
				   i2c_smbus_read_byte_data(client, MAX16065_CURR_SENSE));
		}

		for (i = 0; i < 2; i++)
			WRITE_ONCE(data->fault[i],
				   i2c_smbus_read_byte_data(client, MAX16065_FAULT(i)));

		/*
		 * MAX16067 and MAX16068 have separate undervoltage and
		 * overvoltage alarm bits. Squash them together.

Annotation

Implementation Notes