Skip to contentSkip to conversation

devicetree battery support and client bq27xxx_battery

PATCH Superseded Liam Breck 6 participants 35 messages Mar 15, 2017 – Mar 20, 2017 3 messages not in the archive

Subsystems (4)

v10 of 14 Superseded Latest is v14 →

lore
Share & tools
lore

Liam Breck

author
#0 lore raw

v10 cover devicetree battery support and client bq27xxx_battery

Overview:
* new devicetree battery node specifies static battery data
* fuel gauge and charger nodes shall use monitored-battery=<&battery_node>
* new power_supply_get_battery_info() reads battery data from devicetree
* new struct power_supply_battery_info provides battery data to drivers
* drivers surface battery data in sysfs via related power_supply_prop_* fields
* bq27xxx driver calls the above and writes battery data to RAM/NVM for params essential to correct operation: energy-full-design-microwatt-hours, charge-full-design-microamp-hours, voltage-min-design-microvolt

Changes in v10:
bq27xxx_battery:

*   pass actual chip ID into _setup()
*   add di->unseal_key & di->dm_regs; drop static arrays
*   support bq27425, 441, 621

Changes in v9:
bq27xxx_battery:

*   fix set_cfgupdate()
*   support bq27500, 545, 421; defer others
*   drop print_dm_blocks() patch
*   minor polishing

Documentation/devicetree/.../battery.txt:
* describe rationale for enum power_supply_property names

Changes in v8:
bq27xxx_battery:

*   wait on flag after set_cfgupdate & soft_reset
*   drop print_config(), report status in update_dm_block()
*   clarify error messages
*   cleanup from Andrew's feedback; minor polishing

Changes in v7:
bq27xxx_battery:

*   support chips where terminate_voltage & design_* live in separate blocks
*   draft support for 421, 441, 621 chips
*   new patch to log chip memory fields
*   report bus I/O errors; return error code in bq27xxx_battery_i2c
*   verify checksum in read_dm_block()
*   use set_cfgupdate only if chip provides it, soft_reset on I/O error
*   block_data_control=0 only in write_dm_block()
*   note toxic code from TI bqtool in write_dm_block()
*   lots of functionally neutral polishing

Documentation/devicetree/.../battery.txt:
* mention power_supply_get_battery_info()

Changes in v6:
* Documentation/devictree/... fixes
* bq27xxx_battery: clarify names
* bq27xxx_battery: verify that selected registers are supported
* bq27xxx_battery: allocate NVM buffer on stack
* bq27xxx_battery_i2c: fix return code of bulk_read

Changes in v5:
* incorporate feedback into Documentation/devicetree/.../battery.txt
* use power_supply_prop_* names in devicetree and power_supply_battery_info
* default fields to -EINVAL in power_supply_battery_info
* power_supply_get_battery_info() always looks for "monitored-battery"
* power_supply_get_battery_info() emits a warning if !psy->of_node
* squash patches for power_supply_battery_info
* bq27xxx_battery: check power_supply_battery_info values
* bq27xxx_battery: note missing power_supply_prop_* features
* bq27xxx_battery: new patch for access methods

Changes in v4:
* add "fixed-battery" compatible field to be be more consistant with devicetree

Changes in v3:
* split i2c changes into respective patches
* add documentation for battery information for fuel gauge
* rebased documentation patches on change on the list
* abstracted the battery configuration for the state machine to an generic struct and platform data access function

Changes in v2:
* add documentation for uWh and uAh property units
* change devicetree entries to match new property units

Liam (5):
devicetree: power: Add battery.txt
devicetree: power: bq27xxx: Add monitored-battery documentation
power: power_supply: Add power_supply_battery_info and API
power: bq27xxx_battery: Keep track of specific chip id
power: bq27xxx_battery: Add power_supply_battery_info support

Matt Ranostay (3):
devicetree: property-units: Add uWh and uAh units
power: bq27xxx_battery: Define access methods to write chip registers
power: bq27xxx_battery_i2c: Add I2C bulk read/write functions

 .../devicetree/bindings/power/supply/battery.txt   |  45 ++
 .../devicetree/bindings/power/supply/bq27xxx.txt   |  11 +-
 .../devicetree/bindings/property-units.txt         |   2 +
 drivers/power/supply/bq27xxx_battery.c             | 477 ++++++++++++++++++++-
 drivers/power/supply/bq27xxx_battery_i2c.c         |  98 ++++-
 drivers/power/supply/power_supply_core.c           |  40 ++
 include/linux/power/bq27xxx_battery.h              |  30 +-
 include/linux/power_supply.h                       |  18 +
 8 files changed, 702 insertions(+), 19 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Signature · 1 line
2.9.3

A message that is not in the archive (sent off-list or not yet received): 20170315192653.26799-1-liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org

#2 lore raw

PATCH v10 1/8 devicetree: power: Add battery.txt

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +45 -0
new file mode 100644
index 0000000..0278617
@@ -0,0 +1,45 @@
+Battery Characteristics
+
+Required Properties:
+ - compatible: Must be "fixed-battery"
+
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity
+
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.
+
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".
+
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c
+
+Example:
+
+	bat: battery {
+		compatible = "fixed-battery";
+		voltage-min-design-microvolt = <3200000>;
+		energy-full-design-microwatt-hours = <5290000>;
+		charge-full-design-microamp-hours = <1430000>;
+	};
+
+	charger: charger@11 {
+		....
+		monitored-battery = <&bat>;
+		...
+	};
+
+	fuel_gauge: fuel-gauge@22 {
+		....
+		monitored-battery = <&bat>;
+		...
+	};
Signature · 6 lines
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#3 lore raw

Re: [PATCH v10 1/8] devicetree: power: Add battery.txt

Hi Liam & Matt,

Sorry for my absence in the discussion. I skipped the previous iterations for now and start with this version.

Quoted 21 lines · Liam Breck

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +0 -0
new file mode 100644
index 0000000..0278617

Documentation/devicetree/bindings/power/supply/battery.txt line 1

Quoted 1 line
Documentation/devicetree/bindings/power/supply/battery.txt new file +1 -0
@@ -0,0 +1,45 @@
+Battery Characteristics

Maybe add something like

This device provides static battery information, that is usually available in the EEPROM of a smart battery. It's supposed to be used for batteries, which do not have their own EEPROM (or if its unusable).

Documentation/devicetree/bindings/power/supply/battery.txt line 9

Quoted 7 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +7 -0
+Required Properties:
+ - compatible: Must be "fixed-battery"
+
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity

Looks fine to me.

Documentation/devicetree/bindings/power/supply/battery.txt line 15

Quoted 5 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -0
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.

This is Linux/implementation specific and does not belong into a DT binding document.

Documentation/devicetree/bindings/power/supply/battery.txt line 19

Quoted 3 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +3 -0
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".

This looks fine.

Documentation/devicetree/bindings/power/supply/battery.txt line 24

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c

This is also Linux/implementation specific and should be dropped.

Quoted 23 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +20 -0
+Example:
+
+	bat: battery {
+		compatible = "fixed-battery";
+		voltage-min-design-microvolt = <3200000>;
+		energy-full-design-microwatt-hours = <5290000>;
+		charge-full-design-microamp-hours = <1430000>;
+	};
+
+	charger: charger@11 {
+		....
+		monitored-battery = <&bat>;
+		...
+	};
+
+	fuel_gauge: fuel-gauge@22 {
+		....
+		monitored-battery = <&bat>;
+		...
+	};
Signature · 1 line
2.9.3
#4 lore raw

Re: [PATCH v10 1/8] devicetree: power: Add battery.txt

Hey Sebastian, welcome back :-)

I've taken over work on this patchset from Matt.

Quoted 31 lines · Sebastian Reichel

Hi Liam & Matt,

Sorry for my absence in the discussion. I skipped the previous iterations for now and start with this version.

Quoted 21 lines · Liam Breck

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +0 -0
new file mode 100644
index 0000000..0278617

Documentation/devicetree/bindings/power/supply/battery.txt line 1

Quoted 1 line
Documentation/devicetree/bindings/power/supply/battery.txt new file +1 -0
@@ -0,0 +1,45 @@
+Battery Characteristics

Maybe add something like

Quoted 4 lines

This device provides static battery information, that is usually available in the EEPROM of a smart battery. It's supposed to be used for batteries, which do not have their own EEPROM (or if its unusable).

OK.

Quoted 2 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 4

Quoted 2 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +2 -0
+Required Properties:
+ - compatible: Must be "fixed-battery"

Rob questioned the term "fixed". Shall we consider other terms -- simple-battery, plain-battery...?

Quoted 7 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 9

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity

Looks fine to me.

Quoted 8 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 15

Quoted 5 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -0
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.

This is Linux/implementation specific and does not belong into a DT binding document.

I just wrote on a thread for an earlier version of this patch:

"Sebastian proposed DT:battery specifically to be consumed by power_supply_core. Allowing names in DT:battery and power_supply_property to diverge would cause confusion and wasted time, for no particular benefit. As there is no rationale to reconsider the names of these fields for DT:battery, let's write that into the docs."

Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 19

Quoted 3 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +3 -0
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".

This looks fine.

Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 24

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c

This is also Linux/implementation specific and should be dropped.

We ought to mention how drivers are expected to consume DT:battery.

Quoted 15 lines
Quoted 15 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +15 -0
+Example:
+
+     bat: battery {
+             compatible = "fixed-battery";
+             voltage-min-design-microvolt = <3200000>;
+             energy-full-design-microwatt-hours = <5290000>;
+             charge-full-design-microamp-hours = <1430000>;
+     };
+
+     charger: charger@11 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
+
Quoted 8 lines
Quoted 8 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -1
+     fuel_gauge: fuel-gauge@22 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
--

2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#5 lore raw

Re: [PATCH v10 1/8] devicetree: power: Add battery.txt

Hi,

Quoted 3 lines · Liam Breck

Hey Sebastian, welcome back :-)

I've taken over work on this patchset from Matt.

Ok.

Quoted 37 lines · Sebastian Reichel
Quoted 31 lines

Hi Liam & Matt,

Sorry for my absence in the discussion. I skipped the previous iterations for now and start with this version.

Quoted 21 lines · Liam Breck

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +0 -0
new file mode 100644
index 0000000..0278617

Documentation/devicetree/bindings/power/supply/battery.txt line 1

Quoted 1 line
Documentation/devicetree/bindings/power/supply/battery.txt new file +1 -0
@@ -0,0 +1,45 @@
+Battery Characteristics

Maybe add something like

Quoted 4 lines

This device provides static battery information, that is usually available in the EEPROM of a smart battery. It's supposed to be used for batteries, which do not have their own EEPROM (or if its unusable).

Quoted 7 lines

OK.

Quoted 2 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 4

Quoted 2 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +2 -0
+Required Properties:
+ - compatible: Must be "fixed-battery"

Rob questioned the term "fixed". Shall we consider other terms -- simple-battery, plain-battery...?

I don't like the term either, but it was the best I came up with. They are known as "dumb" batteries, but that term looks too colloquial for DT usage. While I think "simple-battery" is not perfect either, it's better than "fixed-battery", so please switch to that in the next revision.

Quoted 16 lines
Quoted 7 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 9

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity

Looks fine to me.

Quoted 8 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 15

Quoted 5 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -0
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.

This is Linux/implementation specific and does not belong into a DT binding document.

Quoted 8 lines

I just wrote on a thread for an earlier version of this patch:

"Sebastian proposed DT:battery specifically to be consumed by power_supply_core. Allowing names in DT:battery and power_supply_property to diverge would cause confusion and wasted time, for no particular benefit. As there is no rationale to reconsider the names of these fields for DT:battery, let's write that into the docs."

DT bindings are not "Linux hardware information bindings". Of course there is no need to diverge without a good reason, but that kind of Documentation just does not belong into the DT bindings.

Quoted 6 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 19

Quoted 3 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +3 -0
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".

This looks fine.

Quoted 8 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 24

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c

This is also Linux/implementation specific and should be dropped.

We ought to mention how drivers are expected to consume DT:battery.

That kind of documentation does not belong into Documentation/devicetree/bindings. We can add something to Documentation/power/power_supply_class.txt instead.

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +20 -1
+Example:
+
+     bat: battery {
+             compatible = "fixed-battery";
+             voltage-min-design-microvolt = <3200000>;
+             energy-full-design-microwatt-hours = <5290000>;
+             charge-full-design-microamp-hours = <1430000>;
+     };
+
+     charger: charger@11 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
+
+     fuel_gauge: fuel-gauge@22 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
--

2.9.3

#6 lore raw

Re: [PATCH v10 1/8] devicetree: power: Add battery.txt

Quoted 51 lines · Sebastian Reichel

Hi,

Quoted 3 lines · Liam Breck

Hey Sebastian, welcome back :-)

I've taken over work on this patchset from Matt.

Ok.

Quoted 42 lines · Sebastian Reichel
Quoted 31 lines

Hi Liam & Matt,

Sorry for my absence in the discussion. I skipped the previous iterations for now and start with this version.

Quoted 21 lines · Liam Breck

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +0 -0
new file mode 100644
index 0000000..0278617

Documentation/devicetree/bindings/power/supply/battery.txt line 1

Quoted 1 line
Documentation/devicetree/bindings/power/supply/battery.txt new file +1 -0
@@ -0,0 +1,45 @@
+Battery Characteristics

Maybe add something like

Quoted 4 lines

This device provides static battery information, that is usually available in the EEPROM of a smart battery. It's supposed to be used for batteries, which do not have their own EEPROM (or if its unusable).

OK.

Quoted 2 lines
Quoted 2 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +2 -0
+Required Properties:
+ - compatible: Must be "fixed-battery"
Quoted 9 lines
Quoted 2 lines

Rob questioned the term "fixed". Shall we consider other terms -- simple-battery, plain-battery...?

I don't like the term either, but it was the best I came up with. They are known as "dumb" batteries, but that term looks too colloquial for DT usage. While I think "simple-battery" is not perfect either, it's better than "fixed-battery", so please switch to that in the next revision.

I rather like "fixed-battery", it matches the regulator and other power source DTs better. To answer Rob's question on what a non-fixed battery would look like we can think of a future battery that can change its physical properties (chemical or physical perhaps) in response to software. Although I've not seen such a battery I don't think it's too far-fetched.

All the properties described here are "fixed", if we say "simple" then a battery with more properties would be a "complex" battery..

Quoted 63 lines
Quoted 16 lines
Quoted 7 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 9

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity

Looks fine to me.

Quoted 8 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 15

Quoted 5 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -0
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.

This is Linux/implementation specific and does not belong into a DT binding document.

Quoted 8 lines

I just wrote on a thread for an earlier version of this patch:

"Sebastian proposed DT:battery specifically to be consumed by power_supply_core. Allowing names in DT:battery and power_supply_property to diverge would cause confusion and wasted time, for no particular benefit. As there is no rationale to reconsider the names of these fields for DT:battery, let's write that into the docs."

DT bindings are not "Linux hardware information bindings". Of course there is no need to diverge without a good reason, but that kind of Documentation just does not belong into the DT bindings.

Quoted 6 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 19

Quoted 3 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +3 -0
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".

This looks fine.

Quoted 8 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 24

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c

This is also Linux/implementation specific and should be dropped.

We ought to mention how drivers are expected to consume DT:battery.

That kind of documentation does not belong into Documentation/devicetree/bindings. We can add something to Documentation/power/power_supply_class.txt instead.

Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +15 -0
+Example:
+
+     bat: battery {
+             compatible = "fixed-battery";
+             voltage-min-design-microvolt = <3200000>;
+             energy-full-design-microwatt-hours = <5290000>;
+             charge-full-design-microamp-hours = <1430000>;
+     };
+
+     charger: charger@11 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -1
+     fuel_gauge: fuel-gauge@22 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
--

2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

author
#7 lore raw

Re: [PATCH v10 1/8] devicetree: power: Add battery.txt

Quoted 62 lines · Andrew F. Davis
Quoted 51 lines · Sebastian Reichel

Hi,

Quoted 3 lines · Liam Breck

Hey Sebastian, welcome back :-)

I've taken over work on this patchset from Matt.

Ok.

Quoted 42 lines · Sebastian Reichel
Quoted 31 lines

Hi Liam & Matt,

Sorry for my absence in the discussion. I skipped the previous iterations for now and start with this version.

Quoted 21 lines · Liam Breck

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +0 -0
new file mode 100644
index 0000000..0278617

Documentation/devicetree/bindings/power/supply/battery.txt line 1

Quoted 1 line
Documentation/devicetree/bindings/power/supply/battery.txt new file +1 -0
@@ -0,0 +1,45 @@
+Battery Characteristics

Maybe add something like

Quoted 4 lines

This device provides static battery information, that is usually available in the EEPROM of a smart battery. It's supposed to be used for batteries, which do not have their own EEPROM (or if its unusable).

OK.

Quoted 2 lines
Quoted 2 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +2 -0
+Required Properties:
+ - compatible: Must be "fixed-battery"
Quoted 9 lines
Quoted 2 lines

Rob questioned the term "fixed". Shall we consider other terms -- simple-battery, plain-battery...?

I don't like the term either, but it was the best I came up with. They are known as "dumb" batteries, but that term looks too colloquial for DT usage. While I think "simple-battery" is not perfect either, it's better than "fixed-battery", so please switch to that in the next revision.

Quoted 6 lines

I rather like "fixed-battery", it matches the regulator and other power source DTs better. To answer Rob's question on what a non-fixed battery would look like we can think of a future battery that can change its physical properties (chemical or physical perhaps) in response to software. Although I've not seen such a battery I don't think it's too far-fetched.

A "fixed" battery sounds like a non-removable one to me. I'll switch to "simple-battery" in v11 unless a better idea bubbles up first.

Quoted 2 lines

All the properties described here are "fixed", if we say "simple" then a battery with more properties would be a "complex" battery..

Simple is not a boolean term; it really doesn't mandate a "complex-battery" type.

Quoted 71 lines
Quoted 71 lines
Quoted 16 lines
Quoted 7 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 9

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity

Looks fine to me.

Quoted 8 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 15

Quoted 5 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -0
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.

This is Linux/implementation specific and does not belong into a DT binding document.

Quoted 8 lines

I just wrote on a thread for an earlier version of this patch:

"Sebastian proposed DT:battery specifically to be consumed by power_supply_core. Allowing names in DT:battery and power_supply_property to diverge would cause confusion and wasted time, for no particular benefit. As there is no rationale to reconsider the names of these fields for DT:battery, let's write that into the docs."

DT bindings are not "Linux hardware information bindings". Of course there is no need to diverge without a good reason, but that kind of Documentation just does not belong into the DT bindings.

Quoted 6 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 19

Quoted 3 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +3 -0
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".

This looks fine.

Quoted 8 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 24

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c

This is also Linux/implementation specific and should be dropped.

We ought to mention how drivers are expected to consume DT:battery.

That kind of documentation does not belong into Documentation/devicetree/bindings. We can add something to Documentation/power/power_supply_class.txt instead.

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +20 -1
+Example:
+
+     bat: battery {
+             compatible = "fixed-battery";
+             voltage-min-design-microvolt = <3200000>;
+             energy-full-design-microwatt-hours = <5290000>;
+             charge-full-design-microamp-hours = <1430000>;
+     };
+
+     charger: charger@11 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
+
+     fuel_gauge: fuel-gauge@22 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
--

2.9.3

#8 lore raw

Re: [PATCH v10 1/8] devicetree: power: Add battery.txt

Quoted 70 lines · Liam Breck
Quoted 62 lines · Andrew F. Davis
Quoted 51 lines · Sebastian Reichel

Hi,

Quoted 3 lines · Liam Breck

Hey Sebastian, welcome back :-)

I've taken over work on this patchset from Matt.

Ok.

Quoted 42 lines · Sebastian Reichel
Quoted 31 lines

Hi Liam & Matt,

Sorry for my absence in the discussion. I skipped the previous iterations for now and start with this version.

Quoted 21 lines · Liam Breck

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +0 -0
new file mode 100644
index 0000000..0278617

Documentation/devicetree/bindings/power/supply/battery.txt line 1

Quoted 1 line
Documentation/devicetree/bindings/power/supply/battery.txt new file +1 -0
@@ -0,0 +1,45 @@
+Battery Characteristics

Maybe add something like

Quoted 4 lines

This device provides static battery information, that is usually available in the EEPROM of a smart battery. It's supposed to be used for batteries, which do not have their own EEPROM (or if its unusable).

OK.

Quoted 2 lines
Quoted 2 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +2 -0
+Required Properties:
+ - compatible: Must be "fixed-battery"
Quoted 9 lines
Quoted 2 lines

Rob questioned the term "fixed". Shall we consider other terms -- simple-battery, plain-battery...?

I don't like the term either, but it was the best I came up with. They are known as "dumb" batteries, but that term looks too colloquial for DT usage. While I think "simple-battery" is not perfect either, it's better than "fixed-battery", so please switch to that in the next revision.

Quoted 6 lines

I rather like "fixed-battery", it matches the regulator and other power source DTs better. To answer Rob's question on what a non-fixed battery would look like we can think of a future battery that can change its physical properties (chemical or physical perhaps) in response to software. Although I've not seen such a battery I don't think it's too far-fetched.

Quoted 3 lines

A "fixed" battery sounds like a non-removable one to me. I'll switch to "simple-battery" in v11 unless a better idea bubbles up first.

Are fixed-regulators non-removable, or do most people understand. Also this is for non-removable batteries, if a battery is changeable then this DT is not valid as it would be describing the current configuration of the device. I guess it could be done with overlays for the current battery, not sure, but something to think about.

Quoted 6 lines
Quoted 2 lines

All the properties described here are "fixed", if we say "simple" then a battery with more properties would be a "complex" battery..

Simple is not a boolean term; it really doesn't mandate a "complex-battery" type.

Yes, but the spectrum would imply levels of simplicity, what would *you* call a "non-simple" battery?

Quoted 76 lines
Quoted 63 lines
Quoted 63 lines
Quoted 16 lines
Quoted 7 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 9

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity

Looks fine to me.

Quoted 8 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 15

Quoted 5 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -0
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.

This is Linux/implementation specific and does not belong into a DT binding document.

Quoted 8 lines

I just wrote on a thread for an earlier version of this patch:

"Sebastian proposed DT:battery specifically to be consumed by power_supply_core. Allowing names in DT:battery and power_supply_property to diverge would cause confusion and wasted time, for no particular benefit. As there is no rationale to reconsider the names of these fields for DT:battery, let's write that into the docs."

DT bindings are not "Linux hardware information bindings". Of course there is no need to diverge without a good reason, but that kind of Documentation just does not belong into the DT bindings.

Quoted 6 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 19

Quoted 3 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +3 -0
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".

This looks fine.

Quoted 8 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 24

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c

This is also Linux/implementation specific and should be dropped.

We ought to mention how drivers are expected to consume DT:battery.

That kind of documentation does not belong into Documentation/devicetree/bindings. We can add something to Documentation/power/power_supply_class.txt instead.

Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +15 -0
+Example:
+
+     bat: battery {
+             compatible = "fixed-battery";
+             voltage-min-design-microvolt = <3200000>;
+             energy-full-design-microwatt-hours = <5290000>;
+             charge-full-design-microamp-hours = <1430000>;
+     };
+
+     charger: charger@11 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -1
+     fuel_gauge: fuel-gauge@22 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
--

2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author
#9 lore raw

Re: [PATCH v10 1/8] devicetree: power: Add battery.txt

Quoted 75 lines · Andrew F. Davis
Quoted 70 lines · Liam Breck
Quoted 62 lines · Andrew F. Davis
Quoted 51 lines · Sebastian Reichel

Hi,

Quoted 3 lines · Liam Breck

Hey Sebastian, welcome back :-)

I've taken over work on this patchset from Matt.

Ok.

Quoted 42 lines · Sebastian Reichel
Quoted 31 lines

Hi Liam & Matt,

Sorry for my absence in the discussion. I skipped the previous iterations for now and start with this version.

Quoted 21 lines · Liam Breck

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +0 -0
new file mode 100644
index 0000000..0278617

Documentation/devicetree/bindings/power/supply/battery.txt line 1

Quoted 1 line
Documentation/devicetree/bindings/power/supply/battery.txt new file +1 -0
@@ -0,0 +1,45 @@
+Battery Characteristics

Maybe add something like

Quoted 4 lines

This device provides static battery information, that is usually available in the EEPROM of a smart battery. It's supposed to be used for batteries, which do not have their own EEPROM (or if its unusable).

OK.

Quoted 2 lines
Quoted 2 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +2 -0
+Required Properties:
+ - compatible: Must be "fixed-battery"
Quoted 9 lines
Quoted 2 lines

Rob questioned the term "fixed". Shall we consider other terms -- simple-battery, plain-battery...?

I don't like the term either, but it was the best I came up with. They are known as "dumb" batteries, but that term looks too colloquial for DT usage. While I think "simple-battery" is not perfect either, it's better than "fixed-battery", so please switch to that in the next revision.

Quoted 6 lines

I rather like "fixed-battery", it matches the regulator and other power source DTs better. To answer Rob's question on what a non-fixed battery would look like we can think of a future battery that can change its physical properties (chemical or physical perhaps) in response to software. Although I've not seen such a battery I don't think it's too far-fetched.

Quoted 3 lines

A "fixed" battery sounds like a non-removable one to me. I'll switch to "simple-battery" in v11 unless a better idea bubbles up first.

Quoted 5 lines

Are fixed-regulators non-removable, or do most people understand. Also this is for non-removable batteries, if a battery is changeable then this DT is not valid as it would be describing the current configuration of the device. I guess it could be done with overlays for the current battery, not sure, but something to think about.

I know little about regulators, but wikipedia mentions fixed and variable/adjustable kinds. We're not contemplating an "adjustable battery" type, so the fixed/adjustable dichotomy isn't a natural fit here.

Quoted 9 lines
Quoted 6 lines
Quoted 2 lines

All the properties described here are "fixed", if we say "simple" then a battery with more properties would be a "complex" battery..

Simple is not a boolean term; it really doesn't mandate a "complex-battery" type.

Yes, but the spectrum would imply levels of simplicity, what would *you* call a "non-simple" battery?

Simple is not an integral term, either :-)

simple-battery, gauged-battery, coin-battery, bare-battery (no protection circuit)...

Quoted 76 lines
Quoted 76 lines
Quoted 63 lines
Quoted 63 lines
Quoted 16 lines
Quoted 7 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 7

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity

Looks fine to me.

Quoted 8 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 12

Quoted 5 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -0
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.

This is Linux/implementation specific and does not belong into a DT binding document.

Quoted 8 lines

I just wrote on a thread for an earlier version of this patch:

"Sebastian proposed DT:battery specifically to be consumed by power_supply_core. Allowing names in DT:battery and power_supply_property to diverge would cause confusion and wasted time, for no particular benefit. As there is no rationale to reconsider the names of these fields for DT:battery, let's write that into the docs."

DT bindings are not "Linux hardware information bindings". Of course there is no need to diverge without a good reason, but that kind of Documentation just does not belong into the DT bindings.

Quoted 6 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 15

Quoted 3 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +3 -0
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".

This looks fine.

Quoted 8 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 19

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c

This is also Linux/implementation specific and should be dropped.

We ought to mention how drivers are expected to consume DT:battery.

