drivers/power/supply/ug3105_battery.c

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

File Facts

System
Linux kernel
Corpus path
drivers/power/supply/ug3105_battery.c
Extension
.c
Size
6481 bytes
Lines
218
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 ug3105_chip {
	/* Must be the first member see adc-battery-helper documentation */
	struct adc_battery_helper helper;
	struct i2c_client *client;
	struct power_supply *psy;
	int uv_per_unit;
	int ua_per_unit;
};

static int ug3105_read_word(struct i2c_client *client, u8 reg)
{
	int val;

	val = i2c_smbus_read_word_data(client, reg);
	if (val < 0)
		dev_err(&client->dev, "Error reading reg 0x%02x\n", reg);

	return val;
}

static int ug3105_get_voltage_and_current_now(struct power_supply *psy, int *volt, int *curr)
{
	struct ug3105_chip *chip = power_supply_get_drvdata(psy);
	int ret;

	ret = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT);
	if (ret < 0)
		return ret;

	*volt = ret * chip->uv_per_unit;

	ret = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR);
	if (ret < 0)
		return ret;

	*curr = (s16)ret * chip->ua_per_unit;
	return 0;
}

static const struct power_supply_desc ug3105_psy_desc = {
	.name		= "ug3105_battery",
	.type		= POWER_SUPPLY_TYPE_BATTERY,
	.get_property	= adc_battery_helper_get_property,
	.external_power_changed	= adc_battery_helper_external_power_changed,
	.properties	= adc_battery_helper_properties,
	.num_properties	= ADC_HELPER_NUM_PROPERTIES,
};

static void ug3105_start(struct i2c_client *client)
{
	i2c_smbus_write_byte_data(client, UG3105_REG_MODE, UG3105_MODE_RUN);
	i2c_smbus_write_byte_data(client, UG3105_REG_CTRL1, UG3105_CTRL1_RESET_COULOMB_CNT);
}

static void ug3105_stop(struct i2c_client *client)
{
	i2c_smbus_write_byte_data(client, UG3105_REG_MODE, UG3105_MODE_STANDBY);
}

static int ug3105_probe(struct i2c_client *client)
{
	struct power_supply_config psy_cfg = {};
	struct device *dev = &client->dev;
	u32 curr_sense_res_uohm = 10000;
	struct ug3105_chip *chip;
	int ret;

	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
	if (!chip)
		return -ENOMEM;

	chip->client = client;

	ug3105_start(client);

	device_property_read_u32(dev, "upisemi,rsns-microohm", &curr_sense_res_uohm);

	/*
	 * DAC maximum is 4.5V divided by 65536 steps + an unknown factor of 10
	 * coming from somewhere for some reason (verified with a volt-meter).
	 */
	chip->uv_per_unit = 45000000 / 65536;
	/* Datasheet says 8.1 uV per unit for the current ADC */
	chip->ua_per_unit = 8100000 / curr_sense_res_uohm;

	psy_cfg.drv_data = chip;
	chip->psy = devm_power_supply_register(dev, &ug3105_psy_desc, &psy_cfg);
	if (IS_ERR(chip->psy)) {
		ret = PTR_ERR(chip->psy);
		goto stop;

Annotation

Implementation Notes