Linux Power Management development
 help / color / mirror / Atom feed
From: Michael Heinemann <posted@heine.so>
To: Phil Reid <preid@electromag.com.au>
Cc: linux-pm@vger.kernel.org
Subject: Re: sbs-battery: Reading CHARGE in uAh
Date: Mon, 10 Jul 2017 17:42:46 +0200	[thread overview]
Message-ID: <d5cf5eac247af66bba5a260e2eee7c51@heine.so> (raw)
In-Reply-To: <8ec0d59a-6d31-fe3c-8f86-f1bc761d53b0@electromag.com.au>

On 2017-07-10 10:04, Phil Reid wrote:
> On 10/07/2017 15:54, Michael Heinemann wrote:
>> On 2017-07-10 03:35, Phil Reid wrote:
>>> On 7/07/2017 21:06, Michael Heinemann wrote:
>>>> On 2017-07-07 10:27, Phil Reid wrote:
>>>>> On 7/07/2017 16:01, Michael Heinemann wrote:
>>>>>> Hi Phil,
>>>>>> On 2017-07-07 03:49, Phil Reid wrote:
>>>>>>> G'day Michael,
>>>>>>> On 6/07/2017 23:23, Michael Heinemann wrote:
>>>>>>>> 
>>>>>>>> 
>>>>>>>> I got an INSPIRED ENERGY NH2057 Battery which is compliant to 
>>>>>>>> SBS Specification Version 1.1.
>>>>>>>> 
>>>>>>>> The Battery is generally working but I noticed that the values I 
>>>>>>>> get from sysfs for the CHARGE values
>>>>>>>> are identical to the values I get as ENERGY and they are in uWh. 
>>>>>>>> According to the power_supply_class
>>>>>>>> documentation CHARGE should be in uAh and ENERGY in uWh.
>>>>>>>> 
>>>>>>>> So I took a look into the drivers/power/supply/sbs-battery.c and 
>>>>>>>> noticed a possible bug in the code
>>>>>>>> when switching from BATTERY_MODE_WATTS to BATTERY_MODE_AMPS:
>>>>>>>> 
>>>>>>>> The configuration bit, according to the SBS Spec, is bit 15 of 
>>>>>>>> the BatteryMode Register.
>>>>>>>> 
>>>>>>>> These two modes are reflected in the code as:
>>>>>>>> 
>>>>>>>> enum sbs_battery_mode {
>>>>>>>>      BATTERY_MODE_AMPS,
>>>>>>>>      BATTERY_MODE_WATTS
>>>>>>>> };
>>>>>>>> 
>>>>>>>> When I look into the 'sbs_set_battery_mode' function I don't see 
>>>>>>>> any point where these mode bits are
>>>>>>>> shifted to bit 15. When I debug I only see the register being 
>>>>>>>> changed from 0x8000 to 0x8001 and back.
>>>>>>>> 
>>>>>>>> So I'm a bit confused, is this actually working for somebody? I 
>>>>>>>> see in the 'for-next' branch [1] that
>>>>>>>> there is currently work done to add a mutex to the mode switch. 
>>>>>>>> So at least it seems to be working for
>>>>>>>> some people. But I don't see why. Am I missing something?
>>>>>>>> 
>>>>>>>> 
>>>>>>> 
>>>>>>> Your analyse looks correct. I've not look that closely at the 
>>>>>>> data
>>>>>>> from the battery as yet.
>>>>>>> There's looks to be a few issues in there related to switching 
>>>>>>> mode.
>>>>>>> 
>>>>>>> The return value from sbs_set_battery_mode also looks suspect.
>>>>>>> Perhaps it should just return 0 on success.
>>>>>>> 
>>>>>>> And then sbs_get_battery_capacity needs cleaning up as it's using 
>>>>>>> the
>>>>>>> return value to set the mode at the end.
>>>>>>> 
>>>>>>> It setts the mode, and then I guess the intention was to set it 
>>>>>>> back again.
>>>>>>> But do we event need to do that? The next get is going to set the 
>>>>>>> correct mode.
>>>>>>> And the mode setting will soon be wrapped in a mutex.
>>>>>> 
>>>>>> I spend some more time to look at the code and my conclusion is 
>>>>>> that the cause
>>>>>> of the problem is a mix up of two different approaches for the 
>>>>>> mode.
>>>>>> 
>>>>>> The initial mode is passed in as 0 or 1 coming from enum 
>>>>>> sbs_battery_mode.
>>>>>> But when the setting back is done the value comes from the return 
>>>>>> value of
>>>>>> the previous call to sbs_set_battery_mode which is 0x8000 or 
>>>>>> 0x0000.
>>>>>> 
>>>>>> At least for my battery this leads to a situation where the status 
>>>>>> register is
>>>>>> 0x8000 so it's in mWh Mode. Then the mode=0 is passed in to set 
>>>>>> uAh.
>>>>>> 
>>>>>> But this statement
>>>>>> 
>>>>>> if ((original_val & BATTERY_MODE_MASK) == mode)
>>>>>>          return mode;
>>>>>> 
>>>>>> is true by mistake ((0x8000 & 0x8000) == 0) so the function exits 
>>>>>> and never
>>>>>> sets anything.
>>>>> Yeap that what I thought.
>>>>> 
>>>>>> 
>>>>>> What would be the "kernel style" way to fix this?
>>>>> That I'm not sure of. My personal style would be against using the 
>>>>> enum value.
>>>>> Unless is was set to a constant. ie:
>>>>> BATTERY_MODE_AMPS  = 0,
>>>>> BATTERY_MODE_WATTS = 0x8000
>>>>> But I'd probably make the enum a #define instead with above value
>>>>> 
>>>>> 
>>>>>> Define the sbs_battery_mode like this:
>>>>>> 
>>>>>> enum sbs_battery_mode {
>>>>>>      BATTERY_MODE_AMPS,
>>>>>>      BATTERY_MODE_WATTS
>>>>>> };
>>>>>> 
>>>>>> Or add a #define CAPACITY_MODE_OFFSET 0xf and shift the mode bit 
>>>>>> in the function?
>>>>>> 
>>>>>> I tested a bit with the shifted bit and the added mutex and get I 
>>>>>> correct values now.
>>>>>> Without the mutex it's more or less randomly changing between uAh 
>>>>>> and mWh.
>>>>>> I would writeup a patch and submit it as proposal.
>>>>>> 
>>>>>>  From my understanding of the SBS Spec (Page 19) the intention of 
>>>>>> the Mode setting is
>>>>>> to select one Mode for your power source and leave it at that. For 
>>>>>> Example the AtRate()
>>>>>> calculations become wrong when you change the mode. But as the 
>>>>>> driver is not using
>>>>>> these features that might not be an issue.
>>>>> Had a quick look at that and it'd have to do the same thing as the
>>>>> sbs_get_battery_capacity
>>>>> call and use the mutex if it was implemented. Don't think we need 
>>>>> to
>>>>> wrory about it at present thou.
>>>>> 
>>>>>> 
>>>>>> I would agree that the driver does not need to change back the 
>>>>>> Mode bit as it is
>>>>>> set on every read anyway. So this is unnecessary overhead.
>>>>>> If I find time I'll submit a patch to remove this and clean up a 
>>>>>> bit.
>>>>>> 
>>>>> I like any speed improvement. It takes a while to poll all the 
>>>>> values
>>>>> from the battery.
>>>> 
>>>> I did some more testing and came to a bit disappointing outcome. I
>>>> don't know if this is specific to my battery or a general thing with
>>>> SBS devices.
>>>> When I set the CAPACITY_MODE bit the change is not always effective
>>>> immediately. Sometimes it works, sometimes it takes a few ms and
>>>> sometimes the bit never changes and I have to write it again.
>>>> 
>>>> So there seems to be no guarantee to get the reading in the expected
>>>> format.
>>>> 
>>>> How could this be handled? Return an error when the CAPACITY_MODE 
>>>> bit
>>>> was not set succesfully? Retry setting it (which takes time)?
>>> 
>>> Where you getting an i2c error or it just failing to set.
>>> I've got a number of different Inspired Energy batteries on hand that
>>> I can test against.
>>> I'll try and run some tests with you patch today and see what I get 
>>> with them.
>>> 
>> The i2c calls return successfully. The value reported is in the wrong 
>> unit and
>> the status register is also not changed.
>> 
>> I saw that you introduced a delay, this should help at least in
>> ~50% of the times. Do you always see correct values with your
>> batteries?
> 
> Yeah I also saw no error messaging. Battery acks the command ok.
> I hooked a scope up to the sda / scl lines and there was also no 
> evidence of bus
> stretching by the battery to force the host to wait.
> 
> Prior to adding the delay I applied the changes to not reset the mode 
> bit.
> That allowed me to poll the charge / energy registers without the mode
> change reseting.
> 
> I've got a 4 battery system and I'd see some of the batteries change 
> mode.
> Continuously polling them for say energy when they'd all been in charge 
> "mode"
> they'd eventually set themselves to the correct mode and stay there.
> But it was very random.
> 
> After the delay I've done hundreds of cycle on each battery and they
> seem to be behaving.
> Just reading the status register after the set seemed to upset them
> and they wouldn't change mode.
> Bus had to be completely idle.