That kind of documentation does not belong into Documentation/devicetree/bindings. We can add something to Documentation/power/power_supply_class.txt instead.

Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +15 -0
+Example:
+
+     bat: battery {
+             compatible = "fixed-battery";
+             voltage-min-design-microvolt = <3200000>;
+             energy-full-design-microwatt-hours = <5290000>;
+             charge-full-design-microamp-hours = <1430000>;
+     };
+
+     charger: charger@11 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -1
+     fuel_gauge: fuel-gauge@22 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
--

2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): CAKvHMgS92WFoJa=imfAFiEEc0VyiSsDBbuYi4yzZ=LEa7__yKA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#11 lore raw

Re: [PATCH v10 1/8] devicetree: power: Add battery.txt

Quoted 82 lines · Liam Breck
Quoted 75 lines · Andrew F. Davis
Quoted 70 lines · Liam Breck
Quoted 62 lines · Andrew F. Davis
Quoted 51 lines · Sebastian Reichel

Hi,

Quoted 3 lines · Liam Breck

Hey Sebastian, welcome back :-)

I've taken over work on this patchset from Matt.

Ok.

Quoted 42 lines · Sebastian Reichel
Quoted 31 lines

Hi Liam & Matt,

Sorry for my absence in the discussion. I skipped the previous iterations for now and start with this version.

Quoted 21 lines · Liam Breck

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +0 -0
new file mode 100644
index 0000000..0278617

Documentation/devicetree/bindings/power/supply/battery.txt line 1

Quoted 1 line
Documentation/devicetree/bindings/power/supply/battery.txt new file +1 -0
@@ -0,0 +1,45 @@
+Battery Characteristics

Maybe add something like

Quoted 4 lines

This device provides static battery information, that is usually available in the EEPROM of a smart battery. It's supposed to be used for batteries, which do not have their own EEPROM (or if its unusable).

OK.

Quoted 2 lines
Quoted 2 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +2 -0
+Required Properties:
+ - compatible: Must be "fixed-battery"
Quoted 9 lines
Quoted 2 lines

Rob questioned the term "fixed". Shall we consider other terms -- simple-battery, plain-battery...?

I don't like the term either, but it was the best I came up with. They are known as "dumb" batteries, but that term looks too colloquial for DT usage. While I think "simple-battery" is not perfect either, it's better than "fixed-battery", so please switch to that in the next revision.

Quoted 6 lines

I rather like "fixed-battery", it matches the regulator and other power source DTs better. To answer Rob's question on what a non-fixed battery would look like we can think of a future battery that can change its physical properties (chemical or physical perhaps) in response to software. Although I've not seen such a battery I don't think it's too far-fetched.

Quoted 3 lines

A "fixed" battery sounds like a non-removable one to me. I'll switch to "simple-battery" in v11 unless a better idea bubbles up first.

Quoted 5 lines

Are fixed-regulators non-removable, or do most people understand. Also this is for non-removable batteries, if a battery is changeable then this DT is not valid as it would be describing the current configuration of the device. I guess it could be done with overlays for the current battery, not sure, but something to think about.

Quoted 5 lines

I know little about regulators, but wikipedia mentions fixed and variable/adjustable kinds. We're not contemplating an "adjustable battery" type, so the fixed/adjustable dichotomy isn't a natural fit here.

I think we are though, you are saying this is a "simple" battery because it has fixed design parameters. Any battery that does not have fixed design parameters is some kinda futuristic adjustable battery, what else would you call a battery with non-fixed design parameters?

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines

All the properties described here are "fixed", if we say "simple" then a battery with more properties would be a "complex" battery..

Simple is not a boolean term; it really doesn't mandate a "complex-battery" type.

Quoted 8 lines
Quoted 2 lines

Yes, but the spectrum would imply levels of simplicity, what would *you* call a "non-simple" battery?

Simple is not an integral term, either :-)

simple-battery, gauged-battery, coin-battery, bare-battery (no protection circuit)...

Fixed/simple/coin/bare batteries are all the same to DT and so do not need new node/compatible names. "Gauged-battery" would be described by a node representing the fuel-gauge and that node would then point to the battery that it gauges, no still no need for a new term.

In our world we still have only three things:
Charger -

  |      |-> Battery
  \/     |

Gauge - -

Sometimes we will have a battery, sometimes we will have a charger or a gauge with an attached battery, and sometimes we will have charger with embedded gauging functions. All these relations can be described in DT without adding extra compatibles.

Quoted 68 lines
Quoted 68 lines
Quoted 68 lines
Quoted 68 lines
Quoted 68 lines
Quoted 16 lines
Quoted 7 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 7

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity

Looks fine to me.

Quoted 8 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 12

Quoted 5 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -0
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.

This is Linux/implementation specific and does not belong into a DT binding document.

Quoted 8 lines

I just wrote on a thread for an earlier version of this patch:

"Sebastian proposed DT:battery specifically to be consumed by power_supply_core. Allowing names in DT:battery and power_supply_property to diverge would cause confusion and wasted time, for no particular benefit. As there is no rationale to reconsider the names of these fields for DT:battery, let's write that into the docs."

DT bindings are not "Linux hardware information bindings". Of course there is no need to diverge without a good reason, but that kind of Documentation just does not belong into the DT bindings.

Quoted 6 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 15

Quoted 3 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +3 -0
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".

This looks fine.

Quoted 8 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 19

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c

This is also Linux/implementation specific and should be dropped.

We ought to mention how drivers are expected to consume DT:battery.

That kind of documentation does not belong into Documentation/devicetree/bindings. We can add something to Documentation/power/power_supply_class.txt instead.

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +20 -0
+Example:
+
+     bat: battery {
+             compatible = "fixed-battery";
+             voltage-min-design-microvolt = <3200000>;
+             energy-full-design-microwatt-hours = <5290000>;
+             charge-full-design-microamp-hours = <1430000>;
+     };
+
+     charger: charger@11 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
+
+     fuel_gauge: fuel-gauge@22 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

--
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

author
#12 lore raw

Re: [PATCH v10 1/8] devicetree: power: Add battery.txt

Quoted 89 lines · Andrew F. Davis
Quoted 82 lines · Liam Breck
Quoted 75 lines · Andrew F. Davis
Quoted 70 lines · Liam Breck
Quoted 62 lines · Andrew F. Davis
Quoted 51 lines · Sebastian Reichel

Hi,

Quoted 3 lines · Liam Breck

Hey Sebastian, welcome back :-)

I've taken over work on this patchset from Matt.

Ok.

Quoted 42 lines · Sebastian Reichel
Quoted 31 lines

Hi Liam & Matt,

Sorry for my absence in the discussion. I skipped the previous iterations for now and start with this version.

Quoted 21 lines · Liam Breck

From: Liam Breck <[email protected]>

Documentation of static battery characteristics that can be defined for batteries which cannot self-identify. This information is required by fuel-gauge and charger chips for proper handling of the battery.

---
 .../devicetree/bindings/power/supply/battery.txt   | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt
Documentation/devicetree/bindings/power/supply/battery.txt new file +0 -0
new file mode 100644
index 0000000..0278617

Documentation/devicetree/bindings/power/supply/battery.txt line 1

Quoted 1 line
Documentation/devicetree/bindings/power/supply/battery.txt new file +1 -0
@@ -0,0 +1,45 @@
+Battery Characteristics

Maybe add something like

Quoted 4 lines

This device provides static battery information, that is usually available in the EEPROM of a smart battery. It's supposed to be used for batteries, which do not have their own EEPROM (or if its unusable).

OK.

Quoted 2 lines
Quoted 2 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +2 -0
+Required Properties:
+ - compatible: Must be "fixed-battery"
Quoted 9 lines
Quoted 2 lines

Rob questioned the term "fixed". Shall we consider other terms -- simple-battery, plain-battery...?

I don't like the term either, but it was the best I came up with. They are known as "dumb" batteries, but that term looks too colloquial for DT usage. While I think "simple-battery" is not perfect either, it's better than "fixed-battery", so please switch to that in the next revision.

Quoted 6 lines

I rather like "fixed-battery", it matches the regulator and other power source DTs better. To answer Rob's question on what a non-fixed battery would look like we can think of a future battery that can change its physical properties (chemical or physical perhaps) in response to software. Although I've not seen such a battery I don't think it's too far-fetched.

Quoted 3 lines

A "fixed" battery sounds like a non-removable one to me. I'll switch to "simple-battery" in v11 unless a better idea bubbles up first.

Quoted 5 lines

Are fixed-regulators non-removable, or do most people understand. Also this is for non-removable batteries, if a battery is changeable then this DT is not valid as it would be describing the current configuration of the device. I guess it could be done with overlays for the current battery, not sure, but something to think about.

Quoted 5 lines

I know little about regulators, but wikipedia mentions fixed and variable/adjustable kinds. We're not contemplating an "adjustable battery" type, so the fixed/adjustable dichotomy isn't a natural fit here.

Quoted 4 lines

I think we are though, you are saying this is a "simple" battery because it has fixed design parameters. Any battery that does not have fixed design parameters is some kinda futuristic adjustable battery, what else would you call a battery with non-fixed design parameters?

fantasy-battery :-)

Quoted 23 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines

All the properties described here are "fixed", if we say "simple" then a battery with more properties would be a "complex" battery..

Simple is not a boolean term; it really doesn't mandate a "complex-battery" type.

Quoted 8 lines
Quoted 2 lines

Yes, but the spectrum would imply levels of simplicity, what would *you* call a "non-simple" battery?

Simple is not an integral term, either :-)

simple-battery, gauged-battery, coin-battery, bare-battery (no protection circuit)...

Fixed/simple/coin/bare batteries are all the same to DT and so do not need new node/compatible names. "Gauged-battery" would be described by a node representing the fuel-gauge and that node would then point to the battery that it gauges, no still no need for a new term.

In our world we still have only three things:
Charger -

Quoted 8 lines
  |      |-> Battery
  \/     |

Gauge - -

Sometimes we will have a battery, sometimes we will have a charger or a gauge with an attached battery, and sometimes we will have charger with embedded gauging functions. All these relations can be described in DT without adding extra compatibles.

Here's the dichotomy you want: clever-battery, simple-battery :-)

But seriously... acpi-battery could be relevant.

Quoted 76 lines
Quoted 76 lines
Quoted 76 lines
Quoted 76 lines
Quoted 63 lines
Quoted 63 lines
Quoted 16 lines
Quoted 7 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 7

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Optional Properties:
+ - voltage-min-design-microvolt: drained battery voltage
+ - energy-full-design-microwatt-hours: battery design energy
+ - charge-full-design-microamp-hours: battery design capacity

Looks fine to me.

Quoted 8 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 12

Quoted 5 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -0
+Because drivers surface properties in sysfs using names derived
+from enum power_supply_property, e.g.
+/sys/class/power_supply/<device>/charge_full_design, our
+battery properties must be named for the corresponding elements in
+enum power_supply_property, defined in include/linux/power_supply.h.

This is Linux/implementation specific and does not belong into a DT binding document.

Quoted 8 lines

I just wrote on a thread for an earlier version of this patch:

"Sebastian proposed DT:battery specifically to be consumed by power_supply_core. Allowing names in DT:battery and power_supply_property to diverge would cause confusion and wasted time, for no particular benefit. As there is no rationale to reconsider the names of these fields for DT:battery, let's write that into the docs."

DT bindings are not "Linux hardware information bindings". Of course there is no need to diverge without a good reason, but that kind of Documentation just does not belong into the DT bindings.

Quoted 6 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 15

Quoted 3 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +3 -0
+Batteries must be referenced by chargers and/or fuel-gauges
+using a phandle. The phandle's property should be named
+"monitored-battery".

This looks fine.

Quoted 8 lines
Quoted 6 lines

Documentation/devicetree/bindings/power/supply/battery.txt line 19

Quoted 4 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +4 -0
+Driver code should call power_supply_get_battery_info() to obtain
+battery properties via monitored-battery. For details see:
+  drivers/power/supply/power_supply_core.c
+  drivers/power/supply/bq27xxx_battery.c

This is also Linux/implementation specific and should be dropped.

We ought to mention how drivers are expected to consume DT:battery.

That kind of documentation does not belong into Documentation/devicetree/bindings. We can add something to Documentation/power/power_supply_class.txt instead.

Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +15 -0
+Example:
+
+     bat: battery {
+             compatible = "fixed-battery";
+             voltage-min-design-microvolt = <3200000>;
+             energy-full-design-microwatt-hours = <5290000>;
+             charge-full-design-microamp-hours = <1430000>;
+     };
+
+     charger: charger@11 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Documentation/devicetree/bindings/power/supply/battery.txt new file +5 -1
+     fuel_gauge: fuel-gauge@22 {
+             ....
+             monitored-battery = <&bat>;
+             ...
+     };
--

2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#13 lore raw

PATCH v10 3/8 devicetree: power: bq27xxx: Add monitored-battery documentation

In reply to a message not in the archive

From: Liam Breck <[email protected]>

Document monitored-battery = <&battery_node>

---
 Documentation/devicetree/bindings/power/supply/bq27xxx.txt | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/power/supply/bq27xxx.txt +10 -1
index b0c95ef..cf83371 100644
@@ -28,9 +28,18 @@ Required properties:
  * "ti,bq27621" - BQ27621
 - reg: integer, i2c address of the device.
 
+Optional properties:
+- monitored-battery: phandle of battery information devicetree node
+
+  See Documentation/devicetree/bindings/power/supply/battery.txt
+  If either of the referenced battery's *-full-design-*-hours properties are set,
+  then both must be.
+
 Example:
 
