drivers/power/supply/twl6030_charger.c

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

File Facts

System
Linux kernel
Corpus path
drivers/power/supply/twl6030_charger.c
Extension
.c
Size
16262 bytes
Lines
582
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 twl6030_charger_info {
	struct device		*dev;
	struct power_supply	*usb;
	struct power_supply_battery_info *binfo;
	struct work_struct	work;
	int			irq_chg;
	int			input_current_limit;
	struct iio_channel	*channel_vusb;
	struct delayed_work	charger_monitor;
	bool			extended_current_range;
};

struct twl6030_charger_chip_data {
	bool extended_current_range;
};

static int twl6030_charger_read(u8 reg, u8 *val)
{
	return twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, val, reg);
}

static int twl6030_charger_write(u8 reg, u8 val)
{
	return twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, val, reg);
}

static int twl6030_config_cinlimit_reg(struct twl6030_charger_info *charger,
				       unsigned int ua)
{
	if (ua >= 50000 && ua <= 750000) {
		ua = (ua - 50000) / 50000;
	} else if ((ua > 750000) && (ua <= 1500000) && charger->extended_current_range) {
		ua = ((ua % 100000) ? 0x30 : 0x20) + ((ua - 100000) / 100000);
	} else {
		if (ua < 50000) {
			dev_err(charger->dev, "invalid input current limit\n");
			return -EINVAL;
		}
		/* This is no current limit */
		ua = 0x0F;
	}

	return twl6030_charger_write(CHARGERUSB_CINLIMIT, ua);
}

/*
 * rewriting all stuff here, resets to extremely conservative defaults were
 * seen under some circumstances, like charge voltage to 3.5V
 */
static int twl6030_enable_usb(struct twl6030_charger_info *charger)
{
	int ret;

	ret = twl6030_charger_write(CHARGERUSB_VICHRG,
				    UA_TO_VICHRG(charger->binfo->constant_charge_current_max_ua));
	if (ret < 0)
		return ret;

	ret = twl6030_charger_write(CONTROLLER_WDG, 0xff);
	if (ret < 0)
		return ret;

	charger->input_current_limit = 500000;
	ret = twl6030_config_cinlimit_reg(charger, charger->input_current_limit);
	if (ret < 0)
		return ret;

	ret = twl6030_charger_write(CHARGERUSB_CINLIMIT, CHARGERUSB_CIN_LIMIT_500);
	if (ret < 0)
		return ret;

	ret = twl6030_charger_write(CHARGERUSB_VOREG,
				    UV_TO_VOREG(charger->binfo->constant_charge_voltage_max_uv));
	if (ret < 0)
		return ret;

	ret = twl6030_charger_write(CHARGERUSB_CTRL1, TERM);
	if (ret < 0)
		return ret;

	if (charger->binfo->charge_term_current_ua != -EINVAL) {
		ret = twl6030_charger_write(CHARGERUSB_CTRL2,
					    UA_TO_VITERM(charger->binfo->charge_term_current_ua));
		if (ret < 0)
			return ret;
	}

	return twl6030_charger_write(CONTROLLER_CTRL1, CONTROLLER_CTRL1_EN_CHARGER);
}

Annotation

Implementation Notes