@@ -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+
85184static 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+
613736static 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