-bq27510g3 {
+bq27510g3 : fuel-gauge@55 {
     compatible = "ti,bq27510g3";
     reg = <0x55>;
+
+    monitored-battery = <&bat>;
 };
Signature · 6 lines
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20170315192653.26799-4-liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org

#15 lore raw

Re: [PATCH v10 3/8] devicetree: power: bq27xxx: Add monitored-battery documentation

Quoted 9 lines · Liam Breck

From: Liam Breck <[email protected]>

Document monitored-battery = <&battery_node>

-- Sebastian

Quoted 31 lines
---
 Documentation/devicetree/bindings/power/supply/bq27xxx.txt | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/power/supply/bq27xxx.txt +10 -1
index b0c95ef..cf83371 100644
@@ -28,9 +28,18 @@ Required properties:
  * "ti,bq27621" - BQ27621
 - reg: integer, i2c address of the device.
 
+Optional properties:
+- monitored-battery: phandle of battery information devicetree node
+
+  See Documentation/devicetree/bindings/power/supply/battery.txt
+  If either of the referenced battery's *-full-design-*-hours properties are set,
+  then both must be.
+
 Example:
 
-bq27510g3 {
+bq27510g3 : fuel-gauge@55 {
     compatible = "ti,bq27510g3";
     reg = <0x55>;
+
+    monitored-battery = <&bat>;
 };
Signature · 1 line
2.9.3
author
#16 lore raw

PATCH v10 2/8 devicetree: property-units: Add uWh and uAh units

In reply to Liam Breck

From: Matt Ranostay <[email protected]>

Add entries for microwatt-hours and microamp-hours.

---
 Documentation/devicetree/bindings/property-units.txt | 2 ++
 1 file changed, 2 insertions(+)
Documentation/devicetree/bindings/property-units.txt +2 -0
index 12278d7..0849618 100644
@@ -25,8 +25,10 @@ Distance
 Electricity
 ----------------------------------------
 -microamp	: micro amps
+-microamp-hours : micro amp-hours
 -ohms		: Ohms
 -micro-ohms	: micro Ohms
+-microwatt-hours: micro Watt-hours
 -microvolt	: micro volts
 
 Temperature
Signature · 1 line
2.9.3
author
#17 lore raw

PATCH v10 4/8 power: power_supply: Add power_supply_battery_info and API

In reply to Liam Breck

From: Liam Breck <[email protected]>

power_supply_get_battery_info() reads battery data from devicetree. struct power_supply_battery_info provides battery data to drivers. Drivers may surface battery data in sysfs via corresponding POWER_SUPPLY_PROP_* fields.

---
 drivers/power/supply/power_supply_core.c | 40 ++++++++++++++++++++++++++++++++
 include/linux/power_supply.h             | 18 ++++++++++++++
 2 files changed, 58 insertions(+)
drivers/power/supply/power_supply_core.c +40 -0
index a74d8ca..c121931 100644
@@ -17,6 +17,7 @@
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/err.h>
+#include <linux/of.h>
 #include <linux/power_supply.h>
 #include <linux/thermal.h>
 #include "power_supply.h"
@@ -487,6 +488,45 @@ struct power_supply *devm_power_supply_get_by_phandle(struct device *dev,
 EXPORT_SYMBOL_GPL(devm_power_supply_get_by_phandle);
 #endif /* CONFIG_OF */
 
+int power_supply_get_battery_info(struct power_supply *psy,
+				  struct power_supply_battery_info *info)
+{
+	struct device_node *battery_np;
+	const char *value;
+	int err;
+
+	info->energy_full_design_uwh = -EINVAL;
+	info->charge_full_design_uah = -EINVAL;
+	info->voltage_min_design_uv  = -EINVAL;
+
+	if (!psy->of_node) {
+		dev_warn(&psy->dev, "%s currently only supports devicetree\n",
+			 __func__);
+		return -ENXIO;
+	}
+
+	battery_np = of_parse_phandle(psy->of_node, "monitored-battery", 0);
+	if (!battery_np)
+		return -ENODEV;
+
+	err = of_property_read_string(battery_np, "compatible", &value);
+	if (err)
+		return err;
+
+	if (strcmp("fixed-battery", value))
+		return -ENODEV;
+
+	of_property_read_u32(battery_np, "energy-full-design-microwatt-hours",
+			     &info->energy_full_design_uwh);
+	of_property_read_u32(battery_np, "charge-full-design-microamp-hours",
+			     &info->charge_full_design_uah);
+	of_property_read_u32(battery_np, "voltage-min-design-microvolt",
+			     &info->voltage_min_design_uv);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
+
 int power_supply_get_property(struct power_supply *psy,
 			    enum power_supply_property psp,
 			    union power_supply_propval *val)
include/linux/power_supply.h +18 -0
index 3965503..e84f1d3 100644
@@ -288,6 +288,21 @@ struct power_supply_info {
 	int use_for_apm;
 };
 
+/*
+ * This is the recommended struct to manage static battery parameters,
+ * populated by power_supply_get_battery_info(). Most platform drivers should
+ * use these for consistency.
+ * Its field names must correspond to elements in enum power_supply_property.
+ * The default field value is -EINVAL.
+ * Power supply class itself doesn't use this.
+ */
+
+struct power_supply_battery_info {
+	int energy_full_design_uwh;	/* microWatt-hours */
+	int charge_full_design_uah;	/* microAmp-hours */
+	int voltage_min_design_uv;	/* microVolts */
+};
+
 extern struct atomic_notifier_head power_supply_notifier;
 extern int power_supply_reg_notifier(struct notifier_block *nb);
 extern void power_supply_unreg_notifier(struct notifier_block *nb);
@@ -306,6 +321,9 @@ static inline struct power_supply *
 devm_power_supply_get_by_phandle(struct device *dev, const char *property)
 { return NULL; }
 #endif /* CONFIG_OF */
+
+extern int power_supply_get_battery_info(struct power_supply *psy,
+					 struct power_supply_battery_info *info);
 extern void power_supply_changed(struct power_supply *psy);
 extern int power_supply_am_i_supplied(struct power_supply *psy);
 extern int power_supply_set_battery_charged(struct power_supply *psy);
Signature · 1 line
2.9.3
maintainer Acked-by on v10 4/8
#18 lore raw

Re: [PATCH v10 4/8] power: power_supply: Add power_supply_battery_info and API

Hi,

Quoted 9 lines · Liam Breck

From: Liam Breck <[email protected]>

power_supply_get_battery_info() reads battery data from devicetree. struct power_supply_battery_info provides battery data to drivers. Drivers may surface battery data in sysfs via corresponding POWER_SUPPLY_PROP_* fields.

-- Sebastian

Quoted 102 lines
---
 drivers/power/supply/power_supply_core.c | 40 ++++++++++++++++++++++++++++++++
 include/linux/power_supply.h             | 18 ++++++++++++++
 2 files changed, 58 insertions(+)
drivers/power/supply/power_supply_core.c +40 -0
index a74d8ca..c121931 100644
@@ -17,6 +17,7 @@
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/err.h>
+#include <linux/of.h>
 #include <linux/power_supply.h>
 #include <linux/thermal.h>
 #include "power_supply.h"
@@ -487,6 +488,45 @@ struct power_supply *devm_power_supply_get_by_phandle(struct device *dev,
 EXPORT_SYMBOL_GPL(devm_power_supply_get_by_phandle);
 #endif /* CONFIG_OF */
 
+int power_supply_get_battery_info(struct power_supply *psy,
+				  struct power_supply_battery_info *info)
+{
+	struct device_node *battery_np;
+	const char *value;
+	int err;
+
+	info->energy_full_design_uwh = -EINVAL;
+	info->charge_full_design_uah = -EINVAL;
+	info->voltage_min_design_uv  = -EINVAL;
+
+	if (!psy->of_node) {
+		dev_warn(&psy->dev, "%s currently only supports devicetree\n",
+			 __func__);
+		return -ENXIO;
+	}
+
+	battery_np = of_parse_phandle(psy->of_node, "monitored-battery", 0);
+	if (!battery_np)
+		return -ENODEV;
+
+	err = of_property_read_string(battery_np, "compatible", &value);
+	if (err)
+		return err;
+
+	if (strcmp("fixed-battery", value))
+		return -ENODEV;
+
+	of_property_read_u32(battery_np, "energy-full-design-microwatt-hours",
+			     &info->energy_full_design_uwh);
+	of_property_read_u32(battery_np, "charge-full-design-microamp-hours",
+			     &info->charge_full_design_uah);
+	of_property_read_u32(battery_np, "voltage-min-design-microvolt",
+			     &info->voltage_min_design_uv);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
+
 int power_supply_get_property(struct power_supply *psy,
 			    enum power_supply_property psp,
 			    union power_supply_propval *val)
include/linux/power_supply.h +18 -0
index 3965503..e84f1d3 100644
@@ -288,6 +288,21 @@ struct power_supply_info {
 	int use_for_apm;
 };
 
+/*
+ * This is the recommended struct to manage static battery parameters,
+ * populated by power_supply_get_battery_info(). Most platform drivers should
+ * use these for consistency.
+ * Its field names must correspond to elements in enum power_supply_property.
+ * The default field value is -EINVAL.
+ * Power supply class itself doesn't use this.
+ */
+
+struct power_supply_battery_info {
+	int energy_full_design_uwh;	/* microWatt-hours */
+	int charge_full_design_uah;	/* microAmp-hours */
+	int voltage_min_design_uv;	/* microVolts */
+};
+
 extern struct atomic_notifier_head power_supply_notifier;
 extern int power_supply_reg_notifier(struct notifier_block *nb);
 extern void power_supply_unreg_notifier(struct notifier_block *nb);
@@ -306,6 +321,9 @@ static inline struct power_supply *
 devm_power_supply_get_by_phandle(struct device *dev, const char *property)
 { return NULL; }
 #endif /* CONFIG_OF */
+
+extern int power_supply_get_battery_info(struct power_supply *psy,
+					 struct power_supply_battery_info *info);
 extern void power_supply_changed(struct power_supply *psy);
 extern int power_supply_am_i_supplied(struct power_supply *psy);
 extern int power_supply_set_battery_charged(struct power_supply *psy);
Signature · 1 line
2.9.3
author
#19 lore raw

PATCH v10 5/8 power: bq27xxx_battery: Define access methods to write chip registers

In reply to Liam Breck

From: Matt Ranostay <[email protected]>

write(), read_bulk(), write_bulk() support setting chip registers, e.g. with data obtained from power_supply_battery_info.

---
 include/linux/power/bq27xxx_battery.h | 3 +++
 1 file changed, 3 insertions(+)
include/linux/power/bq27xxx_battery.h +3 -0
index bed9557..92df553 100644
@@ -32,6 +32,9 @@ struct bq27xxx_platform_data {
 struct bq27xxx_device_info;
 struct bq27xxx_access_methods {
 	int (*read)(struct bq27xxx_device_info *di, u8 reg, bool single);
+	int (*write)(struct bq27xxx_device_info *di, u8 reg, int value, bool single);
+	int (*read_bulk)(struct bq27xxx_device_info *di, u8 reg, u8 *data, int len);
+	int (*write_bulk)(struct bq27xxx_device_info *di, u8 reg, u8 *data, int len);
 };
 
 struct bq27xxx_reg_cache {
Signature · 1 line
2.9.3
author
#20 lore raw

PATCH v10 6/8 power: bq27xxx_battery: Keep track of specific chip id

In reply to Liam Breck

From: Liam Breck <[email protected]>

Pass actual chip ID into _setup(), which translates it to a group ID, to allow support for all chips by the power_supply_battery_info code. There are no functional changes to the driver.

---
 drivers/power/supply/bq27xxx_battery.c     | 19 +++++++++++++++++++
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++++++++--------
 include/linux/power/bq27xxx_battery.h      | 25 ++++++++++++++++++-------
 3 files changed, 45 insertions(+), 15 deletions(-)
drivers/power/supply/bq27xxx_battery.c +19 -0
index 7272d1e..d613d3d 100644
@@ -1020,6 +1020,25 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 	struct power_supply_desc *psy_desc;
 	struct power_supply_config psy_cfg = { .drv_data = di, };
 
+	switch(di->chip) {
+	case BQ27000:
+	case BQ27010:
+	case BQ27500:
+	case BQ27510:
+	case BQ27530:
+	case BQ27541:
+	case BQ27545:
+	case BQ27421: break;
+	case BQ27520: di->chip = BQ27510; break;
+	case BQ27531: di->chip = BQ27530; break;
+	case BQ27542: di->chip = BQ27541; break;
+	case BQ27546: di->chip = BQ27541; break;
+	case BQ27742: di->chip = BQ27541; break;
+	case BQ27425: di->chip = BQ27421; break;
+	case BQ27441: di->chip = BQ27421; break;
+	case BQ27621: di->chip = BQ27421; break;
+	}
+
 	INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
 	mutex_init(&di->lock);
 	di->regs = bq27xxx_regs[di->chip];
drivers/power/supply/bq27xxx_battery_i2c.c +8 -8
index 5c5c3a6..13def59 100644
@@ -150,18 +150,18 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
 	{ "bq27210", BQ27010 },
 	{ "bq27500", BQ27500 },
 	{ "bq27510", BQ27510 },
-	{ "bq27520", BQ27510 },
+	{ "bq27520", BQ27520 },
 	{ "bq27530", BQ27530 },
-	{ "bq27531", BQ27530 },
+	{ "bq27531", BQ27531 },
 	{ "bq27541", BQ27541 },
-	{ "bq27542", BQ27541 },
-	{ "bq27546", BQ27541 },
-	{ "bq27742", BQ27541 },
+	{ "bq27542", BQ27542 },
+	{ "bq27546", BQ27546 },
+	{ "bq27742", BQ27742 },
 	{ "bq27545", BQ27545 },
 	{ "bq27421", BQ27421 },
-	{ "bq27425", BQ27421 },
-	{ "bq27441", BQ27421 },
-	{ "bq27621", BQ27421 },
+	{ "bq27425", BQ27425 },
+	{ "bq27441", BQ27441 },
+	{ "bq27621", BQ27621 },
 	{},
 };
 MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
include/linux/power/bq27xxx_battery.h +18 -7
index 92df553..90db1cf 100644
@@ -2,14 +2,25 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+	/* categories; index for bq27xxx_regs[] */
 	BQ27000 = 1, /* bq27000, bq27200 */
-	BQ27010, /* bq27010, bq27210 */
-	BQ27500, /* bq27500 */
-	BQ27510, /* bq27510, bq27520 */
-	BQ27530, /* bq27530, bq27531 */
-	BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
-	BQ27545, /* bq27545 */
-	BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+	BQ27010 = 2, /* bq27010, bq27210 */
+	BQ27500 = 3, /* bq27500 */
+	BQ27510 = 4, /* bq27510, bq27520 */
+	BQ27530 = 5, /* bq27530, bq27531 */
+	BQ27541 = 6, /* bq27541, bq27542, bq27546, bq27742 */
+	BQ27545 = 7, /* bq27545 */
+	BQ27421 = 8, /* bq27421, bq27425, bq27441, bq27621 */
+
+	/* members of categories; translate these to category in _setup() */
+	BQ27520 = 101,
+	BQ27531 = 102,
+	BQ27542 = 103,
+	BQ27546 = 104,
+	BQ27742 = 105,
+	BQ27425 = 106,
+	BQ27441 = 107,
+	BQ27621 = 108,
 };
 
 /**
Signature · 1 line
2.9.3
#21 lore raw

Re: [PATCH v10 6/8] power: bq27xxx_battery: Keep track of specific chip id

Quoted 8 lines · Liam Breck

From: Liam Breck <[email protected]>

Pass actual chip ID into _setup(), which translates it to a group ID, to allow support for all chips by the power_supply_battery_info code. There are no functional changes to the driver.

---

What is this patch based on, it doesn't apply to v4.11-rc1 for me.

Quoted 12 lines
 drivers/power/supply/bq27xxx_battery.c     | 19 +++++++++++++++++++
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++++++++--------
 include/linux/power/bq27xxx_battery.h      | 25 ++++++++++++++++++-------
 3 files changed, 45 insertions(+), 15 deletions(-)
drivers/power/supply/bq27xxx_battery.c +0 -0
index 7272d1e..d613d3d 100644
@@ -1020,6 +1020,25 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 	struct power_supply_desc *psy_desc;
 	struct power_supply_config psy_cfg = { .drv_data = di, };

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1031

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +9 -0
 
+	switch(di->chip) {
+	case BQ27000:
+	case BQ27010:
+	case BQ27500:
+	case BQ27510:
+	case BQ27530:
+	case BQ27541:
+	case BQ27545:
+	case BQ27421: break;

Why even have these cases then?

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1039

Quoted 8 lines
drivers/power/supply/bq27xxx_battery.c +8 -0
+	case BQ27520: di->chip = BQ27510; break;
+	case BQ27531: di->chip = BQ27530; break;
+	case BQ27542: di->chip = BQ27541; break;
+	case BQ27546: di->chip = BQ27541; break;
+	case BQ27742: di->chip = BQ27541; break;
+	case BQ27425: di->chip = BQ27421; break;
+	case BQ27441: di->chip = BQ27421; break;
+	case BQ27621: di->chip = BQ27421; break;

Nope, don't like this at all, make a different variable, ->registers or something to map to the register table. Plus I think changing the variable you are switching on can cause undefined behavior.

Quoted 60 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+	}
+
 	INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
 	mutex_init(&di->lock);
 	di->regs = bq27xxx_regs[di->chip];
drivers/power/supply/bq27xxx_battery_i2c.c +8 -8
index 5c5c3a6..13def59 100644
@@ -150,18 +150,18 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
 	{ "bq27210", BQ27010 },
 	{ "bq27500", BQ27500 },
 	{ "bq27510", BQ27510 },
-	{ "bq27520", BQ27510 },
+	{ "bq27520", BQ27520 },
 	{ "bq27530", BQ27530 },
-	{ "bq27531", BQ27530 },
+	{ "bq27531", BQ27531 },
 	{ "bq27541", BQ27541 },
-	{ "bq27542", BQ27541 },
-	{ "bq27546", BQ27541 },
-	{ "bq27742", BQ27541 },
+	{ "bq27542", BQ27542 },
+	{ "bq27546", BQ27546 },
+	{ "bq27742", BQ27742 },
 	{ "bq27545", BQ27545 },
 	{ "bq27421", BQ27421 },
-	{ "bq27425", BQ27421 },
-	{ "bq27441", BQ27421 },
-	{ "bq27621", BQ27421 },
+	{ "bq27425", BQ27425 },
+	{ "bq27441", BQ27441 },
+	{ "bq27621", BQ27621 },
 	{},
 };
 MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
include/linux/power/bq27xxx_battery.h +8 -7
index 92df553..90db1cf 100644
@@ -2,14 +2,25 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+	/* categories; index for bq27xxx_regs[] */
 	BQ27000 = 1, /* bq27000, bq27200 */
-	BQ27010, /* bq27010, bq27210 */
-	BQ27500, /* bq27500 */
-	BQ27510, /* bq27510, bq27520 */
-	BQ27530, /* bq27530, bq27531 */
-	BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
-	BQ27545, /* bq27545 */
-	BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+	BQ27010 = 2, /* bq27010, bq27210 */
+	BQ27500 = 3, /* bq27500 */
+	BQ27510 = 4, /* bq27510, bq27520 */
+	BQ27530 = 5, /* bq27530, bq27531 */
+	BQ27541 = 6, /* bq27541, bq27542, bq27546, bq27742 */
+	BQ27545 = 7, /* bq27545 */
+	BQ27421 = 8, /* bq27421, bq27425, bq27441, bq27621 */

include/linux/power/bq27xxx_battery.h line 23

Quoted 10 lines
include/linux/power/bq27xxx_battery.h +10 -0
+
+	/* members of categories; translate these to category in _setup() */
+	BQ27520 = 101,
+	BQ27531 = 102,
+	BQ27542 = 103,
+	BQ27546 = 104,
+	BQ27742 = 105,
+	BQ27425 = 106,
+	BQ27441 = 107,
+	BQ27621 = 108,

Get rid of this, just add new chip enum names if you need support for new chips.

Quoted 4 lines
include/linux/power/bq27xxx_battery.h +0 -0
 };
 
 /**
author
#22 lore raw

Re: [PATCH v10 6/8] power: bq27xxx_battery: Keep track of specific chip id

Quoted 11 lines · Andrew F. Davis
Quoted 8 lines · Liam Breck

From: Liam Breck <[email protected]>

Pass actual chip ID into _setup(), which translates it to a group ID, to allow support for all chips by the power_supply_battery_info code. There are no functional changes to the driver.

---

What is this patch based on, it doesn't apply to v4.11-rc1 for me.

Sorry, I don't have all of Chris' patches here. It wasn't a factor until we attacked the register arrays. Could you send me his patchset with:
git format-patch --stdout HEAD~x..HEAD~y > bq27xxx-lapa.mbox

Quoted 13 lines
Quoted 13 lines
 drivers/power/supply/bq27xxx_battery.c     | 19 +++++++++++++++++++
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++++++++--------
 include/linux/power/bq27xxx_battery.h      | 25 ++++++++++++++++++-------
 3 files changed, 45 insertions(+), 15 deletions(-)
drivers/power/supply/bq27xxx_battery.c +0 -0
index 7272d1e..d613d3d 100644
@@ -1020,6 +1020,25 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
      struct power_supply_desc *psy_desc;
      struct power_supply_config psy_cfg = { .drv_data = di, };
 
Quoted 11 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1031

Quoted 9 lines
drivers/power/supply/bq27xxx_battery.c +9 -0
+     switch(di->chip) {
+     case BQ27000:
+     case BQ27010:
+     case BQ27500:
+     case BQ27510:
+     case BQ27530:
+     case BQ27541:
+     case BQ27545:
+     case BQ27421: break;

Why even have these cases then?

You'll get a compiler warning if any are missing. Helps when adding new chips.

Quoted 9 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1039

Quoted 8 lines
drivers/power/supply/bq27xxx_battery.c +8 -0
+     case BQ27520: di->chip = BQ27510; break;
+     case BQ27531: di->chip = BQ27530; break;
+     case BQ27542: di->chip = BQ27541; break;
+     case BQ27546: di->chip = BQ27541; break;
+     case BQ27742: di->chip = BQ27541; break;
+     case BQ27425: di->chip = BQ27421; break;
+     case BQ27441: di->chip = BQ27421; break;
+     case BQ27621: di->chip = BQ27421; break;
Quoted 3 lines

Nope, don't like this at all, make a different variable, ->registers or something to map to the register table. Plus I think changing the variable you are switching on can cause undefined behavior.

We had a different variable, .dmid, but you rejected a second ID field. I think this is better, as we eliminated the static arrays .dmid indexed. I didn't rename .chip to .category as that would cause trivial changes all over the file. I could do that in a final patch tho.

You can modify a variable after switching on it, I promise.

Quoted 65 lines
Quoted 65 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+     }
+
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
      mutex_init(&di->lock);
      di->regs = bq27xxx_regs[di->chip];
drivers/power/supply/bq27xxx_battery_i2c.c +8 -8
index 5c5c3a6..13def59 100644
@@ -150,18 +150,18 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
      { "bq27210", BQ27010 },
      { "bq27500", BQ27500 },
      { "bq27510", BQ27510 },
-     { "bq27520", BQ27510 },
+     { "bq27520", BQ27520 },
      { "bq27530", BQ27530 },
-     { "bq27531", BQ27530 },
+     { "bq27531", BQ27531 },
      { "bq27541", BQ27541 },
-     { "bq27542", BQ27541 },
-     { "bq27546", BQ27541 },
-     { "bq27742", BQ27541 },
+     { "bq27542", BQ27542 },
+     { "bq27546", BQ27546 },
+     { "bq27742", BQ27742 },
      { "bq27545", BQ27545 },
      { "bq27421", BQ27421 },
-     { "bq27425", BQ27421 },
-     { "bq27441", BQ27421 },
-     { "bq27621", BQ27421 },
+     { "bq27425", BQ27425 },
+     { "bq27441", BQ27441 },
+     { "bq27621", BQ27621 },
      {},
 };
 MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
include/linux/power/bq27xxx_battery.h +13 -7
index 92df553..90db1cf 100644
@@ -2,14 +2,25 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+     /* categories; index for bq27xxx_regs[] */
      BQ27000 = 1, /* bq27000, bq27200 */
-     BQ27010, /* bq27010, bq27210 */
-     BQ27500, /* bq27500 */
-     BQ27510, /* bq27510, bq27520 */
-     BQ27530, /* bq27530, bq27531 */
-     BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
-     BQ27545, /* bq27545 */
-     BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+     BQ27010 = 2, /* bq27010, bq27210 */
+     BQ27500 = 3, /* bq27500 */
+     BQ27510 = 4, /* bq27510, bq27520 */
+     BQ27530 = 5, /* bq27530, bq27531 */
+     BQ27541 = 6, /* bq27541, bq27542, bq27546, bq27742 */
+     BQ27545 = 7, /* bq27545 */
+     BQ27421 = 8, /* bq27421, bq27425, bq27441, bq27621 */
+
+     /* members of categories; translate these to category in _setup() */
+     BQ27520 = 101,
+     BQ27531 = 102,
+     BQ27542 = 103,
Quoted 8 lines

include/linux/power/bq27xxx_battery.h line 23

Quoted 5 lines
include/linux/power/bq27xxx_battery.h +5 -0
+     BQ27546 = 104,
+     BQ27742 = 105,
+     BQ27425 = 106,
+     BQ27441 = 107,
+     BQ27621 = 108,

Get rid of this, just add new chip enum names if you need support for new chips.

How does a non-DT config obtain chip ID? We want explicit enum values if they appear in external platform-data objects. I'll mention that in the next patch description.

The category (original) IDs index bq27xxx_regs[], and you'll probably extend that in time. So I placed the member (new) IDs well above the categories to allow permanent explicit values.

#23 lore raw

Re: [PATCH v10 6/8] power: bq27xxx_battery: Keep track of specific chip id

Quoted 11 lines · Liam Breck
Quoted 10 lines · Andrew F. Davis
Quoted 8 lines · Liam Breck

From: Liam Breck <[email protected]>

Pass actual chip ID into _setup(), which translates it to a group ID, to allow support for all chips by the power_supply_battery_info code. There are no functional changes to the driver.

---

Quoted 7 lines
Quoted 1 line

What is this patch based on, it doesn't apply to v4.11-rc1 for me.

Sorry, I don't have all of Chris' patches here. It wasn't a factor until we attacked the register arrays. Could you send me his patchset with:
git format-patch --stdout HEAD~x..HEAD~y > bq27xxx-lapa.mbox

Who are you asking?

Quoted 122 lines
Quoted 13 lines
Quoted 13 lines
 drivers/power/supply/bq27xxx_battery.c     | 19 +++++++++++++++++++
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++++++++--------
 include/linux/power/bq27xxx_battery.h      | 25 ++++++++++++++++++-------
 3 files changed, 45 insertions(+), 15 deletions(-)
drivers/power/supply/bq27xxx_battery.c +0 -0
index 7272d1e..d613d3d 100644
@@ -1020,6 +1020,25 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
      struct power_supply_desc *psy_desc;
      struct power_supply_config psy_cfg = { .drv_data = di, };
 
Quoted 11 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1031

Quoted 9 lines
drivers/power/supply/bq27xxx_battery.c +9 -0
+     switch(di->chip) {
+     case BQ27000:
+     case BQ27010:
+     case BQ27500:
+     case BQ27510:
+     case BQ27530:
+     case BQ27541:
+     case BQ27545:
+     case BQ27421: break;

Why even have these cases then?

You'll get a compiler warning if any are missing. Helps when adding new chips.

Quoted 9 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1039

Quoted 8 lines
drivers/power/supply/bq27xxx_battery.c +8 -0
+     case BQ27520: di->chip = BQ27510; break;
+     case BQ27531: di->chip = BQ27530; break;
+     case BQ27542: di->chip = BQ27541; break;
+     case BQ27546: di->chip = BQ27541; break;
+     case BQ27742: di->chip = BQ27541; break;
+     case BQ27425: di->chip = BQ27421; break;
+     case BQ27441: di->chip = BQ27421; break;
+     case BQ27621: di->chip = BQ27421; break;
Quoted 3 lines

Nope, don't like this at all, make a different variable, ->registers or something to map to the register table. Plus I think changing the variable you are switching on can cause undefined behavior.

We had a different variable, .dmid, but you rejected a second ID field. I think this is better, as we eliminated the static arrays .dmid indexed. I didn't rename .chip to .category as that would cause trivial changes all over the file. I could do that in a final patch tho.

You can modify a variable after switching on it, I promise.

Quoted 65 lines
Quoted 65 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+     }
+
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
      mutex_init(&di->lock);
      di->regs = bq27xxx_regs[di->chip];
drivers/power/supply/bq27xxx_battery_i2c.c +8 -8
index 5c5c3a6..13def59 100644
@@ -150,18 +150,18 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
      { "bq27210", BQ27010 },
      { "bq27500", BQ27500 },
      { "bq27510", BQ27510 },
-     { "bq27520", BQ27510 },
+     { "bq27520", BQ27520 },
      { "bq27530", BQ27530 },
-     { "bq27531", BQ27530 },
+     { "bq27531", BQ27531 },
      { "bq27541", BQ27541 },
-     { "bq27542", BQ27541 },
-     { "bq27546", BQ27541 },
-     { "bq27742", BQ27541 },
+     { "bq27542", BQ27542 },
+     { "bq27546", BQ27546 },
+     { "bq27742", BQ27742 },
      { "bq27545", BQ27545 },
      { "bq27421", BQ27421 },
-     { "bq27425", BQ27421 },
-     { "bq27441", BQ27421 },
-     { "bq27621", BQ27421 },
+     { "bq27425", BQ27425 },
+     { "bq27441", BQ27441 },
+     { "bq27621", BQ27621 },
      {},
 };
 MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
include/linux/power/bq27xxx_battery.h +13 -7
index 92df553..90db1cf 100644
@@ -2,14 +2,25 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+     /* categories; index for bq27xxx_regs[] */
      BQ27000 = 1, /* bq27000, bq27200 */
-     BQ27010, /* bq27010, bq27210 */
-     BQ27500, /* bq27500 */
-     BQ27510, /* bq27510, bq27520 */
-     BQ27530, /* bq27530, bq27531 */
-     BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
-     BQ27545, /* bq27545 */
-     BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+     BQ27010 = 2, /* bq27010, bq27210 */
+     BQ27500 = 3, /* bq27500 */
+     BQ27510 = 4, /* bq27510, bq27520 */
+     BQ27530 = 5, /* bq27530, bq27531 */
+     BQ27541 = 6, /* bq27541, bq27542, bq27546, bq27742 */
+     BQ27545 = 7, /* bq27545 */
+     BQ27421 = 8, /* bq27421, bq27425, bq27441, bq27621 */
+
+     /* members of categories; translate these to category in _setup() */
+     BQ27520 = 101,
+     BQ27531 = 102,
+     BQ27542 = 103,
Quoted 8 lines

include/linux/power/bq27xxx_battery.h line 23

Quoted 5 lines
include/linux/power/bq27xxx_battery.h +5 -0
+     BQ27546 = 104,
+     BQ27742 = 105,
+     BQ27425 = 106,
+     BQ27441 = 107,
+     BQ27621 = 108,

Get rid of this, just add new chip enum names if you need support for new chips.

Quoted 4 lines

How does a non-DT config obtain chip ID? We want explicit enum values if they appear in external platform-data objects. I'll mention that in the next patch description.

platform-data is going away, I'm not sure what you are saying here.

Quoted 4 lines

The category (original) IDs index bq27xxx_regs[], and you'll probably extend that in time. So I placed the member (new) IDs well above the categories to allow permanent explicit values.

author
#24 lore raw

Re: [PATCH v10 6/8] power: bq27xxx_battery: Keep track of specific chip id

Quoted 14 lines · Andrew F. Davis
Quoted 13 lines · Liam Breck
Quoted 11 lines · Andrew F. Davis
Quoted 8 lines · Liam Breck

From: Liam Breck <[email protected]>

Pass actual chip ID into _setup(), which translates it to a group ID, to allow support for all chips by the power_supply_battery_info code. There are no functional changes to the driver.

---

What is this patch based on, it doesn't apply to v4.11-rc1 for me.

Quoted 7 lines
Quoted 5 lines

Sorry, I don't have all of Chris' patches here. It wasn't a factor until we attacked the register arrays. Could you send me his patchset with:
git format-patch --stdout HEAD~x..HEAD~y > bq27xxx-lapa.mbox

Who are you asking?

You, if I may impose...

Quoted 122 lines
Quoted 122 lines
Quoted 13 lines
Quoted 13 lines
 drivers/power/supply/bq27xxx_battery.c     | 19 +++++++++++++++++++
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++++++++--------
 include/linux/power/bq27xxx_battery.h      | 25 ++++++++++++++++++-------
 3 files changed, 45 insertions(+), 15 deletions(-)
drivers/power/supply/bq27xxx_battery.c +0 -0
index 7272d1e..d613d3d 100644
@@ -1020,6 +1020,25 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
      struct power_supply_desc *psy_desc;
      struct power_supply_config psy_cfg = { .drv_data = di, };
 
Quoted 11 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1031

Quoted 9 lines
drivers/power/supply/bq27xxx_battery.c +9 -0
+     switch(di->chip) {
+     case BQ27000:
+     case BQ27010:
+     case BQ27500:
+     case BQ27510:
+     case BQ27530:
+     case BQ27541:
+     case BQ27545:
+     case BQ27421: break;

Why even have these cases then?

You'll get a compiler warning if any are missing. Helps when adding new chips.

Quoted 9 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1039

Quoted 8 lines
drivers/power/supply/bq27xxx_battery.c +8 -0
+     case BQ27520: di->chip = BQ27510; break;
+     case BQ27531: di->chip = BQ27530; break;
+     case BQ27542: di->chip = BQ27541; break;
+     case BQ27546: di->chip = BQ27541; break;
+     case BQ27742: di->chip = BQ27541; break;
+     case BQ27425: di->chip = BQ27421; break;
+     case BQ27441: di->chip = BQ27421; break;
+     case BQ27621: di->chip = BQ27421; break;
Quoted 3 lines

Nope, don't like this at all, make a different variable, ->registers or something to map to the register table. Plus I think changing the variable you are switching on can cause undefined behavior.

We had a different variable, .dmid, but you rejected a second ID field. I think this is better, as we eliminated the static arrays .dmid indexed. I didn't rename .chip to .category as that would cause trivial changes all over the file. I could do that in a final patch tho.

You can modify a variable after switching on it, I promise.

Quoted 73 lines
Quoted 60 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+     }
+
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
      mutex_init(&di->lock);
      di->regs = bq27xxx_regs[di->chip];
drivers/power/supply/bq27xxx_battery_i2c.c +8 -8
index 5c5c3a6..13def59 100644
@@ -150,18 +150,18 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
      { "bq27210", BQ27010 },
      { "bq27500", BQ27500 },
      { "bq27510", BQ27510 },
-     { "bq27520", BQ27510 },
+     { "bq27520", BQ27520 },
      { "bq27530", BQ27530 },
-     { "bq27531", BQ27530 },
+     { "bq27531", BQ27531 },
      { "bq27541", BQ27541 },
-     { "bq27542", BQ27541 },
-     { "bq27546", BQ27541 },
-     { "bq27742", BQ27541 },
+     { "bq27542", BQ27542 },
+     { "bq27546", BQ27546 },
+     { "bq27742", BQ27742 },
      { "bq27545", BQ27545 },
      { "bq27421", BQ27421 },
-     { "bq27425", BQ27421 },
-     { "bq27441", BQ27421 },
-     { "bq27621", BQ27421 },
+     { "bq27425", BQ27425 },
+     { "bq27441", BQ27441 },
+     { "bq27621", BQ27621 },
      {},
 };
 MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
include/linux/power/bq27xxx_battery.h +8 -7
index 92df553..90db1cf 100644
@@ -2,14 +2,25 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+     /* categories; index for bq27xxx_regs[] */
      BQ27000 = 1, /* bq27000, bq27200 */
-     BQ27010, /* bq27010, bq27210 */
-     BQ27500, /* bq27500 */
-     BQ27510, /* bq27510, bq27520 */
-     BQ27530, /* bq27530, bq27531 */
-     BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
-     BQ27545, /* bq27545 */
-     BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+     BQ27010 = 2, /* bq27010, bq27210 */
+     BQ27500 = 3, /* bq27500 */
+     BQ27510 = 4, /* bq27510, bq27520 */
+     BQ27530 = 5, /* bq27530, bq27531 */
+     BQ27541 = 6, /* bq27541, bq27542, bq27546, bq27742 */
+     BQ27545 = 7, /* bq27545 */
+     BQ27421 = 8, /* bq27421, bq27425, bq27441, bq27621 */

include/linux/power/bq27xxx_battery.h line 23

Quoted 10 lines
include/linux/power/bq27xxx_battery.h +10 -0
+
+     /* members of categories; translate these to category in _setup() */
+     BQ27520 = 101,
+     BQ27531 = 102,
+     BQ27542 = 103,
+     BQ27546 = 104,
+     BQ27742 = 105,
+     BQ27425 = 106,
+     BQ27441 = 107,
+     BQ27621 = 108,

Get rid of this, just add new chip enum names if you need support for new chips.

Quoted 6 lines
Quoted 4 lines

How does a non-DT config obtain chip ID? We want explicit enum values if they appear in external platform-data objects. I'll mention that in the next patch description.

platform-data is going away, I'm not sure what you are saying here.

Don't 1-wire users have a platform-data config? You plan to force them to replace it with DT? I thought that wasn't kosher.

Quoted 4 lines
Quoted 4 lines

The category (original) IDs index bq27xxx_regs[], and you'll probably extend that in time. So I placed the member (new) IDs well above the categories to allow permanent explicit values.

#25 lore raw

Re: [PATCH v10 6/8] power: bq27xxx_battery: Keep track of specific chip id

Quoted 21 lines · Liam Breck
Quoted 20 lines · Andrew F. Davis
Quoted 18 lines · Liam Breck
Quoted 11 lines · Andrew F. Davis
Quoted 8 lines · Liam Breck

From: Liam Breck <[email protected]>

Pass actual chip ID into _setup(), which translates it to a group ID, to allow support for all chips by the power_supply_battery_info code. There are no functional changes to the driver.

---

What is this patch based on, it doesn't apply to v4.11-rc1 for me.

Sorry, I don't have all of Chris' patches here. It wasn't a factor until we attacked the register arrays. Could you send me his patchset with:
git format-patch --stdout HEAD~x..HEAD~y > bq27xxx-lapa.mbox

Quoted 4 lines
Quoted 1 line

Who are you asking?

You, if I may impose...

Just rebase on v4.11-rc1...

Quoted 127 lines
Quoted 127 lines
Quoted 126 lines
Quoted 13 lines
Quoted 13 lines
 drivers/power/supply/bq27xxx_battery.c     | 19 +++++++++++++++++++
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++++++++--------
 include/linux/power/bq27xxx_battery.h      | 25 ++++++++++++++++++-------
 3 files changed, 45 insertions(+), 15 deletions(-)
drivers/power/supply/bq27xxx_battery.c +0 -0
index 7272d1e..d613d3d 100644
@@ -1020,6 +1020,25 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
      struct power_supply_desc *psy_desc;
      struct power_supply_config psy_cfg = { .drv_data = di, };
 
Quoted 11 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1031

Quoted 9 lines
drivers/power/supply/bq27xxx_battery.c +9 -0
+     switch(di->chip) {
+     case BQ27000:
+     case BQ27010:
+     case BQ27500:
+     case BQ27510:
+     case BQ27530:
+     case BQ27541:
+     case BQ27545:
+     case BQ27421: break;

Why even have these cases then?

You'll get a compiler warning if any are missing. Helps when adding new chips.

Quoted 9 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1039

Quoted 8 lines
drivers/power/supply/bq27xxx_battery.c +8 -0
+     case BQ27520: di->chip = BQ27510; break;
+     case BQ27531: di->chip = BQ27530; break;
+     case BQ27542: di->chip = BQ27541; break;
+     case BQ27546: di->chip = BQ27541; break;
+     case BQ27742: di->chip = BQ27541; break;
+     case BQ27425: di->chip = BQ27421; break;
+     case BQ27441: di->chip = BQ27421; break;
+     case BQ27621: di->chip = BQ27421; break;
Quoted 3 lines

Nope, don't like this at all, make a different variable, ->registers or something to map to the register table. Plus I think changing the variable you are switching on can cause undefined behavior.

We had a different variable, .dmid, but you rejected a second ID field. I think this is better, as we eliminated the static arrays .dmid indexed. I didn't rename .chip to .category as that would cause trivial changes all over the file. I could do that in a final patch tho.

You can modify a variable after switching on it, I promise.

Quoted 65 lines
Quoted 65 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+     }
+
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
      mutex_init(&di->lock);
      di->regs = bq27xxx_regs[di->chip];
drivers/power/supply/bq27xxx_battery_i2c.c +8 -8
index 5c5c3a6..13def59 100644
@@ -150,18 +150,18 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
      { "bq27210", BQ27010 },
      { "bq27500", BQ27500 },
      { "bq27510", BQ27510 },
-     { "bq27520", BQ27510 },
+     { "bq27520", BQ27520 },
      { "bq27530", BQ27530 },
-     { "bq27531", BQ27530 },
+     { "bq27531", BQ27531 },
      { "bq27541", BQ27541 },
-     { "bq27542", BQ27541 },
-     { "bq27546", BQ27541 },
-     { "bq27742", BQ27541 },
+     { "bq27542", BQ27542 },
+     { "bq27546", BQ27546 },
+     { "bq27742", BQ27742 },
      { "bq27545", BQ27545 },
      { "bq27421", BQ27421 },
-     { "bq27425", BQ27421 },
-     { "bq27441", BQ27421 },
-     { "bq27621", BQ27421 },
+     { "bq27425", BQ27425 },
+     { "bq27441", BQ27441 },
+     { "bq27621", BQ27621 },
      {},
 };
 MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
include/linux/power/bq27xxx_battery.h +13 -7
index 92df553..90db1cf 100644
@@ -2,14 +2,25 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+     /* categories; index for bq27xxx_regs[] */
      BQ27000 = 1, /* bq27000, bq27200 */
-     BQ27010, /* bq27010, bq27210 */
-     BQ27500, /* bq27500 */
-     BQ27510, /* bq27510, bq27520 */
-     BQ27530, /* bq27530, bq27531 */
-     BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
-     BQ27545, /* bq27545 */
-     BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+     BQ27010 = 2, /* bq27010, bq27210 */
+     BQ27500 = 3, /* bq27500 */
+     BQ27510 = 4, /* bq27510, bq27520 */
+     BQ27530 = 5, /* bq27530, bq27531 */
+     BQ27541 = 6, /* bq27541, bq27542, bq27546, bq27742 */
+     BQ27545 = 7, /* bq27545 */
+     BQ27421 = 8, /* bq27421, bq27425, bq27441, bq27621 */
+
+     /* members of categories; translate these to category in _setup() */
+     BQ27520 = 101,
+     BQ27531 = 102,
+     BQ27542 = 103,
Quoted 8 lines

include/linux/power/bq27xxx_battery.h line 23

Quoted 5 lines
include/linux/power/bq27xxx_battery.h +5 -0
+     BQ27546 = 104,
+     BQ27742 = 105,
+     BQ27425 = 106,
+     BQ27441 = 107,
+     BQ27621 = 108,

Get rid of this, just add new chip enum names if you need support for new chips.

How does a non-DT config obtain chip ID? We want explicit enum values if they appear in external platform-data objects. I'll mention that in the next patch description.

Quoted 5 lines
Quoted 1 line

platform-data is going away, I'm not sure what you are saying here.

Don't 1-wire users have a platform-data config? You plan to force them to replace it with DT? I thought that wasn't kosher.

The 1-wire driver generates this platform-data, 1-wire is a discoverable bus, they never needed to define DT or platform data and still will not.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

The category (original) IDs index bq27xxx_regs[], and you'll probably extend that in time. So I placed the member (new) IDs well above the categories to allow permanent explicit values.

author
#26 lore raw

Re: [PATCH v10 6/8] power: bq27xxx_battery: Keep track of specific chip id

Quoted 156 lines · Andrew F. Davis
Quoted 21 lines · Liam Breck
Quoted 20 lines · Andrew F. Davis
Quoted 18 lines · Liam Breck
Quoted 11 lines · Andrew F. Davis
Quoted 8 lines · Liam Breck

From: Liam Breck <[email protected]>

Pass actual chip ID into _setup(), which translates it to a group ID, to allow support for all chips by the power_supply_battery_info code. There are no functional changes to the driver.

---

What is this patch based on, it doesn't apply to v4.11-rc1 for me.

Sorry, I don't have all of Chris' patches here. It wasn't a factor until we attacked the register arrays. Could you send me his patchset with:
git format-patch --stdout HEAD~x..HEAD~y > bq27xxx-lapa.mbox

Quoted 4 lines
Quoted 1 line

Who are you asking?

You, if I may impose...

Just rebase on v4.11-rc1...

Quoted 127 lines
Quoted 127 lines
Quoted 126 lines
Quoted 13 lines
Quoted 13 lines
 drivers/power/supply/bq27xxx_battery.c     | 19 +++++++++++++++++++
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++++++++--------
 include/linux/power/bq27xxx_battery.h      | 25 ++++++++++++++++++-------
 3 files changed, 45 insertions(+), 15 deletions(-)
drivers/power/supply/bq27xxx_battery.c +0 -0
index 7272d1e..d613d3d 100644
@@ -1020,6 +1020,25 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
      struct power_supply_desc *psy_desc;
      struct power_supply_config psy_cfg = { .drv_data = di, };
 
Quoted 11 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1031

Quoted 9 lines
drivers/power/supply/bq27xxx_battery.c +9 -0
+     switch(di->chip) {
+     case BQ27000:
+     case BQ27010:
+     case BQ27500:
+     case BQ27510:
+     case BQ27530:
+     case BQ27541:
+     case BQ27545:
+     case BQ27421: break;

Why even have these cases then?

You'll get a compiler warning if any are missing. Helps when adding new chips.

Quoted 9 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1039

Quoted 8 lines
drivers/power/supply/bq27xxx_battery.c +8 -0
+     case BQ27520: di->chip = BQ27510; break;
+     case BQ27531: di->chip = BQ27530; break;
+     case BQ27542: di->chip = BQ27541; break;
+     case BQ27546: di->chip = BQ27541; break;
+     case BQ27742: di->chip = BQ27541; break;
+     case BQ27425: di->chip = BQ27421; break;
+     case BQ27441: di->chip = BQ27421; break;
+     case BQ27621: di->chip = BQ27421; break;
Quoted 3 lines

Nope, don't like this at all, make a different variable, ->registers or something to map to the register table. Plus I think changing the variable you are switching on can cause undefined behavior.

We had a different variable, .dmid, but you rejected a second ID field. I think this is better, as we eliminated the static arrays .dmid indexed. I didn't rename .chip to .category as that would cause trivial changes all over the file. I could do that in a final patch tho.

You can modify a variable after switching on it, I promise.

Quoted 65 lines
Quoted 65 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+     }
+
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
      mutex_init(&di->lock);
      di->regs = bq27xxx_regs[di->chip];
drivers/power/supply/bq27xxx_battery_i2c.c +8 -8
index 5c5c3a6..13def59 100644
@@ -150,18 +150,18 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
      { "bq27210", BQ27010 },
      { "bq27500", BQ27500 },
      { "bq27510", BQ27510 },
-     { "bq27520", BQ27510 },
+     { "bq27520", BQ27520 },
      { "bq27530", BQ27530 },
-     { "bq27531", BQ27530 },
+     { "bq27531", BQ27531 },
      { "bq27541", BQ27541 },
-     { "bq27542", BQ27541 },
-     { "bq27546", BQ27541 },
-     { "bq27742", BQ27541 },
+     { "bq27542", BQ27542 },
+     { "bq27546", BQ27546 },
+     { "bq27742", BQ27742 },
      { "bq27545", BQ27545 },
      { "bq27421", BQ27421 },
-     { "bq27425", BQ27421 },
-     { "bq27441", BQ27421 },
-     { "bq27621", BQ27421 },
+     { "bq27425", BQ27425 },
+     { "bq27441", BQ27441 },
+     { "bq27621", BQ27621 },
      {},
 };
 MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
include/linux/power/bq27xxx_battery.h +13 -7
index 92df553..90db1cf 100644
@@ -2,14 +2,25 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+     /* categories; index for bq27xxx_regs[] */
      BQ27000 = 1, /* bq27000, bq27200 */
-     BQ27010, /* bq27010, bq27210 */
-     BQ27500, /* bq27500 */
-     BQ27510, /* bq27510, bq27520 */
-     BQ27530, /* bq27530, bq27531 */
-     BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
-     BQ27545, /* bq27545 */
-     BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+     BQ27010 = 2, /* bq27010, bq27210 */
+     BQ27500 = 3, /* bq27500 */
+     BQ27510 = 4, /* bq27510, bq27520 */
+     BQ27530 = 5, /* bq27530, bq27531 */
+     BQ27541 = 6, /* bq27541, bq27542, bq27546, bq27742 */
+     BQ27545 = 7, /* bq27545 */
+     BQ27421 = 8, /* bq27421, bq27425, bq27441, bq27621 */
+
+     /* members of categories; translate these to category in _setup() */
+     BQ27520 = 101,
+     BQ27531 = 102,
+     BQ27542 = 103,
Quoted 8 lines

include/linux/power/bq27xxx_battery.h line 23

Quoted 5 lines
include/linux/power/bq27xxx_battery.h +5 -0
+     BQ27546 = 104,
+     BQ27742 = 105,
+     BQ27425 = 106,
+     BQ27441 = 107,
+     BQ27621 = 108,

Get rid of this, just add new chip enum names if you need support for new chips.

How does a non-DT config obtain chip ID? We want explicit enum values if they appear in external platform-data objects. I'll mention that in the next patch description.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

platform-data is going away, I'm not sure what you are saying here.

Don't 1-wire users have a platform-data config? You plan to force them to replace it with DT? I thought that wasn't kosher.

The 1-wire driver generates this platform-data, 1-wire is a discoverable bus, they never needed to define DT or platform data and still will not.

How does it map a discovered chip type to a bq27xxx_chip enum?

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

The category (original) IDs index bq27xxx_regs[], and you'll probably extend that in time. So I placed the member (new) IDs well above the categories to allow permanent explicit values.

#27 lore raw

Re: [PATCH v10 6/8] power: bq27xxx_battery: Keep track of specific chip id

Quoted 159 lines · Liam Breck
Quoted 158 lines · Andrew F. Davis
Quoted 21 lines · Liam Breck
Quoted 20 lines · Andrew F. Davis
Quoted 18 lines · Liam Breck
Quoted 11 lines · Andrew F. Davis
Quoted 8 lines · Liam Breck

From: Liam Breck <[email protected]>

Pass actual chip ID into _setup(), which translates it to a group ID, to allow support for all chips by the power_supply_battery_info code. There are no functional changes to the driver.

---

What is this patch based on, it doesn't apply to v4.11-rc1 for me.

Sorry, I don't have all of Chris' patches here. It wasn't a factor until we attacked the register arrays. Could you send me his patchset with:
git format-patch --stdout HEAD~x..HEAD~y > bq27xxx-lapa.mbox

Quoted 4 lines
Quoted 1 line

Who are you asking?

You, if I may impose...

Just rebase on v4.11-rc1...

Quoted 129 lines
Quoted 128 lines
Quoted 122 lines
Quoted 13 lines
Quoted 13 lines
 drivers/power/supply/bq27xxx_battery.c     | 19 +++++++++++++++++++
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++++++++--------
 include/linux/power/bq27xxx_battery.h      | 25 ++++++++++++++++++-------
 3 files changed, 45 insertions(+), 15 deletions(-)
drivers/power/supply/bq27xxx_battery.c +0 -0
index 7272d1e..d613d3d 100644
@@ -1020,6 +1020,25 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
      struct power_supply_desc *psy_desc;
      struct power_supply_config psy_cfg = { .drv_data = di, };
 
Quoted 11 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1031

Quoted 9 lines
drivers/power/supply/bq27xxx_battery.c +9 -0
+     switch(di->chip) {
+     case BQ27000:
+     case BQ27010:
+     case BQ27500:
+     case BQ27510:
+     case BQ27530:
+     case BQ27541:
+     case BQ27545:
+     case BQ27421: break;

Why even have these cases then?

You'll get a compiler warning if any are missing. Helps when adding new chips.

Quoted 9 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1039

Quoted 8 lines
drivers/power/supply/bq27xxx_battery.c +8 -0
+     case BQ27520: di->chip = BQ27510; break;
+     case BQ27531: di->chip = BQ27530; break;
+     case BQ27542: di->chip = BQ27541; break;
+     case BQ27546: di->chip = BQ27541; break;
+     case BQ27742: di->chip = BQ27541; break;
+     case BQ27425: di->chip = BQ27421; break;
+     case BQ27441: di->chip = BQ27421; break;
+     case BQ27621: di->chip = BQ27421; break;
Quoted 3 lines

Nope, don't like this at all, make a different variable, ->registers or something to map to the register table. Plus I think changing the variable you are switching on can cause undefined behavior.

We had a different variable, .dmid, but you rejected a second ID field. I think this is better, as we eliminated the static arrays .dmid indexed. I didn't rename .chip to .category as that would cause trivial changes all over the file. I could do that in a final patch tho.

You can modify a variable after switching on it, I promise.

Quoted 65 lines
Quoted 65 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+     }
+
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
      mutex_init(&di->lock);
      di->regs = bq27xxx_regs[di->chip];
drivers/power/supply/bq27xxx_battery_i2c.c +8 -8
index 5c5c3a6..13def59 100644
@@ -150,18 +150,18 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
      { "bq27210", BQ27010 },
      { "bq27500", BQ27500 },
      { "bq27510", BQ27510 },
-     { "bq27520", BQ27510 },
+     { "bq27520", BQ27520 },
      { "bq27530", BQ27530 },
-     { "bq27531", BQ27530 },
+     { "bq27531", BQ27531 },
      { "bq27541", BQ27541 },
-     { "bq27542", BQ27541 },
-     { "bq27546", BQ27541 },
-     { "bq27742", BQ27541 },
+     { "bq27542", BQ27542 },
+     { "bq27546", BQ27546 },
+     { "bq27742", BQ27742 },
      { "bq27545", BQ27545 },
      { "bq27421", BQ27421 },
-     { "bq27425", BQ27421 },
-     { "bq27441", BQ27421 },
-     { "bq27621", BQ27421 },
+     { "bq27425", BQ27425 },
+     { "bq27441", BQ27441 },
+     { "bq27621", BQ27621 },
      {},
 };
 MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
