Skip to content

Commit 173d102

Browse files
marcanjannau
authored andcommitted
power: supply: macsmc_power: Add a debug mode to print power usage
power: supply: macsmc_power: Log power data on button presses This helps catch s2idle power stats, since we get early data when the system resumes due to a power button press. Signed-off-by: Hector Martin <marcan@marcan.st>
1 parent 7d65ee4 commit 173d102

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

drivers/power/supply/macsmc-power.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,25 @@ struct macsmc_power {
5050

5151
struct work_struct critical_work;
5252
bool shutdown_started;
53+
54+
struct delayed_work dbg_log_work;
55+
};
56+
57+
static int macsmc_log_power_set(const char *val, const struct kernel_param *kp);
58+
59+
static const struct kernel_param_ops macsmc_log_power_ops = {
60+
.set = macsmc_log_power_set,
61+
.get = param_get_bool,
5362
};
5463

64+
static bool log_power = false;
65+
module_param_cb(log_power, &macsmc_log_power_ops, &log_power, 0644);
66+
MODULE_PARM_DESC(log_power, "Periodically log power consumption for debugging");
67+
68+
#define POWER_LOG_INTERVAL (HZ)
69+
70+
static struct macsmc_power *g_power;
71+
5572
#define CHNC_BATTERY_FULL BIT(0)
5673
#define CHNC_NO_CHARGER BIT(7)
5774
#define CHNC_NOCHG_CH0C BIT(14)
@@ -82,6 +99,88 @@ struct macsmc_power {
8299
#define CHWA_FIXED_END_THRESHOLD 80
83100
#define CHWA_PROP_WRITE_THRESHOLD 95
84101

102+
#define FLT_EXP_BIAS 127
103+
#define FLT_EXP_MASK GENMASK(30, 23)
104+
#define FLT_MANT_BIAS 23
105+
#define FLT_MANT_MASK GENMASK(22, 0)
106+
#define FLT_SIGN_MASK BIT(31)
107+
/*
108+
* Many sensors report their data as IEEE-754 floats. No other SMC function uses
109+
* them.
110+
*/
111+
static int apple_smc_read_f32_scaled(struct apple_smc *smc, smc_key key,
112+
int *p, int scale)
113+
{
114+
u32 fval;
115+
u64 val;
116+
int ret, exp;
117+
118+
BUILD_BUG_ON(scale <= 0);
119+
120+
ret = apple_smc_read_u32(smc, key, &fval);
121+
if (ret < 0)
122+
return ret;
123+
124+
val = ((u64)((fval & FLT_MANT_MASK) | BIT(23)));
125+
exp = ((fval >> 23) & 0xff) - FLT_EXP_BIAS - FLT_MANT_BIAS;
126+
val *= scale;
127+
128+
if (exp > 63)
129+
val = U64_MAX;
130+
else if (exp < -63)
131+
val = 0;
132+
else if (exp < 0)
133+
val >>= -exp;
134+
else if (exp != 0 && (val & ~((1UL << (64 - exp)) - 1))) /* overflow */
135+
val = U64_MAX;
136+
else
137+
val <<= exp;
138+
139+
if (fval & FLT_SIGN_MASK) {
140+
if (val > (-(s64)INT_MIN))
141+
*p = INT_MIN;
142+
else
143+
*p = -val;
144+
} else {
145+
if (val > INT_MAX)
146+
*p = INT_MAX;
147+
else
148+
*p = val;
149+
}
150+
151+
return 0;
152+
}
153+
154+
static void macsmc_do_dbg(struct macsmc_power *power)
155+
{
156+
int p_in = 0, p_sys = 0, p_3v8 = 0, p_mpmu = 0, p_spmu = 0, p_clvr = 0, p_cpu = 0;
157+
s32 p_bat = 0;
158+
s16 t_full = 0, t_empty = 0;
159+
u8 charge = 0;
160+
161+
apple_smc_read_f32_scaled(power->smc, SMC_KEY(PDTR), &p_in, 1000);
162+
apple_smc_read_f32_scaled(power->smc, SMC_KEY(PSTR), &p_sys, 1000);
163+
apple_smc_read_f32_scaled(power->smc, SMC_KEY(PMVR), &p_3v8, 1000);
164+
apple_smc_read_f32_scaled(power->smc, SMC_KEY(PHPC), &p_cpu, 1000);
165+
apple_smc_read_f32_scaled(power->smc, SMC_KEY(PSVR), &p_clvr, 1000);
166+
apple_smc_read_f32_scaled(power->smc, SMC_KEY(PPMC), &p_mpmu, 1000);
167+
apple_smc_read_f32_scaled(power->smc, SMC_KEY(PPSC), &p_spmu, 1000);
168+
apple_smc_read_s32(power->smc, SMC_KEY(B0AP), &p_bat);
169+
apple_smc_read_s16(power->smc, SMC_KEY(B0TE), &t_empty);
170+
apple_smc_read_s16(power->smc, SMC_KEY(B0TF), &t_full);
171+
apple_smc_read_u8(power->smc, SMC_KEY(BUIC), &charge);
172+
173+
#define FD3(x) ((x) / 1000), abs((x) % 1000)
174+
dev_info(power->dev,
175+
"In %2d.%03dW Sys %2d.%03dW 3V8 %2d.%03dW MPMU %2d.%03dW SPMU %2d.%03dW "
176+
"CLVR %2d.%03dW CPU %2d.%03dW Batt %2d.%03dW %d%% T%s %dm\n",
177+
FD3(p_in), FD3(p_sys), FD3(p_3v8), FD3(p_mpmu), FD3(p_spmu), FD3(p_clvr),
178+
FD3(p_cpu), FD3(p_bat), charge,
179+
t_full >= 0 ? "full" : "empty",
180+
t_full >= 0 ? t_full : t_empty);
181+
#undef FD3
182+
}
183+
85184
static int macsmc_battery_get_status(struct macsmc_power *power)
86185
{
87186
u64 nocharge_flags;
@@ -610,6 +709,30 @@ static const struct power_supply_desc macsmc_ac_desc = {
610709
.num_properties = ARRAY_SIZE(macsmc_ac_props),
611710
};
612711

712+
static int macsmc_log_power_set(const char *val, const struct kernel_param *kp)
713+
{
714+
int ret = param_set_bool(val, kp);
715+
716+
if (ret < 0)
717+
return ret;
718+
719+
if (log_power && g_power)
720+
schedule_delayed_work(&g_power->dbg_log_work, 0);
721+
722+
return 0;
723+
}
724+
725+
static void macsmc_dbg_work(struct work_struct *wrk)
726+
{
727+
struct macsmc_power *power = container_of(to_delayed_work(wrk),
728+
struct macsmc_power, dbg_log_work);
729+
730+
macsmc_do_dbg(power);
731+
732+
if (log_power)
733+
schedule_delayed_work(&power->dbg_log_work, POWER_LOG_INTERVAL);
734+
}
735+
613736
static void macsmc_power_critical_work(struct work_struct *wrk)
614737
{
615738
struct macsmc_power *power = container_of(wrk, struct macsmc_power, critical_work);
@@ -699,6 +822,10 @@ static int macsmc_power_event(struct notifier_block *nb, unsigned long event, vo
699822

700823
return NOTIFY_OK;
701824
} else if ((event & 0xffff0000) == 0x72010000) {
825+
/* Button event handled by macsmc-hid, but let's do a debug print */
826+
if (log_power)
827+
macsmc_do_dbg(power);
828+
702829
return NOTIFY_OK;
703830
}
704831

@@ -781,6 +908,12 @@ static int macsmc_power_probe(struct platform_device *pdev)
781908
blocking_notifier_chain_register(&smc->event_handlers, &power->nb);
782909

783910
INIT_WORK(&power->critical_work, macsmc_power_critical_work);
911+
INIT_DELAYED_WORK(&power->dbg_log_work, macsmc_dbg_work);
912+
913+
g_power = power;
914+
915+
if (log_power)
916+
schedule_delayed_work(&power->dbg_log_work, 0);
784917

785918
return 0;
786919
}
@@ -790,6 +923,9 @@ static void macsmc_power_remove(struct platform_device *pdev)
790923
struct macsmc_power *power = dev_get_drvdata(&pdev->dev);
791924

792925
cancel_work(&power->critical_work);
926+
cancel_delayed_work(&power->dbg_log_work);
927+
928+
g_power = NULL;
793929

794930
blocking_notifier_chain_unregister(&power->smc->event_handlers, &power->nb);
795931
}

0 commit comments

Comments
 (0)