Android Battery architecture [turn]

Android Battery Architecture

Android Power

image

android and power-related service they have two/frameworks/base/services/core/java/com/android/server/

One is BatteryService.java, the other is in the directory powe PowerManagerService.java.

Power Management Architecture

Android primarily through Wakelock power management mechanism to manage the state of the system, the entire android power management can be divided into four layers: Application Interface Layer (PowerManager.java), Framework layer (PowerManagerService.java), HAL (power.c) and linux inner nuclear layer (kernel / power).

Application Interface Layer: PowerManager in the open interfaces, applications can call interface application wakelock PM and wake up the system, the system into sleep and other operations.

Framework layers: application calls PowerManager open interface, complete PowerManagerService the operating system, the computing system PowerManagerService and related calculations Power, the whole system is power management decisions. And coordinate power system how to interact with other modules, such as the bright screen, dark screen, system sleep, wake up and so on.

HAL layer: This layer is only a power.c file parameters passed down by the upper layer, data is written to / sys / power / wake_lock or / sys / power / wake_unlock file node to communicate with the Kernel, the main function is to apply / release locks to maintain screen flickering.

kernel layer: kernel / power implement power management framework. drivers / power, device specific power management framework.

Battery Management Architecture

Android battery management system drive inherit the power supply class linux is. In the user layer BatteryService.java manner by the broadcast-related attributes reported to the battery using the app, and registers the battery status monitor uevent varied to obtain real-time status of the battery.

frameworks/base/services/core/java/com/android/server/BatteryService.java

When detecting the battery state changes, a {@link android.content.Intent # ACTION_BATTERY_CHANGED BATTERY_CHANGED action} broadcast to {@link android.content.BroadcastReceiver IntentReceivers} such services.

The new value is stored in the battery state {@link android.content.Intent # getExtra Intent.getExtra}, the contents of storage are as follows:

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 battery monitor registered to the underlying

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());
}

When the underlying information, call update will update BatteryService related values.

    private void update(BatteryProperties props) {
        synchronized (mLock) {
            if (!mUpdatesStopped) {
                mBatteryProps = props;
                // Process the new values.
                processValuesLocked(false);
            } else {
                mLastBatteryProps.set(props);
            }
        }
    }

processValuesLocked function as follows:

 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         }

healtd

healthd was put forward after Android 4.4, monitor events from the kernel of the battery, battery data BatteryService to the framework layer to pass on. BatteryService calculated battery display, remaining power, power level and other information, which code is located in / system / core / healthd.

According Android.mk file.

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

Files in this directory will be compiled into an executable program 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 initialization is as follows:

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 is divided into three cases.

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 function

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);

The next main function calls periodic_chores updated battery status information.

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();
}

image

uevent_event handler as follows.

#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 function was called gBatteryMonitor-> update () method to complete the update on the practical significance.

//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目录下的文件节点。

image

Then save the information to dmesgline years. Dmesg so you can see this information up.

        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" : "");

After obtaining the above information, battery status update

    healthd_mode_ops->battery_update(&props);
   //返回电池是否处在充电状态
    return props.chargerAcOnline | props.chargerUsbOnline |
            props.chargerWirelessOnline;

For the case where the battery update Andrews follows:

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 defined above are as follows:

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());

image

kernel层

一个是充电芯片驱动,一个是电量计,这两个设备统一由power子系统管理。

power子系统主要由如下文件组成:

  • power_supply.h (include\linux)
  • power_supply_core.c (drivers\power)
  • power_supply_sysfs.c (drivers\power)

    charger充电芯片

    适合充电芯片相关的。

一个例子如下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);

power_supply_register函数

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;
 
};

Initialize the probe function and power driver to register
static int bq2589x_charger1_probe (struct i2c_client Client,
const struct i2c_device_id
ID)
{
struct bq2589x * BQ;
// initialize relevant fields
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);

// Create the node SYS
RET = sysfs_create_group (& bq-> the dev-> Kobj, & bq2589x_attr_group);

// Event Processing battery charging chip
ret = request_irq (client-> irq, bq2589x_charger1_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "bq2589x_charger1_irq", bq);

The second step is called power_supply_register register the psy equipment

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;
}

For the BMS electricity meter, an apparatus of this type is, according to like is added.

Guess you like

Origin www.cnblogs.com/linhaostudy/p/11934904.html