include/linux/power/bq27xxx_battery.h +13 -7
index 92df553..90db1cf 100644
@@ -2,14 +2,25 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+     /* categories; index for bq27xxx_regs[] */
      BQ27000 = 1, /* bq27000, bq27200 */
-     BQ27010, /* bq27010, bq27210 */
-     BQ27500, /* bq27500 */
-     BQ27510, /* bq27510, bq27520 */
-     BQ27530, /* bq27530, bq27531 */
-     BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
-     BQ27545, /* bq27545 */
-     BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+     BQ27010 = 2, /* bq27010, bq27210 */
+     BQ27500 = 3, /* bq27500 */
+     BQ27510 = 4, /* bq27510, bq27520 */
+     BQ27530 = 5, /* bq27530, bq27531 */
+     BQ27541 = 6, /* bq27541, bq27542, bq27546, bq27742 */
+     BQ27545 = 7, /* bq27545 */
+     BQ27421 = 8, /* bq27421, bq27425, bq27441, bq27621 */
+
+     /* members of categories; translate these to category in _setup() */
+     BQ27520 = 101,
+     BQ27531 = 102,
+     BQ27542 = 103,
Quoted 8 lines

include/linux/power/bq27xxx_battery.h line 23

Quoted 5 lines
include/linux/power/bq27xxx_battery.h +5 -0
+     BQ27546 = 104,
+     BQ27742 = 105,
+     BQ27425 = 106,
+     BQ27441 = 107,
+     BQ27621 = 108,

Get rid of this, just add new chip enum names if you need support for new chips.

Quoted 4 lines

How does a non-DT config obtain chip ID? We want explicit enum values if they appear in external platform-data objects. I'll mention that in the next patch description.

platform-data is going away, I'm not sure what you are saying here.

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines

Don't 1-wire users have a platform-data config? You plan to force them to replace it with DT? I thought that wasn't kosher.

The 1-wire driver generates this platform-data, 1-wire is a discoverable bus, they never needed to define DT or platform data and still will not.

How does it map a discovered chip type to a bq27xxx_chip enum?

Right now it just assumes the chip is a BQ27000, see line 45 of drivers/w1/slaves/w1_bq27000.c

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

The category (original) IDs index bq27xxx_regs[], and you'll probably extend that in time. So I placed the member (new) IDs well above the categories to allow permanent explicit values.

author
#28 lore raw

Re: [PATCH v10 6/8] power: bq27xxx_battery: Keep track of specific chip id

Quoted 164 lines · Andrew F. Davis
Quoted 163 lines · Liam Breck
Quoted 162 lines · Andrew F. Davis
Quoted 21 lines · Liam Breck
Quoted 20 lines · Andrew F. Davis
Quoted 18 lines · Liam Breck
Quoted 11 lines · Andrew F. Davis
Quoted 8 lines · Liam Breck

From: Liam Breck <[email protected]>

Pass actual chip ID into _setup(), which translates it to a group ID, to allow support for all chips by the power_supply_battery_info code. There are no functional changes to the driver.

---

What is this patch based on, it doesn't apply to v4.11-rc1 for me.

Sorry, I don't have all of Chris' patches here. It wasn't a factor until we attacked the register arrays. Could you send me his patchset with:
git format-patch --stdout HEAD~x..HEAD~y > bq27xxx-lapa.mbox

Quoted 4 lines
Quoted 1 line

Who are you asking?

You, if I may impose...

Just rebase on v4.11-rc1...

Quoted 132 lines
Quoted 122 lines
Quoted 122 lines
Quoted 13 lines
Quoted 13 lines
 drivers/power/supply/bq27xxx_battery.c     | 19 +++++++++++++++++++
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 ++++++++--------
 include/linux/power/bq27xxx_battery.h      | 25 ++++++++++++++++++-------
 3 files changed, 45 insertions(+), 15 deletions(-)
drivers/power/supply/bq27xxx_battery.c +0 -0
index 7272d1e..d613d3d 100644
@@ -1020,6 +1020,25 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
      struct power_supply_desc *psy_desc;
      struct power_supply_config psy_cfg = { .drv_data = di, };
 
Quoted 11 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1031

Quoted 9 lines
drivers/power/supply/bq27xxx_battery.c +9 -0
+     switch(di->chip) {
+     case BQ27000:
+     case BQ27010:
+     case BQ27500:
+     case BQ27510:
+     case BQ27530:
+     case BQ27541:
+     case BQ27545:
+     case BQ27421: break;

Why even have these cases then?

You'll get a compiler warning if any are missing. Helps when adding new chips.

Quoted 9 lines

drivers/power/supply/bq27xxx_battery.c int bq27xxx_battery_setup(struct bq27xxx_device_info *di) · line 1039

Quoted 8 lines
drivers/power/supply/bq27xxx_battery.c +8 -0
+     case BQ27520: di->chip = BQ27510; break;
+     case BQ27531: di->chip = BQ27530; break;
+     case BQ27542: di->chip = BQ27541; break;
+     case BQ27546: di->chip = BQ27541; break;
+     case BQ27742: di->chip = BQ27541; break;
+     case BQ27425: di->chip = BQ27421; break;
+     case BQ27441: di->chip = BQ27421; break;
+     case BQ27621: di->chip = BQ27421; break;
Quoted 3 lines

Nope, don't like this at all, make a different variable, ->registers or something to map to the register table. Plus I think changing the variable you are switching on can cause undefined behavior.

We had a different variable, .dmid, but you rejected a second ID field. I think this is better, as we eliminated the static arrays .dmid indexed. I didn't rename .chip to .category as that would cause trivial changes all over the file. I could do that in a final patch tho.

You can modify a variable after switching on it, I promise.

Quoted 73 lines
Quoted 60 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+     }
+
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
      mutex_init(&di->lock);
      di->regs = bq27xxx_regs[di->chip];
drivers/power/supply/bq27xxx_battery_i2c.c +8 -8
index 5c5c3a6..13def59 100644
@@ -150,18 +150,18 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
      { "bq27210", BQ27010 },
      { "bq27500", BQ27500 },
      { "bq27510", BQ27510 },
-     { "bq27520", BQ27510 },
+     { "bq27520", BQ27520 },
      { "bq27530", BQ27530 },
-     { "bq27531", BQ27530 },
+     { "bq27531", BQ27531 },
      { "bq27541", BQ27541 },
-     { "bq27542", BQ27541 },
-     { "bq27546", BQ27541 },
-     { "bq27742", BQ27541 },
+     { "bq27542", BQ27542 },
+     { "bq27546", BQ27546 },
+     { "bq27742", BQ27742 },
      { "bq27545", BQ27545 },
      { "bq27421", BQ27421 },
-     { "bq27425", BQ27421 },
-     { "bq27441", BQ27421 },
-     { "bq27621", BQ27421 },
+     { "bq27425", BQ27425 },
+     { "bq27441", BQ27441 },
+     { "bq27621", BQ27621 },
      {},
 };
 MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
include/linux/power/bq27xxx_battery.h +8 -7
index 92df553..90db1cf 100644
@@ -2,14 +2,25 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+     /* categories; index for bq27xxx_regs[] */
      BQ27000 = 1, /* bq27000, bq27200 */
-     BQ27010, /* bq27010, bq27210 */
-     BQ27500, /* bq27500 */
-     BQ27510, /* bq27510, bq27520 */
-     BQ27530, /* bq27530, bq27531 */
-     BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
-     BQ27545, /* bq27545 */
-     BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+     BQ27010 = 2, /* bq27010, bq27210 */
+     BQ27500 = 3, /* bq27500 */
+     BQ27510 = 4, /* bq27510, bq27520 */
+     BQ27530 = 5, /* bq27530, bq27531 */
+     BQ27541 = 6, /* bq27541, bq27542, bq27546, bq27742 */
+     BQ27545 = 7, /* bq27545 */
+     BQ27421 = 8, /* bq27421, bq27425, bq27441, bq27621 */

include/linux/power/bq27xxx_battery.h line 23

Quoted 10 lines
include/linux/power/bq27xxx_battery.h +10 -0
+
+     /* members of categories; translate these to category in _setup() */
+     BQ27520 = 101,
+     BQ27531 = 102,
+     BQ27542 = 103,
+     BQ27546 = 104,
+     BQ27742 = 105,
+     BQ27425 = 106,
+     BQ27441 = 107,
+     BQ27621 = 108,

Get rid of this, just add new chip enum names if you need support for new chips.

Quoted 6 lines
Quoted 4 lines

How does a non-DT config obtain chip ID? We want explicit enum values if they appear in external platform-data objects. I'll mention that in the next patch description.

platform-data is going away, I'm not sure what you are saying here.

Don't 1-wire users have a platform-data config? You plan to force them to replace it with DT? I thought that wasn't kosher.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

The 1-wire driver generates this platform-data, 1-wire is a discoverable bus, they never needed to define DT or platform data and still will not.

How does it map a discovered chip type to a bq27xxx_chip enum?

Right now it just assumes the chip is a BQ27000, see line 45 of drivers/w1/slaves/w1_bq27000.c

OK then we don't need explicit enum values. We still need the category members after the categories, since the latter index bq27xxx_regs[].

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

The category (original) IDs index bq27xxx_regs[], and you'll probably extend that in time. So I placed the member (new) IDs well above the categories to allow permanent explicit values.

author
#29 lore raw

PATCH v10 7/8 power: bq27xxx_battery: Add power_supply_battery_info support

In reply to Liam Breck

From: Liam Breck <[email protected]>

Previously there was no way to configure chip registers in the event that the defaults didn't match the battery in question.

BQ27xxx driver now calls power_supply_get_battery_info, checks the inputs, and writes battery data to chip RAM or non-volatile memory.

Supports chips BQ27500, 545, 421, 425, 441, 621. Others may be added.

---
 drivers/power/supply/bq27xxx_battery.c | 478 ++++++++++++++++++++++++++++++++-
 include/linux/power/bq27xxx_battery.h  |   2 +
 2 files changed, 468 insertions(+), 12 deletions(-)
drivers/power/supply/bq27xxx_battery.c +466 -12
index d613d3d..fb062db 100644
@@ -51,7 +51,7 @@
 
 #include <linux/power/bq27xxx_battery.h>
 
-#define DRIVER_VERSION		"1.2.0"
+#define DRIVER_VERSION		"1.3.0"
 
 #define BQ27XXX_MANUFACTURER	"Texas Instruments"
 
@@ -59,6 +59,7 @@
 #define BQ27XXX_FLAG_DSC	BIT(0)
 #define BQ27XXX_FLAG_SOCF	BIT(1) /* State-of-Charge threshold final */
 #define BQ27XXX_FLAG_SOC1	BIT(2) /* State-of-Charge threshold 1 */
+#define BQ27XXX_FLAG_CFGUP	BIT(4)
 #define BQ27XXX_FLAG_FC		BIT(9)
 #define BQ27XXX_FLAG_OTD	BIT(14)
 #define BQ27XXX_FLAG_OTC	BIT(15)
@@ -72,6 +73,11 @@
 #define BQ27000_FLAG_FC		BIT(5)
 #define BQ27000_FLAG_CHGS	BIT(7) /* Charge state flag */
 
+/* control register params */
+#define BQ27XXX_SEALED			0x20
+#define BQ27XXX_SET_CFGUPDATE		0x13
+#define BQ27XXX_SOFT_RESET		0x42
+
 #define BQ27XXX_RS			(20) /* Resistor sense mOhm */
 #define BQ27XXX_POWER_CONSTANT		(29200) /* 29.2 µV^2 * 1000 */
 #define BQ27XXX_CURRENT_CONSTANT	(3570) /* 3.57 µV * 1000 */
@@ -102,6 +108,11 @@ enum bq27xxx_reg_index {
 	BQ27XXX_REG_SOC,	/* State-of-Charge */
 	BQ27XXX_REG_DCAP,	/* Design Capacity */
 	BQ27XXX_REG_AP,		/* Average Power */
+	BQ27XXX_DM_CTRL,	/* BlockDataControl() */
+	BQ27XXX_DM_CLASS,	/* DataClass() */
+	BQ27XXX_DM_BLOCK,	/* DataBlock() */
+	BQ27XXX_DM_DATA,	/* BlockData() */
+	BQ27XXX_DM_CKSUM,	/* BlockDataChecksum() */
 	BQ27XXX_REG_MAX,	/* sentinel */
 };
 
@@ -125,6 +136,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x0b,
 		[BQ27XXX_REG_DCAP] = 0x76,
 		[BQ27XXX_REG_AP] = 0x24,
+		[BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
 	},
 	[BQ27010] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -144,6 +160,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x0b,
 		[BQ27XXX_REG_DCAP] = 0x76,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
 	},
 	[BQ27500] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -163,6 +184,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27510] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -182,6 +208,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x20,
 		[BQ27XXX_REG_DCAP] = 0x2e,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27530] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -201,6 +232,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
 		[BQ27XXX_REG_AP] = 0x24,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27541] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -220,6 +256,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x24,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27545] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -239,6 +280,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
 		[BQ27XXX_REG_AP] = 0x24,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27421] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -258,6 +304,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x1c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x18,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 };
 
