1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * APM emulation for PMU-based machines 4 * 5 * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org) 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/module.h> 10 #include <linux/apm-emulation.h> 11 #include <linux/adb.h> 12 #include <linux/pmu.h> 13 14 #define APM_CRITICAL 10 15 #define APM_LOW 30 16 17 static void pmu_apm_get_power_status(struct apm_power_info *info) 18 { 19 int percentage = -1; 20 int batteries = 0; 21 int time_units = -1; 22 int real_count = 0; 23 int i; 24 char charging = 0; 25 long charge = -1; 26 long amperage = 0; 27 unsigned long btype = 0; 28 29 info->battery_status = APM_BATTERY_STATUS_UNKNOWN; 30 info->battery_flag = APM_BATTERY_FLAG_UNKNOWN; 31 info->units = APM_UNITS_MINS; 32 33 if (pmu_power_flags & PMU_PWR_AC_PRESENT) 34 info->ac_line_status = APM_AC_ONLINE; 35 else 36 info->ac_line_status = APM_AC_OFFLINE; 37 38 for (i=0; i<pmu_battery_count; i++) { 39 if (pmu_batteries[i].flags & PMU_BATT_PRESENT) { 40 batteries++; 41 if (percentage < 0) 42 percentage = 0; 43 if (charge < 0) 44 charge = 0; 45 percentage += (pmu_batteries[i].charge * 100) / 46 pmu_batteries[i].max_charge; 47 charge += pmu_batteries[i].charge; 48 amperage += pmu_batteries[i].amperage; 49 if (btype == 0) 50 btype = (pmu_batteries[i].flags & PMU_BATT_TYPE_MASK); 51 real_count++; 52 if ((pmu_batteries[i].flags & PMU_BATT_CHARGING)) 53 charging++; 54 } 55 } 56 if (batteries == 0) 57 info->ac_line_status = APM_AC_ONLINE; 58 59 if (real_count) { 60 if (amperage < 0) { 61 if (btype == PMU_BATT_TYPE_SMART) 62 time_units = (charge * 59) / (amperage * -1); 63 else 64 time_units = (charge * 16440) / (amperage * -60); 65 } 66 percentage /= real_count; 67 if (charging > 0) { 68 info->battery_status = APM_BATTERY_STATUS_CHARGING; 69 info->battery_flag = APM_BATTERY_FLAG_CHARGING; 70 } else if (percentage <= APM_CRITICAL) { 71 info->battery_status = APM_BATTERY_STATUS_CRITICAL; 72 info->battery_flag = APM_BATTERY_FLAG_CRITICAL; 73 } else if (percentage <= APM_LOW) { 74 info->battery_status = APM_BATTERY_STATUS_LOW; 75 info->battery_flag = APM_BATTERY_FLAG_LOW; 76 } else { 77 info->battery_status = APM_BATTERY_STATUS_HIGH; 78 info->battery_flag = APM_BATTERY_FLAG_HIGH; 79 } 80 } 81 82 info->battery_life = percentage; 83 info->time = time_units; 84 } 85 86 static int __init apm_emu_init(void) 87 { 88 apm_get_power_status = pmu_apm_get_power_status; 89 90 printk(KERN_INFO "apm_emu: PMU APM Emulation initialized.\n"); 91 92 return 0; 93 } 94 95 static void __exit apm_emu_exit(void) 96 { 97 if (apm_get_power_status == pmu_apm_get_power_status) 98 apm_get_power_status = NULL; 99 100 printk(KERN_INFO "apm_emu: PMU APM Emulation removed.\n"); 101 } 102 103 module_init(apm_emu_init); 104 module_exit(apm_emu_exit); 105 106 MODULE_AUTHOR("Benjamin Herrenschmidt"); 107 MODULE_DESCRIPTION("APM emulation for PowerMac"); 108 MODULE_LICENSE("GPL"); 109