 So, my name is Sebastian Reichel. I'm an embedded Linux engineer at Colabora, which is an open source consultancy. I live in North Germany, and I'm an open source contributor, starting with being a WN developer, maintainer of the HSI and power supply subsystem on the kernel, and the co-founder of my local hackerspace. The topic today is the power supply subsystem, which is about measuring the capacity of batteries and the state of charging equipment for those batteries. The subsystem also contains drivers for board level power off and reset, not to be confused with reset drivers and which are just resetting partial things on your board, but I will skip those today. We will focus on the batteries on the chargers. This subsystem has originally been written by Anton, who maintained it from 2007 to 2014, when he didn't have enough time anymore, so Dimitri took over, but he was missing after one kernel release, and when I tried to submit a new driver, there was no maintainer, so I took over maintainership. You may have seen it before, there's a power supply on your notebook, where you can see the status of your system. This is what is being used to see the nice status in the graphical application from GNOME and KDE. Basically exposes a lot of information from the batteries and the chargers, so that your system knows when it runs out of juice. Most of the older batteries just give you information about the capacity and percent, which is the file, which I cut it here in the last line. More modern systems also give you the capacity and watts and how much power is currently being drawn out of your battery. In addition to this CISFS-based interface, there's also UDEV to fetch those information. At this point, they are pushed, so if there's an update and you use UDEV ADM monitor, you will get push-based information of those properties if it's properly implemented in the driver. This is especially important for things like if you plug in the power supply, the external one, then you want to know this as fast as possible that the system is charging again. To implement this, we have a lot of drivers which are device-specific on embedded devices. On most of your notebooks, there's probably an ACPA-based interface and all of this is abstracted. There's a single driver. This one is apparently maintained by Raphael and not by me. One of the limits that we have is that each power supply that is exposed on the CISFS stands for one physical device, so if you see two battery devices in CISFS, your notebook should have two batteries. I will come to that later again. Then all values are exposed in the standard meta. They are usually all micro-Ms, micro-voltage, micro-watts, and so on. For capacity, there's actually two different styles. They are either exposed in micro-watts or in micro-ampere. This depends on your hardware. If the hardware is based on exposing micro-Ms, then the driver should also do this. Technically, you could like calculate the other value once you have all the information, but we try to only expose what the hardware actually measures. So with that, there's two different types for the chargers in addition to the battery, which is mains and USB. There's some clouds for backup batteries, but there's currently no user on Mainline which is using this kind of class. In addition, there's all kinds of subclasses for the USB, which is being deprecated since two kernel releases. I will come to that later. Before starting writing a driver, let me give a short introduction to smart batteries. You probably know what a battery is. You can detach something and get voltage from it, but the batteries in your notebook, they're a bit smarter. You can ask them about how much voltage do you have left. We are some kind of digital interface like iSquare-C or SPI. In Linux, we are mostly interested about this chip that actually measures the data. So this is what we expose as the battery, which is kind of a problem on embedded systems because there sometimes it's not a single chip, but multiple chips. So they have to be exposed as one single chip, and sometimes you have to add more data about the battery, which is not known by the fuel gauge. So let's try starting writing a driver. This is a base construct for what the Linux kernel driver looks like. Nothing special so far about the power supply subsystem. If you write this and compile it, you have some module, you can load it. It will not yet auto probe, but it will not do anything obviously because the probe function is empty, but it should compile and should work. So next we will add some device tree code. This is usually what is being used nowadays on embedded systems. So once we've added the device tree compatible and this match so that the kernel knows that this should be used, the driver will be loaded once it finds the vendor or my battery string in your device tree. So let's add this to the device tree. You may have seen my example was using a platform device because a lot of the power supply drivers are actually multifunction devices. So there's some sub function in a bigger device. So this is below some controller which has a lot of functionality, there's the battery, and once this is being passed by the kernel, the driver will be loaded. At this point, we had an empty probe function, so nothing will happen. So next step is let's add some code to the probe function. The device tree subsystem is not as hard as other subsystems I think. Most code actually lives in the probe function and one more function. We will come to that in the next slide. So we have to load a couple of platform-specific things. So let's start with allocating some memory to put the information. There's actually structure for device-specific data which is just for the driver and the second one which is for the power supply subsystem itself. So after both have been allocated, we can put in some data into the configuration. There's two interesting things here. First, we inform the power supply subsystem that we have this driver-specific information that we want to store for later usage. And second, we remember the device tree off-node. We will see later why this is required. Once this has been done, the later part of the probe function is basically describing what we have. We have a battery. This is a generic name which is what is being exposed on the CISFS. So you can give anything. It should be unique. So if you assume that the same driver is loaded multiple times, you should make sure that there's some kind of identifier in this string. And next, there's the information what properties are actually provided by the battery which is this array of functions. And there's a function which will apparently expose those information. We will see this in one of the next slides. And once all the information has been prepared, the device can be registered using power supply register as seen. And everything else will be done by the kernel infrastructure. So the power supply framework will take care of exposing all those CISFS properties. It will take care of preparing the UDIF interface and all of this. You don't have to worry about that. So as I said, we have to provide information which properties should be exposed. This can usually be seen on the datasheet of your battery chip. A common set is like exposing the status on the health. This is exposed by almost every battery. And usually, you can get at least the voltage. All the other properties depend on the specific type of battery field that you actually are using in your system. And let me get back shortly. So this is what is being exposed. So at this point, the kernel knows what kind of CISFS files should be exported to user space. Once you try to access this, this function will be called, which you registered before. And you will get, again, the regs.property. So for example, if somebody tries to read the status, then this switch case statement will be accessed. And you can code anything into the prop status property. Yes. There's a second... Oh, no. Let me stop with the health first. So most drivers apparently use sub-functions at this point, but really simple ones may just like access the register using, for example, Rackmap or Iceware CREED or whatever. And then they do some translation. The return value is in this. It's supposed to getting integers. There's a different kind of output, like some properties, exposed strings. But most of them expect integers nowadays. So as you can see, it might be a bit of complicated for health because you have to translate to the properties being used by the kernel. But for other properties, like, for example, voltage, it may be really simple, like just get the value from the register and expose it to user space. The only thing that you should make sure is that you're using the right scale because there's a lot of chips exposed millivoltage and the kernel interface exposes microvoltage all the time. So if you're using some kind of high level user space interface, it expects to see microvoltage and the scaling will be completely wrong if you expose something else. Right. In addition to the readable properties, there's also some properties that may be written to. So there's a second function available to set properties, which basically works exactly the same way as the readable properties. There's, again, some function where you get the property that is being written to and you can implement your code and do something with these values. I didn't provide an example this time, but it's like ReactMap set or something. And there's a second function, which is called property is writable, which will be checked in before to see if your property is actually writable. Otherwise, the framework will take care of not forwarding the right call. Oh, yeah. I actually provided one example for the right one. Well, it's not that hard to think of once you've done the read part. My thing about half of the power supply drivers apparently use some kind of writable properties. A lot of drivers don't need this at all. Kind of depends on your hardware. So yes, this is basically a power supply driver. Once you've done this, you will have a working driver and your system knows what the capacity of your system is. But some systems need a bit more details and are more special. So like some drivers have properties which cannot be exposed using the generic ones. For those, there's a couple of custom system first properties that you can just add to your driver. Actually, most drivers use sysfs create to do this, which is racy. So the udev interface won't work for those. There's currently a patch set which fixes this by exposing a new functionality in the framework, which looks like this. You describe your custom attribute. This is the topmost function. It basically describes what should happen when somebody accesses your new property. And then it's registered. The important part is down here. This basically tells the framework that your custom attribute should also be exposed. The nice thing of this is that all the registering and deregistering will be taken care of by the framework. You don't have to worry about this at all. Oh, and obviously it's not racing anymore. So this will most likely arrive in 4.21. I plan to merge this early after the merge window. Then another important thing is one of the harder things you have is what properties can I actually expose? I think this is one of the hardest things that you actually have in power supply. Writing the code is easy, but figuring out if the register in your data sheet actually exposes the open circuit voltage or the current voltage may be hard. So you should definitely check the power documentation to see what each value means. Because this is the only hard thing, and that should be gone right. Because if it's wrong, it's hard to fix later. It will become user space ABI. Okay, so you may remember at the beginning I showed you this handling that the framework wants to know your device tree node. The important thing is for this is that you may have some chain, like the charger. Charger is a specific battery, and the battery wants to know that it's charged by this charger. Because when the charger is plugged, then the battery gets a notification that it's being charged, and it can do some things if this happens. There's a generic way to do this in the framework. The device tree, this is described by adding a node to the device tree node of the battery that is being supplied by different chargers. So once you've properly registered this in the framework, there's a hook which is being called if the external power changed. In this example, if the battery will get notified if the USB charger or the AC charger changes. This is being done using this external power change tool. A lot of drivers use this to just update their values, like seeing the charger changed, so the battery values must also have changed. Let's notify user space that it should update its values. This will only work if you properly provide the device tree node, otherwise the framework cannot find the node that is being described here. So make sure to properly add this one. Everything else will work automatically. Then there's a couple of fuel gaugues which do not know everything about the battery, like it's missing information, how big is the maximum capacity, what's the maximum charge current, all kind of information which is static and which describes the actual battery cells. So two or three current releases ago we added a new function which just describes the cells or the static information. It was written by Lyon Beck for the Texas Instruments Driver, if I remember correctly. It's nowadays used by multiple drivers and it's quite simple to use. There's a structure which has all kind of values and there's a function which will fill in all the information from device tree or ACPI. There's also ACPI support into the structure and then you can just fetch them. So it's usually currently it's being called during the probe function and it's like copied over to the driver specific information. You're not supposed to use all of the information of the structure but that's the ones that you are needing for your driver. One of the new things that we are currently adding is support for converting the open circuit voltage into capacity. Historically we tried to avoid having this in the kernel because it's much easier to do this if you have floating point available and this is a lot of, it's kind of hard to describe the curves but there's a lot of users who actually want this in the kernel and it kind of makes sense. So we are currently preparing some code so that you can describe this nice curve in device tree for different temperatures and then when the system sees some voltage it can translate it using some framework functionality into capacity. Not micro ampere like it's shown here but just capacity and percentage. And other than that I told you in the beginning there's some new things for USB chargers. Historically if you had like some USB CDP or DCP device then the type property had to change at runtime which is not the way it should be done. So it has been changed quite some time ago, I think like a year. There's now always, the type is always USB independently of what your current USB mode is and you have a new USB type where you can see what mode is used at the moment and also what modes are available. So if you cut this device similar to LED triggers you see in brackets the mode which is currently selected and all the other modes being available. And just like the other properties this property can be writable so you can write DCP into USB type and then the mode is supposed to change from CDP to DCP and the selection will change. To do this there's a couple of structures in the corner. First of all you have to let the framework know what modes are available by your charging driver which is similar to how the other properties are exposed except that it's not exposing Sys-of-S properties but just some strings inside of the USB type property. And then as I said you will obviously want to expose that there's the USB type property otherwise there won't be any Sys-of-S file. And once you're done with that there's new structure entries for USB type and the number of USB type which is of the array size and then you're done because all the other special handling is done in the Sys-of-S handling of prop USB type which you're supposed to implement in this big switch case statement. Alright so we have a couple of shortcomings still in this subsystem. First of all if you have a battery which is measured by more than one fuel gauge there's a problem because basically you would want to write two drivers which will end up exposing two different directory structures in the Sys-of-S tree. So user space will assume that you have two batteries but it's actually the same one. We currently don't have a solution for this because there's not a lot of devices doing this. At the moment I only know of the N900 and if somebody wants to work on this it's highly appreciated. The second one is charging. On x86 all the charging is handled by an embedded controller. It takes care of starting the charge process and stopping it automatically without Linux being involved at all. The advantage of that is that it will also work when there's no operating system loaded but on embedded devices this is sometimes implemented differently where the kernel or user space is supposed to take care of this. Samsung wrote a driver for this. It's called a charging manager which can take care of all the state machines but it's specific for a couple of chips and you have to do a lot of description and device tree to get it running and it should work automatically. So we would like to have support in the framework itself so that you just have to describe the charger and the battery and the subsystem will take care of probably charging everything automatically. Unfortunately this is currently not working and nobody is working on this as far as I know. Alright so that's it. Are there any questions? Yeah? Come to the mic. Yes. Fuel gauge sounds pretty much like an industrial IO type of device. Is there any relation between batteries in IO? There's some kind of relation. So the fuel gauge itself usually it's not in IO but some of them use IO to get the temperature of the battery. In that case we have some links to IO. IO provides an internal API to get data from it. In theory it would be possible to get all the data from IO but I don't think we can only have a driver for that. Are there any other questions? How would it be possible to get the battery left time in seconds in user space? So what is being done is basically that on better fuel gauge you get the remaining capacity in microwatts or in microampere hours and you also see how much power is being taken out of the battery in microwatts or microampere. So you can basically divide both numbers and you get the time. It's obviously quite dependent on the system load because if you do more then more current is drawn and then your time will go down. Thank you. You're welcome. It looks like this is all of the questions. So have fun eating lunch.