@@ -432,6 +483,82 @@ static struct {
 static DEFINE_MUTEX(bq27xxx_list_lock);
 static LIST_HEAD(bq27xxx_battery_devices);
 
+#define BQ27XXX_DM_SZ	32
+
+#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
+
+struct bq27xxx_dm_reg {
+	u8 subclass_id;
+	u8 offset;
+	u8 bytes;
+	u16 min, max;
+};
+
+struct bq27xxx_dm_buf {
+	u8 class;
+	u8 block;
+	u8 a[BQ27XXX_DM_SZ];
+	bool full, updt;
+};
+
+#define BQ27XXX_DM_BUF(di, i) { \
+	.class = (di)->dm_regs[i].subclass_id, \
+	.block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \
+}
+
+static inline u16* bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf,
+				      struct bq27xxx_dm_reg *reg)
+{
+	if (buf->class == reg->subclass_id
+	&&  buf->block == reg->offset / BQ27XXX_DM_SZ)
+		return (u16*) (buf->a + reg->offset % BQ27XXX_DM_SZ);
+
+	return NULL;
+}
+
+enum bq27xxx_dm_reg_id {
+	BQ27XXX_DM_DESIGN_CAPACITY = 0,
+	BQ27XXX_DM_DESIGN_ENERGY,
+	BQ27XXX_DM_TERMINATE_VOLTAGE,
+};
+
+static const char* bq27xxx_dm_reg_name[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
+	[BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
+};
+
+static struct bq27xxx_dm_reg bq27500_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 10, 2,    0, 65535 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { }, /* missing on chip */
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 },
+};
+
+static struct bq27xxx_dm_reg bq27545_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 23, 2,    0, 32767 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { 48, 25, 2,    0, 32767 },
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27421_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 10, 2,    0,  8000 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 12, 2,    0, 32767 },
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27425_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 12, 2,    0, 32767 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 14, 2,    0, 32767 },
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27621_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 3, 2,    0,  8000 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 5, 2,    0, 32767 },
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500,  3700 },
+};
+
+
 static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
 {
 	struct bq27xxx_device_info *di;
@@ -476,6 +603,317 @@ static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index,
 	return di->bus.read(di, di->regs[reg_index], single);
 }
 
+static int bq27xxx_battery_set_seal_state(struct bq27xxx_device_info *di,
+					  bool state)
+{
+	int ret;
+
+	if (state) {
+		ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], BQ27XXX_SEALED, false);
+		if (ret < 0)
+			goto out;
+	} else {
+		ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)(di->unseal_key >> 16), false);
+		if (ret < 0)
+			goto out;
+
+		ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)di->unseal_key, false);
+		if (ret < 0)
+			goto out;
+	}
+	return 0;
+
+out:
+	dev_err(di->dev, "bus error on %s: %d\n", state ? "seal" : "unseal", ret);
+	return ret;
+}
+
+static u8 bq27xxx_battery_checksum_dm_block(struct bq27xxx_dm_buf *buf)
+{
+	u16 sum = 0;
+	int i;
+
+	for (i = 0; i < BQ27XXX_DM_SZ; i++)
+		sum += buf->a[i];
+	sum &= 0xff;
+
+	return 0xff - sum;
+}
+
+static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
+					 struct bq27xxx_dm_buf *buf)
+{
+	int ret;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+	if (ret < 0)
+		goto out;
+
+	BQ27XXX_MSLEEP(1);
+
+	ret = di->bus.read_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.read(di, di->regs[BQ27XXX_DM_CKSUM], true);
+	if (ret < 0)
+		goto out;
+
+	if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	buf->full = true;
+	buf->updt = false;
+	return 0;
+
+out:
+	dev_err(di->dev, "bus error reading chip memory: %d\n", ret);
+	return ret;
+}
+
+static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di,
+					    struct bq27xxx_dm_buf *buf,
+					    enum bq27xxx_dm_reg_id reg_id,
+					    unsigned int val)
+{
+	struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id];
+	const char* str = bq27xxx_dm_reg_name[reg_id];
+	u16 *prev = bq27xxx_dm_reg_ptr(buf, reg);
+
+	if (prev == NULL) {
+		dev_warn(di->dev, "buffer does not match %s dm spec\n", str);
+		return;
+	}
+
+	if (reg->bytes != 2) {
+		dev_warn(di->dev, "%s dm spec has unsupported byte size\n", str);
+		return;
+	}
+
+	if (!buf->full)
+		return;
+
+	if (be16_to_cpup(prev) == val) {
+		dev_info(di->dev, "%s has %u\n", str, val);
+		return;
+	}
+
+	dev_info(di->dev, "update %s to %u\n", str, val);
+
+	*prev = cpu_to_be16(val);
+	buf->updt = true;
+}
+
+static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di,
+					 bool state)
+{
+	int ret, try=100;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL],
+			    state ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET,
+			    false);
+	if (ret < 0)
+		goto out;
+
+	do {
+		BQ27XXX_MSLEEP(25);
+		ret = di->bus.read(di, di->regs[BQ27XXX_REG_FLAGS], false);
+		if (ret < 0)
+			goto out;
+	} while (!(ret & BQ27XXX_FLAG_CFGUP) == state && --try);
+
+	if (!try) {
+		dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", state);
+		return -EINVAL;
+	}
+
+	if (100-try > 3)
+		dev_warn(di->dev, "cfgupdate %d, retries %d\n", state, 100-try);
+
+	return 0;
+
+out:
+	dev_err(di->dev, "bus error on %s: %d\n", state ? "set_cfgupdate" : "soft_reset", ret);
+	return ret;
+}
+
+static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
+					  struct bq27xxx_dm_buf *buf)
+{
+	bool cfgup = di->chip == BQ27421; /* assume group supports cfgupdate */
+	int ret;
+
+	if (!buf->updt)
+		return 0;
+
+	if (cfgup) {
+		ret = bq27xxx_battery_set_cfgupdate(di, true);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_CTRL], 0, true);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+	if (ret < 0)
+		goto out;
+
+	BQ27XXX_MSLEEP(1);
+
+	ret = di->bus.write_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_CKSUM],
+			    bq27xxx_battery_checksum_dm_block(buf), true);
+	if (ret < 0)
+		goto out;
+
+	/* THE FOLLOWING SEQUENCE IS TOXIC. DO NOT USE!
+	 * If the 'time' delay is insufficient, NVM corruption results on
+	 * the '425 chip (and perhaps others), which could damage the chip.
+	 * It was suggested in this TI tool:
+	 *   http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
+	 *
+	 * 1. MSLEEP(time) after above write(BQ27XXX_DM_CKSUM, ...)
+	 * 2. write(BQ27XXX_DM_BLOCK, buf->block)
+	 * 3. sum = read(BQ27XXX_DM_CKSUM)
+	 * 4. if (sum != bq27xxx_battery_checksum_dm_block(buf))
+	 *      report error
+	 */
+
+	if (cfgup) {
+		BQ27XXX_MSLEEP(1);
+		ret = bq27xxx_battery_set_cfgupdate(di, false);
+		if (ret < 0)
+			return ret;
+	} else {
+		/* flash DM updates in <100ms, but reset time isn't documented */
+		BQ27XXX_MSLEEP(400);
+	}
+
+	buf->updt = false;
+	return 0;
+
+out:
+	if (cfgup)
+		bq27xxx_battery_set_cfgupdate(di, false);
+
+	dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
+	return ret;
+}
+
+static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di,
+				       struct power_supply_battery_info *info)
+{
+	struct bq27xxx_dm_buf bd = BQ27XXX_DM_BUF(di, BQ27XXX_DM_DESIGN_CAPACITY);
+	struct bq27xxx_dm_buf bt = BQ27XXX_DM_BUF(di, BQ27XXX_DM_TERMINATE_VOLTAGE);
+
+	if (info->charge_full_design_uah != -EINVAL
+	 && info->energy_full_design_uwh != -EINVAL) {
+		bq27xxx_battery_read_dm_block(di, &bd);
+		/* assume design energy & capacity are in same block */
+		bq27xxx_battery_update_dm_block(di, &bd,
+					BQ27XXX_DM_DESIGN_CAPACITY,
+					info->charge_full_design_uah / 1000);
+		bq27xxx_battery_update_dm_block(di, &bd,
+					BQ27XXX_DM_DESIGN_ENERGY,
+					info->energy_full_design_uwh / 1000);
+	}
+
+	if (info->voltage_min_design_uv != -EINVAL) {
+		bool same = bd.class == bt.class && bd.block == bt.block;
+		if (!same)
+			bq27xxx_battery_read_dm_block(di, &bt);
+		bq27xxx_battery_update_dm_block(di, same ? &bd : &bt,
+					BQ27XXX_DM_TERMINATE_VOLTAGE,
+					info->voltage_min_design_uv / 1000);
+	}
+
+	bq27xxx_battery_write_dm_block(di, &bd);
+	bq27xxx_battery_write_dm_block(di, &bt);
+}
+
+void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
+{
+	struct power_supply_battery_info info = {};
+	unsigned int min, max;
+
+	/* functions don't exist for writing data so abort */
+	if (!di->bus.write || !di->bus.write_bulk)
+		return;
+
+	/* no settings to be set for this chipset so abort */
+	if (!di->dm_regs)
+		return;
+
+	if (bq27xxx_battery_set_seal_state(di, false) < 0)
+		return;
+
+	if (power_supply_get_battery_info(di->bat, &info) < 0)
+		goto out;
+
+	if (info.energy_full_design_uwh != info.charge_full_design_uah) {
+		if (info.energy_full_design_uwh == -EINVAL)
+			dev_warn(di->dev,
+				"missing battery:energy-full-design-microwatt-hours\n");
+		else if (info.charge_full_design_uah == -EINVAL)
+			dev_warn(di->dev,
+				"missing battery:charge-full-design-microamp-hours\n");
+	}
+
+	/* assume min == 0 */
+	max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max;
+	if (info.energy_full_design_uwh > max * 1000) {
+		dev_err(di->dev,
+		       "invalid battery:energy-full-design-microwatt-hours %d\n",
+			info.energy_full_design_uwh);
+		info.energy_full_design_uwh = -EINVAL;
+	}
+
+	/* assume min == 0 */
+	max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max;
+	if (info.charge_full_design_uah > max * 1000) {
+		dev_err(di->dev,
+		       "invalid battery:charge-full-design-microamp-hours %d\n",
+			info.charge_full_design_uah);
+		info.charge_full_design_uah = -EINVAL;
+	}
+
+	min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min;
+	max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max;
+	if ((info.voltage_min_design_uv < min * 1000
+	  || info.voltage_min_design_uv > max * 1000)
+	  && info.voltage_min_design_uv != -EINVAL) {
+		dev_err(di->dev,
+		       "invalid battery:voltage-min-design-microvolt %d\n",
+			info.voltage_min_design_uv);
+		info.voltage_min_design_uv = -EINVAL;
+	}
+
+	if ((info.energy_full_design_uwh == -EINVAL
+	  || info.charge_full_design_uah == -EINVAL)
+	  && info.voltage_min_design_uv  == -EINVAL)
+		goto out;
+
+	bq27xxx_battery_set_config(di, &info);
+
+out:
+	bq27xxx_battery_set_seal_state(di, true);
+}
+
 /*
  * Return the battery State-of-Charge
  * Or < 0 if something fails.
@@ -985,6 +1423,13 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 		ret = bq27xxx_simple_value(di->charge_design_full, val);
 		break;
+	/*
+	 * TODO: Implement these to make registers set from
+	 * power_supply_battery_info visible in sysfs.
+	 */
+	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+		return -EINVAL;
 	case POWER_SUPPLY_PROP_CYCLE_COUNT:
 		ret = bq27xxx_simple_value(di->cache.cycle_count, val);
 		break;
@@ -1015,28 +1460,36 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
 	schedule_delayed_work(&di->work, 0);
 }
 
+#define BQ27XXX_INIT(c,d,k)   \
+	di->chip       = (c); \
+	di->dm_regs    = (d); \
+	di->unseal_key = (k)
+
 int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 {
 	struct power_supply_desc *psy_desc;
-	struct power_supply_config psy_cfg = { .drv_data = di, };
+	struct power_supply_config psy_cfg = {
+		.of_node = di->dev->of_node,
+		.drv_data = di,
+	};
 
 	switch(di->chip) {
 	case BQ27000:
-	case BQ27010:
-	case BQ27500:
-	case BQ27510:
-	case BQ27530:
-	case BQ27541:
-	case BQ27545:
-	case BQ27421: break;
+	case BQ27010: break;
+	case BQ27500: BQ27XXX_INIT(BQ27500, bq27500_dm_regs, 0x04143672); break;
+	case BQ27510: break;
+	case BQ27530: break;
+	case BQ27541: break;
+	case BQ27545: BQ27XXX_INIT(BQ27545, bq27545_dm_regs, 0x04143672); break;
+	case BQ27421: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
 	case BQ27520: di->chip = BQ27510; break;
 	case BQ27531: di->chip = BQ27530; break;
 	case BQ27542: di->chip = BQ27541; break;
 	case BQ27546: di->chip = BQ27541; break;
 	case BQ27742: di->chip = BQ27541; break;
-	case BQ27425: di->chip = BQ27421; break;
-	case BQ27441: di->chip = BQ27421; break;
-	case BQ27621: di->chip = BQ27421; break;
+	case BQ27425: BQ27XXX_INIT(BQ27421, bq27425_dm_regs, 0x04143672); break;
+	case BQ27441: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
+	case BQ27621: BQ27XXX_INIT(BQ27421, bq27621_dm_regs, 0x80008000); break;
 	}
 
 	INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
@@ -1062,6 +1515,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 
 	dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 
+	bq27xxx_battery_settings(di);
 	bq27xxx_battery_update(di);
 
 	mutex_lock(&bq27xxx_list_lock);
include/linux/power/bq27xxx_battery.h +2 -0
index 90db1cf..dbf1ab9 100644
@@ -67,6 +67,8 @@ struct bq27xxx_device_info {
 	int id;
 	enum bq27xxx_chip chip;
 	const char *name;
+	struct bq27xxx_dm_reg *dm_regs;
+	u32 unseal_key;
 	struct bq27xxx_access_methods bus;
 	struct bq27xxx_reg_cache cache;
 	int charge_design_full;
Signature · 1 line
2.9.3
#30 lore raw

Re: [PATCH v10 7/8] power: bq27xxx_battery: Add power_supply_battery_info support

Quoted 242 lines · Liam Breck

From: Liam Breck <[email protected]>

Previously there was no way to configure chip registers in the event that the defaults didn't match the battery in question.

BQ27xxx driver now calls power_supply_get_battery_info, checks the inputs, and writes battery data to chip RAM or non-volatile memory.

Supports chips BQ27500, 545, 421, 425, 441, 621. Others may be added.

---
 drivers/power/supply/bq27xxx_battery.c | 478 ++++++++++++++++++++++++++++++++-
 include/linux/power/bq27xxx_battery.h  |   2 +
 2 files changed, 468 insertions(+), 12 deletions(-)
drivers/power/supply/bq27xxx_battery.c +128 -1
index d613d3d..fb062db 100644
@@ -51,7 +51,7 @@
 
 #include <linux/power/bq27xxx_battery.h>
 
-#define DRIVER_VERSION		"1.2.0"
+#define DRIVER_VERSION		"1.3.0"
 
 #define BQ27XXX_MANUFACTURER	"Texas Instruments"
 
@@ -59,6 +59,7 @@
 #define BQ27XXX_FLAG_DSC	BIT(0)
 #define BQ27XXX_FLAG_SOCF	BIT(1) /* State-of-Charge threshold final */
 #define BQ27XXX_FLAG_SOC1	BIT(2) /* State-of-Charge threshold 1 */
+#define BQ27XXX_FLAG_CFGUP	BIT(4)
 #define BQ27XXX_FLAG_FC		BIT(9)
 #define BQ27XXX_FLAG_OTD	BIT(14)
 #define BQ27XXX_FLAG_OTC	BIT(15)
@@ -72,6 +73,11 @@
 #define BQ27000_FLAG_FC		BIT(5)
 #define BQ27000_FLAG_CHGS	BIT(7) /* Charge state flag */
 
+/* control register params */
+#define BQ27XXX_SEALED			0x20
+#define BQ27XXX_SET_CFGUPDATE		0x13
+#define BQ27XXX_SOFT_RESET		0x42
+
 #define BQ27XXX_RS			(20) /* Resistor sense mOhm */
 #define BQ27XXX_POWER_CONSTANT		(29200) /* 29.2 µV^2 * 1000 */
 #define BQ27XXX_CURRENT_CONSTANT	(3570) /* 3.57 µV * 1000 */
@@ -102,6 +108,11 @@ enum bq27xxx_reg_index {
 	BQ27XXX_REG_SOC,	/* State-of-Charge */
 	BQ27XXX_REG_DCAP,	/* Design Capacity */
 	BQ27XXX_REG_AP,		/* Average Power */
+	BQ27XXX_DM_CTRL,	/* BlockDataControl() */
+	BQ27XXX_DM_CLASS,	/* DataClass() */
+	BQ27XXX_DM_BLOCK,	/* DataBlock() */
+	BQ27XXX_DM_DATA,	/* BlockData() */
+	BQ27XXX_DM_CKSUM,	/* BlockDataChecksum() */
 	BQ27XXX_REG_MAX,	/* sentinel */
 };
 
@@ -125,6 +136,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x0b,
 		[BQ27XXX_REG_DCAP] = 0x76,
 		[BQ27XXX_REG_AP] = 0x24,
+		[BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
 	},
 	[BQ27010] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -144,6 +160,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x0b,
 		[BQ27XXX_REG_DCAP] = 0x76,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
 	},
 	[BQ27500] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -163,6 +184,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27510] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -182,6 +208,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x20,
 		[BQ27XXX_REG_DCAP] = 0x2e,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27530] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -201,6 +232,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
 		[BQ27XXX_REG_AP] = 0x24,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27541] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -220,6 +256,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x24,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27545] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -239,6 +280,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
 		[BQ27XXX_REG_AP] = 0x24,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 	[BQ27421] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -258,6 +304,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x1c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x18,
+		[BQ27XXX_DM_CTRL] = 0x61,
+		[BQ27XXX_DM_CLASS] = 0x3e,
+		[BQ27XXX_DM_BLOCK] = 0x3f,
+		[BQ27XXX_DM_DATA] = 0x40,
+		[BQ27XXX_DM_CKSUM] = 0x60,
 	},
 };
 
@@ -432,6 +483,82 @@ static struct {
 static DEFINE_MUTEX(bq27xxx_list_lock);
 static LIST_HEAD(bq27xxx_battery_devices);
 
+#define BQ27XXX_DM_SZ	32
+
+#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
+
+struct bq27xxx_dm_reg {
+	u8 subclass_id;
+	u8 offset;
+	u8 bytes;
+	u16 min, max;
+};
+
+struct bq27xxx_dm_buf {
+	u8 class;
+	u8 block;
+	u8 a[BQ27XXX_DM_SZ];
+	bool full, updt;
+};
+
+#define BQ27XXX_DM_BUF(di, i) { \
+	.class = (di)->dm_regs[i].subclass_id, \
+	.block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \
+}
+
+static inline u16* bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf,
+				      struct bq27xxx_dm_reg *reg)
+{
+	if (buf->class == reg->subclass_id
+	&&  buf->block == reg->offset / BQ27XXX_DM_SZ)
+		return (u16*) (buf->a + reg->offset % BQ27XXX_DM_SZ);
+
+	return NULL;
+}
+
+enum bq27xxx_dm_reg_id {
+	BQ27XXX_DM_DESIGN_CAPACITY = 0,
+	BQ27XXX_DM_DESIGN_ENERGY,
+	BQ27XXX_DM_TERMINATE_VOLTAGE,
+};
+
+static const char* bq27xxx_dm_reg_name[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
+	[BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
+};
+
+static struct bq27xxx_dm_reg bq27500_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 10, 2,    0, 65535 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { }, /* missing on chip */
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 },
+};
+
+static struct bq27xxx_dm_reg bq27545_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 23, 2,    0, 32767 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { 48, 25, 2,    0, 32767 },
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27421_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 10, 2,    0,  8000 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 12, 2,    0, 32767 },
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27425_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 12, 2,    0, 32767 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 14, 2,    0, 32767 },
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27621_dm_regs[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 3, 2,    0,  8000 },
+	[BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 5, 2,    0, 32767 },
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500,  3700 },
+};
+
+
 static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
 {
 	struct bq27xxx_device_info *di;

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 612

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +7 -0
@@ -476,6 +603,317 @@ static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index,
 	return di->bus.read(di, di->regs[reg_index], single);
 }
 
+static int bq27xxx_battery_set_seal_state(struct bq27xxx_device_info *di,
+					  bool state)
+{
+	int ret;
+
+	if (state) {
+		ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], BQ27XXX_SEALED, false);

Look at how reads are done, we have a function bq27xxx_read() that checks the register and handles the access methods. Do something like that for write, then replace all these with that, "bus" should only be accessed in that function.

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 623

Quoted 11 lines
drivers/power/supply/bq27xxx_battery.c +11 -0
+		if (ret < 0)
+			goto out;
+	} else {
+		ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)(di->unseal_key >> 16), false);
+		if (ret < 0)
+			goto out;
+
+		ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)di->unseal_key, false);
+		if (ret < 0)
+			goto out;
+	}

+space

Has this been run through checkpatch?

Quoted 43 lines
drivers/power/supply/bq27xxx_battery.c +43 -0
+	return 0;
+
+out:
+	dev_err(di->dev, "bus error on %s: %d\n", state ? "seal" : "unseal", ret);
+	return ret;
+}
+
+static u8 bq27xxx_battery_checksum_dm_block(struct bq27xxx_dm_buf *buf)
+{
+	u16 sum = 0;
+	int i;
+
+	for (i = 0; i < BQ27XXX_DM_SZ; i++)
+		sum += buf->a[i];
+	sum &= 0xff;
+
+	return 0xff - sum;
+}
+
+static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
+					 struct bq27xxx_dm_buf *buf)
+{
+	int ret;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+	if (ret < 0)
+		goto out;
+
+	BQ27XXX_MSLEEP(1);
+
+	ret = di->bus.read_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.read(di, di->regs[BQ27XXX_DM_CKSUM], true);
+	if (ret < 0)
+		goto out;
+
+	if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 676

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +10 -0
+		ret = -EINVAL;
+		goto out;
+	}
+
+	buf->full = true;
+	buf->updt = false;
+	return 0;
+
+out:
+	dev_err(di->dev, "bus error reading chip memory: %d\n", ret);

Instead of this catch-all, each spot should have an error message that explains what failed. If they all end up with this generic message we cannot possibly diagnose issues for people.

Quoted 28 lines
drivers/power/supply/bq27xxx_battery.c +28 -0
+	return ret;
+}
+
+static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di,
+					    struct bq27xxx_dm_buf *buf,
+					    enum bq27xxx_dm_reg_id reg_id,
+					    unsigned int val)
+{
+	struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id];
+	const char* str = bq27xxx_dm_reg_name[reg_id];
+	u16 *prev = bq27xxx_dm_reg_ptr(buf, reg);
+
+	if (prev == NULL) {
+		dev_warn(di->dev, "buffer does not match %s dm spec\n", str);
+		return;
+	}
+
+	if (reg->bytes != 2) {
+		dev_warn(di->dev, "%s dm spec has unsupported byte size\n", str);
+		return;
+	}
+
+	if (!buf->full)
+		return;
+
+	if (be16_to_cpup(prev) == val) {
+		dev_info(di->dev, "%s has %u\n", str, val);
+		return;

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 714

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +10 -0
+	}
+
+	dev_info(di->dev, "update %s to %u\n", str, val);
+
+	*prev = cpu_to_be16(val);
+	buf->updt = true;
+}
+
+static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di,
+					 bool state)

Why only two states? why bool? you should probably be passing in the value, if you really want to do this as a state, then the states should have an enum for each state.

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +10 -0
+{
+	int ret, try=100;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL],
+			    state ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET,
+			    false);
+	if (ret < 0)
+		goto out;
+
+	do {

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 734

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +10 -0
+		BQ27XXX_MSLEEP(25);
+		ret = di->bus.read(di, di->regs[BQ27XXX_REG_FLAGS], false);
+		if (ret < 0)
+			goto out;
+	} while (!(ret & BQ27XXX_FLAG_CFGUP) == state && --try);
+
+	if (!try) {
+		dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", state);
+		return -EINVAL;
+	}

Put this check inside the loop.

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 736

Quoted 2 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+
+	if (100-try > 3)

Why 3? lets also count up to a set value, 100 is a magic number, if I change try to =200, I have to change it down here, that is going to be buggy.

