drivers/hwmon/tsc1641.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/tsc1641.c
Extension
.c
Size
18622 bytes
Lines
749
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 tsc1641_data {
	long rshunt_uohm;
	long current_lsb_ua;
	struct regmap *regmap;
};

/*
 * Upper limit due to chip 16-bit shunt register, lower limit to
 * prevent current and power registers overflow
 */
static inline int tsc1641_validate_shunt(u32 val)
{
	if (val < TSC1641_RSHUNT_MIN_UOHM || val > TSC1641_RSHUNT_MAX_UOHM)
		return -EINVAL;
	return 0;
}

static int tsc1641_set_shunt(struct tsc1641_data *data, u32 val)
{
	struct regmap *regmap = data->regmap;
	long rshunt_reg;

	/* RSHUNT register LSB is 10uOhm so need to divide further */
	rshunt_reg = DIV_ROUND_CLOSEST(val, TSC1641_RSHUNT_LSB_UOHM);
	/*
	 * Clamp value to the nearest multiple of TSC1641_RSHUNT_LSB_UOHM
	 * in case shunt value provided was not a multiple
	 */
	data->rshunt_uohm = rshunt_reg * TSC1641_RSHUNT_LSB_UOHM;
	data->current_lsb_ua = DIV_ROUND_CLOSEST(TSC1641_VSHUNT_LSB_NVOLT * 1000,
						 data->rshunt_uohm);

	return regmap_write(regmap, TSC1641_RSHUNT, rshunt_reg);
}

/*
 * Conversion times in uS, value in CONFIG[CT3:CT0] corresponds to index in this array
 * See "Table 14. CT3 to CT0: conversion time" in:
 * https://www.st.com/resource/en/datasheet/tsc1641.pdf
 */
static const int tsc1641_conv_times[] = { 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 };

static int tsc1641_reg_to_upd_interval(u16 config)
{
	int idx = FIELD_GET(TSC1641_CONV_TIME_MASK, config);

	idx = clamp_val(idx, 0, ARRAY_SIZE(tsc1641_conv_times) - 1);
	int conv_time = tsc1641_conv_times[idx];

	/* Don't support sub-millisecond update interval as it's not supported in hwmon */
	conv_time = max(conv_time, TSC1641_MIN_UPDATE_INTERVAL);
	/* Return nearest value in milliseconds */
	return DIV_ROUND_CLOSEST(conv_time, 1000);
}

static u16 tsc1641_upd_interval_to_reg(long interval)
{
	/* Supported interval is 1ms - 33ms */
	interval = clamp_val(interval, 1, 33);

	int conv = interval * 1000;
	int conv_bits = find_closest(conv, tsc1641_conv_times,
				     ARRAY_SIZE(tsc1641_conv_times));

	return FIELD_PREP(TSC1641_CONV_TIME_MASK, conv_bits);
}

static int tsc1641_chip_write(struct device *dev, u32 attr, long val)
{
	struct tsc1641_data *data = dev_get_drvdata(dev);

	switch (attr) {
	case hwmon_chip_update_interval:
		return regmap_update_bits(data->regmap, TSC1641_CONFIG,
					  TSC1641_CONV_TIME_MASK,
					  tsc1641_upd_interval_to_reg(val));
	default:
		return -EOPNOTSUPP;
	}
}

static int tsc1641_chip_read(struct device *dev, u32 attr, long *val)
{
	struct tsc1641_data *data = dev_get_drvdata(dev);
	u32 regval;
	int ret;

	switch (attr) {
	case hwmon_chip_update_interval:
		ret = regmap_read(data->regmap, TSC1641_CONFIG, &regval);

Annotation

Implementation Notes