drivers/power/supply/axp20x_usb_power.c

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

File Facts

System
Linux kernel
Corpus path
drivers/power/supply/axp20x_usb_power.c
Extension
.c
Size
29580 bytes
Lines
1083
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 axp_data {
	const struct power_supply_desc	*power_desc;
	const char * const		*irq_names;
	unsigned int			num_irq_names;
	const int			*curr_lim_table;
	int				curr_lim_table_size;
	struct reg_field		curr_lim_fld;
	struct reg_field		vbus_valid_bit;
	struct reg_field		vbus_mon_bit;
	struct reg_field		usb_bc_en_bit;
	struct reg_field		usb_bc_det_fld;
	struct reg_field		vbus_disable_bit;
	bool				vbus_needs_polling: 1;
	void (*axp20x_read_vbus)(struct work_struct *work);
	int (*axp20x_cfg_iio_chan)(struct platform_device *pdev,
				   struct axp20x_usb_power *power);
	int (*axp20x_cfg_adc_reg)(struct axp20x_usb_power *power);
};

struct axp20x_usb_power {
	struct device *dev;
	struct regmap *regmap;
	struct regmap_field *curr_lim_fld;
	struct regmap_field *vbus_valid_bit;
	struct regmap_field *vbus_mon_bit;
	struct regmap_field *usb_bc_en_bit;
	struct regmap_field *usb_bc_det_fld;
	struct regmap_field *vbus_disable_bit;
	struct power_supply *supply;
	const struct axp_data *axp_data;
	struct iio_channel *vbus_v;
	struct iio_channel *vbus_i;
	struct delayed_work vbus_detect;
	int max_input_cur;
	unsigned int old_status;
	unsigned int online;
	unsigned int num_irqs;
	unsigned int irqs[] __counted_by(num_irqs);
};

static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power)
{
	/*
	 * Polling is only necessary while VBUS is offline. While online, a
	 * present->absent transition implies an online->offline transition
	 * and will trigger the VBUS_REMOVAL IRQ.
	 */
	if (power->axp_data->vbus_needs_polling && !power->online)
		return true;

	return false;
}

static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
{
	struct axp20x_usb_power *power = devid;

	power_supply_changed(power->supply);

	mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);

	return IRQ_HANDLED;
}

static void axp20x_usb_power_poll_vbus(struct work_struct *work)
{
	struct axp20x_usb_power *power =
		container_of(work, struct axp20x_usb_power, vbus_detect.work);
	unsigned int val;
	int ret;

	ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val);
	if (ret)
		goto out;

	val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED);
	if (val != power->old_status)
		power_supply_changed(power->supply);

	if (power->usb_bc_en_bit && (val & AXP20X_PWR_STATUS_VBUS_PRESENT) !=
		(power->old_status & AXP20X_PWR_STATUS_VBUS_PRESENT)) {
		dev_dbg(power->dev, "Cable status changed, re-enabling USB BC");
		ret = regmap_field_write(power->usb_bc_en_bit, 1);
		if (ret)
			dev_err(power->dev, "failed to enable USB BC: errno %d",
				ret);
	}

	power->old_status = val;
	power->online = val & AXP20X_PWR_STATUS_VBUS_USED;

Annotation

Implementation Notes