Quoted 168 lines
drivers/power/supply/bq27xxx_battery.c +168 -0
+		dev_warn(di->dev, "cfgupdate %d, retries %d\n", state, 100-try);
+
+	return 0;
+
+out:
+	dev_err(di->dev, "bus error on %s: %d\n", state ? "set_cfgupdate" : "soft_reset", ret);
+	return ret;
+}
+
+static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
+					  struct bq27xxx_dm_buf *buf)
+{
+	bool cfgup = di->chip == BQ27421; /* assume group supports cfgupdate */
+	int ret;
+
+	if (!buf->updt)
+		return 0;
+
+	if (cfgup) {
+		ret = bq27xxx_battery_set_cfgupdate(di, true);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_CTRL], 0, true);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+	if (ret < 0)
+		goto out;
+
+	BQ27XXX_MSLEEP(1);
+
+	ret = di->bus.write_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+	if (ret < 0)
+		goto out;
+
+	ret = di->bus.write(di, di->regs[BQ27XXX_DM_CKSUM],
+			    bq27xxx_battery_checksum_dm_block(buf), true);
+	if (ret < 0)
+		goto out;
+
+	/* THE FOLLOWING SEQUENCE IS TOXIC. DO NOT USE!
+	 * If the 'time' delay is insufficient, NVM corruption results on
+	 * the '425 chip (and perhaps others), which could damage the chip.
+	 * It was suggested in this TI tool:
+	 *   http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
+	 *
+	 * 1. MSLEEP(time) after above write(BQ27XXX_DM_CKSUM, ...)
+	 * 2. write(BQ27XXX_DM_BLOCK, buf->block)
+	 * 3. sum = read(BQ27XXX_DM_CKSUM)
+	 * 4. if (sum != bq27xxx_battery_checksum_dm_block(buf))
+	 *      report error
+	 */
+
+	if (cfgup) {
+		BQ27XXX_MSLEEP(1);
+		ret = bq27xxx_battery_set_cfgupdate(di, false);
+		if (ret < 0)
+			return ret;
+	} else {
+		/* flash DM updates in <100ms, but reset time isn't documented */
+		BQ27XXX_MSLEEP(400);
+	}
+
+	buf->updt = false;
+	return 0;
+
+out:
+	if (cfgup)
+		bq27xxx_battery_set_cfgupdate(di, false);
+
+	dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
+	return ret;
+}
+
+static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di,
+				       struct power_supply_battery_info *info)
+{
+	struct bq27xxx_dm_buf bd = BQ27XXX_DM_BUF(di, BQ27XXX_DM_DESIGN_CAPACITY);
+	struct bq27xxx_dm_buf bt = BQ27XXX_DM_BUF(di, BQ27XXX_DM_TERMINATE_VOLTAGE);
+
+	if (info->charge_full_design_uah != -EINVAL
+	 && info->energy_full_design_uwh != -EINVAL) {
+		bq27xxx_battery_read_dm_block(di, &bd);
+		/* assume design energy & capacity are in same block */
+		bq27xxx_battery_update_dm_block(di, &bd,
+					BQ27XXX_DM_DESIGN_CAPACITY,
+					info->charge_full_design_uah / 1000);
+		bq27xxx_battery_update_dm_block(di, &bd,
+					BQ27XXX_DM_DESIGN_ENERGY,
+					info->energy_full_design_uwh / 1000);
+	}
+
+	if (info->voltage_min_design_uv != -EINVAL) {
+		bool same = bd.class == bt.class && bd.block == bt.block;
+		if (!same)
+			bq27xxx_battery_read_dm_block(di, &bt);
+		bq27xxx_battery_update_dm_block(di, same ? &bd : &bt,
+					BQ27XXX_DM_TERMINATE_VOLTAGE,
+					info->voltage_min_design_uv / 1000);
+	}
+
+	bq27xxx_battery_write_dm_block(di, &bd);
+	bq27xxx_battery_write_dm_block(di, &bt);
+}
+
+void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
+{
+	struct power_supply_battery_info info = {};
+	unsigned int min, max;
+
+	/* functions don't exist for writing data so abort */
+	if (!di->bus.write || !di->bus.write_bulk)
+		return;
+
+	/* no settings to be set for this chipset so abort */
+	if (!di->dm_regs)
+		return;
+
+	if (bq27xxx_battery_set_seal_state(di, false) < 0)
+		return;
+
+	if (power_supply_get_battery_info(di->bat, &info) < 0)
+		goto out;
+
+	if (info.energy_full_design_uwh != info.charge_full_design_uah) {
+		if (info.energy_full_design_uwh == -EINVAL)
+			dev_warn(di->dev,
+				"missing battery:energy-full-design-microwatt-hours\n");
+		else if (info.charge_full_design_uah == -EINVAL)
+			dev_warn(di->dev,
+				"missing battery:charge-full-design-microamp-hours\n");
+	}
+
+	/* assume min == 0 */
+	max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max;
+	if (info.energy_full_design_uwh > max * 1000) {
+		dev_err(di->dev,
+		       "invalid battery:energy-full-design-microwatt-hours %d\n",
+			info.energy_full_design_uwh);
+		info.energy_full_design_uwh = -EINVAL;
+	}
+
+	/* assume min == 0 */
+	max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max;
+	if (info.charge_full_design_uah > max * 1000) {
+		dev_err(di->dev,
+		       "invalid battery:charge-full-design-microamp-hours %d\n",
+			info.charge_full_design_uah);
+		info.charge_full_design_uah = -EINVAL;
+	}
+
+	min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min;
+	max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max;
+	if ((info.voltage_min_design_uv < min * 1000
+	  || info.voltage_min_design_uv > max * 1000)
+	  && info.voltage_min_design_uv != -EINVAL) {
+		dev_err(di->dev,
+		       "invalid battery:voltage-min-design-microvolt %d\n",
+			info.voltage_min_design_uv);
+		info.voltage_min_design_uv = -EINVAL;
+	}

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 914

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +10 -0
+
+	if ((info.energy_full_design_uwh == -EINVAL
+	  || info.charge_full_design_uah == -EINVAL)
+	  && info.voltage_min_design_uv  == -EINVAL)
+		goto out;
+
+	bq27xxx_battery_set_config(di, &info);
+
+out:
+	bq27xxx_battery_set_seal_state(di, true);

Don't use goto unless you have to, this is not such a case.

Quoted 89 lines
drivers/power/supply/bq27xxx_battery.c +29 -11
+}
+
 /*
  * Return the battery State-of-Charge
  * Or < 0 if something fails.
@@ -985,6 +1423,13 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 		ret = bq27xxx_simple_value(di->charge_design_full, val);
 		break;
+	/*
+	 * TODO: Implement these to make registers set from
+	 * power_supply_battery_info visible in sysfs.
+	 */
+	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+		return -EINVAL;
 	case POWER_SUPPLY_PROP_CYCLE_COUNT:
 		ret = bq27xxx_simple_value(di->cache.cycle_count, val);
 		break;
@@ -1015,28 +1460,36 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
 	schedule_delayed_work(&di->work, 0);
 }
 
+#define BQ27XXX_INIT(c,d,k)   \
+	di->chip       = (c); \
+	di->dm_regs    = (d); \
+	di->unseal_key = (k)
+
 int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 {
 	struct power_supply_desc *psy_desc;
-	struct power_supply_config psy_cfg = { .drv_data = di, };
+	struct power_supply_config psy_cfg = {
+		.of_node = di->dev->of_node,
+		.drv_data = di,
+	};
 
 	switch(di->chip) {
 	case BQ27000:
-	case BQ27010:
-	case BQ27500:
-	case BQ27510:
-	case BQ27530:
-	case BQ27541:
-	case BQ27545:
-	case BQ27421: break;
+	case BQ27010: break;
+	case BQ27500: BQ27XXX_INIT(BQ27500, bq27500_dm_regs, 0x04143672); break;
+	case BQ27510: break;
+	case BQ27530: break;
+	case BQ27541: break;
+	case BQ27545: BQ27XXX_INIT(BQ27545, bq27545_dm_regs, 0x04143672); break;
+	case BQ27421: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
 	case BQ27520: di->chip = BQ27510; break;
 	case BQ27531: di->chip = BQ27530; break;
 	case BQ27542: di->chip = BQ27541; break;
 	case BQ27546: di->chip = BQ27541; break;
 	case BQ27742: di->chip = BQ27541; break;
-	case BQ27425: di->chip = BQ27421; break;
-	case BQ27441: di->chip = BQ27421; break;
-	case BQ27621: di->chip = BQ27421; break;
+	case BQ27425: BQ27XXX_INIT(BQ27421, bq27425_dm_regs, 0x04143672); break;
+	case BQ27441: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
+	case BQ27621: BQ27XXX_INIT(BQ27421, bq27621_dm_regs, 0x80008000); break;
 	}
 
 	INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
@@ -1062,6 +1515,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 
 	dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 
+	bq27xxx_battery_settings(di);
 	bq27xxx_battery_update(di);
 
 	mutex_lock(&bq27xxx_list_lock);
include/linux/power/bq27xxx_battery.h +2 -0
index 90db1cf..dbf1ab9 100644
@@ -67,6 +67,8 @@ struct bq27xxx_device_info {
 	int id;
 	enum bq27xxx_chip chip;
 	const char *name;
+	struct bq27xxx_dm_reg *dm_regs;
+	u32 unseal_key;
 	struct bq27xxx_access_methods bus;
 	struct bq27xxx_reg_cache cache;
 	int charge_design_full;
author
#31 lore raw

Re: [PATCH v10 7/8] power: bq27xxx_battery: Add power_supply_battery_info support

Quoted 246 lines · Andrew F. Davis
Quoted 245 lines · Liam Breck

From: Liam Breck <[email protected]>

Previously there was no way to configure chip registers in the event that the defaults didn't match the battery in question.

BQ27xxx driver now calls power_supply_get_battery_info, checks the inputs, and writes battery data to chip RAM or non-volatile memory.

Supports chips BQ27500, 545, 421, 425, 441, 621. Others may be added.

---
 drivers/power/supply/bq27xxx_battery.c | 478 ++++++++++++++++++++++++++++++++-
 include/linux/power/bq27xxx_battery.h  |   2 +
 2 files changed, 468 insertions(+), 12 deletions(-)
drivers/power/supply/bq27xxx_battery.c +128 -1
index d613d3d..fb062db 100644
@@ -51,7 +51,7 @@
 
 #include <linux/power/bq27xxx_battery.h>
 
-#define DRIVER_VERSION               "1.2.0"
+#define DRIVER_VERSION               "1.3.0"
 
 #define BQ27XXX_MANUFACTURER "Texas Instruments"
 
@@ -59,6 +59,7 @@
 #define BQ27XXX_FLAG_DSC     BIT(0)
 #define BQ27XXX_FLAG_SOCF    BIT(1) /* State-of-Charge threshold final */
 #define BQ27XXX_FLAG_SOC1    BIT(2) /* State-of-Charge threshold 1 */
+#define BQ27XXX_FLAG_CFGUP   BIT(4)
 #define BQ27XXX_FLAG_FC              BIT(9)
 #define BQ27XXX_FLAG_OTD     BIT(14)
 #define BQ27XXX_FLAG_OTC     BIT(15)
@@ -72,6 +73,11 @@
 #define BQ27000_FLAG_FC              BIT(5)
 #define BQ27000_FLAG_CHGS    BIT(7) /* Charge state flag */
 
+/* control register params */
+#define BQ27XXX_SEALED                       0x20
+#define BQ27XXX_SET_CFGUPDATE                0x13
+#define BQ27XXX_SOFT_RESET           0x42
+
 #define BQ27XXX_RS                   (20) /* Resistor sense mOhm */
 #define BQ27XXX_POWER_CONSTANT               (29200) /* 29.2 µV^2 * 1000 */
 #define BQ27XXX_CURRENT_CONSTANT     (3570) /* 3.57 µV * 1000 */
@@ -102,6 +108,11 @@ enum bq27xxx_reg_index {
      BQ27XXX_REG_SOC,        /* State-of-Charge */
      BQ27XXX_REG_DCAP,       /* Design Capacity */
      BQ27XXX_REG_AP,         /* Average Power */
+     BQ27XXX_DM_CTRL,        /* BlockDataControl() */
+     BQ27XXX_DM_CLASS,       /* DataClass() */
+     BQ27XXX_DM_BLOCK,       /* DataBlock() */
+     BQ27XXX_DM_DATA,        /* BlockData() */
+     BQ27XXX_DM_CKSUM,       /* BlockDataChecksum() */
      BQ27XXX_REG_MAX,        /* sentinel */
 };
 
@@ -125,6 +136,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x0b,
              [BQ27XXX_REG_DCAP] = 0x76,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
      },
      [BQ27010] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -144,6 +160,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x0b,
              [BQ27XXX_REG_DCAP] = 0x76,
              [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
      },
      [BQ27500] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -163,6 +184,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = 0x3c,
              [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27510] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -182,6 +208,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x20,
              [BQ27XXX_REG_DCAP] = 0x2e,
              [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27530] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -201,6 +232,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27541] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -220,6 +256,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = 0x3c,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27545] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -239,6 +280,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27421] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -258,6 +304,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x1c,
              [BQ27XXX_REG_DCAP] = 0x3c,
              [BQ27XXX_REG_AP] = 0x18,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
 };
 
@@ -432,6 +483,82 @@ static struct {
 static DEFINE_MUTEX(bq27xxx_list_lock);
 static LIST_HEAD(bq27xxx_battery_devices);
 
+#define BQ27XXX_DM_SZ        32
+
+#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
+
+struct bq27xxx_dm_reg {
+     u8 subclass_id;
+     u8 offset;
+     u8 bytes;
+     u16 min, max;
+};
+
+struct bq27xxx_dm_buf {
+     u8 class;
+     u8 block;
+     u8 a[BQ27XXX_DM_SZ];
+     bool full, updt;
+};
+
+#define BQ27XXX_DM_BUF(di, i) { \
+     .class = (di)->dm_regs[i].subclass_id, \
+     .block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \
+}
+
+static inline u16* bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf,
+                                   struct bq27xxx_dm_reg *reg)
+{
+     if (buf->class == reg->subclass_id
+     &&  buf->block == reg->offset / BQ27XXX_DM_SZ)
+             return (u16*) (buf->a + reg->offset % BQ27XXX_DM_SZ);
+
+     return NULL;
+}
+
+enum bq27xxx_dm_reg_id {
+     BQ27XXX_DM_DESIGN_CAPACITY = 0,
+     BQ27XXX_DM_DESIGN_ENERGY,
+     BQ27XXX_DM_TERMINATE_VOLTAGE,
+};
+
+static const char* bq27xxx_dm_reg_name[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
+     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
+};
+
+static struct bq27xxx_dm_reg bq27500_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 10, 2,    0, 65535 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { }, /* missing on chip */
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 },
+};
+
+static struct bq27xxx_dm_reg bq27545_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 23, 2,    0, 32767 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 48, 25, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27421_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 10, 2,    0,  8000 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 12, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27425_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 12, 2,    0, 32767 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 14, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27621_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 3, 2,    0,  8000 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 5, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500,  3700 },
+};
+
+
 static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
 {
      struct bq27xxx_device_info *di;
@@ -476,6 +603,317 @@ static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index,
      return di->bus.read(di, di->regs[reg_index], single);
 }
 
Quoted 13 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 612

Quoted 7 lines
drivers/power/supply/bq27xxx_battery.c +7 -0
+static int bq27xxx_battery_set_seal_state(struct bq27xxx_device_info *di,
+                                       bool state)
+{
+     int ret;
+
+     if (state) {
+             ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], BQ27XXX_SEALED, false);

Look at how reads are done, we have a function bq27xxx_read() that checks the register and handles the access methods. Do something like that for write, then replace all these with that, "bus" should only be accessed in that function.

OK. And for bus.{read,write}_bulk() too? They only occur once.

Quoted 65 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 623

Quoted 11 lines
drivers/power/supply/bq27xxx_battery.c +11 -0
+             if (ret < 0)
+                     goto out;
+     } else {
+             ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)(di->unseal_key >> 16), false);
+             if (ret < 0)
+                     goto out;
+
+             ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)di->unseal_key, false);
+             if (ret < 0)
+                     goto out;
+     }

+space

Has this been run through checkpatch?

Quoted 49 lines
drivers/power/supply/bq27xxx_battery.c +49 -0
+     return 0;
+
+out:
+     dev_err(di->dev, "bus error on %s: %d\n", state ? "seal" : "unseal", ret);
+     return ret;
+}
+
+static u8 bq27xxx_battery_checksum_dm_block(struct bq27xxx_dm_buf *buf)
+{
+     u16 sum = 0;
+     int i;
+
+     for (i = 0; i < BQ27XXX_DM_SZ; i++)
+             sum += buf->a[i];
+     sum &= 0xff;
+
+     return 0xff - sum;
+}
+
+static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
+                                      struct bq27xxx_dm_buf *buf)
+{
+     int ret;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+     if (ret < 0)
+             goto out;
+
+     BQ27XXX_MSLEEP(1);
+
+     ret = di->bus.read_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.read(di, di->regs[BQ27XXX_DM_CKSUM], true);
+     if (ret < 0)
+             goto out;
+
+     if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {
+             ret = -EINVAL;
+             goto out;
+     }
+
+     buf->full = true;
+     buf->updt = false;
Quoted 8 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 676

Quoted 4 lines
drivers/power/supply/bq27xxx_battery.c +4 -0
+     return 0;
+
+out:
+     dev_err(di->dev, "bus error reading chip memory: %d\n", ret);

Instead of this catch-all, each spot should have an error message that explains what failed. If they all end up with this generic message we cannot possibly diagnose issues for people.

Knowing which bus op failed doesn't help. Any error means either the bus hw failed or chip died. If we're debugging a new chip, we'll need extra print statements anyway.

Quoted 34 lines
Quoted 34 lines
drivers/power/supply/bq27xxx_battery.c +34 -0
+     return ret;
+}
+
+static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di,
+                                         struct bq27xxx_dm_buf *buf,
+                                         enum bq27xxx_dm_reg_id reg_id,
+                                         unsigned int val)
+{
+     struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id];
+     const char* str = bq27xxx_dm_reg_name[reg_id];
+     u16 *prev = bq27xxx_dm_reg_ptr(buf, reg);
+
+     if (prev == NULL) {
+             dev_warn(di->dev, "buffer does not match %s dm spec\n", str);
+             return;
+     }
+
+     if (reg->bytes != 2) {
+             dev_warn(di->dev, "%s dm spec has unsupported byte size\n", str);
+             return;
+     }
+
+     if (!buf->full)
+             return;
+
+     if (be16_to_cpup(prev) == val) {
+             dev_info(di->dev, "%s has %u\n", str, val);
+             return;
+     }
+
+     dev_info(di->dev, "update %s to %u\n", str, val);
+
+     *prev = cpu_to_be16(val);
+     buf->updt = true;
Quoted 8 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 714

Quoted 4 lines
drivers/power/supply/bq27xxx_battery.c +4 -0
+}
+
+static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di,
+                                      bool state)

Why only two states? why bool? you should probably be passing in the value, if you really want to do this as a state, then the states should have an enum for each state.

You can enter or exit cfgupdate mode. We do the same for set_seal_state(). And bq27xxx_read() takes a bool arg to indicate one or two bytes.

Quoted 14 lines
Quoted 14 lines
drivers/power/supply/bq27xxx_battery.c +14 -0
+{
+     int ret, try=100;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL],
+                         state ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET,
+                         false);
+     if (ret < 0)
+             goto out;
+
+     do {
+             BQ27XXX_MSLEEP(25);
+             ret = di->bus.read(di, di->regs[BQ27XXX_REG_FLAGS], false);
+             if (ret < 0)
+                     goto out;
Quoted 8 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 734

Quoted 6 lines
drivers/power/supply/bq27xxx_battery.c +6 -0
+     } while (!(ret & BQ27XXX_FLAG_CFGUP) == state && --try);
+
+     if (!try) {
+             dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", state);
+             return -EINVAL;
+     }

Put this check inside the loop.

We test try inside the loop. This test is only relevant after the loop.

Quoted 6 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 736

Quoted 2 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+
+     if (100-try > 3)

Why 3? lets also count up to a set value, 100 is a magic number, if I change try to =200, I have to change it down here, that is going to be buggy.

OK. 3 because 75ms is a long time.

Quoted 172 lines
Quoted 172 lines
drivers/power/supply/bq27xxx_battery.c +172 -0
+             dev_warn(di->dev, "cfgupdate %d, retries %d\n", state, 100-try);
+
+     return 0;
+
+out:
+     dev_err(di->dev, "bus error on %s: %d\n", state ? "set_cfgupdate" : "soft_reset", ret);
+     return ret;
+}
+
+static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
+                                       struct bq27xxx_dm_buf *buf)
+{
+     bool cfgup = di->chip == BQ27421; /* assume group supports cfgupdate */
+     int ret;
+
+     if (!buf->updt)
+             return 0;
+
+     if (cfgup) {
+             ret = bq27xxx_battery_set_cfgupdate(di, true);
+             if (ret < 0)
+                     return ret;
+     }
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CTRL], 0, true);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+     if (ret < 0)
+             goto out;
+
+     BQ27XXX_MSLEEP(1);
+
+     ret = di->bus.write_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CKSUM],
+                         bq27xxx_battery_checksum_dm_block(buf), true);
+     if (ret < 0)
+             goto out;
+
+     /* THE FOLLOWING SEQUENCE IS TOXIC. DO NOT USE!
+      * If the 'time' delay is insufficient, NVM corruption results on
+      * the '425 chip (and perhaps others), which could damage the chip.
+      * It was suggested in this TI tool:
+      *   http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
+      *
+      * 1. MSLEEP(time) after above write(BQ27XXX_DM_CKSUM, ...)
+      * 2. write(BQ27XXX_DM_BLOCK, buf->block)
+      * 3. sum = read(BQ27XXX_DM_CKSUM)
+      * 4. if (sum != bq27xxx_battery_checksum_dm_block(buf))
+      *      report error
+      */
+
+     if (cfgup) {
+             BQ27XXX_MSLEEP(1);
+             ret = bq27xxx_battery_set_cfgupdate(di, false);
+             if (ret < 0)
+                     return ret;
+     } else {
+             /* flash DM updates in <100ms, but reset time isn't documented */
+             BQ27XXX_MSLEEP(400);
+     }
+
+     buf->updt = false;
+     return 0;
+
+out:
+     if (cfgup)
+             bq27xxx_battery_set_cfgupdate(di, false);
+
+     dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
+     return ret;
+}
+
+static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di,
+                                    struct power_supply_battery_info *info)
+{
+     struct bq27xxx_dm_buf bd = BQ27XXX_DM_BUF(di, BQ27XXX_DM_DESIGN_CAPACITY);
+     struct bq27xxx_dm_buf bt = BQ27XXX_DM_BUF(di, BQ27XXX_DM_TERMINATE_VOLTAGE);
+
+     if (info->charge_full_design_uah != -EINVAL
+      && info->energy_full_design_uwh != -EINVAL) {
+             bq27xxx_battery_read_dm_block(di, &bd);
+             /* assume design energy & capacity are in same block */
+             bq27xxx_battery_update_dm_block(di, &bd,
+                                     BQ27XXX_DM_DESIGN_CAPACITY,
+                                     info->charge_full_design_uah / 1000);
+             bq27xxx_battery_update_dm_block(di, &bd,
+                                     BQ27XXX_DM_DESIGN_ENERGY,
+                                     info->energy_full_design_uwh / 1000);
+     }
+
+     if (info->voltage_min_design_uv != -EINVAL) {
+             bool same = bd.class == bt.class && bd.block == bt.block;
+             if (!same)
+                     bq27xxx_battery_read_dm_block(di, &bt);
+             bq27xxx_battery_update_dm_block(di, same ? &bd : &bt,
+                                     BQ27XXX_DM_TERMINATE_VOLTAGE,
+                                     info->voltage_min_design_uv / 1000);
+     }
+
+     bq27xxx_battery_write_dm_block(di, &bd);
+     bq27xxx_battery_write_dm_block(di, &bt);
+}
+
+void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
+{
+     struct power_supply_battery_info info = {};
+     unsigned int min, max;
+
+     /* functions don't exist for writing data so abort */
+     if (!di->bus.write || !di->bus.write_bulk)
+             return;
+
+     /* no settings to be set for this chipset so abort */
+     if (!di->dm_regs)
+             return;
+
+     if (bq27xxx_battery_set_seal_state(di, false) < 0)
+             return;
+
+     if (power_supply_get_battery_info(di->bat, &info) < 0)
+             goto out;
+
+     if (info.energy_full_design_uwh != info.charge_full_design_uah) {
+             if (info.energy_full_design_uwh == -EINVAL)
+                     dev_warn(di->dev,
+                             "missing battery:energy-full-design-microwatt-hours\n");
+             else if (info.charge_full_design_uah == -EINVAL)
+                     dev_warn(di->dev,
+                             "missing battery:charge-full-design-microamp-hours\n");
+     }
+
+     /* assume min == 0 */
+     max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max;
+     if (info.energy_full_design_uwh > max * 1000) {
+             dev_err(di->dev,
+                    "invalid battery:energy-full-design-microwatt-hours %d\n",
+                     info.energy_full_design_uwh);
+             info.energy_full_design_uwh = -EINVAL;
+     }
+
+     /* assume min == 0 */
+     max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max;
+     if (info.charge_full_design_uah > max * 1000) {
+             dev_err(di->dev,
+                    "invalid battery:charge-full-design-microamp-hours %d\n",
+                     info.charge_full_design_uah);
+             info.charge_full_design_uah = -EINVAL;
+     }
+
+     min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min;
+     max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max;
+     if ((info.voltage_min_design_uv < min * 1000
+       || info.voltage_min_design_uv > max * 1000)
+       && info.voltage_min_design_uv != -EINVAL) {
+             dev_err(di->dev,
+                    "invalid battery:voltage-min-design-microvolt %d\n",
+                     info.voltage_min_design_uv);
+             info.voltage_min_design_uv = -EINVAL;
+     }
+
+     if ((info.energy_full_design_uwh == -EINVAL
+       || info.charge_full_design_uah == -EINVAL)
+       && info.voltage_min_design_uv  == -EINVAL)
Quoted 8 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 914

Quoted 6 lines
drivers/power/supply/bq27xxx_battery.c +6 -0
+             goto out;
+
+     bq27xxx_battery_set_config(di, &info);
+
+out:
+     bq27xxx_battery_set_seal_state(di, true);

Don't use goto unless you have to, this is not such a case.

OK.

Quoted 89 lines
Quoted 89 lines
drivers/power/supply/bq27xxx_battery.c +29 -11
+}
+
 /*
  * Return the battery State-of-Charge
  * Or < 0 if something fails.
@@ -985,6 +1423,13 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
      case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
              ret = bq27xxx_simple_value(di->charge_design_full, val);
              break;
+     /*
+      * TODO: Implement these to make registers set from
+      * power_supply_battery_info visible in sysfs.
+      */
+     case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+     case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+             return -EINVAL;
      case POWER_SUPPLY_PROP_CYCLE_COUNT:
              ret = bq27xxx_simple_value(di->cache.cycle_count, val);
              break;
@@ -1015,28 +1460,36 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
      schedule_delayed_work(&di->work, 0);
 }
 
+#define BQ27XXX_INIT(c,d,k)   \
+     di->chip       = (c); \
+     di->dm_regs    = (d); \
+     di->unseal_key = (k)
+
 int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 {
      struct power_supply_desc *psy_desc;
-     struct power_supply_config psy_cfg = { .drv_data = di, };
+     struct power_supply_config psy_cfg = {
+             .of_node = di->dev->of_node,
+             .drv_data = di,
+     };
 
      switch(di->chip) {
      case BQ27000:
-     case BQ27010:
-     case BQ27500:
-     case BQ27510:
-     case BQ27530:
-     case BQ27541:
-     case BQ27545:
-     case BQ27421: break;
+     case BQ27010: break;
+     case BQ27500: BQ27XXX_INIT(BQ27500, bq27500_dm_regs, 0x04143672); break;
+     case BQ27510: break;
+     case BQ27530: break;
+     case BQ27541: break;
+     case BQ27545: BQ27XXX_INIT(BQ27545, bq27545_dm_regs, 0x04143672); break;
+     case BQ27421: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
      case BQ27520: di->chip = BQ27510; break;
      case BQ27531: di->chip = BQ27530; break;
      case BQ27542: di->chip = BQ27541; break;
      case BQ27546: di->chip = BQ27541; break;
      case BQ27742: di->chip = BQ27541; break;
-     case BQ27425: di->chip = BQ27421; break;
-     case BQ27441: di->chip = BQ27421; break;
-     case BQ27621: di->chip = BQ27421; break;
+     case BQ27425: BQ27XXX_INIT(BQ27421, bq27425_dm_regs, 0x04143672); break;
+     case BQ27441: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
+     case BQ27621: BQ27XXX_INIT(BQ27421, bq27621_dm_regs, 0x80008000); break;
      }
 
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
@@ -1062,6 +1515,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 
      dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 
+     bq27xxx_battery_settings(di);
      bq27xxx_battery_update(di);
 
      mutex_lock(&bq27xxx_list_lock);
include/linux/power/bq27xxx_battery.h +2 -0
index 90db1cf..dbf1ab9 100644
@@ -67,6 +67,8 @@ struct bq27xxx_device_info {
      int id;
      enum bq27xxx_chip chip;
      const char *name;
+     struct bq27xxx_dm_reg *dm_regs;
+     u32 unseal_key;
      struct bq27xxx_access_methods bus;
      struct bq27xxx_reg_cache cache;
      int charge_design_full;
#32 lore raw

Re: [PATCH v10 7/8] power: bq27xxx_battery: Add power_supply_battery_info support

Quoted 261 lines · Liam Breck
Quoted 246 lines · Andrew F. Davis
Quoted 245 lines · Liam Breck

From: Liam Breck <[email protected]>

Previously there was no way to configure chip registers in the event that the defaults didn't match the battery in question.

BQ27xxx driver now calls power_supply_get_battery_info, checks the inputs, and writes battery data to chip RAM or non-volatile memory.

Supports chips BQ27500, 545, 421, 425, 441, 621. Others may be added.

---
 drivers/power/supply/bq27xxx_battery.c | 478 ++++++++++++++++++++++++++++++++-
 include/linux/power/bq27xxx_battery.h  |   2 +
 2 files changed, 468 insertions(+), 12 deletions(-)
drivers/power/supply/bq27xxx_battery.c +128 -1
index d613d3d..fb062db 100644
@@ -51,7 +51,7 @@
 
 #include <linux/power/bq27xxx_battery.h>
 
-#define DRIVER_VERSION               "1.2.0"
+#define DRIVER_VERSION               "1.3.0"
 
 #define BQ27XXX_MANUFACTURER "Texas Instruments"
 
@@ -59,6 +59,7 @@
 #define BQ27XXX_FLAG_DSC     BIT(0)
 #define BQ27XXX_FLAG_SOCF    BIT(1) /* State-of-Charge threshold final */
 #define BQ27XXX_FLAG_SOC1    BIT(2) /* State-of-Charge threshold 1 */
+#define BQ27XXX_FLAG_CFGUP   BIT(4)
 #define BQ27XXX_FLAG_FC              BIT(9)
 #define BQ27XXX_FLAG_OTD     BIT(14)
 #define BQ27XXX_FLAG_OTC     BIT(15)
@@ -72,6 +73,11 @@
 #define BQ27000_FLAG_FC              BIT(5)
 #define BQ27000_FLAG_CHGS    BIT(7) /* Charge state flag */
 
+/* control register params */
+#define BQ27XXX_SEALED                       0x20
+#define BQ27XXX_SET_CFGUPDATE                0x13
+#define BQ27XXX_SOFT_RESET           0x42
+
 #define BQ27XXX_RS                   (20) /* Resistor sense mOhm */
 #define BQ27XXX_POWER_CONSTANT               (29200) /* 29.2 µV^2 * 1000 */
 #define BQ27XXX_CURRENT_CONSTANT     (3570) /* 3.57 µV * 1000 */
@@ -102,6 +108,11 @@ enum bq27xxx_reg_index {
      BQ27XXX_REG_SOC,        /* State-of-Charge */
      BQ27XXX_REG_DCAP,       /* Design Capacity */
      BQ27XXX_REG_AP,         /* Average Power */
+     BQ27XXX_DM_CTRL,        /* BlockDataControl() */
+     BQ27XXX_DM_CLASS,       /* DataClass() */
+     BQ27XXX_DM_BLOCK,       /* DataBlock() */
+     BQ27XXX_DM_DATA,        /* BlockData() */
+     BQ27XXX_DM_CKSUM,       /* BlockDataChecksum() */
      BQ27XXX_REG_MAX,        /* sentinel */
 };
 
@@ -125,6 +136,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x0b,
              [BQ27XXX_REG_DCAP] = 0x76,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
      },
      [BQ27010] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -144,6 +160,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x0b,
              [BQ27XXX_REG_DCAP] = 0x76,
              [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
      },
      [BQ27500] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -163,6 +184,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = 0x3c,
              [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27510] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -182,6 +208,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x20,
              [BQ27XXX_REG_DCAP] = 0x2e,
              [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27530] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -201,6 +232,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27541] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -220,6 +256,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = 0x3c,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27545] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -239,6 +280,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27421] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -258,6 +304,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x1c,
              [BQ27XXX_REG_DCAP] = 0x3c,
              [BQ27XXX_REG_AP] = 0x18,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
 };
 
@@ -432,6 +483,82 @@ static struct {
 static DEFINE_MUTEX(bq27xxx_list_lock);
 static LIST_HEAD(bq27xxx_battery_devices);
 
+#define BQ27XXX_DM_SZ        32
+
+#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
+
+struct bq27xxx_dm_reg {
+     u8 subclass_id;
+     u8 offset;
+     u8 bytes;
+     u16 min, max;
+};
+
+struct bq27xxx_dm_buf {
+     u8 class;
+     u8 block;
+     u8 a[BQ27XXX_DM_SZ];
+     bool full, updt;
+};
+
+#define BQ27XXX_DM_BUF(di, i) { \
+     .class = (di)->dm_regs[i].subclass_id, \
+     .block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \
+}
+
+static inline u16* bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf,
+                                   struct bq27xxx_dm_reg *reg)
+{
+     if (buf->class == reg->subclass_id
+     &&  buf->block == reg->offset / BQ27XXX_DM_SZ)
+             return (u16*) (buf->a + reg->offset % BQ27XXX_DM_SZ);
+
+     return NULL;
+}
+
+enum bq27xxx_dm_reg_id {
+     BQ27XXX_DM_DESIGN_CAPACITY = 0,
+     BQ27XXX_DM_DESIGN_ENERGY,
+     BQ27XXX_DM_TERMINATE_VOLTAGE,
+};
+
+static const char* bq27xxx_dm_reg_name[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
+     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
+};
+
+static struct bq27xxx_dm_reg bq27500_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 10, 2,    0, 65535 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { }, /* missing on chip */
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 },
+};
+
+static struct bq27xxx_dm_reg bq27545_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 23, 2,    0, 32767 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 48, 25, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27421_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 10, 2,    0,  8000 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 12, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27425_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 12, 2,    0, 32767 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 14, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27621_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 3, 2,    0,  8000 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 5, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500,  3700 },
+};
+
+
 static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
 {
      struct bq27xxx_device_info *di;
@@ -476,6 +603,317 @@ static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index,
      return di->bus.read(di, di->regs[reg_index], single);
 }
 
Quoted 13 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 612

Quoted 7 lines
drivers/power/supply/bq27xxx_battery.c +7 -0
+static int bq27xxx_battery_set_seal_state(struct bq27xxx_device_info *di,
+                                       bool state)
+{
+     int ret;
+
+     if (state) {
+             ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], BQ27XXX_SEALED, false);

Look at how reads are done, we have a function bq27xxx_read() that checks the register and handles the access methods. Do something like that for write, then replace all these with that, "bus" should only be accessed in that function.

Quoted 2 lines

OK. And for bus.{read,write}_bulk() too? They only occur once.

Sure, why not

Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
drivers/power/supply/bq27xxx_battery.c +11 -0
+             if (ret < 0)
+                     goto out;
+     } else {
+             ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)(di->unseal_key >> 16), false);
+             if (ret < 0)
+                     goto out;
+
+             ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)di->unseal_key, false);
+             if (ret < 0)
+                     goto out;
+     }
Quoted 4 lines
Quoted 4 lines

+space

Has this been run through checkpatch?

Well...

Quoted 58 lines
Quoted 49 lines
Quoted 49 lines
drivers/power/supply/bq27xxx_battery.c +49 -0
+     return 0;
+
+out:
+     dev_err(di->dev, "bus error on %s: %d\n", state ? "seal" : "unseal", ret);
+     return ret;
+}
+
+static u8 bq27xxx_battery_checksum_dm_block(struct bq27xxx_dm_buf *buf)
+{
+     u16 sum = 0;
+     int i;
+
+     for (i = 0; i < BQ27XXX_DM_SZ; i++)
+             sum += buf->a[i];
+     sum &= 0xff;
+
+     return 0xff - sum;
+}
+
+static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
+                                      struct bq27xxx_dm_buf *buf)
+{
+     int ret;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+     if (ret < 0)
+             goto out;
+
+     BQ27XXX_MSLEEP(1);
+
+     ret = di->bus.read_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.read(di, di->regs[BQ27XXX_DM_CKSUM], true);
+     if (ret < 0)
+             goto out;
+
+     if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {
+             ret = -EINVAL;
+             goto out;
+     }
+
+     buf->full = true;
+     buf->updt = false;
Quoted 8 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 676

Quoted 4 lines
drivers/power/supply/bq27xxx_battery.c +4 -0
+     return 0;
+
+out:
+     dev_err(di->dev, "bus error reading chip memory: %d\n", ret);

Instead of this catch-all, each spot should have an error message that explains what failed. If they all end up with this generic message we cannot possibly diagnose issues for people.

Quoted 1 line

Knowing which bus op failed doesn't help.

Sure it does, knowing which step it fails or locks the chip is useful.

Quoted 47 lines

Any error means either the
bus hw failed or chip died. If we're debugging a new chip, we'll need extra print statements anyway.

Quoted 34 lines
Quoted 34 lines
drivers/power/supply/bq27xxx_battery.c +34 -0
+     return ret;
+}
+
+static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di,
+                                         struct bq27xxx_dm_buf *buf,
+                                         enum bq27xxx_dm_reg_id reg_id,
+                                         unsigned int val)
+{
+     struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id];
+     const char* str = bq27xxx_dm_reg_name[reg_id];
+     u16 *prev = bq27xxx_dm_reg_ptr(buf, reg);
+
+     if (prev == NULL) {
+             dev_warn(di->dev, "buffer does not match %s dm spec\n", str);
+             return;
+     }
+
+     if (reg->bytes != 2) {
+             dev_warn(di->dev, "%s dm spec has unsupported byte size\n", str);
+             return;
+     }
+
+     if (!buf->full)
+             return;
+
+     if (be16_to_cpup(prev) == val) {
+             dev_info(di->dev, "%s has %u\n", str, val);
+             return;
+     }
+
+     dev_info(di->dev, "update %s to %u\n", str, val);
+
+     *prev = cpu_to_be16(val);
+     buf->updt = true;
Quoted 8 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 714

Quoted 4 lines
drivers/power/supply/bq27xxx_battery.c +4 -0
+}
+
+static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di,
+                                      bool state)

Why only two states? why bool? you should probably be passing in the value, if you really want to do this as a state, then the states should have an enum for each state.

Quoted 4 lines

You can enter or exit cfgupdate mode. We do the same for set_seal_state(). And bq27xxx_read() takes a bool arg to indicate one or two bytes.

bq27xxx_read() has the arg as a question, "Is this a two byte read? (true/false)", yours is "What state would you like to set? (true/false)", see how one doesn't work, fix that.

Quoted 23 lines
Quoted 14 lines
Quoted 14 lines
drivers/power/supply/bq27xxx_battery.c +14 -0
+{
+     int ret, try=100;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL],
+                         state ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET,
+                         false);
+     if (ret < 0)
+             goto out;
+
+     do {
+             BQ27XXX_MSLEEP(25);
+             ret = di->bus.read(di, di->regs[BQ27XXX_REG_FLAGS], false);
+             if (ret < 0)
+                     goto out;
Quoted 8 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 734

Quoted 6 lines
drivers/power/supply/bq27xxx_battery.c +6 -0
+     } while (!(ret & BQ27XXX_FLAG_CFGUP) == state && --try);
+
+     if (!try) {
+             dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", state);
+             return -EINVAL;
+     }

Put this check inside the loop.

Quoted 2 lines

We test try inside the loop. This test is only relevant after the loop.

It is not, try to think what I'm saying, if you move the test inside, then we don't have to test as part of the while, and we don't have to test after.

Quoted 9 lines
Quoted 6 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 736

Quoted 2 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+
+     if (100-try > 3)

Why 3? lets also count up to a set value, 100 is a magic number, if I change try to =200, I have to change it down here, that is going to be buggy.

OK. 3 because 75ms is a long time.

says who?

Quoted 272 lines
Quoted 172 lines
Quoted 172 lines
drivers/power/supply/bq27xxx_battery.c +172 -0
+             dev_warn(di->dev, "cfgupdate %d, retries %d\n", state, 100-try);
+
+     return 0;
+
+out:
+     dev_err(di->dev, "bus error on %s: %d\n", state ? "set_cfgupdate" : "soft_reset", ret);
+     return ret;
+}
+
+static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
+                                       struct bq27xxx_dm_buf *buf)
+{
+     bool cfgup = di->chip == BQ27421; /* assume group supports cfgupdate */
+     int ret;
+
+     if (!buf->updt)
+             return 0;
+
+     if (cfgup) {
+             ret = bq27xxx_battery_set_cfgupdate(di, true);
+             if (ret < 0)
+                     return ret;
+     }
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CTRL], 0, true);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+     if (ret < 0)
+             goto out;
+
+     BQ27XXX_MSLEEP(1);
+
+     ret = di->bus.write_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CKSUM],
+                         bq27xxx_battery_checksum_dm_block(buf), true);
+     if (ret < 0)
+             goto out;
+
+     /* THE FOLLOWING SEQUENCE IS TOXIC. DO NOT USE!
+      * If the 'time' delay is insufficient, NVM corruption results on
+      * the '425 chip (and perhaps others), which could damage the chip.
+      * It was suggested in this TI tool:
+      *   http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
+      *
+      * 1. MSLEEP(time) after above write(BQ27XXX_DM_CKSUM, ...)
+      * 2. write(BQ27XXX_DM_BLOCK, buf->block)
+      * 3. sum = read(BQ27XXX_DM_CKSUM)
+      * 4. if (sum != bq27xxx_battery_checksum_dm_block(buf))
+      *      report error
+      */
+
+     if (cfgup) {
+             BQ27XXX_MSLEEP(1);
+             ret = bq27xxx_battery_set_cfgupdate(di, false);
+             if (ret < 0)
+                     return ret;
+     } else {
+             /* flash DM updates in <100ms, but reset time isn't documented */
+             BQ27XXX_MSLEEP(400);
+     }
+
+     buf->updt = false;
+     return 0;
+
+out:
+     if (cfgup)
+             bq27xxx_battery_set_cfgupdate(di, false);
+
+     dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
+     return ret;
+}
+
+static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di,
+                                    struct power_supply_battery_info *info)
+{
+     struct bq27xxx_dm_buf bd = BQ27XXX_DM_BUF(di, BQ27XXX_DM_DESIGN_CAPACITY);
+     struct bq27xxx_dm_buf bt = BQ27XXX_DM_BUF(di, BQ27XXX_DM_TERMINATE_VOLTAGE);
+
+     if (info->charge_full_design_uah != -EINVAL
+      && info->energy_full_design_uwh != -EINVAL) {
+             bq27xxx_battery_read_dm_block(di, &bd);
+             /* assume design energy & capacity are in same block */
+             bq27xxx_battery_update_dm_block(di, &bd,
+                                     BQ27XXX_DM_DESIGN_CAPACITY,
+                                     info->charge_full_design_uah / 1000);
+             bq27xxx_battery_update_dm_block(di, &bd,
+                                     BQ27XXX_DM_DESIGN_ENERGY,
+                                     info->energy_full_design_uwh / 1000);
+     }
+
+     if (info->voltage_min_design_uv != -EINVAL) {
+             bool same = bd.class == bt.class && bd.block == bt.block;
+             if (!same)
+                     bq27xxx_battery_read_dm_block(di, &bt);
+             bq27xxx_battery_update_dm_block(di, same ? &bd : &bt,
+                                     BQ27XXX_DM_TERMINATE_VOLTAGE,
+                                     info->voltage_min_design_uv / 1000);
+     }
+
+     bq27xxx_battery_write_dm_block(di, &bd);
+     bq27xxx_battery_write_dm_block(di, &bt);
+}
+
+void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
+{
+     struct power_supply_battery_info info = {};
+     unsigned int min, max;
+
+     /* functions don't exist for writing data so abort */
+     if (!di->bus.write || !di->bus.write_bulk)
+             return;
+
+     /* no settings to be set for this chipset so abort */
+     if (!di->dm_regs)
+             return;
+
+     if (bq27xxx_battery_set_seal_state(di, false) < 0)
+             return;
+
+     if (power_supply_get_battery_info(di->bat, &info) < 0)
+             goto out;
+
+     if (info.energy_full_design_uwh != info.charge_full_design_uah) {
+             if (info.energy_full_design_uwh == -EINVAL)
+                     dev_warn(di->dev,
+                             "missing battery:energy-full-design-microwatt-hours\n");
+             else if (info.charge_full_design_uah == -EINVAL)
+                     dev_warn(di->dev,
+                             "missing battery:charge-full-design-microamp-hours\n");
+     }
+
+     /* assume min == 0 */
+     max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max;
+     if (info.energy_full_design_uwh > max * 1000) {
+             dev_err(di->dev,
+                    "invalid battery:energy-full-design-microwatt-hours %d\n",
+                     info.energy_full_design_uwh);
+             info.energy_full_design_uwh = -EINVAL;
+     }
+
+     /* assume min == 0 */
+     max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max;
+     if (info.charge_full_design_uah > max * 1000) {
+             dev_err(di->dev,
+                    "invalid battery:charge-full-design-microamp-hours %d\n",
+                     info.charge_full_design_uah);
+             info.charge_full_design_uah = -EINVAL;
+     }
+
+     min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min;
+     max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max;
+     if ((info.voltage_min_design_uv < min * 1000
+       || info.voltage_min_design_uv > max * 1000)
+       && info.voltage_min_design_uv != -EINVAL) {
+             dev_err(di->dev,
+                    "invalid battery:voltage-min-design-microvolt %d\n",
+                     info.voltage_min_design_uv);
+             info.voltage_min_design_uv = -EINVAL;
+     }
+
+     if ((info.energy_full_design_uwh == -EINVAL
+       || info.charge_full_design_uah == -EINVAL)
+       && info.voltage_min_design_uv  == -EINVAL)
Quoted 8 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 914

Quoted 6 lines
drivers/power/supply/bq27xxx_battery.c +6 -0
+             goto out;
+
+     bq27xxx_battery_set_config(di, &info);
+
+out:
+     bq27xxx_battery_set_seal_state(di, true);

Don't use goto unless you have to, this is not such a case.

OK.

Quoted 89 lines
Quoted 89 lines
drivers/power/supply/bq27xxx_battery.c +29 -11
+}
+
 /*
  * Return the battery State-of-Charge
  * Or < 0 if something fails.
@@ -985,6 +1423,13 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
      case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
              ret = bq27xxx_simple_value(di->charge_design_full, val);
              break;
+     /*
+      * TODO: Implement these to make registers set from
+      * power_supply_battery_info visible in sysfs.
+      */
+     case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+     case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+             return -EINVAL;
      case POWER_SUPPLY_PROP_CYCLE_COUNT:
              ret = bq27xxx_simple_value(di->cache.cycle_count, val);
              break;
@@ -1015,28 +1460,36 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
      schedule_delayed_work(&di->work, 0);
 }
 
+#define BQ27XXX_INIT(c,d,k)   \
+     di->chip       = (c); \
+     di->dm_regs    = (d); \
+     di->unseal_key = (k)
+
 int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 {
      struct power_supply_desc *psy_desc;
-     struct power_supply_config psy_cfg = { .drv_data = di, };
+     struct power_supply_config psy_cfg = {
+             .of_node = di->dev->of_node,
+             .drv_data = di,
+     };
 
      switch(di->chip) {
      case BQ27000:
-     case BQ27010:
-     case BQ27500:
-     case BQ27510:
-     case BQ27530:
-     case BQ27541:
-     case BQ27545:
-     case BQ27421: break;
+     case BQ27010: break;
+     case BQ27500: BQ27XXX_INIT(BQ27500, bq27500_dm_regs, 0x04143672); break;
+     case BQ27510: break;
+     case BQ27530: break;
+     case BQ27541: break;
+     case BQ27545: BQ27XXX_INIT(BQ27545, bq27545_dm_regs, 0x04143672); break;
+     case BQ27421: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
      case BQ27520: di->chip = BQ27510; break;
      case BQ27531: di->chip = BQ27530; break;
      case BQ27542: di->chip = BQ27541; break;
      case BQ27546: di->chip = BQ27541; break;
      case BQ27742: di->chip = BQ27541; break;
-     case BQ27425: di->chip = BQ27421; break;
-     case BQ27441: di->chip = BQ27421; break;
-     case BQ27621: di->chip = BQ27421; break;
+     case BQ27425: BQ27XXX_INIT(BQ27421, bq27425_dm_regs, 0x04143672); break;
+     case BQ27441: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
+     case BQ27621: BQ27XXX_INIT(BQ27421, bq27621_dm_regs, 0x80008000); break;
      }
 
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
@@ -1062,6 +1515,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 
      dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 
+     bq27xxx_battery_settings(di);
      bq27xxx_battery_update(di);
 
      mutex_lock(&bq27xxx_list_lock);
include/linux/power/bq27xxx_battery.h +2 -0
index 90db1cf..dbf1ab9 100644
@@ -67,6 +67,8 @@ struct bq27xxx_device_info {
      int id;
      enum bq27xxx_chip chip;
      const char *name;
+     struct bq27xxx_dm_reg *dm_regs;
+     u32 unseal_key;
      struct bq27xxx_access_methods bus;
      struct bq27xxx_reg_cache cache;
      int charge_design_full;
author
#33 lore raw

Re: [PATCH v10 7/8] power: bq27xxx_battery: Add power_supply_battery_info support

Quoted 262 lines · Andrew F. Davis
Quoted 261 lines · Liam Breck
Quoted 259 lines · Andrew F. Davis
Quoted 242 lines · Liam Breck

From: Liam Breck <[email protected]>

Previously there was no way to configure chip registers in the event that the defaults didn't match the battery in question.

BQ27xxx driver now calls power_supply_get_battery_info, checks the inputs, and writes battery data to chip RAM or non-volatile memory.

Supports chips BQ27500, 545, 421, 425, 441, 621. Others may be added.

---
 drivers/power/supply/bq27xxx_battery.c | 478 ++++++++++++++++++++++++++++++++-
 include/linux/power/bq27xxx_battery.h  |   2 +
 2 files changed, 468 insertions(+), 12 deletions(-)
drivers/power/supply/bq27xxx_battery.c +128 -1
index d613d3d..fb062db 100644
@@ -51,7 +51,7 @@
 
 #include <linux/power/bq27xxx_battery.h>
 
-#define DRIVER_VERSION               "1.2.0"
+#define DRIVER_VERSION               "1.3.0"
 
 #define BQ27XXX_MANUFACTURER "Texas Instruments"
 
@@ -59,6 +59,7 @@
 #define BQ27XXX_FLAG_DSC     BIT(0)
 #define BQ27XXX_FLAG_SOCF    BIT(1) /* State-of-Charge threshold final */
 #define BQ27XXX_FLAG_SOC1    BIT(2) /* State-of-Charge threshold 1 */
+#define BQ27XXX_FLAG_CFGUP   BIT(4)
 #define BQ27XXX_FLAG_FC              BIT(9)
 #define BQ27XXX_FLAG_OTD     BIT(14)
 #define BQ27XXX_FLAG_OTC     BIT(15)
@@ -72,6 +73,11 @@
 #define BQ27000_FLAG_FC              BIT(5)
 #define BQ27000_FLAG_CHGS    BIT(7) /* Charge state flag */
 
+/* control register params */
+#define BQ27XXX_SEALED                       0x20
+#define BQ27XXX_SET_CFGUPDATE                0x13
+#define BQ27XXX_SOFT_RESET           0x42
+
 #define BQ27XXX_RS                   (20) /* Resistor sense mOhm */
 #define BQ27XXX_POWER_CONSTANT               (29200) /* 29.2 µV^2 * 1000 */
 #define BQ27XXX_CURRENT_CONSTANT     (3570) /* 3.57 µV * 1000 */
@@ -102,6 +108,11 @@ enum bq27xxx_reg_index {
      BQ27XXX_REG_SOC,        /* State-of-Charge */
      BQ27XXX_REG_DCAP,       /* Design Capacity */
      BQ27XXX_REG_AP,         /* Average Power */
+     BQ27XXX_DM_CTRL,        /* BlockDataControl() */
+     BQ27XXX_DM_CLASS,       /* DataClass() */
+     BQ27XXX_DM_BLOCK,       /* DataBlock() */
+     BQ27XXX_DM_DATA,        /* BlockData() */
+     BQ27XXX_DM_CKSUM,       /* BlockDataChecksum() */
      BQ27XXX_REG_MAX,        /* sentinel */
 };
 
@@ -125,6 +136,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x0b,
              [BQ27XXX_REG_DCAP] = 0x76,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
      },
      [BQ27010] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -144,6 +160,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x0b,
              [BQ27XXX_REG_DCAP] = 0x76,
              [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
      },
      [BQ27500] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -163,6 +184,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = 0x3c,
              [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27510] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -182,6 +208,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x20,
              [BQ27XXX_REG_DCAP] = 0x2e,
              [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27530] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -201,6 +232,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27541] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -220,6 +256,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = 0x3c,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27545] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -239,6 +280,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x2c,
              [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
              [BQ27XXX_REG_AP] = 0x24,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
      [BQ27421] = {
              [BQ27XXX_REG_CTRL] = 0x00,
@@ -258,6 +304,11 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
              [BQ27XXX_REG_SOC] = 0x1c,
              [BQ27XXX_REG_DCAP] = 0x3c,
              [BQ27XXX_REG_AP] = 0x18,
+             [BQ27XXX_DM_CTRL] = 0x61,
+             [BQ27XXX_DM_CLASS] = 0x3e,
+             [BQ27XXX_DM_BLOCK] = 0x3f,
+             [BQ27XXX_DM_DATA] = 0x40,
+             [BQ27XXX_DM_CKSUM] = 0x60,
      },
 };
 
@@ -432,6 +483,82 @@ static struct {
 static DEFINE_MUTEX(bq27xxx_list_lock);
 static LIST_HEAD(bq27xxx_battery_devices);
 
+#define BQ27XXX_DM_SZ        32
+
+#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
+
+struct bq27xxx_dm_reg {
+     u8 subclass_id;
+     u8 offset;
+     u8 bytes;
+     u16 min, max;
+};
+
+struct bq27xxx_dm_buf {
+     u8 class;
+     u8 block;
+     u8 a[BQ27XXX_DM_SZ];
+     bool full, updt;
+};
+
+#define BQ27XXX_DM_BUF(di, i) { \
+     .class = (di)->dm_regs[i].subclass_id, \
+     .block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \
+}
+
+static inline u16* bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf,
+                                   struct bq27xxx_dm_reg *reg)
+{
+     if (buf->class == reg->subclass_id
+     &&  buf->block == reg->offset / BQ27XXX_DM_SZ)
+             return (u16*) (buf->a + reg->offset % BQ27XXX_DM_SZ);
+
+     return NULL;
+}
+
+enum bq27xxx_dm_reg_id {
+     BQ27XXX_DM_DESIGN_CAPACITY = 0,
+     BQ27XXX_DM_DESIGN_ENERGY,
+     BQ27XXX_DM_TERMINATE_VOLTAGE,
+};
+
+static const char* bq27xxx_dm_reg_name[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
+     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
+};
+
+static struct bq27xxx_dm_reg bq27500_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 10, 2,    0, 65535 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { }, /* missing on chip */
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 },
+};
+
+static struct bq27xxx_dm_reg bq27545_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 48, 23, 2,    0, 32767 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 48, 25, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27421_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 10, 2,    0,  8000 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 12, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27425_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 12, 2,    0, 32767 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 14, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800,  3700 },
+};
+
+static struct bq27xxx_dm_reg bq27621_dm_regs[] = {
+     [BQ27XXX_DM_DESIGN_CAPACITY]   = { 82, 3, 2,    0,  8000 },
+     [BQ27XXX_DM_DESIGN_ENERGY]     = { 82, 5, 2,    0, 32767 },
+     [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500,  3700 },
+};
+
+
 static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
 {
      struct bq27xxx_device_info *di;

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 612

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +7 -0
@@ -476,6 +603,317 @@ static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index,
      return di->bus.read(di, di->regs[reg_index], single);
 }
 
