drivers/power/supply/intel_dc_ti_battery.c

Source file repositories/reference/linux-study-clean/drivers/power/supply/intel_dc_ti_battery.c

File Facts

System
Linux kernel
Corpus path
drivers/power/supply/intel_dc_ti_battery.c
Extension
.c
Size
11618 bytes
Lines
392
Domain
Driver Families
Bucket
drivers/power
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 dc_ti_battery_chip {
	/* Must be the first member see adc-battery-helper documentation */
	struct adc_battery_helper helper;
	struct device *dev;
	struct regmap *regmap;
	struct iio_channel *vbat_channel;
	struct power_supply *psy;
	int cc_gain;
	int cc_offset;
};

static int dc_ti_battery_get_voltage_and_current_now(struct power_supply *psy, int *volt, int *curr)
{
	struct dc_ti_battery_chip *chip = power_supply_get_drvdata(psy);
	ktime_t ktime;
	s64 sleep_usec;
	unsigned int reg_val;
	s32 acc, smpl_ctr;
	int ret;

	/*
	 * Enable coulomb-counter before reading Vbat from ADC, so that the CC
	 * samples are from the same time period as the Vbat reading.
	 */
	ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG,
			   CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN | CC_CNTL_CC_CTR_EN);
	if (ret)
		goto out_err;

	ktime = ktime_get();

	/* Read Vbat, convert IIO mV to power-supply ųV */
	ret = iio_read_channel_processed_scale(chip->vbat_channel, volt, 1000);
	if (ret < 0)
		goto out_err;

	ktime = ktime_sub(ktime_get(), ktime);

	/* Sleep at least 3 sample-times + slack to get 3+ CC samples */
	sleep_usec = 3 * SMPL_INTVL_US + SLEEP_SLACK_US - ktime_to_us(ktime);
	if (sleep_usec > 0 && sleep_usec < 1000000)
		usleep_range(sleep_usec, sleep_usec + SLEEP_SLACK_US);

	/*
	 * The PMIC latches the coulomb- and sample-counters upon reading the
	 * CC_ACC0 register. Reading multiple registers at once is not supported.
	 *
	 * Step 1: Read CC_ACC0 - CC_ACC3
	 */
	ret = regmap_read(chip->regmap, DC_TI_CC_ACC0_REG, &reg_val);
	if (ret)
		goto out_err;

	acc = reg_val;

	ret = regmap_read(chip->regmap, DC_TI_CC_ACC1_REG, &reg_val);
	if (ret)
		goto out_err;

	acc |= reg_val << 8;

	ret = regmap_read(chip->regmap, DC_TI_CC_ACC2_REG, &reg_val);
	if (ret)
		goto out_err;

	acc |= reg_val << 16;

	ret = regmap_read(chip->regmap, DC_TI_CC_ACC3_REG, &reg_val);
	if (ret)
		goto out_err;

	acc |= reg_val << 24;

	/* Step 2: Read SMPL_CTR0 - SMPL_CTR2 */
	ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR0_REG, &reg_val);
	if (ret)
		goto out_err;

	smpl_ctr = reg_val;

	ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR1_REG, &reg_val);
	if (ret)
		goto out_err;

	smpl_ctr |= reg_val << 8;

	ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR2_REG, &reg_val);
	if (ret)
		goto out_err;

Annotation

Implementation Notes