I have some testing with your patches running and it seems to give 
stable
correct results. When I additionaly check the register after the delay I
start seeing wrong values. So I can confirm your observation that they
don't seem to like it.

> 
> Thought I'd post the patches for you to have a play with and anyone
> else to comment on.
> 
> I was also going to send Insipred Energy support an email to see what
> they had to say.
> 
Cool! Since the standard doesn't define timings that might be pretty
helpful.

> 
>> 
>> I added something like this at the end of sbs_set_battery_mode
>> 
>>      ret = sbs_read_word_data(client, BATTERY_MODE_OFFSET);
>>      if ((ret & BATTERY_MODE_MASK) != mode)
>>                 return -ENODATA;
>> 
>> In this way one knows if the value is actually in the right unit
>> which as it is currently implemented is not the case. But this of
>> course adds more delay.
>> 
>> I will now do some tests with your submitted patches.
>> 

      reply	other threads:[~2017-07-10 15:42 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-06 15:23 sbs-battery: Reading CHARGE in uAh Michael Heinemann
2017-07-07  1:49 ` Phil Reid
2017-07-07  8:01   ` Michael Heinemann
2017-07-07  8:27     ` Phil Reid
2017-07-07 13:06       ` Michael Heinemann
2017-07-10  1:35         ` Phil Reid
2017-07-10  7:54           ` Michael Heinemann
2017-07-10  8:04             ` Phil Reid
2017-07-10 15:42               ` Michael Heinemann [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d5cf5eac247af66bba5a260e2eee7c51@heine.so \
    --to=posted@heine.so \
    --cc=linux-pm@vger.kernel.org \
    --cc=preid@electromag.com.au \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox