drivers/power/supply/gpio-charger.c

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

File Facts

System
Linux kernel
Corpus path
drivers/power/supply/gpio-charger.c
Extension
.c
Size
11504 bytes
Lines
425
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 gpio_mapping {
	u32 limit_ua;
	u32 gpiodata;
} __packed;

struct gpio_charger {
	struct device *dev;
	unsigned int irq;
	unsigned int charge_status_irq;
	bool wakeup_enabled;

	struct power_supply *charger;
	struct power_supply_desc charger_desc;
	struct gpio_desc *gpiod;
	struct gpio_desc *charge_status;

	struct gpio_descs *current_limit_gpios;
	struct gpio_mapping *current_limit_map;
	u32 current_limit_map_size;
	u32 charge_current_limit;
};

static irqreturn_t gpio_charger_irq(int irq, void *devid)
{
	struct power_supply *charger = devid;

	power_supply_changed(charger);

	return IRQ_HANDLED;
}

static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
{
	return power_supply_get_drvdata(psy);
}

static int set_charge_current_limit(struct gpio_charger *gpio_charger, int val)
{
	struct gpio_mapping mapping;
	int ndescs = gpio_charger->current_limit_gpios->ndescs;
	struct gpio_desc **gpios = gpio_charger->current_limit_gpios->desc;
	int i;

	if (!gpio_charger->current_limit_map_size)
		return -EINVAL;

	for (i = 0; i < gpio_charger->current_limit_map_size; i++) {
		if (gpio_charger->current_limit_map[i].limit_ua <= val)
			break;
	}

	/*
	 * If a valid charge current limit isn't found, default to smallest
	 * current limitation for safety reasons.
	 */
	if (i >= gpio_charger->current_limit_map_size)
		i = gpio_charger->current_limit_map_size - 1;

	mapping = gpio_charger->current_limit_map[i];

	for (i = 0; i < ndescs; i++) {
		bool val = (mapping.gpiodata >> i) & 1;

		gpiod_set_value_cansleep(gpios[ndescs - i - 1], val);
	}

	gpio_charger->charge_current_limit = mapping.limit_ua;

	dev_dbg(gpio_charger->dev, "set charge current limit to %d (requested: %d)\n",
		gpio_charger->charge_current_limit, val);

	return 0;
}

static int gpio_charger_get_property(struct power_supply *psy,
		enum power_supply_property psp, union power_supply_propval *val)
{
	struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);

	switch (psp) {
	case POWER_SUPPLY_PROP_ONLINE:
		val->intval = gpiod_get_value_cansleep(gpio_charger->gpiod);
		break;
	case POWER_SUPPLY_PROP_STATUS:
		if (gpiod_get_value_cansleep(gpio_charger->charge_status))
			val->intval = POWER_SUPPLY_STATUS_CHARGING;
		else
			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
		break;
	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:

Annotation

Implementation Notes