drivers/power/supply/macsmc-power.c

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

File Facts

System
Linux kernel
Corpus path
drivers/power/supply/macsmc-power.c
Extension
.c
Size
25950 bytes
Lines
856
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 macsmc_power {
	struct device *dev;
	struct apple_smc *smc;

	struct power_supply_desc ac_desc;
	struct power_supply_desc batt_desc;

	struct power_supply *batt;
	struct power_supply *ac;

	char model_name[MAX_STRING_LENGTH];
	char serial_number[MAX_STRING_LENGTH];
	char mfg_date[MAX_STRING_LENGTH];

	/* Supported feature flags based on SMC key presence */
	bool has_chwa; /* Charge limit (Modern firmware) */
	bool has_chls; /* Charge limit (Older firmware) */
	bool has_ch0i; /* Force discharge (Older firmware) */
	bool has_ch0c; /* Inhibit charge (Older firmware) */
	bool has_chte; /* Inhibit charge (Modern firmware) */

	u8 num_cells;
	int nominal_voltage_mv;

	struct notifier_block nb;
	struct work_struct critical_work;
	bool emergency_shutdown_triggered;
	bool orderly_shutdown_triggered;
};

static int macsmc_battery_get_status(struct macsmc_power *power)
{
	u64 nocharge_flags;
	u32 nopower_flags;
	u16 ac_current;
	int charge_limit = 0;
	bool limited = false;
	bool flag;
	int ret;

	/*
	 * B0AV (Voltage) is fundamental. If we can't read it, we assume the
	 * battery is gone. CHCE (Hardware charger present) / CHCC (Hardware
	 * charger capable) are fundamental status flags.
	 * BSFC (System full charge) / CHSC (System charging) are fundamental
	 * status flags.
	 */

	/* Check if power input is inhibited (e.g. BMS balancing cycle) */
	ret = apple_smc_read_u32(power->smc, SMC_KEY(CH0R), &nopower_flags);
	if (!ret && (nopower_flags & CH0R_LOWER_FLAGS & ~CH0R_BMS_BUSY))
		return POWER_SUPPLY_STATUS_DISCHARGING;

	/* Check if charger is present */
	ret = apple_smc_read_flag(power->smc, SMC_KEY(CHCE), &flag);
	if (ret < 0)
		return ret;
	if (!flag)
		return POWER_SUPPLY_STATUS_DISCHARGING;

	/* Check if AC is charge capable */
	ret = apple_smc_read_flag(power->smc, SMC_KEY(CHCC), &flag);
	if (ret < 0)
		return ret;
	if (!flag)
		return POWER_SUPPLY_STATUS_DISCHARGING;

	/* Check if AC input limit is too low */
	ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-i), &ac_current);
	if (!ret && ac_current < 100)
		return POWER_SUPPLY_STATUS_DISCHARGING;

	/* Check if battery is full */
	ret = apple_smc_read_flag(power->smc, SMC_KEY(BSFC), &flag);
	if (ret < 0)
		return ret;
	if (flag)
		return POWER_SUPPLY_STATUS_FULL;

	/* Check for user-defined charge limits */
	if (power->has_chls) {
		u16 vu16;

		ret = apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16);
		if (ret == 0 && (vu16 & 0xff) >= CHLS_MIN_END_THRESHOLD)
			charge_limit = (vu16 & 0xff) - CHWA_CHLS_FIXED_START_OFFSET;
	} else if (power->has_chwa) {
		ret = apple_smc_read_flag(power->smc, SMC_KEY(CHWA), &flag);
		if (ret == 0 && flag)
			charge_limit = CHWA_FIXED_END_THRESHOLD - CHWA_CHLS_FIXED_START_OFFSET;

Annotation

Implementation Notes