+static int bq27xxx_battery_set_seal_state(struct bq27xxx_device_info *di,
+                                       bool state)
+{
+     int ret;
+
+     if (state) {
+             ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], BQ27XXX_SEALED, false);

Look at how reads are done, we have a function bq27xxx_read() that checks the register and handles the access methods. Do something like that for write, then replace all these with that, "bus" should only be accessed in that function.

Quoted 4 lines
Quoted 2 lines

OK. And for bus.{read,write}_bulk() too? They only occur once.

Sure, why not

OK

Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
drivers/power/supply/bq27xxx_battery.c +11 -0
+             if (ret < 0)
+                     goto out;
+     } else {
+             ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)(di->unseal_key >> 16), false);
+             if (ret < 0)
+                     goto out;
+
+             ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL], (u16)di->unseal_key, false);
+             if (ret < 0)
+                     goto out;
+     }
Quoted 1 line
Quoted 1 line
Quoted 1 line

+space

Where?

Quoted 3 lines
Quoted 1 line
Quoted 1 line

Has this been run through checkpatch?

Well...

I defer newline formatting if things are in-flux.

Quoted 58 lines
Quoted 58 lines
Quoted 57 lines
Quoted 43 lines
drivers/power/supply/bq27xxx_battery.c +43 -0
+     return 0;
+
+out:
+     dev_err(di->dev, "bus error on %s: %d\n", state ? "seal" : "unseal", ret);
+     return ret;
+}
+
+static u8 bq27xxx_battery_checksum_dm_block(struct bq27xxx_dm_buf *buf)
+{
+     u16 sum = 0;
+     int i;
+
+     for (i = 0; i < BQ27XXX_DM_SZ; i++)
+             sum += buf->a[i];
+     sum &= 0xff;
+
+     return 0xff - sum;
+}
+
+static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
+                                      struct bq27xxx_dm_buf *buf)
+{
+     int ret;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+     if (ret < 0)
+             goto out;
+
+     BQ27XXX_MSLEEP(1);
+
+     ret = di->bus.read_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.read(di, di->regs[BQ27XXX_DM_CKSUM], true);
+     if (ret < 0)
+             goto out;
+
+     if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 676

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +10 -0
+             ret = -EINVAL;
+             goto out;
+     }
+
+     buf->full = true;
+     buf->updt = false;
+     return 0;
+
+out:
+     dev_err(di->dev, "bus error reading chip memory: %d\n", ret);

Instead of this catch-all, each spot should have an error message that explains what failed. If they all end up with this generic message we cannot possibly diagnose issues for people.

Quoted 3 lines
Quoted 1 line

Knowing which bus op failed doesn't help.

Sure it does, knowing which step it fails or locks the chip is useful.

The chips do not check/reject register inputs. If the bus hw or chip are flaky, any step may fail. Knowing which won't diagnose anything. If there's a bug in the bus driver, you need print stmts elsewhere.

Quoted 47 lines
Quoted 47 lines

Any error means either the
bus hw failed or chip died. If we're debugging a new chip, we'll need extra print statements anyway.

Quoted 42 lines
Quoted 28 lines
drivers/power/supply/bq27xxx_battery.c +28 -0
+     return ret;
+}
+
+static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di,
+                                         struct bq27xxx_dm_buf *buf,
+                                         enum bq27xxx_dm_reg_id reg_id,
+                                         unsigned int val)
+{
+     struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id];
+     const char* str = bq27xxx_dm_reg_name[reg_id];
+     u16 *prev = bq27xxx_dm_reg_ptr(buf, reg);
+
+     if (prev == NULL) {
+             dev_warn(di->dev, "buffer does not match %s dm spec\n", str);
+             return;
+     }
+
+     if (reg->bytes != 2) {
+             dev_warn(di->dev, "%s dm spec has unsupported byte size\n", str);
+             return;
+     }
+
+     if (!buf->full)
+             return;
+
+     if (be16_to_cpup(prev) == val) {
+             dev_info(di->dev, "%s has %u\n", str, val);
+             return;

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 714

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +10 -0
+     }
+
+     dev_info(di->dev, "update %s to %u\n", str, val);
+
+     *prev = cpu_to_be16(val);
+     buf->updt = true;
+}
+
+static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di,
+                                      bool state)

Why only two states? why bool? you should probably be passing in the value, if you really want to do this as a state, then the states should have an enum for each state.

Quoted 8 lines
Quoted 4 lines

You can enter or exit cfgupdate mode. We do the same for set_seal_state(). And bq27xxx_read() takes a bool arg to indicate one or two bytes.

bq27xxx_read() has the arg as a question, "Is this a two byte read? (true/false)", yours is "What state would you like to set? (true/false)", see how one doesn't work, fix that.

This? set_cfgupdate(struct bq27xxx_device_info *di, bool updt)

Quoted 23 lines
Quoted 23 lines
Quoted 22 lines
Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +10 -0
+{
+     int ret, try=100;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_REG_CTRL],
+                         state ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET,
+                         false);
+     if (ret < 0)
+             goto out;
+
+     do {

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 734

Quoted 10 lines
drivers/power/supply/bq27xxx_battery.c +10 -0
+             BQ27XXX_MSLEEP(25);
+             ret = di->bus.read(di, di->regs[BQ27XXX_REG_FLAGS], false);
+             if (ret < 0)
+                     goto out;
+     } while (!(ret & BQ27XXX_FLAG_CFGUP) == state && --try);
+
+     if (!try) {
+             dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", state);
+             return -EINVAL;
+     }

Put this check inside the loop.

Quoted 6 lines
Quoted 2 lines

We test try inside the loop. This test is only relevant after the loop.

It is not, try to think what I'm saying, if you move the test inside, then we don't have to test as part of the while, and we don't have to test after.

We have to test flag before try, so this would duplicate the flag test. Duplicating the try test is simpler.

Quoted 11 lines
Quoted 9 lines
Quoted 6 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 736

Quoted 2 lines
drivers/power/supply/bq27xxx_battery.c +2 -0
+
+     if (100-try > 3)

Why 3? lets also count up to a set value, 100 is a magic number, if I change try to =200, I have to change it down here, that is going to be buggy.

OK. 3 because 75ms is a long time.

says who?

I intend it to succeed after the first sleep. If it doesn't we should warn at some level. 2, 3, 4, 10, 42?

Quoted 272 lines
Quoted 272 lines
Quoted 172 lines
Quoted 172 lines
drivers/power/supply/bq27xxx_battery.c +172 -0
+             dev_warn(di->dev, "cfgupdate %d, retries %d\n", state, 100-try);
+
+     return 0;
+
+out:
+     dev_err(di->dev, "bus error on %s: %d\n", state ? "set_cfgupdate" : "soft_reset", ret);
+     return ret;
+}
+
+static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
+                                       struct bq27xxx_dm_buf *buf)
+{
+     bool cfgup = di->chip == BQ27421; /* assume group supports cfgupdate */
+     int ret;
+
+     if (!buf->updt)
+             return 0;
+
+     if (cfgup) {
+             ret = bq27xxx_battery_set_cfgupdate(di, true);
+             if (ret < 0)
+                     return ret;
+     }
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CTRL], 0, true);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CLASS], buf->class, true);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_BLOCK], buf->block, true);
+     if (ret < 0)
+             goto out;
+
+     BQ27XXX_MSLEEP(1);
+
+     ret = di->bus.write_bulk(di, di->regs[BQ27XXX_DM_DATA], buf->a, BQ27XXX_DM_SZ);
+     if (ret < 0)
+             goto out;
+
+     ret = di->bus.write(di, di->regs[BQ27XXX_DM_CKSUM],
+                         bq27xxx_battery_checksum_dm_block(buf), true);
+     if (ret < 0)
+             goto out;
+
+     /* THE FOLLOWING SEQUENCE IS TOXIC. DO NOT USE!
+      * If the 'time' delay is insufficient, NVM corruption results on
+      * the '425 chip (and perhaps others), which could damage the chip.
+      * It was suggested in this TI tool:
+      *   http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
+      *
+      * 1. MSLEEP(time) after above write(BQ27XXX_DM_CKSUM, ...)
+      * 2. write(BQ27XXX_DM_BLOCK, buf->block)
+      * 3. sum = read(BQ27XXX_DM_CKSUM)
+      * 4. if (sum != bq27xxx_battery_checksum_dm_block(buf))
+      *      report error
+      */
+
+     if (cfgup) {
+             BQ27XXX_MSLEEP(1);
+             ret = bq27xxx_battery_set_cfgupdate(di, false);
+             if (ret < 0)
+                     return ret;
+     } else {
+             /* flash DM updates in <100ms, but reset time isn't documented */
+             BQ27XXX_MSLEEP(400);
+     }
+
+     buf->updt = false;
+     return 0;
+
+out:
+     if (cfgup)
+             bq27xxx_battery_set_cfgupdate(di, false);
+
+     dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
+     return ret;
+}
+
+static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di,
+                                    struct power_supply_battery_info *info)
+{
+     struct bq27xxx_dm_buf bd = BQ27XXX_DM_BUF(di, BQ27XXX_DM_DESIGN_CAPACITY);
+     struct bq27xxx_dm_buf bt = BQ27XXX_DM_BUF(di, BQ27XXX_DM_TERMINATE_VOLTAGE);
+
+     if (info->charge_full_design_uah != -EINVAL
+      && info->energy_full_design_uwh != -EINVAL) {
+             bq27xxx_battery_read_dm_block(di, &bd);
+             /* assume design energy & capacity are in same block */
+             bq27xxx_battery_update_dm_block(di, &bd,
+                                     BQ27XXX_DM_DESIGN_CAPACITY,
+                                     info->charge_full_design_uah / 1000);
+             bq27xxx_battery_update_dm_block(di, &bd,
+                                     BQ27XXX_DM_DESIGN_ENERGY,
+                                     info->energy_full_design_uwh / 1000);
+     }
+
+     if (info->voltage_min_design_uv != -EINVAL) {
+             bool same = bd.class == bt.class && bd.block == bt.block;
+             if (!same)
+                     bq27xxx_battery_read_dm_block(di, &bt);
+             bq27xxx_battery_update_dm_block(di, same ? &bd : &bt,
+                                     BQ27XXX_DM_TERMINATE_VOLTAGE,
+                                     info->voltage_min_design_uv / 1000);
+     }
+
+     bq27xxx_battery_write_dm_block(di, &bd);
+     bq27xxx_battery_write_dm_block(di, &bt);
+}
+
+void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
+{
+     struct power_supply_battery_info info = {};
+     unsigned int min, max;
+
+     /* functions don't exist for writing data so abort */
+     if (!di->bus.write || !di->bus.write_bulk)
+             return;
+
+     /* no settings to be set for this chipset so abort */
+     if (!di->dm_regs)
+             return;
+
+     if (bq27xxx_battery_set_seal_state(di, false) < 0)
+             return;
+
+     if (power_supply_get_battery_info(di->bat, &info) < 0)
+             goto out;
+
+     if (info.energy_full_design_uwh != info.charge_full_design_uah) {
+             if (info.energy_full_design_uwh == -EINVAL)
+                     dev_warn(di->dev,
+                             "missing battery:energy-full-design-microwatt-hours\n");
+             else if (info.charge_full_design_uah == -EINVAL)
+                     dev_warn(di->dev,
+                             "missing battery:charge-full-design-microamp-hours\n");
+     }
+
+     /* assume min == 0 */
+     max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max;
+     if (info.energy_full_design_uwh > max * 1000) {
+             dev_err(di->dev,
+                    "invalid battery:energy-full-design-microwatt-hours %d\n",
+                     info.energy_full_design_uwh);
+             info.energy_full_design_uwh = -EINVAL;
+     }
+
+     /* assume min == 0 */
+     max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max;
+     if (info.charge_full_design_uah > max * 1000) {
+             dev_err(di->dev,
+                    "invalid battery:charge-full-design-microamp-hours %d\n",
+                     info.charge_full_design_uah);
+             info.charge_full_design_uah = -EINVAL;
+     }
+
+     min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min;
+     max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max;
+     if ((info.voltage_min_design_uv < min * 1000
+       || info.voltage_min_design_uv > max * 1000)
+       && info.voltage_min_design_uv != -EINVAL) {
+             dev_err(di->dev,
+                    "invalid battery:voltage-min-design-microvolt %d\n",
+                     info.voltage_min_design_uv);
+             info.voltage_min_design_uv = -EINVAL;
+     }
+
+     if ((info.energy_full_design_uwh == -EINVAL
+       || info.charge_full_design_uah == -EINVAL)
+       && info.voltage_min_design_uv  == -EINVAL)
Quoted 8 lines

drivers/power/supply/bq27xxx_battery.c static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, · line 914

Quoted 6 lines
drivers/power/supply/bq27xxx_battery.c +6 -0
+             goto out;
+
+     bq27xxx_battery_set_config(di, &info);
+
+out:
+     bq27xxx_battery_set_seal_state(di, true);

Don't use goto unless you have to, this is not such a case.

OK.

Quoted 89 lines
Quoted 89 lines
drivers/power/supply/bq27xxx_battery.c +29 -11
+}
+
 /*
  * Return the battery State-of-Charge
  * Or < 0 if something fails.
@@ -985,6 +1423,13 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
      case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
              ret = bq27xxx_simple_value(di->charge_design_full, val);
              break;
+     /*
+      * TODO: Implement these to make registers set from
+      * power_supply_battery_info visible in sysfs.
+      */
+     case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+     case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+             return -EINVAL;
      case POWER_SUPPLY_PROP_CYCLE_COUNT:
              ret = bq27xxx_simple_value(di->cache.cycle_count, val);
              break;
@@ -1015,28 +1460,36 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
      schedule_delayed_work(&di->work, 0);
 }
 
+#define BQ27XXX_INIT(c,d,k)   \
+     di->chip       = (c); \
+     di->dm_regs    = (d); \
+     di->unseal_key = (k)
+
 int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 {
      struct power_supply_desc *psy_desc;
-     struct power_supply_config psy_cfg = { .drv_data = di, };
+     struct power_supply_config psy_cfg = {
+             .of_node = di->dev->of_node,
+             .drv_data = di,
+     };
 
      switch(di->chip) {
      case BQ27000:
-     case BQ27010:
-     case BQ27500:
-     case BQ27510:
-     case BQ27530:
-     case BQ27541:
-     case BQ27545:
-     case BQ27421: break;
+     case BQ27010: break;
+     case BQ27500: BQ27XXX_INIT(BQ27500, bq27500_dm_regs, 0x04143672); break;
+     case BQ27510: break;
+     case BQ27530: break;
+     case BQ27541: break;
+     case BQ27545: BQ27XXX_INIT(BQ27545, bq27545_dm_regs, 0x04143672); break;
+     case BQ27421: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
      case BQ27520: di->chip = BQ27510; break;
      case BQ27531: di->chip = BQ27530; break;
      case BQ27542: di->chip = BQ27541; break;
      case BQ27546: di->chip = BQ27541; break;
      case BQ27742: di->chip = BQ27541; break;
-     case BQ27425: di->chip = BQ27421; break;
-     case BQ27441: di->chip = BQ27421; break;
-     case BQ27621: di->chip = BQ27421; break;
+     case BQ27425: BQ27XXX_INIT(BQ27421, bq27425_dm_regs, 0x04143672); break;
+     case BQ27441: BQ27XXX_INIT(BQ27421, bq27421_dm_regs, 0x80008000); break;
+     case BQ27621: BQ27XXX_INIT(BQ27421, bq27621_dm_regs, 0x80008000); break;
      }
 
      INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
@@ -1062,6 +1515,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 
      dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 
+     bq27xxx_battery_settings(di);
      bq27xxx_battery_update(di);
 
      mutex_lock(&bq27xxx_list_lock);
include/linux/power/bq27xxx_battery.h +2 -0
index 90db1cf..dbf1ab9 100644
@@ -67,6 +67,8 @@ struct bq27xxx_device_info {
      int id;
      enum bq27xxx_chip chip;
      const char *name;
+     struct bq27xxx_dm_reg *dm_regs;
+     u32 unseal_key;
      struct bq27xxx_access_methods bus;
      struct bq27xxx_reg_cache cache;
      int charge_design_full;
author
#34 lore raw

PATCH v10 8/8 power: bq27xxx_battery_i2c: Add I2C bulk read/write functions

In reply to Liam Breck

From: Matt Ranostay <[email protected]>

write(), read_bulk(), write_bulk() are required by bq27xxx_battery power_supply_battery_info code.

---
 drivers/power/supply/bq27xxx_battery_i2c.c | 82 +++++++++++++++++++++++++++++-
 1 file changed, 81 insertions(+), 1 deletion(-)
drivers/power/supply/bq27xxx_battery_i2c.c +81 -1
index 13def59..abdc266 100644
@@ -38,7 +38,7 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
 {
 	struct i2c_client *client = to_i2c_client(di->dev);
 	struct i2c_msg msg[2];
-	unsigned char data[2];
+	u8 data[2];
 	int ret;
 
 	if (!client->adapter)
@@ -68,6 +68,82 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
 	return ret;
 }
 
+static int bq27xxx_battery_i2c_write(struct bq27xxx_device_info *di, u8 reg,
+				     int value, bool single)
+{
+	struct i2c_client *client = to_i2c_client(di->dev);
+	struct i2c_msg msg;
+	u8 data[4];
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	data[0] = reg;
+	if (single) {
+		data[1] = (u8) value;
+		msg.len = 2;
+	} else {
+		put_unaligned_le16(value, &data[1]);
+		msg.len = 3;
+	}
+
+	msg.buf = data;
+	msg.addr = client->addr;
+	msg.flags = 0;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EINVAL;
+	return 0;
+}
+
+static int bq27xxx_battery_i2c_bulk_read(struct bq27xxx_device_info *di, u8 reg,
+					 u8 *data, int len)
+{
+	struct i2c_client *client = to_i2c_client(di->dev);
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	ret = i2c_smbus_read_i2c_block_data(client, reg, len, data);
+	if (ret < 0)
+		return ret;
+	if (ret != len)
+		return -EINVAL;
+	return 0;
+}
+
+static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di,
+					  u8 reg, u8 *data, int len)
+{
+	struct i2c_client *client = to_i2c_client(di->dev);
+	struct i2c_msg msg;
+	u8 buf[33];
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	buf[0] = reg;
+	memcpy(&buf[1], data, len);
+
+	msg.buf = buf;
+	msg.addr = client->addr;
+	msg.flags = 0;
+	msg.len = len + 1;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EINVAL;
+	return 0;
+}
+
 static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
 				     const struct i2c_device_id *id)
 {
@@ -95,7 +171,11 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
 	di->dev = &client->dev;
 	di->chip = id->driver_data;
 	di->name = name;
+
 	di->bus.read = bq27xxx_battery_i2c_read;
+	di->bus.write = bq27xxx_battery_i2c_write;
+	di->bus.read_bulk = bq27xxx_battery_i2c_bulk_read;
+	di->bus.write_bulk = bq27xxx_battery_i2c_bulk_write;
 
 	ret = bq27xxx_battery_setup(di);
 	if (ret)
Signature · 1 line
2.9.3
#35 lore raw

Re: [PATCH v10 8/8] power: bq27xxx_battery_i2c: Add I2C bulk read/write functions

Hi,

Quoted 7 lines · Liam Breck

From: Matt Ranostay <[email protected]>

write(), read_bulk(), write_bulk() are required by bq27xxx_battery power_supply_battery_info code.

This is required by the previous patch, so your order is not bisect safe. Please just merge it with Patch 5.

-- Sebastian

Quoted 114 lines
 drivers/power/supply/bq27xxx_battery_i2c.c | 82 +++++++++++++++++++++++++++++-
 1 file changed, 81 insertions(+), 1 deletion(-)
drivers/power/supply/bq27xxx_battery_i2c.c +81 -1
index 13def59..abdc266 100644
@@ -38,7 +38,7 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
 {
 	struct i2c_client *client = to_i2c_client(di->dev);
 	struct i2c_msg msg[2];
-	unsigned char data[2];
+	u8 data[2];
 	int ret;
 
 	if (!client->adapter)
@@ -68,6 +68,82 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
 	return ret;
 }
 
+static int bq27xxx_battery_i2c_write(struct bq27xxx_device_info *di, u8 reg,
+				     int value, bool single)
+{
+	struct i2c_client *client = to_i2c_client(di->dev);
+	struct i2c_msg msg;
+	u8 data[4];
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	data[0] = reg;
+	if (single) {
+		data[1] = (u8) value;
+		msg.len = 2;
+	} else {
+		put_unaligned_le16(value, &data[1]);
+		msg.len = 3;
+	}
+
+	msg.buf = data;
+	msg.addr = client->addr;
+	msg.flags = 0;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EINVAL;
+	return 0;
+}
+
+static int bq27xxx_battery_i2c_bulk_read(struct bq27xxx_device_info *di, u8 reg,
+					 u8 *data, int len)
+{
+	struct i2c_client *client = to_i2c_client(di->dev);
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	ret = i2c_smbus_read_i2c_block_data(client, reg, len, data);
+	if (ret < 0)
+		return ret;
+	if (ret != len)
+		return -EINVAL;
+	return 0;
+}
+
+static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di,
+					  u8 reg, u8 *data, int len)
+{
+	struct i2c_client *client = to_i2c_client(di->dev);
+	struct i2c_msg msg;
+	u8 buf[33];
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	buf[0] = reg;
+	memcpy(&buf[1], data, len);
+
+	msg.buf = buf;
+	msg.addr = client->addr;
+	msg.flags = 0;
+	msg.len = len + 1;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret < 0)
+		return ret;
+	if (ret != 1)
+		return -EINVAL;
+	return 0;
+}
+
 static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
 				     const struct i2c_device_id *id)
 {
@@ -95,7 +171,11 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
 	di->dev = &client->dev;
 	di->chip = id->driver_data;
 	di->name = name;
+
 	di->bus.read = bq27xxx_battery_i2c_read;
+	di->bus.write = bq27xxx_battery_i2c_write;
+	di->bus.read_bulk = bq27xxx_battery_i2c_bulk_read;
+	di->bus.write_bulk = bq27xxx_battery_i2c_bulk_write;
 
 	ret = bq27xxx_battery_setup(di);
 	if (ret)
Signature · 1 line
2.9.3
author
#36 lore raw

Re: [PATCH v10 8/8] power: bq27xxx_battery_i2c: Add I2C bulk read/write functions

Quoted 5 lines · Sebastian Reichel

Hi,

Quoted 2 lines · Liam Breck

From: Matt Ranostay <[email protected]>

Quoted 8 lines
Quoted 5 lines

write(), read_bulk(), write_bulk() are required by bq27xxx_battery power_supply_battery_info code.

This is required by the previous patch, so your order is not bisect safe. Please just merge it with Patch 5.

It is bisect-safe; bq27xxx_battery only uses the functions if available.

Patch 5 could be merged with 7. But the I2C implementation should be separate from the header.

Quoted 114 lines
Quoted 114 lines
 drivers/power/supply/bq27xxx_battery_i2c.c | 82 +++++++++++++++++++++++++++++-
 1 file changed, 81 insertions(+), 1 deletion(-)
drivers/power/supply/bq27xxx_battery_i2c.c +81 -2
index 13def59..abdc266 100644
@@ -38,7 +38,7 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
 {
      struct i2c_client *client = to_i2c_client(di->dev);
      struct i2c_msg msg[2];
-     unsigned char data[2];
+     u8 data[2];
      int ret;
 
      if (!client->adapter)
@@ -68,6 +68,82 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
      return ret;
 }
 
+static int bq27xxx_battery_i2c_write(struct bq27xxx_device_info *di, u8 reg,
+                                  int value, bool single)
+{
+     struct i2c_client *client = to_i2c_client(di->dev);
+     struct i2c_msg msg;
+     u8 data[4];
+     int ret;
+
+     if (!client->adapter)
+             return -ENODEV;
+
+     data[0] = reg;
+     if (single) {
+             data[1] = (u8) value;
+             msg.len = 2;
+     } else {
+             put_unaligned_le16(value, &data[1]);
+             msg.len = 3;
+     }
+
+     msg.buf = data;
+     msg.addr = client->addr;
+     msg.flags = 0;
+
+     ret = i2c_transfer(client->adapter, &msg, 1);
+     if (ret < 0)
+             return ret;
+     if (ret != 1)
+             return -EINVAL;
+     return 0;
+}
+
+static int bq27xxx_battery_i2c_bulk_read(struct bq27xxx_device_info *di, u8 reg,
+                                      u8 *data, int len)
+{
+     struct i2c_client *client = to_i2c_client(di->dev);
+     int ret;
+
+     if (!client->adapter)
+             return -ENODEV;
+
+     ret = i2c_smbus_read_i2c_block_data(client, reg, len, data);
+     if (ret < 0)
+             return ret;
+     if (ret != len)
+             return -EINVAL;
+     return 0;
+}
+
+static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di,
+                                       u8 reg, u8 *data, int len)
+{
+     struct i2c_client *client = to_i2c_client(di->dev);
+     struct i2c_msg msg;
+     u8 buf[33];
+     int ret;
+
+     if (!client->adapter)
+             return -ENODEV;
+
+     buf[0] = reg;
+     memcpy(&buf[1], data, len);
+
+     msg.buf = buf;
+     msg.addr = client->addr;
+     msg.flags = 0;
+     msg.len = len + 1;
+
+     ret = i2c_transfer(client->adapter, &msg, 1);
+     if (ret < 0)
+             return ret;
+     if (ret != 1)
+             return -EINVAL;
+     return 0;
+}
+
 static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
                                   const struct i2c_device_id *id)
 {
@@ -95,7 +171,11 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
      di->dev = &client->dev;
      di->chip = id->driver_data;
      di->name = name;
+
      di->bus.read = bq27xxx_battery_i2c_read;
+     di->bus.write = bq27xxx_battery_i2c_write;
+     di->bus.read_bulk = bq27xxx_battery_i2c_bulk_read;
+     di->bus.write_bulk = bq27xxx_battery_i2c_bulk_write;
 
      ret = bq27xxx_battery_setup(di);
      if (ret)
--

2.9.3

#37 lore raw

Re: [PATCH v10 8/8] power: bq27xxx_battery_i2c: Add I2C bulk read/write functions

Hi,

Quoted 9 lines · Liam Breck
Quoted 8 lines · Sebastian Reichel

Hi,

Quoted 5 lines · Liam Breck

From: Matt Ranostay <[email protected]>

write(), read_bulk(), write_bulk() are required by bq27xxx_battery power_supply_battery_info code.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

This is required by the previous patch, so your order is not bisect safe. Please just merge it with Patch 5.

It is bisect-safe; bq27xxx_battery only uses the functions if available.

ok.

Quoted 2 lines

Patch 5 could be merged with 7. But the I2C implementation should be separate from the header.

Please at least move the patches together.

-- Sebastian