android中和電源相關的服務有兩個他們在/frameworks/base/services/core/java/com/android/server/
linux
一個是BatteryService.java
,另外一個是在目錄powe下的PowerManagerService.java
。android
Android電源管理主要經過Wakelock機制來管理系統的狀態,整個android電源管理,能夠分爲四個層次:應用接口層(PowerManager.java),Framework層(PowerManagerService.java), HAL(power.c)和linux內核層(kernel/power)。git
應用接口層:PowerManager中開放的接口,應用能夠調用PM的接口申請wakelock,喚醒系統,使系統進入休眠等操做。github
Framework層:應用程序調用PowerManager開放的接口,對系統操做在PowerManagerService中完成,PowerManagerService計算系統中和power相關的計算,是整個電源管理的決策系統。同時協調power如何與系統其它模塊的交互,如亮屏,暗屏,系統睡眠,喚醒等。架構
HAL層:該層只有一個power.c文件,該文件經過上層傳下來的參數,向/sys/power/wake_lock或/sys/power/wake_unlock文件節點寫入數據來與kernel進行通訊,主要功能是申請/釋放鎖,維持屏幕亮滅。app
kernel層:kernel/power實現電源管理框架。 drivers/power,設備特定的電源管理框架。框架
Android系統對電池的管理驅動繼承了linux的power supply class。在用戶層在BatteryService.java中經過廣播的方式將電池相關的屬性報給app使用,而且註冊了uevent監聽電池狀態變化,以實時獲取電池狀態。less
frameworks/base/services/core/java/com/android/server/BatteryService.java
當檢測到電池狀態變化時,給 {@link android.content.Intent#ACTION_BATTERY_CHANGED BATTERY_CHANGED action}廣播給{@link android.content.BroadcastReceiver IntentReceivers}這類的服務。socket
電池狀態新的值存放在{@link android.content.Intent#getExtra Intent.getExtra} ,存放的內容以下:
scale:最大電池電量值,一般100 level:當前電量值,從0到scale status;當前充電狀態 health:電池狀態 present:bool值,若是有電池則值爲true icon-small:整型,該狀態建議使用的icon。 plugged:0,設備未插入,1:AC適配器插入, 2, USB插入 voltage:當前電池電壓mv temperature:當前電池溫度。 technology:電池類型,如:Li-ion
onStart將電池監聽註冊到底層
public void onStart() { IBinder b = ServiceManager.getService("batteryproperties"); final IBatteryPropertiesRegistrar batteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b); try { //註冊電池監聽,當底層電池電量發生變化調用此監聽,並調用update。 batteryPropertiesRegistrar.registerListener(new BatteryListener()); } catch (RemoteException e) { // Should never happen. } //將POWER_SERVICE做爲Binder的服務端,註冊到SystemService中 publishBinderService("battery", new BinderService()); //將BatteryManagerInternal註冊到本地服務 publishLocalService(BatteryManagerInternal.class, new LocalService()); }
當底層有信息,會調用update更新BatteryService中相關值。
private void update(BatteryProperties props) { synchronized (mLock) { if (!mUpdatesStopped) { mBatteryProps = props; // Process the new values. processValuesLocked(false); } else { mLastBatteryProps.set(props); } } }
processValuesLocked函數以下:
private void processValuesLocked(boolean force) { 313 boolean logOutlier = false; 314 long dischargeDuration = 0; 315 //獲取電池電量是否低於critical界限 316 mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel); //獲取充電狀態,AC,USB,無線以及什麼都沒有接 317 if (mBatteryProps.chargerAcOnline) { 318 mPlugType = BatteryManager.BATTERY_PLUGGED_AC; 319 } else if (mBatteryProps.chargerUsbOnline) { 320 mPlugType = BatteryManager.BATTERY_PLUGGED_USB; 321 } else if (mBatteryProps.chargerWirelessOnline) { 322 mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS; 323 } else { 324 mPlugType = BATTERY_PLUGGED_NONE; 325 } 344 // Let the battery stats keep track of the current level.電池統計信息和當前狀態保持一致 345 try { 346 mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, 347 mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature, 348 mBatteryProps.batteryVoltage); 349 } catch (RemoteException e) { 350 // Should never happen. 351 } //低電量關機 353 shutdownIfNoPowerLocked(); //電池溫度太高關機 354 shutdownIfOverTempLocked(); //force是第一次調用時標誌,若是狀態有更改依然會調用下面的代碼 356 if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus || 357 mBatteryProps.batteryHealth != mLastBatteryHealth || 358 mBatteryProps.batteryPresent != mLastBatteryPresent || 359 mBatteryProps.batteryLevel != mLastBatteryLevel || 360 mPlugType != mLastPlugType || 361 mBatteryProps.batteryVoltage != mLastBatteryVoltage || 362 mBatteryProps.batteryTemperature != mLastBatteryTemperature || 363 mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent || 364 mInvalidCharger != mLastInvalidCharger)) //插入狀態有更改 366 if (mPlugType != mLastPlugType) { 367 if (mLastPlugType == BATTERY_PLUGGED_NONE) { 368 // 不充電-->充電 369 370 // There's no value in this data unless we've discharged at least once and the 371 // battery level has changed; so don't log until it does. 372 if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) { 373 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; 374 logOutlier = true; 375 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration, 376 mDischargeStartLevel, mBatteryProps.batteryLevel); 377 // make sure we see a discharge event before logging again 378 mDischargeStartTime = 0; 379 } 380 } else if (mPlugType == BATTERY_PLUGGED_NONE) { 381 // 充電-->不充電 或者開機上電 382 mDischargeStartTime = SystemClock.elapsedRealtime(); 383 mDischargeStartLevel = mBatteryProps.batteryLevel; 384 } 385 } //電池狀態更新 386 if (mBatteryProps.batteryStatus != mLastBatteryStatus || 387 mBatteryProps.batteryHealth != mLastBatteryHealth || 388 mBatteryProps.batteryPresent != mLastBatteryPresent || 389 mPlugType != mLastPlugType) { 390 EventLog.writeEvent(EventLogTags.BATTERY_STATUS, 391 mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0, 392 mPlugType, mBatteryProps.batteryTechnology); 393 } //電池電量更新 394 if (mBatteryProps.batteryLevel != mLastBatteryLevel) { 395 // Don't do this just from voltage or temperature changes, that is 396 // too noisy. 397 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL, 398 mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature); 399 } ... //發送電池狀態變化廣播 427 sendIntentLocked(); //對電源鏈接/斷開進行單獨的廣播,由於標準的intent將不會喚醒任何應用程序而且一些應用程序基於這個信息能夠作一些單獨的「智能」行爲 432 if (mPlugType != 0 && mLastPlugType == 0) { 433 mHandler.post(new Runnable() { 434 @Override 435 public void run() { 436 Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED); 437 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 438 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL); 439 } 440 }); 441 } 442 else if (mPlugType == 0 && mLastPlugType != 0) { 443 mHandler.post(new Runnable() { 444 @Override 445 public void run() { 446 Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED); 447 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 448 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL); 449 } 450 }); 451 } //低電量電池事件通知 453 if (shouldSendBatteryLowLocked()) { 454 mSentLowBatteryBroadcast = true; 455 mHandler.post(new Runnable() { 456 @Override 457 public void run() { 458 Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW); 459 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 460 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL); 461 } 462 }); 463 } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) { 464 mSentLowBatteryBroadcast = false; 465 mHandler.post(new Runnable() { 466 @Override 467 public void run() { 468 Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY); 469 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 470 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL); 471 } 472 }); 473 } 475 // Update the battery LED 476 mLed.updateLightsLocked(); 478 // This needs to be done after sendIntent() so that we get the lastest battery stats. 479 if (logOutlier && dischargeDuration != 0) { 480 logOutlierLocked(dischargeDuration); 481 } 482 483 mLastBatteryStatus = mBatteryProps.batteryStatus; 484 mLastBatteryHealth = mBatteryProps.batteryHealth; 485 mLastBatteryPresent = mBatteryProps.batteryPresent; 486 mLastBatteryLevel = mBatteryProps.batteryLevel; 487 mLastPlugType = mPlugType; 488 mLastBatteryVoltage = mBatteryProps.batteryVoltage; 489 mLastBatteryTemperature = mBatteryProps.batteryTemperature; 490 mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent; 491 mLastBatteryLevelCritical = mBatteryLevelCritical; 492 mLastInvalidCharger = mInvalidCharger; 493 }
healthd是安卓4.4以後提出來的,監聽來自kernel的電池事件,並向上傳遞電池數據給framework層的BatteryService。BatteryService計算電池電量顯示,剩餘電量,電量級別等信息,其代碼位於/system/core/healthd。
根據Android.mk文件。
LOCAL_SRC_FILES := \ healthd.cpp \ healthd_mode_android.cpp \ healthd_mode_charger.cpp \ BatteryMonitor.cpp \ BatteryPropertiesRegistrar.cpp LOCAL_MODULE := healthd LOCAL_MODULE_TAGS := optional LOCAL_FORCE_STATIC_EXECUTABLE := true
這個目錄下的文件會被編譯成healthd可執行程序。
int main(int argc, char **argv) { int ch; int ret; static pthread_t thread;//Talen klog_set_level(KLOG_LEVEL); //正常開機啓動 healthd_mode_ops = &android_ops; if (!strcmp(basename(argv[0]), "charger")) { //關機充電 healthd_mode_ops = &charger_ops; } else { while ((ch = getopt(argc, argv, "cr")) != -1) { switch (ch) { case 'c': healthd_mode_ops = &charger_ops; break; case 'r': //recovery下操做 healthd_mode_ops = &recovery_ops; break; case '?': default: KLOG_ERROR(LOG_TAG, "Talen, Unrecognized healthd option: %c\n", optopt); exit(1); } } } ret = healthd_init();
healthd_init的初始化以下:
static int healthd_init() { epollfd = epoll_create(MAX_EPOLL_EVENTS); if (epollfd == -1) { KLOG_ERROR(LOG_TAG, "epoll_create failed; errno=%d\n", errno); return -1; } //和板子級別相關的初始化 healthd_board_init(&healthd_config); //根據所處的模式,有三種狀況的init,分別是正常安卓系統,關機充電以及recovery。 healthd_mode_ops->init(&healthd_config); //wakealarm定時器初始化 wakealarm_init(); //uevent事件初始化,用以監聽電池的uevent事件 uevent_init(); //BatteryMonitor初始化。 gBatteryMonitor = new BatteryMonitor(); gBatteryMonitor->init(&healthd_config); return 0; }
init分爲三種狀況。
android(healthd_mode_android.cpp)
void healthd_mode_android_init(struct healthd_config* /*config*/) { ProcessState::self()->setThreadPoolMaxThreadCount(0);//獲取線程池最大線程數 IPCThreadState::self()->disableBackgroundScheduling(true);//禁止後臺調用 IPCThreadState::self()->setupPolling(&gBinderFd);//將gBinderFd加入到epoll中。 if (gBinderFd >= 0) { //將binder_event事件註冊到gBinderfd文件節點用以監聽Binder事件。 if (healthd_register_event(gBinderFd, binder_event)) KLOG_ERROR(LOG_TAG, "Register for binder events failed\n"); } gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(); //將batteryProperties註冊到ServiceManager中 gBatteryPropertiesRegistrar->publish(); }
charger狀況(healthd_mode_charger.cpp)
1105 void healthd_mode_charger_init(struct healthd_config* config) 1106 { 1118 ret = ev_init(input_callback, charger); 1119 if (!ret) { 1120 epollfd = ev_get_epollfd(); 1121 healthd_register_event(epollfd, charger_event_handler); 1122 } 1123 1124 ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown); 1125 if (ret < 0) { 1126 LOGE("Cannot load battery_fail image\n"); 1127 charger->surf_unknown = NULL; 1128 } 1129 1130 charger->batt_anim = &battery_animation; 1131 1132 GRSurface** scale_frames; 1133 int scale_count; 1134 ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames); 1135 if (ret < 0) { 1136 LOGE("Cannot load battery_scale image\n"); 1137 charger->batt_anim->num_frames = 0; 1138 charger->batt_anim->num_cycles = 1; 1139 } else if (scale_count != charger->batt_anim->num_frames) { 1140 LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n", 1141 scale_count, charger->batt_anim->num_frames);
uevent_init函數
static void uevent_init(void) { //建立並打開一個64K的socket文件描述符uevent_fd. uevent_fd = uevent_open_socket(64*1024, true); //將其設置爲非阻塞模式 fcntl(uevent_fd, F_SETFL, O_NONBLOCK); //將其註冊到healthd_init建立的描述符集合裏 if (healthd_register_event(uevent_fd, uevent_event)) KLOG_ERROR(LOG_TAG, "register for uevent events failed\n"); }
BatteryMonitor.cpp
void BatteryMonitor::init(struct healthd_config *hc) { String8 path; char pval[PROPERTY_VALUE_MAX]; mHealthdConfig = hc; //打開/sys/class/power_supply,遍歷該節點下的電池參數初始化healthd的config參數 DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
接下來main函數調用periodic_chores更新電池狀態信息。
void healthd_battery_update(void) { // Fast wake interval when on charger (watch for overheat); // slow wake interval when on battery (watch for drained battery). //獲取新的wakealarm喚醒間隔,fast wake處於充電模式,slow是處於非充電模式的喚醒間隔。 int new_wake_interval = gBatteryMonitor->update() ? healthd_config.periodic_chores_interval_fast : healthd_config.periodic_chores_interval_slow; //斷定並跟新新的喚醒間隔 if (new_wake_interval != wakealarm_wake_interval) wakealarm_set_interval(new_wake_interval); // During awake periods poll at fast rate. If wake alarm is set at fast // rate then just use the alarm; if wake alarm is set at slow rate then // poll at fast rate while awake and let alarm wake up at slow rate when // asleep. if (healthd_config.periodic_chores_interval_fast == -1) awake_poll_interval = -1; else //輪詢間隔時間調節 awake_poll_interval = new_wake_interval == healthd_config.periodic_chores_interval_fast ? -1 : healthd_config.periodic_chores_interval_fast * 1000; } static void periodic_chores() { healthd_battery_update(); }
uevent_event處理函數以下。
#define UEVENT_MSG_LEN 2048 static void uevent_event(uint32_t /*epevents*/) { char msg[UEVENT_MSG_LEN+2]; char *cp; int n; n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN); if (n <= 0) return; if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ return; msg[n] = '\0'; msg[n+1] = '\0'; cp = msg; while (*cp) { //判斷是不是power_supply目錄下的事件,若是是則更新電池狀態。 if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) { healthd_battery_update(); break; } /* advance to after the next \0 */ while (*cp++) ; } }
update函數裏調用了 gBatteryMonitor->update()方法去完成實際意義上的更新。
//BatteryMonitor.cpp 181 bool BatteryMonitor::update(void) { 182 bool logthis; 183 184 props.chargerAcOnline = false; 185 props.chargerUsbOnline = false; 186 props.chargerWirelessOnline = false; 187 props.batteryStatus = BATTERY_STATUS_UNKNOWN; 188 props.batteryHealth = BATTERY_HEALTH_UNKNOWN; 189 props.maxChargingCurrent = 0; 接下來跟新props.batteryPresent,props.batteryLevel,props.batteryVoltage等信息,這些信息的來源是/sys/class/power_supply/battery目錄下的文件節點。
接下來將信息保存到dmesgline裏。這樣dmesg就能夠看到這樣的信息了。
if (props.batteryPresent) { snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d", props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "", abs(props.batteryTemperature / 10), abs(props.batteryTemperature % 10), props.batteryHealth, props.batteryStatus); if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { int c = getIntField(mHealthdConfig->batteryCurrentNowPath); char b[20]; snprintf(b, sizeof(b), " c=%d", c / 1000); strlcat(dmesgline, b, sizeof(dmesgline)); } } size_t len = strlen(dmesgline); snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s", props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "", props.chargerWirelessOnline ? "w" : "");
獲取到以上信息後,更新電池狀態
healthd_mode_ops->battery_update(&props); //返回電池是否處在充電狀態 return props.chargerAcOnline | props.chargerUsbOnline | props.chargerWirelessOnline;
對於安卓狀況的battery update狀況以下:
void healthd_mode_android_battery_update( struct android::BatteryProperties *props) { if (gBatteryPropertiesRegistrar != NULL) gBatteryPropertiesRegistrar->notifyListeners(*props); return; } void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) { Mutex::Autolock _l(mRegistrationLock); for (size_t i = 0; i < mListeners.size(); i++) { mListeners[i]->batteryPropertiesChanged(props); } }
上面mListeners的定義以下:
class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar, public IBinder::DeathRecipient { public: void publish(); void notifyListeners(struct BatteryProperties props); private: Mutex mRegistrationLock; Vector<sp<IBatteryPropertiesListener> > mListeners; void registerListener(const sp<IBatteryPropertiesListener>& listener); void unregisterListener(const sp<IBatteryPropertiesListener>& listener); status_t getProperty(int id, struct BatteryProperty *val); status_t dump(int fd, const Vector<String16>& args); void binderDied(const wp<IBinder>& who); };
調用batteryPropertiesRegistrar的notifyListeners通知props改變了。這個通知必然是給調用registerListener註冊的,也必然是給framework層的。
@Override public void onStart() { IBinder b = ServiceManager.getService("batteryproperties"); final IBatteryPropertiesRegistrar batteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b); try { batteryPropertiesRegistrar.registerListener(new BatteryListener()); } catch (RemoteException e) { // Should never happen. } publishBinderService("battery", new BinderService()); publishLocalService(BatteryManagerInternal.class, new LocalService()); }
在初始化時,healthd初始化時候會建立BatteryPropertiesRegister對象,並將其publish到系統服務中去。
void BatteryPropertiesRegistrar::publish() { defaultServiceManager()->addService(String16("batteryproperties"), this); }
framework/base/services/core/java/com/android/server/BatteryService.java
@Override public void onStart() { IBinder b = ServiceManager.getService("batteryproperties"); final IBatteryPropertiesRegistrar batteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b); try { batteryPropertiesRegistrar.registerListener(new BatteryListener()); } catch (RemoteException e) { // Should never happen. } publishBinderService("battery", new BinderService()); publishLocalService(BatteryManagerInternal.class, new LocalService());
一個是充電芯片驅動,一個是電量計,這兩個設備統一由power子系統管理。
power子系統主要由以下文件組成:
power_supply_sysfs.c (drivers\power)
適合充電芯片相關的。
一個例子以下https://github.com/tibms/dual-bq2589x;這個並無battery。
對於高通平臺,早期使用了分立的器件,但如今採用AP內部集成了該模塊。高通平臺經常使用的名詞以下:
qpnp-bms.c(qcom plug n play)
qpnp-charger.c
BMS:battery monitoring system;
ICC:intelligent coulomb counter,基於高通BMS系統。
RC:remaing capacity。當前狀態下的剩餘電量,充滿電時RC=FCC。假設放電電流小於1/20C。
UUC:unusable capacity。因爲電池電阻致使的電池壓降而沒法使用的電量,其是放電電流的函數。
UC:usable capacity。UC=FCC-UUC
RUC:剩餘可用電量RUC=RC-UUC
SoC:state of charge;SoC=RC/FCC,對於上層應用,包含UUC更好:SoC=RUC/UC=(RC-UUC)/(FCC-UUC)。
C(rate):放電速率的測量方法,一個小時放完電的狀況測量;如若是電池等級是1Ah,也就是1A放電能持續1h,也就是按1C標準放電。若是按0.5C放電,則500mA能夠持續2h。
OCV:open circuit voltage。近乎於0電流狀況下的穩定電壓。電池帶負載工做後,須要5~30min恢復OCV。
FCC:Full-charge capacity
CC:Coulumb counter
### linux 電源子系統核心框架 #include/linux/power_supply.h struct power_supply { const char *name;//對應於/sys/class/power_supply/XXX 文件夾 enum power_supply_type type;//電池類型,UPS/BATTERY/USB等 enum power_supply_property *properties;//其具備的屬性集合 size_t num_properties;//屬性的數量 char **supplied_to;//此電源模塊變化時,須要通知的模塊。 size_t num_supplicants;//通知對象數量 //獲取屬性值 int (*get_property)(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val); //寫屬性值 int (*set_property)(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val); int (*property_is_writeable)(struct power_supply *psy, enum power_supply_property psp); //外部電源變化時所做的工做 void (*external_power_changed)(struct power_supply *psy); void (*set_charged)(struct power_supply *psy); /* For APM emulation, think legacy userspace. */ int use_for_apm; /* private */ struct device *dev; struct work_struct changed_work; spinlock_t changed_lock; bool changed; struct wake_lock work_wake_lock; }
extern int power_supply_register(struct device *parent, struct power_supply *psy); extern void power_supply_unregister(struct power_supply *psy);
int power_supply_register(struct device *parent, struct power_supply *psy) { struct device *dev; int rc; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; device_initialize(dev); dev->class = power_supply_class; dev->type = &power_supply_dev_type; dev->parent = parent; dev->release = power_supply_dev_release; dev_set_drvdata(dev, psy); psy->dev = dev; INIT_WORK(&psy->changed_work, power_supply_changed_work); rc = kobject_set_name(&dev->kobj, "%s", psy->name); if (rc) goto kobject_set_name_failed; rc = device_add(dev);//添加電源設備 if (rc) goto device_add_failed; spin_lock_init(&psy->changed_lock); wake_lock_init(&psy->work_wake_lock, WAKE_LOCK_SUSPEND, "power-supply"); //和電源led相關的門限設置 rc = power_supply_create_triggers(psy); if (rc) goto create_triggers_failed; //調度psy的power_supply_changed_work,即上面的INIT_WORK初始化的函數,向用戶空間發送uevent, 通知系統和用戶電源有變化 power_supply_changed(psy); goto success; create_triggers_failed: wake_lock_destroy(&psy->work_wake_lock); device_del(dev); kobject_set_name_failed: device_add_failed: put_device(dev); success: return rc; }
總結來講電源驅動通常要作以下幾部分工做:
1.定義struct power_supply,該定義能夠是全局的或者是嵌入到驅動中的專有數據,如上面給的參考程序:
struct bq2589x { struct device *dev; struct i2c_client *client; enum bq2589x_part_no part_no; int revision; unsigned int status; int vbus_type; bool enabled; bool interrupt; int vbus_volt; int vbat_volt; int rsoc; struct bq2589x_config cfg; struct work_struct irq_work; struct work_struct adapter_in_work; struct work_struct adapter_out_work; struct delayed_work monitor_work; struct delayed_work ico_work; struct delayed_work pe_volt_tune_work; struct delayed_work check_pe_tuneup_work; struct delayed_work charger2_enable_work; struct power_supply usb; struct power_supply wall; struct power_supply *batt_psy; };
在probe函數中初始化並註冊這個電源驅動到
static int bq2589x_charger1_probe(struct i2c_client client,
const struct i2c_device_id id)
{
struct bq2589x *bq;
//初始化相關字段
bq = devm_kzalloc(&client->dev, sizeof(struct bq2589x), GFP_KERNEL);
bq->dev = &client->dev; bq->client = client; i2c_set_clientdata(client, bq); ret = bq2589x_detect_device(bq); bq->batt_psy = power_supply_get_by_name("battery"); g_bq1 = bq; ret = bq2589x_psy_register(bq); INIT_WORK(&bq->irq_work, bq2589x_charger1_irq_workfunc); INIT_WORK(&bq->adapter_in_work, bq2589x_adapter_in_workfunc); INIT_WORK(&bq->adapter_out_work, bq2589x_adapter_out_workfunc); INIT_DELAYED_WORK(&bq->monitor_work, bq2589x_monitor_workfunc); INIT_DELAYED_WORK(&bq->ico_work, bq2589x_ico_workfunc); INIT_DELAYED_WORK(&bq->pe_volt_tune_work, bq2589x_pe_tune_volt_workfunc); INIT_DELAYED_WORK(&bq->check_pe_tuneup_work, bq2589x_check_pe_tuneup_workfunc); INIT_DELAYED_WORK(&bq->charger2_enable_work, bq2589x_charger2_enable_workfunc);
//建立sys下節點
ret = sysfs_create_group(&bq->dev->kobj, &bq2589x_attr_group);
//處理充電芯片電池事件
ret = request_irq(client->irq, bq2589x_charger1_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "bq2589x_charger1_irq", bq);
第二步,調用power_supply_register註冊這個psy設備
static int bq2589x_psy_register(struct bq2589x *bq) { int ret; bq->usb.name = "bq2589x-usb"; bq->usb.type = POWER_SUPPLY_TYPE_USB; bq->usb.properties = bq2589x_charger_props; bq->usb.num_properties = ARRAY_SIZE(bq2589x_charger_props); bq->usb.get_property = bq2589x_usb_get_property; bq->usb.external_power_changed = NULL; ret = power_supply_register(bq->dev, &bq->usb); if (ret < 0) { dev_err(bq->dev, "%s:failed to register usb psy:%d\n", __func__, ret); return ret; } bq->wall.name = "bq2589x-Wall"; bq->wall.type = POWER_SUPPLY_TYPE_MAINS; bq->wall.properties = bq2589x_charger_props; bq->wall.num_properties = ARRAY_SIZE(bq2589x_charger_props); bq->wall.get_property = bq2589x_wall_get_property; bq->wall.external_power_changed = NULL; ret = power_supply_register(bq->dev, &bq->wall); if (ret < 0) { dev_err(bq->dev, "%s:failed to register wall psy:%d\n", __func__, ret); goto fail_1; }
對於電量計BMS,也是這個類型的一種設備,照樣子添加。