All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery
@ 2017-05-04  6:18 Liam Breck
  2017-05-04  6:18   ` Liam Breck
                   ` (10 more replies)
  0 siblings, 11 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm

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 v13:
  Doc...bindings/power/supply/*
*   add fields in battery.txt, see below
*   caution about changing battery type in battery.txt
*   note: Rob acked v11 battery.txt containing URL to Linux header
*   more detail in bq27xxx.txt
  power_supply_core:
*   add battery_info fields precharge-current-microamp & charge-term-current-microamp
*   new patch for power_supply_prop_precharge_current
  bq27xxx_battery:
*   add copyright notice
*   for flash/NVM chips, emit warning instead of doing update
*   config_battery_bq27xxx_dt_updates_nvm enables update of flash/NVM
*   module param dt_monitored_battery_updates_nvm lets user disallow update
*   new patch to flag dupes in bq27xxx_regs[]
*   drop patch to clean up error reporting
*   polishing from Andrew's feedback
*   resolve checkpatch errors
*   refactor patchset
*   fix missing static keyword flagged by Colin

Changes in v12: (several partial series posts; see above)

Changes in v11:
  power_supply_core:
*   switch to compatible = "simple-battery"
*   add docs to power_supply_class.txt
  Documentation/devicetree/.../battery.txt:
*   add description, drop refs to Linux, "simple-battery"
  bq27xxx_battery:
*   reset flash chips after DM update
*   add bq27xxx_write/xfer()
*   polishing from Andrew's feedback
*   new patch to clean up error reporting
*   new patch to consolidate duplicate register/property arrays

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 Breck (9):
  dt-bindings: power: supply: Add battery.txt with simple-battery binding
  power: supply: core: Add power_supply_battery_info and API
  power: supply: core: Add power_supply_prop_precharge
  dt-bindings: power: supply: bq27xxx: Add monitored-battery documentation
  power: supply: bq27xxx_battery: Add chip data memory read/write support
  power: supply: bq27xxx_battery: Add power_supply_battery_info support
  power: supply: bq27xxx_battery: Enable data memory update for certain chips
  power: supply: bq27xxx_battery: Flag identical register maps when in debug mode
  power: supply: bq27xxx_battery: Remove duplicate register arrays

Matt Ranostay (2):
  devicetree: property-units: Add uWh and uAh units
  power: supply: bq27xxx_battery: Add bulk transfer bus methods

 .../devicetree/bindings/power/supply/battery.txt   |  53 ++
 .../devicetree/bindings/power/supply/bq27xxx.txt   |  31 +-
 .../devicetree/bindings/property-units.txt         |   2 +
 Documentation/power/power_supply_class.txt         |  31 +-
 drivers/power/supply/Kconfig                       |   9 +
 drivers/power/supply/bq27xxx_battery.c             | 750 +++++++++++++++++----
 drivers/power/supply/bq27xxx_battery_i2c.c         |  98 ++-
 drivers/power/supply/power_supply_core.c           |  51 ++
 drivers/power/supply/power_supply_sysfs.c          |   1 +
 include/linux/power/bq27xxx_battery.h              |  29 +-
 include/linux/power_supply.h                       |  23 +
 11 files changed, 920 insertions(+), 158 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt

-- 
2.9.3

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH v13 01/11] devicetree: property-units: Add uWh and uAh units
       [not found] ` <20170504061811.18107-1-liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
@ 2017-05-04  6:18   ` Liam Breck
  0 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm
  Cc: Rob Herring, Mark Rutland, devicetree, linux-kernel,
	Matt Ranostay, Liam Breck

From: Matt Ranostay <matt@ranostay.consulting>

Add entries for microwatt-hours and microamp-hours.

Cc: Rob Herring <robh@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
Signed-off-by: Liam Breck <kernel@networkimprov.net>
Acked-by: Sebastian Reichel <sre@kernel.org>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/property-units.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/property-units.txt b/Documentation/devicetree/bindings/property-units.txt
index 12278d7..0849618 100644
--- a/Documentation/devicetree/bindings/property-units.txt
+++ b/Documentation/devicetree/bindings/property-units.txt
@@ -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
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 01/11] devicetree: property-units: Add uWh and uAh units
@ 2017-05-04  6:18   ` Liam Breck
  0 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Matt Ranostay, Liam Breck

From: Matt Ranostay <matt-sk+viVC6FLCDq+mSdOJa79kegs52MxvZ@public.gmane.org>

Add entries for microwatt-hours and microamp-hours.

Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Matt Ranostay <matt-sk+viVC6FLCDq+mSdOJa79kegs52MxvZ@public.gmane.org>
Signed-off-by: Liam Breck <kernel-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
Acked-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 Documentation/devicetree/bindings/property-units.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/property-units.txt b/Documentation/devicetree/bindings/property-units.txt
index 12278d7..0849618 100644
--- a/Documentation/devicetree/bindings/property-units.txt
+++ b/Documentation/devicetree/bindings/property-units.txt
@@ -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
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 02/11] dt-bindings: power: supply: Add battery.txt with simple-battery binding
  2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
  2017-05-04  6:18   ` Liam Breck
@ 2017-05-04  6:18 ` Liam Breck
  2017-05-04  6:18 ` [PATCH v13 03/11] power: supply: core: Add power_supply_battery_info and API Liam Breck
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm
  Cc: Rob Herring, devicetree, Matt Ranostay, Liam Breck

From: Liam Breck <kernel@networkimprov.net>

Documentation of static battery characteristics that can be defined
for batteries that do not embed this data, which are required by
fuel-gauge and charger chips for proper handling of the battery.

The following properties are defined:
  voltage-min-design-microvolt
  charge-full-design-microamp-hours
  energy-full-design-microwatt-hours
  precharge-current-microamp
  charge-term-current-microamp

Property names are derived from corresponding elements in
enum power_supply_property from include/linux/power_supply.h
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/power_supply.h

Cc: Rob Herring <robh@kernel.org>
Cc: devicetree@vger.kernel.org
Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
Signed-off-by: Liam Breck <kernel@networkimprov.net>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../devicetree/bindings/power/supply/battery.txt   | 53 ++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/battery.txt

diff --git a/Documentation/devicetree/bindings/power/supply/battery.txt b/Documentation/devicetree/bindings/power/supply/battery.txt
new file mode 100644
index 0000000..61d9153
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/battery.txt
@@ -0,0 +1,53 @@
+Battery Characteristics
+
+The devicetree battery node provides static battery characteristics.
+In smart batteries, these are typically stored in non-volatile memory
+on a fuel gauge chip. The battery node should be used where there is
+no appropriate non-volatile memory, or it is unprogrammed/incorrect.
+
+Upstream dts files should not include battery nodes, unless the battery
+represented cannot easily be replaced in the system by one of a
+different type. This prevents unpredictable, potentially harmful,
+behavior should a replacement that changes the battery type occur
+without a corresponding update to the dtb.
+
+Required Properties:
+ - compatible: Must be "simple-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
+ - precharge-current-microamp: current for pre-charge phase
+ - charge-term-current-microamp: current for charge termination phase
+
+Battery properties are named, where possible, for the corresponding
+elements in enum power_supply_property, defined in
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/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".
+
+Example:
+
+	bat: battery {
+		compatible = "simple-battery";
+		voltage-min-design-microvolt = <3200000>;
+		energy-full-design-microwatt-hours = <5290000>;
+		charge-full-design-microamp-hours = <1430000>;
+		precharge-current-microamp = <256000>;
+		charge-term-current-microamp = <128000>;
+	};
+
+	charger: charger@11 {
+		....
+		monitored-battery = <&bat>;
+		...
+	};
+
+	fuel_gauge: fuel-gauge@22 {
+		....
+		monitored-battery = <&bat>;
+		...
+	};
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 03/11] power: supply: core: Add power_supply_battery_info and API
  2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
  2017-05-04  6:18   ` Liam Breck
  2017-05-04  6:18 ` [PATCH v13 02/11] dt-bindings: power: supply: Add battery.txt with simple-battery binding Liam Breck
@ 2017-05-04  6:18 ` Liam Breck
  2017-05-04  6:18 ` [PATCH v13 04/11] power: supply: core: Add power_supply_prop_precharge Liam Breck
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm; +Cc: Matt Ranostay, Liam Breck

From: Liam Breck <kernel@networkimprov.net>

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

Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
Signed-off-by: Liam Breck <kernel@networkimprov.net>
---
 Documentation/power/power_supply_class.txt | 12 +++++++
 drivers/power/supply/power_supply_core.c   | 51 ++++++++++++++++++++++++++++++
 include/linux/power_supply.h               | 20 ++++++++++++
 3 files changed, 83 insertions(+)

diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
index 0c72588..01f0075 100644
--- a/Documentation/power/power_supply_class.txt
+++ b/Documentation/power/power_supply_class.txt
@@ -174,6 +174,18 @@ issued by external power supply will notify supplicants via
 external_power_changed callback.
 
 
+Devicetree battery characteristics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Drivers should call power_supply_get_battery_info() to obtain battery
+characteristics from a devicetree battery node, defined in
+Documentation/devicetree/bindings/power/supply/battery.txt. This is
+implemented in drivers/power/supply/bq27xxx_battery.c.
+
+Properties in struct power_supply_battery_info and their counterparts in the
+battery node have names corresponding to elements in enum power_supply_property,
+for naming consistency between sysfs attributes and battery node properties.
+
+
 QA
 ~~
 Q: Where is POWER_SUPPLY_PROP_XYZ attribute?
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index a74d8ca..8376a76 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -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,56 @@ 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;
+	info->precharge_current_ua   = -EINVAL;
+	info->charge_term_current_ua = -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("simple-battery", value))
+		return -ENODEV;
+
+	/* The property and field names below must correspond to elements
+	 * in enum power_supply_property. For reasoning, see
+	 * Documentation/power/power_supply_class.txt.
+	 */
+
+	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);
+	of_property_read_u32(battery_np, "precharge-current-microamp",
+			     &info->precharge_current_ua);
+	of_property_read_u32(battery_np, "charge-term-current-microamp",
+			     &info->charge_term_current_ua);
+
+	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)
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 3965503..67f363b 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -288,6 +288,23 @@ 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 */
+	int precharge_current_ua;	/* microAmps */
+	int charge_term_current_ua;     /* microAmps */
+};
+
 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 +323,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);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 04/11] power: supply: core: Add power_supply_prop_precharge
  2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
                   ` (2 preceding siblings ...)
  2017-05-04  6:18 ` [PATCH v13 03/11] power: supply: core: Add power_supply_battery_info and API Liam Breck
@ 2017-05-04  6:18 ` Liam Breck
       [not found] ` <20170504061811.18107-1-liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm; +Cc: Liam Breck

From: Liam Breck <kernel@networkimprov.net>

Battery chargers use POWER_SUPPLY_PROP_PRECHARGE_CURRENT
Clarify related item POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT

Signed-off-by: Liam Breck <kernel@networkimprov.net>
---
 Documentation/power/power_supply_class.txt | 19 ++++++++++++-------
 drivers/power/supply/power_supply_sysfs.c  |  1 +
 include/linux/power_supply.h               |  3 +++
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
index 01f0075..300d378 100644
--- a/Documentation/power/power_supply_class.txt
+++ b/Documentation/power/power_supply_class.txt
@@ -115,28 +115,33 @@ of charge when battery became full/empty". It also could mean "value of
 charge when battery considered full/empty at given conditions (temperature,
 age)". I.e. these attributes represents real thresholds, not design values.
 
+ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
+
 CHARGE_COUNTER - the current charge counter (in µAh).  This could easily
 be negative; there is no empty or full value.  It is only useful for
 relative, time-based measurements.
 
+PRECHARGE_CURRENT - the maximum charge current during precharge phase
+of charge cycle (typically 20% of battery capacity).
+CHARGE_TERM_CURRENT - Charge termination current. The charge cycle
+terminates when battery voltage is above recharge threshold, and charge
+current is below this setting (typically 10% of battery capacity).
+
 CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger.
 CONSTANT_CHARGE_CURRENT_MAX - maximum charge current supported by the
 power supply object.
-INPUT_CURRENT_LIMIT - input current limit programmed by charger. Indicates
-the current drawn from a charging source.
-CHARGE_TERM_CURRENT - Charge termination current used to detect the end of charge
-condition.
-
-CALIBRATE - battery or coulomb counter calibration status
 
 CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger.
 CONSTANT_CHARGE_VOLTAGE_MAX - maximum charge voltage supported by the
 power supply object.
 
+INPUT_CURRENT_LIMIT - input current limit programmed by charger. Indicates
+the current drawn from a charging source.
+
 CHARGE_CONTROL_LIMIT - current charge control limit setting
 CHARGE_CONTROL_LIMIT_MAX - maximum charge control limit setting
 
-ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
+CALIBRATE - battery or coulomb counter calibration status
 
 CAPACITY - capacity in percents.
 CAPACITY_ALERT_MIN - minimum capacity alert value in percents.
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index bcde8d1..937b03c 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -196,6 +196,7 @@ static struct device_attribute power_supply_attrs[] = {
 	POWER_SUPPLY_ATTR(time_to_full_avg),
 	POWER_SUPPLY_ATTR(type),
 	POWER_SUPPLY_ATTR(scope),
+	POWER_SUPPLY_ATTR(precharge_current),
 	POWER_SUPPLY_ATTR(charge_term_current),
 	POWER_SUPPLY_ATTR(calibrate),
 	/* Properties of type `const char *' */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 67f363b..1a83f47 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -146,6 +146,7 @@ enum power_supply_property {
 	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
 	POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
 	POWER_SUPPLY_PROP_SCOPE,
+	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
 	POWER_SUPPLY_PROP_CALIBRATE,
 	/* Properties of type `const char *' */
@@ -379,6 +380,8 @@ static inline bool power_supply_is_amp_property(enum power_supply_property psp)
 	case POWER_SUPPLY_PROP_CHARGE_NOW:
 	case POWER_SUPPLY_PROP_CHARGE_AVG:
 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
 	case POWER_SUPPLY_PROP_CURRENT_MAX:
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 05/11] dt-bindings: power: supply: bq27xxx: Add monitored-battery documentation
       [not found] ` <20170504061811.18107-1-liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
@ 2017-05-04  6:18   ` Liam Breck
  0 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, devicetree-u79uwXL29TY76Z2rM5mHXA, Matt Ranostay,
	Liam Breck

From: Liam Breck <kernel-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>

Document monitored-battery = <&battery_node>

Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Matt Ranostay <matt-sk+viVC6FLCDq+mSdOJa79kegs52MxvZ@public.gmane.org>
Signed-off-by: Liam Breck <kernel-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 .../devicetree/bindings/power/supply/bq27xxx.txt   | 31 +++++++++++++++++-----
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt
index b0c95ef..6858e1a 100644
--- a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt
+++ b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt
@@ -1,7 +1,7 @@
-Binding for TI BQ27XXX fuel gauge family
+TI BQ27XXX fuel gauge family
 
 Required properties:
-- compatible: Should contain one of the following:
+- compatible: contains one of the following:
  * "ti,bq27200" - BQ27200
  * "ti,bq27210" - BQ27210
  * "ti,bq27500" - deprecated, use revision specific property below
@@ -26,11 +26,28 @@ Required properties:
  * "ti,bq27425" - BQ27425
  * "ti,bq27441" - BQ27441
  * "ti,bq27621" - BQ27621
-- reg: integer, i2c address of the device.
+- reg: integer, I2C address of the fuel gauge.
+
+Optional properties:
+- monitored-battery: phandle of battery characteristics node
+    The fuel gauge uses the following battery properties:
+    + energy-full-design-microwatt-hours
+    + charge-full-design-microamp-hours
+    + voltage-min-design-microvolt
+  Both or neither of the *-full-design-*-hours properties must be set.
+  See Documentation/devicetree/bindings/power/supply/battery.txt
 
 Example:
 
-bq27510g3 {
-    compatible = "ti,bq27510g3";
-    reg = <0x55>;
-};
+	bat: battery {
+		compatible = "simple-battery";
+		voltage-min-design-microvolt = <3200000>;
+		energy-full-design-microwatt-hours = <5290000>;
+		charge-full-design-microamp-hours = <1430000>;
+	};
+
+	bq27510g3: fuel-gauge@55 {
+		compatible = "ti,bq27510g3";
+		reg = <0x55>;
+		monitored-battery = <&bat>;
+	};
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 06/11] power: supply: bq27xxx_battery: Add bulk transfer bus methods
  2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
                   ` (4 preceding siblings ...)
       [not found] ` <20170504061811.18107-1-liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
@ 2017-05-04  6:18 ` Liam Breck
  2017-05-04  6:18 ` [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support Liam Breck
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm; +Cc: Matt Ranostay, Liam Breck

From: Matt Ranostay <matt@ranostay.consulting>

Declare bus.write/read_bulk/write_bulk().
Add I2C write/read_bulk/write_bulk() to implement the above.
Add bq27xxx_write/read_block/write_block() helpers to call the above.

Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
Signed-off-by: Liam Breck <kernel@networkimprov.net>
Acked-by: "Andrew F. Davis" <afd@ti.com>
---
 drivers/power/supply/bq27xxx_battery.c     | 67 +++++++++++++++++++++++-
 drivers/power/supply/bq27xxx_battery_i2c.c | 82 +++++++++++++++++++++++++++++-
 include/linux/power/bq27xxx_battery.h      |  3 ++
 3 files changed, 149 insertions(+), 3 deletions(-)

diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index 398801a..a11dfad 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -794,11 +794,74 @@ MODULE_PARM_DESC(poll_interval,
 static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index,
 			       bool single)
 {
-	/* Reports EINVAL for invalid/missing registers */
+	int ret;
+
 	if (!di || di->regs[reg_index] == INVALID_REG_ADDR)
 		return -EINVAL;
 
-	return di->bus.read(di, di->regs[reg_index], single);
+	ret = di->bus.read(di, di->regs[reg_index], single);
+	if (ret < 0)
+		dev_dbg(di->dev, "failed to read register 0x%02x (index %d)\n",
+			di->regs[reg_index], reg_index);
+
+	return ret;
+}
+
+static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index,
+				u16 value, bool single)
+{
+	int ret;
+
+	if (!di || di->regs[reg_index] == INVALID_REG_ADDR)
+		return -EINVAL;
+
+	if (!di->bus.write)
+		return -EPERM;
+
+	ret = di->bus.write(di, di->regs[reg_index], value, single);
+	if (ret < 0)
+		dev_dbg(di->dev, "failed to write register 0x%02x (index %d)\n",
+			di->regs[reg_index], reg_index);
+
+	return ret;
+}
+
+static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_index,
+				     u8 *data, int len)
+{
+	int ret;
+
+	if (!di || di->regs[reg_index] == INVALID_REG_ADDR)
+		return -EINVAL;
+
+	if (!di->bus.read_bulk)
+		return -EPERM;
+
+	ret = di->bus.read_bulk(di, di->regs[reg_index], data, len);
+	if (ret < 0)
+		dev_dbg(di->dev, "failed to read_bulk register 0x%02x (index %d)\n",
+			di->regs[reg_index], reg_index);
+
+	return ret;
+}
+
+static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_index,
+				      u8 *data, int len)
+{
+	int ret;
+
+	if (!di || di->regs[reg_index] == INVALID_REG_ADDR)
+		return -EINVAL;
+
+	if (!di->bus.write_bulk)
+		return -EPERM;
+
+	ret = di->bus.write_bulk(di, di->regs[reg_index], data, len);
+	if (ret < 0)
+		dev_dbg(di->dev, "failed to write_bulk register 0x%02x (index %d)\n",
+			di->regs[reg_index], reg_index);
+
+	return ret;
 }
 
 /*
diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
index c68fbc3..a597221 100644
--- a/drivers/power/supply/bq27xxx_battery_i2c.c
+++ b/drivers/power/supply/bq27xxx_battery_i2c.c
@@ -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)
diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
index b312bce..c3369fa 100644
--- a/include/linux/power/bq27xxx_battery.h
+++ b/include/linux/power/bq27xxx_battery.h
@@ -40,6 +40,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 {
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support
  2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
                   ` (5 preceding siblings ...)
  2017-05-04  6:18 ` [PATCH v13 06/11] power: supply: bq27xxx_battery: Add bulk transfer bus methods Liam Breck
@ 2017-05-04  6:18 ` Liam Breck
  2017-05-04 16:44   ` Andrew F. Davis
  2017-05-04  6:18 ` [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support Liam Breck
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm; +Cc: Matt Ranostay, Liam Breck

From: Liam Breck <kernel@networkimprov.net>

Add these to enable read/write of chip data memory RAM/NVM/flash:
  bq27xxx_battery_seal()
  bq27xxx_battery_unseal()
  bq27xxx_battery_set_cfgupdate()
  bq27xxx_battery_read_dm_block()
  bq27xxx_battery_write_dm_block()
  bq27xxx_battery_checksum_dm_block()

Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
Signed-off-by: Liam Breck <kernel@networkimprov.net>
---
 drivers/power/supply/bq27xxx_battery.c | 253 +++++++++++++++++++++++++++++++++
 include/linux/power/bq27xxx_battery.h  |   1 +
 2 files changed, 254 insertions(+)

diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index a11dfad..8ab184c 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
  * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
  * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2017 Liam Breck <kernel@networkimprov.net>
  *
  * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
  *
@@ -65,6 +66,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)
@@ -78,6 +80,12 @@
 #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_RESET			0x41
+
 #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 */
@@ -108,9 +116,21 @@ enum bq27xxx_reg_index {
 	BQ27XXX_REG_SOC,	/* State-of-Charge */
 	BQ27XXX_REG_DCAP,	/* Design Capacity */
 	BQ27XXX_REG_AP,		/* Average Power */
+	BQ27XXX_DM_CTRL,	/* Block Data Control */
+	BQ27XXX_DM_CLASS,	/* Data Class */
+	BQ27XXX_DM_BLOCK,	/* Data Block */
+	BQ27XXX_DM_DATA,	/* Block Data */
+	BQ27XXX_DM_CKSUM,	/* Block Data Checksum */
 	BQ27XXX_REG_MAX,	/* sentinel */
 };
 
+#define BQ27XXX_DM_REG_ROWS \
+	[BQ27XXX_DM_CTRL] = 0x61,  \
+	[BQ27XXX_DM_CLASS] = 0x3e, \
+	[BQ27XXX_DM_BLOCK] = 0x3f, \
+	[BQ27XXX_DM_DATA] = 0x40,  \
+	[BQ27XXX_DM_CKSUM] = 0x60
+
 /* Register mappings */
 static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 	[BQ27000] = {
@@ -131,6 +151,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,
@@ -150,6 +175,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,
 	},
 	[BQ2750X] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -169,6 +199,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ2751X] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -188,6 +219,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x20,
 		[BQ27XXX_REG_DCAP] = 0x2e,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27500] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -207,6 +239,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x24,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27510G1] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -226,6 +259,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x24,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27510G2] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -245,6 +279,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x24,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27510G3] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -264,6 +299,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x20,
 		[BQ27XXX_REG_DCAP] = 0x2e,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27520G1] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -283,6 +319,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x24,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27520G2] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -302,6 +339,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x24,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27520G3] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -321,6 +359,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x24,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27520G4] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -340,6 +379,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x20,
 		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27530] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -359,6 +399,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
 		[BQ27XXX_REG_AP] = 0x24,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27541] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -378,6 +419,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x24,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27545] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -397,6 +439,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x2c,
 		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
 		[BQ27XXX_REG_AP] = 0x24,
+		BQ27XXX_DM_REG_ROWS,
 	},
 	[BQ27421] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
@@ -416,6 +459,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_SOC] = 0x1c,
 		[BQ27XXX_REG_DCAP] = 0x3c,
 		[BQ27XXX_REG_AP] = 0x18,
+		BQ27XXX_DM_REG_ROWS,
 	},
 };
 
@@ -757,6 +801,28 @@ static struct {
 static DEFINE_MUTEX(bq27xxx_list_lock);
 static LIST_HEAD(bq27xxx_battery_devices);
 
+#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
+
+#define BQ27XXX_DM_SZ	32
+
+/**
+ * struct bq27xxx_dm_buf - chip data memory buffer
+ * @class: data memory subclass_id
+ * @block: data memory block number
+ * @data: data from/for the block
+ * @has_data: true if data has been filled by read
+ * @dirty: true if data has changed since last read/write
+ *
+ * Encapsulates info required to manage chip data memory blocks.
+ */
+struct bq27xxx_dm_buf {
+	u8 class;
+	u8 block;
+	u8 data[BQ27XXX_DM_SZ];
+	bool has_data, dirty;
+};
+
+
 static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
 {
 	struct bq27xxx_device_info *di;
@@ -864,6 +930,193 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in
 	return ret;
 }
 
+static int bq27xxx_battery_seal(struct bq27xxx_device_info *di)
+{
+	int ret;
+
+	ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_SEALED, false);
+	if (ret < 0) {
+		dev_err(di->dev, "bus error on seal: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int bq27xxx_battery_unseal(struct bq27xxx_device_info *di)
+{
+	int ret;
+
+	if (di->unseal_key == 0) {
+		dev_err(di->dev, "unseal failed due to missing key\n");
+		return -EINVAL;
+	}
+
+	ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)(di->unseal_key >> 16), false);
+	if (ret < 0)
+		goto out;
+
+	ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)di->unseal_key, false);
+	if (ret < 0)
+		goto out;
+
+	return 0;
+
+out:
+	dev_err(di->dev, "bus error on unseal: %d\n", 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->data[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;
+
+	buf->has_data = false;
+
+	ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
+	if (ret < 0)
+		goto out;
+
+	ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
+	if (ret < 0)
+		goto out;
+
+	BQ27XXX_MSLEEP(1);
+
+	ret = bq27xxx_read_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
+	if (ret < 0)
+		goto out;
+
+	ret = bq27xxx_read(di, BQ27XXX_DM_CKSUM, true);
+	if (ret < 0)
+		goto out;
+
+	if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	buf->has_data = true;
+	buf->dirty = false;
+
+	return 0;
+
+out:
+	dev_err(di->dev, "bus error reading chip memory: %d\n", ret);
+	return ret;
+}
+
+static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
+{
+	const int limit = 100;
+	int ret, try = limit;
+
+	ret = bq27xxx_write(di, 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 (limit-try > 3)
+		dev_warn(di->dev, "cfgupdate %d, retries %d\n", !!state, limit-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->dirty)
+		return 0;
+
+	if (cfgup) {
+		ret = bq27xxx_battery_set_cfgupdate(di, BQ27XXX_FLAG_CFGUP);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = bq27xxx_write(di, BQ27XXX_DM_CTRL, 0, true);
+	if (ret < 0)
+		goto out;
+
+	ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
+	if (ret < 0)
+		goto out;
+
+	ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
+	if (ret < 0)
+		goto out;
+
+	BQ27XXX_MSLEEP(1);
+
+	ret = bq27xxx_write_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
+	if (ret < 0)
+		goto out;
+
+	ret = bq27xxx_write(di, BQ27XXX_DM_CKSUM,
+			    bq27xxx_battery_checksum_dm_block(buf), true);
+	if (ret < 0)
+		goto out;
+
+	/* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM
+	 * corruption on the '425 chip (and perhaps others), which can damage
+	 * the chip. See TI bqtool for what not to do:
+	 * http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
+	 */
+
+	if (cfgup) {
+		BQ27XXX_MSLEEP(1);
+		ret = bq27xxx_battery_set_cfgupdate(di, 0);
+		if (ret < 0)
+			return ret;
+	} else {
+		BQ27XXX_MSLEEP(100); /* flash DM updates in <100ms */
+	}
+
+	buf->dirty = false;
+
+	return 0;
+
+out:
+	if (cfgup)
+		bq27xxx_battery_set_cfgupdate(di, 0);
+
+	dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
+	return ret;
+}
+
 /*
  * Return the battery State-of-Charge
  * Or < 0 if something fails.
diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
index c3369fa..b1defb8 100644
--- a/include/linux/power/bq27xxx_battery.h
+++ b/include/linux/power/bq27xxx_battery.h
@@ -64,6 +64,7 @@ struct bq27xxx_device_info {
 	int id;
 	enum bq27xxx_chip chip;
 	const char *name;
+	u32 unseal_key;
 	struct bq27xxx_access_methods bus;
 	struct bq27xxx_reg_cache cache;
 	int charge_design_full;
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
                   ` (6 preceding siblings ...)
  2017-05-04  6:18 ` [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support Liam Breck
@ 2017-05-04  6:18 ` Liam Breck
  2017-05-04 16:52   ` Andrew F. Davis
  2017-05-04  6:18 ` [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips Liam Breck
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm; +Cc: Matt Ranostay, Liam Breck

From: Liam Breck <kernel@networkimprov.net>

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

For chips with RAM data memory (and also those with flash/NVM data memory
if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
set module param dt_monitored_battery_updates_nvm=0) we now call
power_supply_get_battery_info(), check its values, and write battery
properties to chip data memory if there is a dm_regs table for the chip.

Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
Signed-off-by: Liam Breck <kernel@networkimprov.net>
---
 drivers/power/supply/Kconfig           |   9 ++
 drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
 include/linux/power/bq27xxx_battery.h  |   2 +
 3 files changed, 209 insertions(+), 1 deletion(-)

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 76806a0..85e2fb2 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
 	  Say Y here to enable support for batteries with BQ27xxx chips
 	  connected over an I2C bus.
 
+config BATTERY_BQ27XXX_DT_UPDATES_NVM
+	bool "BQ27xxx support for update of NVM/flash data memory"
+	depends on BATTERY_BQ27XXX_I2C
+	help
+	  Say Y here to enable devicetree monitored-battery config to update
+	  NVM/flash data memory. Only enable this option for devices with a
+	  fuel gauge mounted on the circuit board, and a battery that cannot
+	  be replaced with one of a different type.
+
 config BATTERY_DA9030
 	tristate "DA9030 battery driver"
 	depends on PMIC_DA903X
diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index 8ab184c..06f15da 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
 
 #define BQ27XXX_DM_SZ	32
 
+struct bq27xxx_dm_reg {
+	u8 subclass_id;
+	u8 offset;
+	u8 bytes;
+	u16 min, max;
+};
+
 /**
  * struct bq27xxx_dm_buf - chip data memory buffer
  * @class: data memory subclass_id
@@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
 	bool has_data, dirty;
 };
 
+#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->data + 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 * const bq27xxx_dm_reg_name[] = {
+	[BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
+	[BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
+	[BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
+};
+
+
+#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
+static bool bq27xxx_dt_to_nvm = true;
+
+module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
+MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
+	"Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
+#else
+static bool bq27xxx_dt_to_nvm = false;
+#endif
 
 static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
 {
@@ -1019,6 +1063,51 @@ static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
 	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->has_data)
+		return;
+
+	if (be16_to_cpup(prev) == val) {
+		dev_info(di->dev, "%s has %u\n", str, val);
+		return;
+	}
+
+	if (!di->ram_chip && !bq27xxx_dt_to_nvm) {
+		/* devicetree and NVM differ; defer to NVM */
+		dev_warn(di->dev, "%s has %u; update to %u disallowed "
+#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
+			 "by dt_monitored_battery_updates_nvm=0"
+#else
+			 "for flash/NVM data memory"
+#endif
+			 "\n", str, be16_to_cpup(prev), val);
+		return;
+	}
+
+	dev_info(di->dev, "update %s to %u\n", str, val);
+
+	*prev = cpu_to_be16(val);
+	buf->dirty = true;
+}
+
 static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
 {
 	const int limit = 100;
@@ -1117,6 +1206,103 @@ static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
 	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);
+	bool updated;
+
+	if (bq27xxx_battery_unseal(di) < 0)
+		return;
+
+	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);
+	}
+
+	updated = bd.dirty || bt.dirty;
+
+	bq27xxx_battery_write_dm_block(di, &bd);
+	bq27xxx_battery_write_dm_block(di, &bt);
+
+	bq27xxx_battery_seal(di);
+
+	if (updated && di->chip != BQ27421) { /* not a cfgupdate chip, so reset */
+		bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false);
+		BQ27XXX_MSLEEP(300); /* reset time is not documented */
+	}
+	/* assume bq27xxx_battery_update() is called hereafter */
+}
+
+static void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
+{
+	struct power_supply_battery_info info = {};
+	unsigned int min, max;
+
+	if (power_supply_get_battery_info(di->bat, &info) < 0)
+		return;
+
+	if (!di->dm_regs) {
+		dev_warn(di->dev, "data memory update not supported for chip\n");
+		return;
+	}
+
+	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)
+		bq27xxx_battery_set_config(di, &info);
+}
+
 /*
  * Return the battery State-of-Charge
  * Or < 0 if something fails.
@@ -1634,6 +1820,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;
@@ -1667,7 +1860,10 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
 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,
+	};
 
 	INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
 	mutex_init(&di->lock);
@@ -1692,6 +1888,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);
diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
index b1defb8..11e1168 100644
--- a/include/linux/power/bq27xxx_battery.h
+++ b/include/linux/power/bq27xxx_battery.h
@@ -63,7 +63,9 @@ struct bq27xxx_device_info {
 	struct device *dev;
 	int id;
 	enum bq27xxx_chip chip;
+	bool ram_chip;
 	const char *name;
+	struct bq27xxx_dm_reg *dm_regs;
 	u32 unseal_key;
 	struct bq27xxx_access_methods bus;
 	struct bq27xxx_reg_cache cache;
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
                   ` (7 preceding siblings ...)
  2017-05-04  6:18 ` [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support Liam Breck
@ 2017-05-04  6:18 ` Liam Breck
  2017-05-04 17:00   ` Andrew F. Davis
  2017-05-10  9:16   ` Liam Breck
  2017-05-04  6:18 ` [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode Liam Breck
  2017-05-04  6:18 ` [PATCH v13 11/11] power: supply: bq27xxx_battery: Remove duplicate register arrays Liam Breck
  10 siblings, 2 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm; +Cc: Liam Breck

From: Liam Breck <kernel@networkimprov.net>

Support data memory update on BQ27500, 545, 425, 421, 441, 621.

Create IDs for for previously unID'd chips, to index arrays for unseal keys
and data memory register tables.

Signed-off-by: Liam Breck <kernel@networkimprov.net>
---
 drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
 drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
 include/linux/power/bq27xxx_battery.h      | 13 +++++
 3 files changed, 107 insertions(+), 12 deletions(-)

diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index 06f15da..0aecd41 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -58,7 +58,7 @@
 
 #include <linux/power/bq27xxx_battery.h>
 
-#define DRIVER_VERSION		"1.2.0"
+#define DRIVER_VERSION		"1.3.0"
 
 #define BQ27XXX_MANUFACTURER	"Texas Instruments"
 
@@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
 	[BQ27XXX_DM_CKSUM] = 0x60
 
 /* Register mappings */
-static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
+static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
 	[BQ27000] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
 		[BQ27XXX_REG_TEMP] = 0x06,
@@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
 static struct {
 	enum power_supply_property *props;
 	size_t size;
-} bq27xxx_battery_props[] = {
+} bq27xxx_battery_props[BQ27MAX] = {
 	BQ27XXX_PROP(BQ27000, bq27000_battery_props),
 	BQ27XXX_PROP(BQ27010, bq27010_battery_props),
 	BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
@@ -798,6 +798,33 @@ static struct {
 	BQ27XXX_PROP(BQ27421, bq27421_battery_props),
 };
 
+static enum bq27xxx_chip bq27xxx_chips[] = {
+	[BQ27000]   = BQ27000,
+	[BQ27010]   = BQ27010,
+	[BQ2750X]   = BQ2750X,
+	[BQ2751X]   = BQ2751X,
+	[BQ2752X]   = BQ2751X,
+	[BQ27500]   = BQ27500,
+	[BQ27510G1] = BQ27510G1,
+	[BQ27510G2] = BQ27510G2,
+	[BQ27510G3] = BQ27510G3,
+	[BQ27520G1] = BQ27520G1,
+	[BQ27520G2] = BQ27520G2,
+	[BQ27520G3] = BQ27520G3,
+	[BQ27520G4] = BQ27520G4,
+	[BQ27530]   = BQ27530,
+	[BQ27531]   = BQ27530,
+	[BQ27541]   = BQ27541,
+	[BQ27542]   = BQ27541,
+	[BQ27546]   = BQ27541,
+	[BQ27742]   = BQ27541,
+	[BQ27545]   = BQ27545,
+	[BQ27421]   = BQ27421,
+	[BQ27425]   = BQ27421,
+	[BQ27441]   = BQ27421,
+	[BQ27621]   = BQ27421,
+};
+
 static DEFINE_MUTEX(bq27xxx_list_lock);
 static LIST_HEAD(bq27xxx_battery_devices);
 
@@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
 	[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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
+	[BQ27500] = bq27500_dm_regs,
+	[BQ27545] = bq27545_dm_regs,
+	[BQ27421] = bq27421_dm_regs,
+	[BQ27425] = bq27425_dm_regs,
+	[BQ27441] = bq27421_dm_regs,
+	[BQ27621] = bq27621_dm_regs,
+};
+
+static u32 bq27xxx_unseal_keys[] = {
+	[BQ27500] = 0x04143672,
+	[BQ27545] = 0x04143672,
+	[BQ27421] = 0x80008000,
+	[BQ27425] = 0x04143672,
+	[BQ27441] = 0x80008000,
+	[BQ27621] = 0x80008000,
+};
+
 
 #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
 static bool bq27xxx_dt_to_nvm = true;
@@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 		.drv_data = di,
 	};
 
+	di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
+
+	di->unseal_key = bq27xxx_unseal_keys[di->chip];
+	di->dm_regs = bq27xxx_dm_regs[di->chip];
+	di->chip = bq27xxx_chips[di->chip];
+
+	di->regs = bq27xxx_regs[di->chip];
+
 	INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
 	mutex_init(&di->lock);
-	di->regs = bq27xxx_regs[di->chip];
 
 	psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
 	if (!psy_desc)
diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
index a597221..0b11ed4 100644
--- a/drivers/power/supply/bq27xxx_battery_i2c.c
+++ b/drivers/power/supply/bq27xxx_battery_i2c.c
@@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
 	{ "bq27210", BQ27010 },
 	{ "bq27500", BQ2750X },
 	{ "bq27510", BQ2751X },
-	{ "bq27520", BQ2751X },
+	{ "bq27520", BQ2752X },
 	{ "bq27500-1", BQ27500 },
 	{ "bq27510g1", BQ27510G1 },
 	{ "bq27510g2", BQ27510G2 },
@@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
 	{ "bq27520g3", BQ27520G3 },
 	{ "bq27520g4", BQ27520G4 },
 	{ "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);
diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
index 11e1168..543c10e 100644
--- a/include/linux/power/bq27xxx_battery.h
+++ b/include/linux/power/bq27xxx_battery.h
@@ -2,6 +2,8 @@
 #define __LINUX_BQ27X00_BATTERY_H__
 
 enum bq27xxx_chip {
+	/* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
+	/* and map to themselves in bq27xxx_chips[]             */
 	BQ27000 = 1, /* bq27000, bq27200 */
 	BQ27010, /* bq27010, bq27210 */
 	BQ2750X, /* bq27500 deprecated alias */
@@ -18,6 +20,17 @@ enum bq27xxx_chip {
 	BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
 	BQ27545, /* bq27545 */
 	BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
+	BQ27MAX,
+
+	/* these map to above in bq27xxx_chips[] */
+	BQ2752X, /* deprecated alias */
+	BQ27531,
+	BQ27542,
+	BQ27546,
+	BQ27742,
+	BQ27425,
+	BQ27441,
+	BQ27621,
 };
 
 /**
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode
  2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
                   ` (8 preceding siblings ...)
  2017-05-04  6:18 ` [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips Liam Breck
@ 2017-05-04  6:18 ` Liam Breck
  2017-05-04 16:38   ` Andrew F. Davis
  2017-05-04  6:18 ` [PATCH v13 11/11] power: supply: bq27xxx_battery: Remove duplicate register arrays Liam Breck
  10 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm; +Cc: Liam Breck

From: Liam Breck <kernel@networkimprov.net>

We tie multiple chips to unique register maps. When supporting a new chip,
it's easy to add a duplicate map by mistake.

In debug mode we now scan the register maps for duplicates.

Signed-off-by: Liam Breck <kernel@networkimprov.net>
---
 drivers/power/supply/bq27xxx_battery.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index 0aecd41..97c646c 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -1932,6 +1932,25 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
 	schedule_delayed_work(&di->work, 0);
 }
 
+#ifdef DEBUG
+static void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di)
+{
+	const size_t max = ARRAY_SIZE(bq27xxx_regs);
+	int a, b;
+
+	for (a = 1; a < max-1; a++) {
+		for (b = a+1; b < max; b++) {
+			if (!memcmp(bq27xxx_regs[a], bq27xxx_regs[b],
+				    sizeof(bq27xxx_regs[0])))
+				dev_warn(di->dev,
+					"bq27xxx_regs[%d] & [%d] are identical\n", a, b);
+		}
+	}
+}
+#else
+static inline void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di) {}
+#endif
+
 int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 {
 	struct power_supply_desc *psy_desc;
@@ -1940,6 +1959,8 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
 		.drv_data = di,
 	};
 
+	bq27xxx_battery_dbg_regs_dupes(di);
+
 	di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
 
 	di->unseal_key = bq27xxx_unseal_keys[di->chip];
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v13 11/11] power: supply: bq27xxx_battery: Remove duplicate register arrays
  2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
                   ` (9 preceding siblings ...)
  2017-05-04  6:18 ` [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode Liam Breck
@ 2017-05-04  6:18 ` Liam Breck
  10 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04  6:18 UTC (permalink / raw)
  To: Sebastian Reichel, Andrew F. Davis, linux-pm; +Cc: Liam Breck

From: Liam Breck <kernel@networkimprov.net>

BQ2751X & BQ27510G3 are identical.
BQ27500 & BQ27510G1 & BQ27510G2 are identical.
Make BQ2751X & BQ27510G1/2 aliases.
Remove the duplicate arrays, etc.

Signed-off-by: Liam Breck <kernel@networkimprov.net>
---
 drivers/power/supply/bq27xxx_battery.c | 134 +--------------------------------
 include/linux/power/bq27xxx_battery.h  |  12 +--
 2 files changed, 10 insertions(+), 136 deletions(-)

diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index 97c646c..1293248 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -201,26 +201,6 @@ static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
 		BQ27XXX_DM_REG_ROWS,
 	},
-	[BQ2751X] = {
-		[BQ27XXX_REG_CTRL] = 0x00,
-		[BQ27XXX_REG_TEMP] = 0x06,
-		[BQ27XXX_REG_INT_TEMP] = 0x28,
-		[BQ27XXX_REG_VOLT] = 0x08,
-		[BQ27XXX_REG_AI] = 0x14,
-		[BQ27XXX_REG_FLAGS] = 0x0a,
-		[BQ27XXX_REG_TTE] = 0x16,
-		[BQ27XXX_REG_TTF] = INVALID_REG_ADDR,
-		[BQ27XXX_REG_TTES] = 0x1a,
-		[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
-		[BQ27XXX_REG_NAC] = 0x0c,
-		[BQ27XXX_REG_FCC] = 0x12,
-		[BQ27XXX_REG_CYCT] = 0x1e,
-		[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
-		[BQ27XXX_REG_SOC] = 0x20,
-		[BQ27XXX_REG_DCAP] = 0x2e,
-		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
-		BQ27XXX_DM_REG_ROWS,
-	},
 	[BQ27500] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
 		[BQ27XXX_REG_TEMP] = 0x06,
@@ -241,46 +221,6 @@ static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
 		[BQ27XXX_REG_AP] = 0x24,
 		BQ27XXX_DM_REG_ROWS,
 	},
-	[BQ27510G1] = {
-		[BQ27XXX_REG_CTRL] = 0x00,
-		[BQ27XXX_REG_TEMP] = 0x06,
-		[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
-		[BQ27XXX_REG_VOLT] = 0x08,
-		[BQ27XXX_REG_AI] = 0x14,
-		[BQ27XXX_REG_FLAGS] = 0x0a,
-		[BQ27XXX_REG_TTE] = 0x16,
-		[BQ27XXX_REG_TTF] = 0x18,
-		[BQ27XXX_REG_TTES] = 0x1c,
-		[BQ27XXX_REG_TTECP] = 0x26,
-		[BQ27XXX_REG_NAC] = 0x0c,
-		[BQ27XXX_REG_FCC] = 0x12,
-		[BQ27XXX_REG_CYCT] = 0x2a,
-		[BQ27XXX_REG_AE] = 0x22,
-		[BQ27XXX_REG_SOC] = 0x2c,
-		[BQ27XXX_REG_DCAP] = 0x3c,
-		[BQ27XXX_REG_AP] = 0x24,
-		BQ27XXX_DM_REG_ROWS,
-	},
-	[BQ27510G2] = {
-		[BQ27XXX_REG_CTRL] = 0x00,
-		[BQ27XXX_REG_TEMP] = 0x06,
-		[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
-		[BQ27XXX_REG_VOLT] = 0x08,
-		[BQ27XXX_REG_AI] = 0x14,
-		[BQ27XXX_REG_FLAGS] = 0x0a,
-		[BQ27XXX_REG_TTE] = 0x16,
-		[BQ27XXX_REG_TTF] = 0x18,
-		[BQ27XXX_REG_TTES] = 0x1c,
-		[BQ27XXX_REG_TTECP] = 0x26,
-		[BQ27XXX_REG_NAC] = 0x0c,
-		[BQ27XXX_REG_FCC] = 0x12,
-		[BQ27XXX_REG_CYCT] = 0x2a,
-		[BQ27XXX_REG_AE] = 0x22,
-		[BQ27XXX_REG_SOC] = 0x2c,
-		[BQ27XXX_REG_DCAP] = 0x3c,
-		[BQ27XXX_REG_AP] = 0x24,
-		BQ27XXX_DM_REG_ROWS,
-	},
 	[BQ27510G3] = {
 		[BQ27XXX_REG_CTRL] = 0x00,
 		[BQ27XXX_REG_TEMP] = 0x06,
@@ -523,24 +463,6 @@ static enum power_supply_property bq2750x_battery_props[] = {
 	POWER_SUPPLY_PROP_MANUFACTURER,
 };
 
-static enum power_supply_property bq2751x_battery_props[] = {
-	POWER_SUPPLY_PROP_STATUS,
-	POWER_SUPPLY_PROP_PRESENT,
-	POWER_SUPPLY_PROP_VOLTAGE_NOW,
-	POWER_SUPPLY_PROP_CURRENT_NOW,
-	POWER_SUPPLY_PROP_CAPACITY,
-	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-	POWER_SUPPLY_PROP_TEMP,
-	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
-	POWER_SUPPLY_PROP_TECHNOLOGY,
-	POWER_SUPPLY_PROP_CHARGE_FULL,
-	POWER_SUPPLY_PROP_CHARGE_NOW,
-	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-	POWER_SUPPLY_PROP_CYCLE_COUNT,
-	POWER_SUPPLY_PROP_HEALTH,
-	POWER_SUPPLY_PROP_MANUFACTURER,
-};
-
 static enum power_supply_property bq27500_battery_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_PRESENT,
@@ -562,48 +484,6 @@ static enum power_supply_property bq27500_battery_props[] = {
 	POWER_SUPPLY_PROP_MANUFACTURER,
 };
 
-static enum power_supply_property bq27510g1_battery_props[] = {
-	POWER_SUPPLY_PROP_STATUS,
-	POWER_SUPPLY_PROP_PRESENT,
-	POWER_SUPPLY_PROP_VOLTAGE_NOW,
-	POWER_SUPPLY_PROP_CURRENT_NOW,
-	POWER_SUPPLY_PROP_CAPACITY,
-	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-	POWER_SUPPLY_PROP_TEMP,
-	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
-	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
-	POWER_SUPPLY_PROP_TECHNOLOGY,
-	POWER_SUPPLY_PROP_CHARGE_FULL,
-	POWER_SUPPLY_PROP_CHARGE_NOW,
-	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-	POWER_SUPPLY_PROP_CYCLE_COUNT,
-	POWER_SUPPLY_PROP_ENERGY_NOW,
-	POWER_SUPPLY_PROP_POWER_AVG,
-	POWER_SUPPLY_PROP_HEALTH,
-	POWER_SUPPLY_PROP_MANUFACTURER,
-};
-
-static enum power_supply_property bq27510g2_battery_props[] = {
-	POWER_SUPPLY_PROP_STATUS,
-	POWER_SUPPLY_PROP_PRESENT,
-	POWER_SUPPLY_PROP_VOLTAGE_NOW,
-	POWER_SUPPLY_PROP_CURRENT_NOW,
-	POWER_SUPPLY_PROP_CAPACITY,
-	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-	POWER_SUPPLY_PROP_TEMP,
-	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
-	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
-	POWER_SUPPLY_PROP_TECHNOLOGY,
-	POWER_SUPPLY_PROP_CHARGE_FULL,
-	POWER_SUPPLY_PROP_CHARGE_NOW,
-	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-	POWER_SUPPLY_PROP_CYCLE_COUNT,
-	POWER_SUPPLY_PROP_ENERGY_NOW,
-	POWER_SUPPLY_PROP_POWER_AVG,
-	POWER_SUPPLY_PROP_HEALTH,
-	POWER_SUPPLY_PROP_MANUFACTURER,
-};
-
 static enum power_supply_property bq27510g3_battery_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_PRESENT,
@@ -783,10 +663,7 @@ static struct {
 	BQ27XXX_PROP(BQ27000, bq27000_battery_props),
 	BQ27XXX_PROP(BQ27010, bq27010_battery_props),
 	BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
-	BQ27XXX_PROP(BQ2751X, bq2751x_battery_props),
 	BQ27XXX_PROP(BQ27500, bq27500_battery_props),
-	BQ27XXX_PROP(BQ27510G1, bq27510g1_battery_props),
-	BQ27XXX_PROP(BQ27510G2, bq27510g2_battery_props),
 	BQ27XXX_PROP(BQ27510G3, bq27510g3_battery_props),
 	BQ27XXX_PROP(BQ27520G1, bq27520g1_battery_props),
 	BQ27XXX_PROP(BQ27520G2, bq27520g2_battery_props),
@@ -802,11 +679,11 @@ static enum bq27xxx_chip bq27xxx_chips[] = {
 	[BQ27000]   = BQ27000,
 	[BQ27010]   = BQ27010,
 	[BQ2750X]   = BQ2750X,
-	[BQ2751X]   = BQ2751X,
-	[BQ2752X]   = BQ2751X,
+	[BQ2751X]   = BQ27510G3,
+	[BQ2752X]   = BQ27510G3,
 	[BQ27500]   = BQ27500,
-	[BQ27510G1] = BQ27510G1,
-	[BQ27510G2] = BQ27510G2,
+	[BQ27510G1] = BQ27500,
+	[BQ27510G2] = BQ27500,
 	[BQ27510G3] = BQ27510G3,
 	[BQ27520G1] = BQ27520G1,
 	[BQ27520G2] = BQ27520G2,
@@ -1578,10 +1455,7 @@ static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags)
 {
 	switch (di->chip) {
 	case BQ2750X:
-	case BQ2751X:
 	case BQ27500:
-	case BQ27510G1:
-	case BQ27510G2:
 	case BQ27510G3:
 	case BQ27520G1:
 	case BQ27520G2:
diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
index 543c10e..4702b86 100644
--- a/include/linux/power/bq27xxx_battery.h
+++ b/include/linux/power/bq27xxx_battery.h
@@ -7,11 +7,8 @@ enum bq27xxx_chip {
 	BQ27000 = 1, /* bq27000, bq27200 */
 	BQ27010, /* bq27010, bq27210 */
 	BQ2750X, /* bq27500 deprecated alias */
-	BQ2751X, /* bq27510, bq27520 deprecated alias */
-	BQ27500, /* bq27500/1 */
-	BQ27510G1, /* bq27510G1 */
-	BQ27510G2, /* bq27510G2 */
-	BQ27510G3, /* bq27510G3 */
+	BQ27500, /* bq27500/1, bq27510G1, bq27510G2 */
+	BQ27510G3, /* bq27510G3, bq27510, bq27520 */
 	BQ27520G1, /* bq27520G1 */
 	BQ27520G2, /* bq27520G2 */
 	BQ27520G3, /* bq27520G3 */
@@ -23,7 +20,10 @@ enum bq27xxx_chip {
 	BQ27MAX,
 
 	/* these map to above in bq27xxx_chips[] */
-	BQ2752X, /* deprecated alias */
+	BQ2751X, /* bq27510 deprecated alias */
+	BQ2752X, /* bq27520 deprecated alias */
+	BQ27510G1,
+	BQ27510G2,
 	BQ27531,
 	BQ27542,
 	BQ27546,
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode
  2017-05-04  6:18 ` [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode Liam Breck
@ 2017-05-04 16:38   ` Andrew F. Davis
  2017-05-08  6:18     ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-04 16:38 UTC (permalink / raw)
  To: Liam Breck, Sebastian Reichel, linux-pm; +Cc: Liam Breck

On 05/04/2017 01:18 AM, Liam Breck wrote:
> From: Liam Breck <kernel@networkimprov.net>
> 
> We tie multiple chips to unique register maps. When supporting a new chip,
> it's easy to add a duplicate map by mistake.
> 
> In debug mode we now scan the register maps for duplicates.
> 

Debugging stuff doesn't need to go upstream.

> Signed-off-by: Liam Breck <kernel@networkimprov.net>
> ---
>  drivers/power/supply/bq27xxx_battery.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
> index 0aecd41..97c646c 100644
> --- a/drivers/power/supply/bq27xxx_battery.c
> +++ b/drivers/power/supply/bq27xxx_battery.c
> @@ -1932,6 +1932,25 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
>  	schedule_delayed_work(&di->work, 0);
>  }
>  
> +#ifdef DEBUG
> +static void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di)
> +{
> +	const size_t max = ARRAY_SIZE(bq27xxx_regs);
> +	int a, b;
> +
> +	for (a = 1; a < max-1; a++) {
> +		for (b = a+1; b < max; b++) {
> +			if (!memcmp(bq27xxx_regs[a], bq27xxx_regs[b],
> +				    sizeof(bq27xxx_regs[0])))
> +				dev_warn(di->dev,
> +					"bq27xxx_regs[%d] & [%d] are identical\n", a, b);
> +		}
> +	}
> +}
> +#else
> +static inline void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di) {}
> +#endif
> +
>  int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>  {
>  	struct power_supply_desc *psy_desc;
> @@ -1940,6 +1959,8 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>  		.drv_data = di,
>  	};
>  
> +	bq27xxx_battery_dbg_regs_dupes(di);
> +
>  	di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>  
>  	di->unseal_key = bq27xxx_unseal_keys[di->chip];
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support
  2017-05-04  6:18 ` [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support Liam Breck
@ 2017-05-04 16:44   ` Andrew F. Davis
  2017-05-04 18:07     ` Liam Breck
  2017-05-05 12:45     ` Liam Breck
  0 siblings, 2 replies; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-04 16:44 UTC (permalink / raw)
  To: Liam Breck, Sebastian Reichel, linux-pm; +Cc: Matt Ranostay, Liam Breck

On 05/04/2017 01:18 AM, Liam Breck wrote:
> From: Liam Breck <kernel@networkimprov.net>
> 
> Add these to enable read/write of chip data memory RAM/NVM/flash:
>   bq27xxx_battery_seal()
>   bq27xxx_battery_unseal()
>   bq27xxx_battery_set_cfgupdate()
>   bq27xxx_battery_read_dm_block()
>   bq27xxx_battery_write_dm_block()
>   bq27xxx_battery_checksum_dm_block()
> 
> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
> Signed-off-by: Liam Breck <kernel@networkimprov.net>
> ---
>  drivers/power/supply/bq27xxx_battery.c | 253 +++++++++++++++++++++++++++++++++
>  include/linux/power/bq27xxx_battery.h  |   1 +
>  2 files changed, 254 insertions(+)
> 
> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
> index a11dfad..8ab184c 100644
> --- a/drivers/power/supply/bq27xxx_battery.c
> +++ b/drivers/power/supply/bq27xxx_battery.c
> @@ -5,6 +5,7 @@
>   * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
>   * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
>   * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
> + * Copyright (C) 2017 Liam Breck <kernel@networkimprov.net>
>   *
>   * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
>   *
> @@ -65,6 +66,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)
> @@ -78,6 +80,12 @@
>  #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_RESET			0x41
> +
>  #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 */
> @@ -108,9 +116,21 @@ enum bq27xxx_reg_index {
>  	BQ27XXX_REG_SOC,	/* State-of-Charge */
>  	BQ27XXX_REG_DCAP,	/* Design Capacity */
>  	BQ27XXX_REG_AP,		/* Average Power */
> +	BQ27XXX_DM_CTRL,	/* Block Data Control */
> +	BQ27XXX_DM_CLASS,	/* Data Class */
> +	BQ27XXX_DM_BLOCK,	/* Data Block */
> +	BQ27XXX_DM_DATA,	/* Block Data */
> +	BQ27XXX_DM_CKSUM,	/* Block Data Checksum */
>  	BQ27XXX_REG_MAX,	/* sentinel */
>  };
>  
> +#define BQ27XXX_DM_REG_ROWS \
> +	[BQ27XXX_DM_CTRL] = 0x61,  \
> +	[BQ27XXX_DM_CLASS] = 0x3e, \
> +	[BQ27XXX_DM_BLOCK] = 0x3f, \
> +	[BQ27XXX_DM_DATA] = 0x40,  \
> +	[BQ27XXX_DM_CKSUM] = 0x60
> +
>  /* Register mappings */
>  static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  	[BQ27000] = {
> @@ -131,6 +151,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,
> @@ -150,6 +175,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,
>  	},
>  	[BQ2750X] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -169,6 +199,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = 0x3c,
>  		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ2751X] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -188,6 +219,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x20,
>  		[BQ27XXX_REG_DCAP] = 0x2e,
>  		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27500] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -207,6 +239,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = 0x3c,
>  		[BQ27XXX_REG_AP] = 0x24,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27510G1] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -226,6 +259,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = 0x3c,
>  		[BQ27XXX_REG_AP] = 0x24,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27510G2] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -245,6 +279,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = 0x3c,
>  		[BQ27XXX_REG_AP] = 0x24,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27510G3] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -264,6 +299,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x20,
>  		[BQ27XXX_REG_DCAP] = 0x2e,
>  		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27520G1] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -283,6 +319,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = 0x3c,
>  		[BQ27XXX_REG_AP] = 0x24,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27520G2] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -302,6 +339,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = 0x3c,
>  		[BQ27XXX_REG_AP] = 0x24,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27520G3] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -321,6 +359,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = 0x3c,
>  		[BQ27XXX_REG_AP] = 0x24,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27520G4] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -340,6 +379,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x20,
>  		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>  		[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27530] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -359,6 +399,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>  		[BQ27XXX_REG_AP] = 0x24,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27541] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -378,6 +419,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = 0x3c,
>  		[BQ27XXX_REG_AP] = 0x24,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27545] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -397,6 +439,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x2c,
>  		[BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>  		[BQ27XXX_REG_AP] = 0x24,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  	[BQ27421] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
> @@ -416,6 +459,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>  		[BQ27XXX_REG_SOC] = 0x1c,
>  		[BQ27XXX_REG_DCAP] = 0x3c,
>  		[BQ27XXX_REG_AP] = 0x18,
> +		BQ27XXX_DM_REG_ROWS,
>  	},
>  };
>  
> @@ -757,6 +801,28 @@ static struct {
>  static DEFINE_MUTEX(bq27xxx_list_lock);
>  static LIST_HEAD(bq27xxx_battery_devices);
>  
> +#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
> +
> +#define BQ27XXX_DM_SZ	32
> +
> +/**
> + * struct bq27xxx_dm_buf - chip data memory buffer
> + * @class: data memory subclass_id
> + * @block: data memory block number
> + * @data: data from/for the block
> + * @has_data: true if data has been filled by read
> + * @dirty: true if data has changed since last read/write
> + *
> + * Encapsulates info required to manage chip data memory blocks.
> + */
> +struct bq27xxx_dm_buf {
> +	u8 class;
> +	u8 block;
> +	u8 data[BQ27XXX_DM_SZ];
> +	bool has_data, dirty;
> +};
> +
> +
>  static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
>  {
>  	struct bq27xxx_device_info *di;
> @@ -864,6 +930,193 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in
>  	return ret;
>  }
>  
> +static int bq27xxx_battery_seal(struct bq27xxx_device_info *di)
> +{
> +	int ret;
> +
> +	ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_SEALED, false);
> +	if (ret < 0) {
> +		dev_err(di->dev, "bus error on seal: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int bq27xxx_battery_unseal(struct bq27xxx_device_info *di)
> +{
> +	int ret;
> +
> +	if (di->unseal_key == 0) {
> +		dev_err(di->dev, "unseal failed due to missing key\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)(di->unseal_key >> 16), false);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)di->unseal_key, false);
> +	if (ret < 0)
> +		goto out;
> +
> +	return 0;
> +
> +out:
> +	dev_err(di->dev, "bus error on unseal: %d\n", 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->data[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;
> +
> +	buf->has_data = false;
> +
> +	ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
> +	if (ret < 0)
> +		goto out;
> +
> +	BQ27XXX_MSLEEP(1);
> +
> +	ret = bq27xxx_read_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = bq27xxx_read(di, BQ27XXX_DM_CKSUM, true);
> +	if (ret < 0)
> +		goto out;
> +
> +	if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	buf->has_data = true;
> +	buf->dirty = false;
> +
> +	return 0;
> +
> +out:
> +	dev_err(di->dev, "bus error reading chip memory: %d\n", ret);
> +	return ret;
> +}
> +
> +static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)

Why do you pass in a flag but treat it like a bool? This whole function
needs to be re-factored.

> +{
> +	const int limit = 100;
> +	int ret, try = limit;
> +
> +	ret = bq27xxx_write(di, 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 (limit-try > 3)
> +		dev_warn(di->dev, "cfgupdate %d, retries %d\n", !!state, limit-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 */

Group? This is a single chip ID.

> +	int ret;
> +
> +	if (!buf->dirty)
> +		return 0;
> +
> +	if (cfgup) {
> +		ret = bq27xxx_battery_set_cfgupdate(di, BQ27XXX_FLAG_CFGUP);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	ret = bq27xxx_write(di, BQ27XXX_DM_CTRL, 0, true);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
> +	if (ret < 0)
> +		goto out;
> +
> +	BQ27XXX_MSLEEP(1);
> +
> +	ret = bq27xxx_write_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = bq27xxx_write(di, BQ27XXX_DM_CKSUM,
> +			    bq27xxx_battery_checksum_dm_block(buf), true);
> +	if (ret < 0)
> +		goto out;
> +
> +	/* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM
> +	 * corruption on the '425 chip (and perhaps others), which can damage
> +	 * the chip. See TI bqtool for what not to do:
> +	 * http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
> +	 */
> +

Again, this is not needed, I'm sorry you fried your chip somehow but
this program is not incorrect, it is used by our customers all the time
and does not fry chips, drop this comment.

> +	if (cfgup) {
> +		BQ27XXX_MSLEEP(1);
> +		ret = bq27xxx_battery_set_cfgupdate(di, 0);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		BQ27XXX_MSLEEP(100); /* flash DM updates in <100ms */
> +	}
> +
> +	buf->dirty = false;
> +
> +	return 0;
> +
> +out:
> +	if (cfgup)
> +		bq27xxx_battery_set_cfgupdate(di, 0);
> +
> +	dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
> +	return ret;
> +}
> +
>  /*
>   * Return the battery State-of-Charge
>   * Or < 0 if something fails.
> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
> index c3369fa..b1defb8 100644
> --- a/include/linux/power/bq27xxx_battery.h
> +++ b/include/linux/power/bq27xxx_battery.h
> @@ -64,6 +64,7 @@ struct bq27xxx_device_info {
>  	int id;
>  	enum bq27xxx_chip chip;
>  	const char *name;
> +	u32 unseal_key;
>  	struct bq27xxx_access_methods bus;
>  	struct bq27xxx_reg_cache cache;
>  	int charge_design_full;
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-04  6:18 ` [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support Liam Breck
@ 2017-05-04 16:52   ` Andrew F. Davis
  2017-05-04 18:40     ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-04 16:52 UTC (permalink / raw)
  To: Liam Breck, Sebastian Reichel, linux-pm; +Cc: Matt Ranostay, Liam Breck

On 05/04/2017 01:18 AM, Liam Breck wrote:
> From: Liam Breck <kernel@networkimprov.net>
> 
> Previously there was no way to configure these chips in the event that the
> defaults didn't match the battery in question.
> 
> For chips with RAM data memory (and also those with flash/NVM data memory
> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
> set module param dt_monitored_battery_updates_nvm=0) we now call
> power_supply_get_battery_info(), check its values, and write battery
> properties to chip data memory if there is a dm_regs table for the chip.
> 
> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
> Signed-off-by: Liam Breck <kernel@networkimprov.net>
> ---
>  drivers/power/supply/Kconfig           |   9 ++
>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>  include/linux/power/bq27xxx_battery.h  |   2 +
>  3 files changed, 209 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index 76806a0..85e2fb2 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>  	  Say Y here to enable support for batteries with BQ27xxx chips
>  	  connected over an I2C bus.
>  
> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
> +	bool "BQ27xxx support for update of NVM/flash data memory"
> +	depends on BATTERY_BQ27XXX_I2C
> +	help
> +	  Say Y here to enable devicetree monitored-battery config to update
> +	  NVM/flash data memory. Only enable this option for devices with a
> +	  fuel gauge mounted on the circuit board, and a battery that cannot
> +	  be replaced with one of a different type.
> +
>  config BATTERY_DA9030
>  	tristate "DA9030 battery driver"
>  	depends on PMIC_DA903X
> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
> index 8ab184c..06f15da 100644
> --- a/drivers/power/supply/bq27xxx_battery.c
> +++ b/drivers/power/supply/bq27xxx_battery.c
> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>  
>  #define BQ27XXX_DM_SZ	32
>  
> +struct bq27xxx_dm_reg {
> +	u8 subclass_id;
> +	u8 offset;
> +	u8 bytes;
> +	u16 min, max;
> +};
> +
>  /**
>   * struct bq27xxx_dm_buf - chip data memory buffer
>   * @class: data memory subclass_id
> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>  	bool has_data, dirty;
>  };
>  
> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
> +	[BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
> +	[BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
> +	[BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
> +};
> +
> +
> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
> +static bool bq27xxx_dt_to_nvm = true;
> +
> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
> +	"Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");

As before, the default should not be y, this is a rare case and I can't
see it being useful or wanted by anyone but device manufacturers. I
don't want everyones chip's factory programmed NVM overwritten by
accident when someone compiles and ships a kernel with
BATTERY_BQ27XXX_DT_UPDATES_NVM=y

> +#else
> +static bool bq27xxx_dt_to_nvm = false;
> +#endif
>  
>  static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
>  {
> @@ -1019,6 +1063,51 @@ static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
>  	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->has_data)
> +		return;
> +
> +	if (be16_to_cpup(prev) == val) {
> +		dev_info(di->dev, "%s has %u\n", str, val);
> +		return;
> +	}
> +
> +	if (!di->ram_chip && !bq27xxx_dt_to_nvm) {
> +		/* devicetree and NVM differ; defer to NVM */
> +		dev_warn(di->dev, "%s has %u; update to %u disallowed "
> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
> +			 "by dt_monitored_battery_updates_nvm=0"
> +#else
> +			 "for flash/NVM data memory"
> +#endif
> +			 "\n", str, be16_to_cpup(prev), val);
> +		return;
> +	}
> +
> +	dev_info(di->dev, "update %s to %u\n", str, val);
> +
> +	*prev = cpu_to_be16(val);
> +	buf->dirty = true;
> +}
> +
>  static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
>  {
>  	const int limit = 100;
> @@ -1117,6 +1206,103 @@ static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
>  	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);
> +	bool updated;
> +
> +	if (bq27xxx_battery_unseal(di) < 0)
> +		return;
> +
> +	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);
> +	}
> +
> +	updated = bd.dirty || bt.dirty;
> +
> +	bq27xxx_battery_write_dm_block(di, &bd);
> +	bq27xxx_battery_write_dm_block(di, &bt);
> +
> +	bq27xxx_battery_seal(di);
> +
> +	if (updated && di->chip != BQ27421) { /* not a cfgupdate chip, so reset */
> +		bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false);
> +		BQ27XXX_MSLEEP(300); /* reset time is not documented */
> +	}
> +	/* assume bq27xxx_battery_update() is called hereafter */
> +}
> +
> +static void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
> +{
> +	struct power_supply_battery_info info = {};
> +	unsigned int min, max;
> +
> +	if (power_supply_get_battery_info(di->bat, &info) < 0)
> +		return;
> +
> +	if (!di->dm_regs) {
> +		dev_warn(di->dev, "data memory update not supported for chip\n");
> +		return;
> +	}
> +
> +	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)
> +		bq27xxx_battery_set_config(di, &info);
> +}
> +
>  /*
>   * Return the battery State-of-Charge
>   * Or < 0 if something fails.
> @@ -1634,6 +1820,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;
> @@ -1667,7 +1860,10 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
>  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,
> +	};
>  
>  	INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>  	mutex_init(&di->lock);
> @@ -1692,6 +1888,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);
> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
> index b1defb8..11e1168 100644
> --- a/include/linux/power/bq27xxx_battery.h
> +++ b/include/linux/power/bq27xxx_battery.h
> @@ -63,7 +63,9 @@ struct bq27xxx_device_info {
>  	struct device *dev;
>  	int id;
>  	enum bq27xxx_chip chip;
> +	bool ram_chip;
>  	const char *name;
> +	struct bq27xxx_dm_reg *dm_regs;
>  	u32 unseal_key;
>  	struct bq27xxx_access_methods bus;
>  	struct bq27xxx_reg_cache cache;
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-04  6:18 ` [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips Liam Breck
@ 2017-05-04 17:00   ` Andrew F. Davis
  2017-05-04 19:12     ` Liam Breck
  2017-05-05 19:31     ` Liam Breck
  2017-05-10  9:16   ` Liam Breck
  1 sibling, 2 replies; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-04 17:00 UTC (permalink / raw)
  To: Liam Breck, Sebastian Reichel, linux-pm; +Cc: Liam Breck

On 05/04/2017 01:18 AM, Liam Breck wrote:
> From: Liam Breck <kernel@networkimprov.net>
> 
> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
> 
> Create IDs for for previously unID'd chips, to index arrays for unseal keys
> and data memory register tables.
> 
> Signed-off-by: Liam Breck <kernel@networkimprov.net>
> ---
>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>  3 files changed, 107 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
> index 06f15da..0aecd41 100644
> --- a/drivers/power/supply/bq27xxx_battery.c
> +++ b/drivers/power/supply/bq27xxx_battery.c
> @@ -58,7 +58,7 @@
>  
>  #include <linux/power/bq27xxx_battery.h>
>  
> -#define DRIVER_VERSION		"1.2.0"
> +#define DRIVER_VERSION		"1.3.0"
>  
>  #define BQ27XXX_MANUFACTURER	"Texas Instruments"
>  
> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>  	[BQ27XXX_DM_CKSUM] = 0x60
>  
>  /* Register mappings */
> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>  	[BQ27000] = {
>  		[BQ27XXX_REG_CTRL] = 0x00,
>  		[BQ27XXX_REG_TEMP] = 0x06,
> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>  static struct {
>  	enum power_supply_property *props;
>  	size_t size;
> -} bq27xxx_battery_props[] = {
> +} bq27xxx_battery_props[BQ27MAX] = {
>  	BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>  	BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>  	BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
> @@ -798,6 +798,33 @@ static struct {
>  	BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>  };
>  
> +static enum bq27xxx_chip bq27xxx_chips[] = {
> +	[BQ27000]   = BQ27000,
> +	[BQ27010]   = BQ27010,
> +	[BQ2750X]   = BQ2750X,
> +	[BQ2751X]   = BQ2751X,
> +	[BQ2752X]   = BQ2751X,
> +	[BQ27500]   = BQ27500,
> +	[BQ27510G1] = BQ27510G1,
> +	[BQ27510G2] = BQ27510G2,
> +	[BQ27510G3] = BQ27510G3,
> +	[BQ27520G1] = BQ27520G1,
> +	[BQ27520G2] = BQ27520G2,
> +	[BQ27520G3] = BQ27520G3,
> +	[BQ27520G4] = BQ27520G4,
> +	[BQ27530]   = BQ27530,
> +	[BQ27531]   = BQ27530,
> +	[BQ27541]   = BQ27541,
> +	[BQ27542]   = BQ27541,
> +	[BQ27546]   = BQ27541,
> +	[BQ27742]   = BQ27541,
> +	[BQ27545]   = BQ27545,
> +	[BQ27421]   = BQ27421,
> +	[BQ27425]   = BQ27421,
> +	[BQ27441]   = BQ27421,
> +	[BQ27621]   = BQ27421,
> +};
> +
>  static DEFINE_MUTEX(bq27xxx_list_lock);
>  static LIST_HEAD(bq27xxx_battery_devices);
>  
> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>  	[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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
> +	[BQ27500] = bq27500_dm_regs,
> +	[BQ27545] = bq27545_dm_regs,
> +	[BQ27421] = bq27421_dm_regs,
> +	[BQ27425] = bq27425_dm_regs,
> +	[BQ27441] = bq27421_dm_regs,
> +	[BQ27621] = bq27621_dm_regs,
> +};
> +
> +static u32 bq27xxx_unseal_keys[] = {
> +	[BQ27500] = 0x04143672,
> +	[BQ27545] = 0x04143672,
> +	[BQ27421] = 0x80008000,
> +	[BQ27425] = 0x04143672,
> +	[BQ27441] = 0x80008000,
> +	[BQ27621] = 0x80008000,
> +};
> +
>  
>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>  static bool bq27xxx_dt_to_nvm = true;
> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>  		.drv_data = di,
>  	};
>  
> +	di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
> +
> +	di->unseal_key = bq27xxx_unseal_keys[di->chip];
> +	di->dm_regs = bq27xxx_dm_regs[di->chip];
> +	di->chip = bq27xxx_chips[di->chip];

NACK, this is a mess, you should not be using a table to change what
chip was passed in, it may be needed later. The chip is still the same,
it should have the same one correct ID, use a different index or array
if you would like, but this is very hacky.

Just stop trying to hack around it, add the extra tables, even if they
are clones, so we can be done with this series already. I'm sure you
want that more than you want this "clever" work-around, right?

Also fix all the checkpatch --strict warnings.

> +
> +	di->regs = bq27xxx_regs[di->chip];
> +
>  	INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>  	mutex_init(&di->lock);
> -	di->regs = bq27xxx_regs[di->chip];
>  
>  	psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>  	if (!psy_desc)
> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
> index a597221..0b11ed4 100644
> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>  	{ "bq27210", BQ27010 },
>  	{ "bq27500", BQ2750X },
>  	{ "bq27510", BQ2751X },
> -	{ "bq27520", BQ2751X },
> +	{ "bq27520", BQ2752X },
>  	{ "bq27500-1", BQ27500 },
>  	{ "bq27510g1", BQ27510G1 },
>  	{ "bq27510g2", BQ27510G2 },
> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>  	{ "bq27520g3", BQ27520G3 },
>  	{ "bq27520g4", BQ27520G4 },
>  	{ "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);
> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
> index 11e1168..543c10e 100644
> --- a/include/linux/power/bq27xxx_battery.h
> +++ b/include/linux/power/bq27xxx_battery.h
> @@ -2,6 +2,8 @@
>  #define __LINUX_BQ27X00_BATTERY_H__
>  
>  enum bq27xxx_chip {
> +	/* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
> +	/* and map to themselves in bq27xxx_chips[]             */
>  	BQ27000 = 1, /* bq27000, bq27200 */
>  	BQ27010, /* bq27010, bq27210 */
>  	BQ2750X, /* bq27500 deprecated alias */
> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>  	BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>  	BQ27545, /* bq27545 */
>  	BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
> +	BQ27MAX,
> +
> +	/* these map to above in bq27xxx_chips[] */
> +	BQ2752X, /* deprecated alias */
> +	BQ27531,
> +	BQ27542,
> +	BQ27546,
> +	BQ27742,
> +	BQ27425,
> +	BQ27441,
> +	BQ27621,
>  };
>  
>  /**
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support
  2017-05-04 16:44   ` Andrew F. Davis
@ 2017-05-04 18:07     ` Liam Breck
  2017-05-05 12:45     ` Liam Breck
  1 sibling, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04 18:07 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Matt Ranostay, Liam Breck

On Thu, May 4, 2017 at 9:44 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/04/2017 01:18 AM, Liam Breck wrote:
>> From: Liam Breck <kernel@networkimprov.net>
>>
>> Add these to enable read/write of chip data memory RAM/NVM/flash:
>>   bq27xxx_battery_seal()
>>   bq27xxx_battery_unseal()
>>   bq27xxx_battery_set_cfgupdate()
>>   bq27xxx_battery_read_dm_block()
>>   bq27xxx_battery_write_dm_block()
>>   bq27xxx_battery_checksum_dm_block()
>>
>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>> ---
>>  drivers/power/supply/bq27xxx_battery.c | 253 +++++++++++++++++++++++++++++++++
>>  include/linux/power/bq27xxx_battery.h  |   1 +
>>  2 files changed, 254 insertions(+)
>>
>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>> index a11dfad..8ab184c 100644
>> --- a/drivers/power/supply/bq27xxx_battery.c
>> +++ b/drivers/power/supply/bq27xxx_battery.c
>> @@ -5,6 +5,7 @@
>>   * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
>>   * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
>>   * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
>> + * Copyright (C) 2017 Liam Breck <kernel@networkimprov.net>
>>   *
>>   * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
>>   *
>> @@ -65,6 +66,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)
>> @@ -78,6 +80,12 @@
>>  #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_RESET                        0x41
>> +
>>  #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 */
>> @@ -108,9 +116,21 @@ enum bq27xxx_reg_index {
>>       BQ27XXX_REG_SOC,        /* State-of-Charge */
>>       BQ27XXX_REG_DCAP,       /* Design Capacity */
>>       BQ27XXX_REG_AP,         /* Average Power */
>> +     BQ27XXX_DM_CTRL,        /* Block Data Control */
>> +     BQ27XXX_DM_CLASS,       /* Data Class */
>> +     BQ27XXX_DM_BLOCK,       /* Data Block */
>> +     BQ27XXX_DM_DATA,        /* Block Data */
>> +     BQ27XXX_DM_CKSUM,       /* Block Data Checksum */
>>       BQ27XXX_REG_MAX,        /* sentinel */
>>  };
>>
>> +#define BQ27XXX_DM_REG_ROWS \
>> +     [BQ27XXX_DM_CTRL] = 0x61,  \
>> +     [BQ27XXX_DM_CLASS] = 0x3e, \
>> +     [BQ27XXX_DM_BLOCK] = 0x3f, \
>> +     [BQ27XXX_DM_DATA] = 0x40,  \
>> +     [BQ27XXX_DM_CKSUM] = 0x60
>> +
>>  /* Register mappings */
>>  static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>       [BQ27000] = {
>> @@ -131,6 +151,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,
>> @@ -150,6 +175,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,
>>       },
>>       [BQ2750X] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -169,6 +199,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ2751X] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -188,6 +219,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x20,
>>               [BQ27XXX_REG_DCAP] = 0x2e,
>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27500] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -207,6 +239,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27510G1] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -226,6 +259,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27510G2] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -245,6 +279,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27510G3] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -264,6 +299,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x20,
>>               [BQ27XXX_REG_DCAP] = 0x2e,
>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27520G1] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -283,6 +319,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27520G2] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -302,6 +339,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27520G3] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -321,6 +359,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27520G4] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -340,6 +379,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x20,
>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27530] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -359,6 +399,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27541] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -378,6 +419,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27545] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -397,6 +439,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27421] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -416,6 +459,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x1c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x18,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>  };
>>
>> @@ -757,6 +801,28 @@ static struct {
>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>  static LIST_HEAD(bq27xxx_battery_devices);
>>
>> +#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
>> +
>> +#define BQ27XXX_DM_SZ        32
>> +
>> +/**
>> + * struct bq27xxx_dm_buf - chip data memory buffer
>> + * @class: data memory subclass_id
>> + * @block: data memory block number
>> + * @data: data from/for the block
>> + * @has_data: true if data has been filled by read
>> + * @dirty: true if data has changed since last read/write
>> + *
>> + * Encapsulates info required to manage chip data memory blocks.
>> + */
>> +struct bq27xxx_dm_buf {
>> +     u8 class;
>> +     u8 block;
>> +     u8 data[BQ27XXX_DM_SZ];
>> +     bool has_data, dirty;
>> +};
>> +
>> +
>>  static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
>>  {
>>       struct bq27xxx_device_info *di;
>> @@ -864,6 +930,193 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in
>>       return ret;
>>  }
>>
>> +static int bq27xxx_battery_seal(struct bq27xxx_device_info *di)
>> +{
>> +     int ret;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_SEALED, false);
>> +     if (ret < 0) {
>> +             dev_err(di->dev, "bus error on seal: %d\n", ret);
>> +             return ret;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int bq27xxx_battery_unseal(struct bq27xxx_device_info *di)
>> +{
>> +     int ret;
>> +
>> +     if (di->unseal_key == 0) {
>> +             dev_err(di->dev, "unseal failed due to missing key\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)(di->unseal_key >> 16), false);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)di->unseal_key, false);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     return 0;
>> +
>> +out:
>> +     dev_err(di->dev, "bus error on unseal: %d\n", 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->data[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;
>> +
>> +     buf->has_data = false;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     BQ27XXX_MSLEEP(1);
>> +
>> +     ret = bq27xxx_read_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_read(di, BQ27XXX_DM_CKSUM, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {
>> +             ret = -EINVAL;
>> +             goto out;
>> +     }
>> +
>> +     buf->has_data = true;
>> +     buf->dirty = false;
>> +
>> +     return 0;
>> +
>> +out:
>> +     dev_err(di->dev, "bus error reading chip memory: %d\n", ret);
>> +     return ret;
>> +}
>> +
>> +static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
>
> Why do you pass in a flag but treat it like a bool? This whole function
> needs to be re-factored.

I will rename this cfgupdate_priv() and add apis set_cfgupdate() and
soft_reset() to call it.

>> +{
>> +     const int limit = 100;
>> +     int ret, try = limit;
>> +
>> +     ret = bq27xxx_write(di, 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 (limit-try > 3)
>> +             dev_warn(di->dev, "cfgupdate %d, retries %d\n", !!state, limit-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 */
>
> Group? This is a single chip ID.

Many of the "single" chip IDs represent several chips. That predates
this patchset. I will change "group" to "class".

>> +     int ret;
>> +
>> +     if (!buf->dirty)
>> +             return 0;
>> +
>> +     if (cfgup) {
>> +             ret = bq27xxx_battery_set_cfgupdate(di, BQ27XXX_FLAG_CFGUP);
>> +             if (ret < 0)
>> +                     return ret;
>> +     }
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CTRL, 0, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     BQ27XXX_MSLEEP(1);
>> +
>> +     ret = bq27xxx_write_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CKSUM,
>> +                         bq27xxx_battery_checksum_dm_block(buf), true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     /* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM
>> +      * corruption on the '425 chip (and perhaps others), which can damage
>> +      * the chip. See TI bqtool for what not to do:
>> +      * http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
>> +      */
>> +
>
> Again, this is not needed, I'm sorry you fried your chip somehow but
> this program is not incorrect, it is used by our customers all the time
> and does not fry chips, drop this comment.

Bqtool works because it has a long-enough initial delay, but it
implies that the delay is flexible, because on failure it delays again
and retries. I read that and assumed we could use a shorter delay,
which ruined a chip. The datasheet does not indicate a required delay
after checksum write.

I will take out the link to bqtool, but we need to leave the comment
in to prevent others making that mistake.

>> +     if (cfgup) {
>> +             BQ27XXX_MSLEEP(1);
>> +             ret = bq27xxx_battery_set_cfgupdate(di, 0);
>> +             if (ret < 0)
>> +                     return ret;
>> +     } else {
>> +             BQ27XXX_MSLEEP(100); /* flash DM updates in <100ms */
>> +     }
>> +
>> +     buf->dirty = false;
>> +
>> +     return 0;
>> +
>> +out:
>> +     if (cfgup)
>> +             bq27xxx_battery_set_cfgupdate(di, 0);
>> +
>> +     dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
>> +     return ret;
>> +}
>> +
>>  /*
>>   * Return the battery State-of-Charge
>>   * Or < 0 if something fails.
>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>> index c3369fa..b1defb8 100644
>> --- a/include/linux/power/bq27xxx_battery.h
>> +++ b/include/linux/power/bq27xxx_battery.h
>> @@ -64,6 +64,7 @@ struct bq27xxx_device_info {
>>       int id;
>>       enum bq27xxx_chip chip;
>>       const char *name;
>> +     u32 unseal_key;
>>       struct bq27xxx_access_methods bus;
>>       struct bq27xxx_reg_cache cache;
>>       int charge_design_full;
>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-04 16:52   ` Andrew F. Davis
@ 2017-05-04 18:40     ` Liam Breck
  2017-05-08  6:16       ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-04 18:40 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Matt Ranostay, Liam Breck

On Thu, May 4, 2017 at 9:52 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/04/2017 01:18 AM, Liam Breck wrote:
>> From: Liam Breck <kernel@networkimprov.net>
>>
>> Previously there was no way to configure these chips in the event that the
>> defaults didn't match the battery in question.
>>
>> For chips with RAM data memory (and also those with flash/NVM data memory
>> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
>> set module param dt_monitored_battery_updates_nvm=0) we now call
>> power_supply_get_battery_info(), check its values, and write battery
>> properties to chip data memory if there is a dm_regs table for the chip.
>>
>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>> ---
>>  drivers/power/supply/Kconfig           |   9 ++
>>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>>  include/linux/power/bq27xxx_battery.h  |   2 +
>>  3 files changed, 209 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>> index 76806a0..85e2fb2 100644
>> --- a/drivers/power/supply/Kconfig
>> +++ b/drivers/power/supply/Kconfig
>> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>>         Say Y here to enable support for batteries with BQ27xxx chips
>>         connected over an I2C bus.
>>
>> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
>> +     bool "BQ27xxx support for update of NVM/flash data memory"
>> +     depends on BATTERY_BQ27XXX_I2C
>> +     help
>> +       Say Y here to enable devicetree monitored-battery config to update
>> +       NVM/flash data memory. Only enable this option for devices with a
>> +       fuel gauge mounted on the circuit board, and a battery that cannot
>> +       be replaced with one of a different type.
>> +
>>  config BATTERY_DA9030
>>       tristate "DA9030 battery driver"
>>       depends on PMIC_DA903X
>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>> index 8ab184c..06f15da 100644
>> --- a/drivers/power/supply/bq27xxx_battery.c
>> +++ b/drivers/power/supply/bq27xxx_battery.c
>> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>>
>>  #define BQ27XXX_DM_SZ        32
>>
>> +struct bq27xxx_dm_reg {
>> +     u8 subclass_id;
>> +     u8 offset;
>> +     u8 bytes;
>> +     u16 min, max;
>> +};
>> +
>>  /**
>>   * struct bq27xxx_dm_buf - chip data memory buffer
>>   * @class: data memory subclass_id
>> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>>       bool has_data, dirty;
>>  };
>>
>> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
>> +     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
>> +     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
>> +     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>> +};
>> +
>> +
>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>> +static bool bq27xxx_dt_to_nvm = true;
>> +
>> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
>> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
>> +     "Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
>
> As before, the default should not be y, this is a rare case and I can't
> see it being useful or wanted by anyone but device manufacturers. I
> don't want everyones chip's factory programmed NVM overwritten by
> accident when someone compiles and ships a kernel with
> BATTERY_BQ27XXX_DT_UPDATES_NVM=y

Right, the point of the config option is to let a device vendor ship a
kernel + dtb which can field-upgrade NVM. (Setting the option does
nothing absent the necessary dtb.)

Module params are for end-user config; we can't require a device
vendor to ship /etc/modprobe.d/xyz. And we certainly don't want a
kernel package update to defeat the end-user config of
dt_monitored_battery_updates_nvm=0 !!

I believe Sebastian agrees, given that he queued this patch :-)

>> +#else
>> +static bool bq27xxx_dt_to_nvm = false;
>> +#endif
>>
>>  static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
>>  {
>> @@ -1019,6 +1063,51 @@ static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
>>       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->has_data)
>> +             return;
>> +
>> +     if (be16_to_cpup(prev) == val) {
>> +             dev_info(di->dev, "%s has %u\n", str, val);
>> +             return;
>> +     }
>> +
>> +     if (!di->ram_chip && !bq27xxx_dt_to_nvm) {
>> +             /* devicetree and NVM differ; defer to NVM */
>> +             dev_warn(di->dev, "%s has %u; update to %u disallowed "
>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>> +                      "by dt_monitored_battery_updates_nvm=0"
>> +#else
>> +                      "for flash/NVM data memory"
>> +#endif
>> +                      "\n", str, be16_to_cpup(prev), val);
>> +             return;
>> +     }
>> +
>> +     dev_info(di->dev, "update %s to %u\n", str, val);
>> +
>> +     *prev = cpu_to_be16(val);
>> +     buf->dirty = true;
>> +}
>> +
>>  static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
>>  {
>>       const int limit = 100;
>> @@ -1117,6 +1206,103 @@ static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
>>       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);
>> +     bool updated;
>> +
>> +     if (bq27xxx_battery_unseal(di) < 0)
>> +             return;
>> +
>> +     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);
>> +     }
>> +
>> +     updated = bd.dirty || bt.dirty;
>> +
>> +     bq27xxx_battery_write_dm_block(di, &bd);
>> +     bq27xxx_battery_write_dm_block(di, &bt);
>> +
>> +     bq27xxx_battery_seal(di);
>> +
>> +     if (updated && di->chip != BQ27421) { /* not a cfgupdate chip, so reset */
>> +             bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false);
>> +             BQ27XXX_MSLEEP(300); /* reset time is not documented */
>> +     }
>> +     /* assume bq27xxx_battery_update() is called hereafter */
>> +}
>> +
>> +static void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
>> +{
>> +     struct power_supply_battery_info info = {};
>> +     unsigned int min, max;
>> +
>> +     if (power_supply_get_battery_info(di->bat, &info) < 0)
>> +             return;
>> +
>> +     if (!di->dm_regs) {
>> +             dev_warn(di->dev, "data memory update not supported for chip\n");
>> +             return;
>> +     }
>> +
>> +     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)
>> +             bq27xxx_battery_set_config(di, &info);
>> +}
>> +
>>  /*
>>   * Return the battery State-of-Charge
>>   * Or < 0 if something fails.
>> @@ -1634,6 +1820,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;
>> @@ -1667,7 +1860,10 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
>>  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,
>> +     };
>>
>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>       mutex_init(&di->lock);
>> @@ -1692,6 +1888,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);
>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>> index b1defb8..11e1168 100644
>> --- a/include/linux/power/bq27xxx_battery.h
>> +++ b/include/linux/power/bq27xxx_battery.h
>> @@ -63,7 +63,9 @@ struct bq27xxx_device_info {
>>       struct device *dev;
>>       int id;
>>       enum bq27xxx_chip chip;
>> +     bool ram_chip;
>>       const char *name;
>> +     struct bq27xxx_dm_reg *dm_regs;
>>       u32 unseal_key;
>>       struct bq27xxx_access_methods bus;
>>       struct bq27xxx_reg_cache cache;
>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-04 17:00   ` Andrew F. Davis
@ 2017-05-04 19:12     ` Liam Breck
  2017-05-05 19:31     ` Liam Breck
  1 sibling, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-04 19:12 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/04/2017 01:18 AM, Liam Breck wrote:
>> From: Liam Breck <kernel@networkimprov.net>
>>
>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>
>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>> and data memory register tables.
>>
>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>> ---
>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>> index 06f15da..0aecd41 100644
>> --- a/drivers/power/supply/bq27xxx_battery.c
>> +++ b/drivers/power/supply/bq27xxx_battery.c
>> @@ -58,7 +58,7 @@
>>
>>  #include <linux/power/bq27xxx_battery.h>
>>
>> -#define DRIVER_VERSION               "1.2.0"
>> +#define DRIVER_VERSION               "1.3.0"
>>
>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>
>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>       [BQ27XXX_DM_CKSUM] = 0x60
>>
>>  /* Register mappings */
>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>       [BQ27000] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>>               [BQ27XXX_REG_TEMP] = 0x06,
>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>  static struct {
>>       enum power_supply_property *props;
>>       size_t size;
>> -} bq27xxx_battery_props[] = {
>> +} bq27xxx_battery_props[BQ27MAX] = {
>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>> @@ -798,6 +798,33 @@ static struct {
>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>  };
>>
>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>> +     [BQ27000]   = BQ27000,
>> +     [BQ27010]   = BQ27010,
>> +     [BQ2750X]   = BQ2750X,
>> +     [BQ2751X]   = BQ2751X,
>> +     [BQ2752X]   = BQ2751X,
>> +     [BQ27500]   = BQ27500,
>> +     [BQ27510G1] = BQ27510G1,
>> +     [BQ27510G2] = BQ27510G2,
>> +     [BQ27510G3] = BQ27510G3,
>> +     [BQ27520G1] = BQ27520G1,
>> +     [BQ27520G2] = BQ27520G2,
>> +     [BQ27520G3] = BQ27520G3,
>> +     [BQ27520G4] = BQ27520G4,
>> +     [BQ27530]   = BQ27530,
>> +     [BQ27531]   = BQ27530,
>> +     [BQ27541]   = BQ27541,
>> +     [BQ27542]   = BQ27541,
>> +     [BQ27546]   = BQ27541,
>> +     [BQ27742]   = BQ27541,
>> +     [BQ27545]   = BQ27545,
>> +     [BQ27421]   = BQ27421,
>> +     [BQ27425]   = BQ27421,
>> +     [BQ27441]   = BQ27421,
>> +     [BQ27621]   = BQ27421,
>> +};
>> +
>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>  static LIST_HEAD(bq27xxx_battery_devices);
>>
>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>> +     [BQ27500] = bq27500_dm_regs,
>> +     [BQ27545] = bq27545_dm_regs,
>> +     [BQ27421] = bq27421_dm_regs,
>> +     [BQ27425] = bq27425_dm_regs,
>> +     [BQ27441] = bq27421_dm_regs,
>> +     [BQ27621] = bq27621_dm_regs,
>> +};
>> +
>> +static u32 bq27xxx_unseal_keys[] = {
>> +     [BQ27500] = 0x04143672,
>> +     [BQ27545] = 0x04143672,
>> +     [BQ27421] = 0x80008000,
>> +     [BQ27425] = 0x04143672,
>> +     [BQ27441] = 0x80008000,
>> +     [BQ27621] = 0x80008000,
>> +};
>> +
>>
>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>  static bool bq27xxx_dt_to_nvm = true;
>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>               .drv_data = di,
>>       };
>>
>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>> +
>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>> +     di->chip = bq27xxx_chips[di->chip];
>
> NACK, this is a mess, you should not be using a table to change what
> chip was passed in, it may be needed later. The chip is still the same,
> it should have the same one correct ID, use a different index or array
> if you would like, but this is very hacky.

You forget that the original I2C table did this exact translation.
This isn't any more hacky than that. I do not see a better
alternative. If you do, pls draft a little code to illustrate it.

> Just stop trying to hack around it, add the extra tables, even if they
> are clones, so we can be done with this series already. I'm sure you
> want that more than you want this "clever" work-around, right?

I have simply replicated the original design, which avoided dupes in
the reg & properties tables by translating IDs in the I2C table. It's
not a work-around on my part, and I believe it's the correct scheme.

> Also fix all the checkpatch --strict warnings.

OK, but some lines are more readable over 80 chars, so I will leave them as is.

Can you take another pass or two to illuminate any remaining issues
before my next rev? I'd like it to be the last one :-)

>> +
>> +     di->regs = bq27xxx_regs[di->chip];
>> +
>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>       mutex_init(&di->lock);
>> -     di->regs = bq27xxx_regs[di->chip];
>>
>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>       if (!psy_desc)
>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>> index a597221..0b11ed4 100644
>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>       { "bq27210", BQ27010 },
>>       { "bq27500", BQ2750X },
>>       { "bq27510", BQ2751X },
>> -     { "bq27520", BQ2751X },
>> +     { "bq27520", BQ2752X },
>>       { "bq27500-1", BQ27500 },
>>       { "bq27510g1", BQ27510G1 },
>>       { "bq27510g2", BQ27510G2 },
>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>       { "bq27520g3", BQ27520G3 },
>>       { "bq27520g4", BQ27520G4 },
>>       { "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);
>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>> index 11e1168..543c10e 100644
>> --- a/include/linux/power/bq27xxx_battery.h
>> +++ b/include/linux/power/bq27xxx_battery.h
>> @@ -2,6 +2,8 @@
>>  #define __LINUX_BQ27X00_BATTERY_H__
>>
>>  enum bq27xxx_chip {
>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>> +     /* and map to themselves in bq27xxx_chips[]             */
>>       BQ27000 = 1, /* bq27000, bq27200 */
>>       BQ27010, /* bq27010, bq27210 */
>>       BQ2750X, /* bq27500 deprecated alias */
>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>       BQ27545, /* bq27545 */
>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>> +     BQ27MAX,
>> +
>> +     /* these map to above in bq27xxx_chips[] */
>> +     BQ2752X, /* deprecated alias */
>> +     BQ27531,
>> +     BQ27542,
>> +     BQ27546,
>> +     BQ27742,
>> +     BQ27425,
>> +     BQ27441,
>> +     BQ27621,
>>  };
>>
>>  /**
>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support
  2017-05-04 16:44   ` Andrew F. Davis
  2017-05-04 18:07     ` Liam Breck
@ 2017-05-05 12:45     ` Liam Breck
  2017-05-05 15:40       ` Andrew F. Davis
  1 sibling, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-05 12:45 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Matt Ranostay, Liam Breck

On Thu, May 4, 2017 at 9:44 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/04/2017 01:18 AM, Liam Breck wrote:
>> From: Liam Breck <kernel@networkimprov.net>
>>
>> Add these to enable read/write of chip data memory RAM/NVM/flash:
>>   bq27xxx_battery_seal()
>>   bq27xxx_battery_unseal()
>>   bq27xxx_battery_set_cfgupdate()
>>   bq27xxx_battery_read_dm_block()
>>   bq27xxx_battery_write_dm_block()
>>   bq27xxx_battery_checksum_dm_block()
>>
>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>> ---
>>  drivers/power/supply/bq27xxx_battery.c | 253 +++++++++++++++++++++++++++++++++
>>  include/linux/power/bq27xxx_battery.h  |   1 +
>>  2 files changed, 254 insertions(+)
>>
>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>> index a11dfad..8ab184c 100644
>> --- a/drivers/power/supply/bq27xxx_battery.c
>> +++ b/drivers/power/supply/bq27xxx_battery.c
>> @@ -5,6 +5,7 @@
>>   * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
>>   * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
>>   * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
>> + * Copyright (C) 2017 Liam Breck <kernel@networkimprov.net>
>>   *
>>   * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
>>   *
>> @@ -65,6 +66,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)
>> @@ -78,6 +80,12 @@
>>  #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_RESET                        0x41
>> +
>>  #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 */
>> @@ -108,9 +116,21 @@ enum bq27xxx_reg_index {
>>       BQ27XXX_REG_SOC,        /* State-of-Charge */
>>       BQ27XXX_REG_DCAP,       /* Design Capacity */
>>       BQ27XXX_REG_AP,         /* Average Power */
>> +     BQ27XXX_DM_CTRL,        /* Block Data Control */
>> +     BQ27XXX_DM_CLASS,       /* Data Class */
>> +     BQ27XXX_DM_BLOCK,       /* Data Block */
>> +     BQ27XXX_DM_DATA,        /* Block Data */
>> +     BQ27XXX_DM_CKSUM,       /* Block Data Checksum */
>>       BQ27XXX_REG_MAX,        /* sentinel */
>>  };
>>
>> +#define BQ27XXX_DM_REG_ROWS \
>> +     [BQ27XXX_DM_CTRL] = 0x61,  \
>> +     [BQ27XXX_DM_CLASS] = 0x3e, \
>> +     [BQ27XXX_DM_BLOCK] = 0x3f, \
>> +     [BQ27XXX_DM_DATA] = 0x40,  \
>> +     [BQ27XXX_DM_CKSUM] = 0x60
>> +
>>  /* Register mappings */
>>  static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>       [BQ27000] = {
>> @@ -131,6 +151,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,
>> @@ -150,6 +175,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,
>>       },
>>       [BQ2750X] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -169,6 +199,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ2751X] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -188,6 +219,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x20,
>>               [BQ27XXX_REG_DCAP] = 0x2e,
>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27500] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -207,6 +239,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27510G1] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -226,6 +259,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27510G2] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -245,6 +279,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27510G3] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -264,6 +299,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x20,
>>               [BQ27XXX_REG_DCAP] = 0x2e,
>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27520G1] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -283,6 +319,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27520G2] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -302,6 +339,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27520G3] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -321,6 +359,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27520G4] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -340,6 +379,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x20,
>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27530] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -359,6 +399,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27541] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -378,6 +419,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27545] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -397,6 +439,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x2c,
>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>               [BQ27XXX_REG_AP] = 0x24,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>       [BQ27421] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>> @@ -416,6 +459,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>               [BQ27XXX_REG_SOC] = 0x1c,
>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>               [BQ27XXX_REG_AP] = 0x18,
>> +             BQ27XXX_DM_REG_ROWS,
>>       },
>>  };
>>
>> @@ -757,6 +801,28 @@ static struct {
>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>  static LIST_HEAD(bq27xxx_battery_devices);
>>
>> +#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
>> +
>> +#define BQ27XXX_DM_SZ        32
>> +
>> +/**
>> + * struct bq27xxx_dm_buf - chip data memory buffer
>> + * @class: data memory subclass_id
>> + * @block: data memory block number
>> + * @data: data from/for the block
>> + * @has_data: true if data has been filled by read
>> + * @dirty: true if data has changed since last read/write
>> + *
>> + * Encapsulates info required to manage chip data memory blocks.
>> + */
>> +struct bq27xxx_dm_buf {
>> +     u8 class;
>> +     u8 block;
>> +     u8 data[BQ27XXX_DM_SZ];
>> +     bool has_data, dirty;
>> +};
>> +
>> +
>>  static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
>>  {
>>       struct bq27xxx_device_info *di;
>> @@ -864,6 +930,193 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in
>>       return ret;
>>  }
>>
>> +static int bq27xxx_battery_seal(struct bq27xxx_device_info *di)
>> +{
>> +     int ret;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_SEALED, false);
>> +     if (ret < 0) {
>> +             dev_err(di->dev, "bus error on seal: %d\n", ret);
>> +             return ret;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int bq27xxx_battery_unseal(struct bq27xxx_device_info *di)
>> +{
>> +     int ret;
>> +
>> +     if (di->unseal_key == 0) {
>> +             dev_err(di->dev, "unseal failed due to missing key\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)(di->unseal_key >> 16), false);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)di->unseal_key, false);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     return 0;
>> +
>> +out:
>> +     dev_err(di->dev, "bus error on unseal: %d\n", 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->data[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;
>> +
>> +     buf->has_data = false;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     BQ27XXX_MSLEEP(1);
>> +
>> +     ret = bq27xxx_read_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_read(di, BQ27XXX_DM_CKSUM, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {
>> +             ret = -EINVAL;
>> +             goto out;
>> +     }
>> +
>> +     buf->has_data = true;
>> +     buf->dirty = false;
>> +
>> +     return 0;
>> +
>> +out:
>> +     dev_err(di->dev, "bus error reading chip memory: %d\n", ret);
>> +     return ret;
>> +}
>> +
>> +static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
>
> Why do you pass in a flag but treat it like a bool? This whole function
> needs to be re-factored.

How's this look?


static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info
*di, bool active)
{
        const int limit = 100;
        int ret, try = limit;

        ret = bq27xxx_write(di, BQ27XXX_REG_CTRL,
                            active ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET,
                            false);
        if (ret < 0)
                return ret;

        do {
                BQ27XXX_MSLEEP(25);
                ret = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false);
                if (ret < 0)
                        return ret;
        } while (!!(ret & BQ27XXX_FLAG_CFGUP) != active && --try);

        if (!try) {
                dev_err(di->dev, "timed out waiting for cfgupdate flag
%d\n", active);
                return -EINVAL;
        }

        if (limit - try > 3)
                dev_warn(di->dev, "cfgupdate %d, retries %d\n",
active, limit - try);

        return 0;
}

static inline int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di)
{
        int ret = bq27xxx_battery_cfgupdate_priv(di, true);
        if (ret < 0 && ret != -EINVAL)
                dev_err(di->dev, "bus error on set_cfgupdate: %d\n", ret);

        return ret;
}

static inline int bq27xxx_battery_soft_reset(struct bq27xxx_device_info *di)
{
        int ret = bq27xxx_battery_cfgupdate_priv(di, false);
        if (ret < 0 && ret != -EINVAL)
                dev_err(di->dev, "bus error on soft_reset: %d\n", ret);

        return ret;
}


>> +{
>> +     const int limit = 100;
>> +     int ret, try = limit;
>> +
>> +     ret = bq27xxx_write(di, 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 (limit-try > 3)
>> +             dev_warn(di->dev, "cfgupdate %d, retries %d\n", !!state, limit-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 */
>
> Group? This is a single chip ID.
>
>> +     int ret;
>> +
>> +     if (!buf->dirty)
>> +             return 0;
>> +
>> +     if (cfgup) {
>> +             ret = bq27xxx_battery_set_cfgupdate(di, BQ27XXX_FLAG_CFGUP);
>> +             if (ret < 0)
>> +                     return ret;
>> +     }
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CTRL, 0, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     BQ27XXX_MSLEEP(1);
>> +
>> +     ret = bq27xxx_write_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CKSUM,
>> +                         bq27xxx_battery_checksum_dm_block(buf), true);
>> +     if (ret < 0)
>> +             goto out;
>> +
>> +     /* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM
>> +      * corruption on the '425 chip (and perhaps others), which can damage
>> +      * the chip. See TI bqtool for what not to do:
>> +      * http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
>> +      */
>> +
>
> Again, this is not needed, I'm sorry you fried your chip somehow but
> this program is not incorrect, it is used by our customers all the time
> and does not fry chips, drop this comment.
>
>> +     if (cfgup) {
>> +             BQ27XXX_MSLEEP(1);
>> +             ret = bq27xxx_battery_set_cfgupdate(di, 0);
>> +             if (ret < 0)
>> +                     return ret;
>> +     } else {
>> +             BQ27XXX_MSLEEP(100); /* flash DM updates in <100ms */
>> +     }
>> +
>> +     buf->dirty = false;
>> +
>> +     return 0;
>> +
>> +out:
>> +     if (cfgup)
>> +             bq27xxx_battery_set_cfgupdate(di, 0);
>> +
>> +     dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
>> +     return ret;
>> +}
>> +
>>  /*
>>   * Return the battery State-of-Charge
>>   * Or < 0 if something fails.
>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>> index c3369fa..b1defb8 100644
>> --- a/include/linux/power/bq27xxx_battery.h
>> +++ b/include/linux/power/bq27xxx_battery.h
>> @@ -64,6 +64,7 @@ struct bq27xxx_device_info {
>>       int id;
>>       enum bq27xxx_chip chip;
>>       const char *name;
>> +     u32 unseal_key;
>>       struct bq27xxx_access_methods bus;
>>       struct bq27xxx_reg_cache cache;
>>       int charge_design_full;
>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support
  2017-05-05 12:45     ` Liam Breck
@ 2017-05-05 15:40       ` Andrew F. Davis
  2017-05-05 18:44         ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-05 15:40 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Matt Ranostay, Liam Breck

On 05/05/2017 07:45 AM, Liam Breck wrote:
> On Thu, May 4, 2017 at 9:44 AM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>> From: Liam Breck <kernel@networkimprov.net>
>>>
>>> Add these to enable read/write of chip data memory RAM/NVM/flash:
>>>   bq27xxx_battery_seal()
>>>   bq27xxx_battery_unseal()
>>>   bq27xxx_battery_set_cfgupdate()
>>>   bq27xxx_battery_read_dm_block()
>>>   bq27xxx_battery_write_dm_block()
>>>   bq27xxx_battery_checksum_dm_block()
>>>
>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>> ---
>>>  drivers/power/supply/bq27xxx_battery.c | 253 +++++++++++++++++++++++++++++++++
>>>  include/linux/power/bq27xxx_battery.h  |   1 +
>>>  2 files changed, 254 insertions(+)
>>>
>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>> index a11dfad..8ab184c 100644
>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>> @@ -5,6 +5,7 @@
>>>   * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
>>>   * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
>>>   * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
>>> + * Copyright (C) 2017 Liam Breck <kernel@networkimprov.net>
>>>   *
>>>   * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
>>>   *
>>> @@ -65,6 +66,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)
>>> @@ -78,6 +80,12 @@
>>>  #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_RESET                        0x41
>>> +
>>>  #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 */
>>> @@ -108,9 +116,21 @@ enum bq27xxx_reg_index {
>>>       BQ27XXX_REG_SOC,        /* State-of-Charge */
>>>       BQ27XXX_REG_DCAP,       /* Design Capacity */
>>>       BQ27XXX_REG_AP,         /* Average Power */
>>> +     BQ27XXX_DM_CTRL,        /* Block Data Control */
>>> +     BQ27XXX_DM_CLASS,       /* Data Class */
>>> +     BQ27XXX_DM_BLOCK,       /* Data Block */
>>> +     BQ27XXX_DM_DATA,        /* Block Data */
>>> +     BQ27XXX_DM_CKSUM,       /* Block Data Checksum */
>>>       BQ27XXX_REG_MAX,        /* sentinel */
>>>  };
>>>
>>> +#define BQ27XXX_DM_REG_ROWS \
>>> +     [BQ27XXX_DM_CTRL] = 0x61,  \
>>> +     [BQ27XXX_DM_CLASS] = 0x3e, \
>>> +     [BQ27XXX_DM_BLOCK] = 0x3f, \
>>> +     [BQ27XXX_DM_DATA] = 0x40,  \
>>> +     [BQ27XXX_DM_CKSUM] = 0x60
>>> +
>>>  /* Register mappings */
>>>  static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>       [BQ27000] = {
>>> @@ -131,6 +151,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,
>>> @@ -150,6 +175,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,
>>>       },
>>>       [BQ2750X] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -169,6 +199,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ2751X] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -188,6 +219,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x20,
>>>               [BQ27XXX_REG_DCAP] = 0x2e,
>>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27500] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -207,6 +239,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>               [BQ27XXX_REG_AP] = 0x24,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27510G1] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -226,6 +259,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>               [BQ27XXX_REG_AP] = 0x24,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27510G2] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -245,6 +279,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>               [BQ27XXX_REG_AP] = 0x24,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27510G3] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -264,6 +299,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x20,
>>>               [BQ27XXX_REG_DCAP] = 0x2e,
>>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27520G1] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -283,6 +319,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>               [BQ27XXX_REG_AP] = 0x24,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27520G2] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -302,6 +339,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>               [BQ27XXX_REG_AP] = 0x24,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27520G3] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -321,6 +359,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>               [BQ27XXX_REG_AP] = 0x24,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27520G4] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -340,6 +379,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x20,
>>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27530] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -359,6 +399,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>>               [BQ27XXX_REG_AP] = 0x24,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27541] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -378,6 +419,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>               [BQ27XXX_REG_AP] = 0x24,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27545] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -397,6 +439,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>>               [BQ27XXX_REG_AP] = 0x24,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>       [BQ27421] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>> @@ -416,6 +459,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>               [BQ27XXX_REG_SOC] = 0x1c,
>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>               [BQ27XXX_REG_AP] = 0x18,
>>> +             BQ27XXX_DM_REG_ROWS,
>>>       },
>>>  };
>>>
>>> @@ -757,6 +801,28 @@ static struct {
>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>
>>> +#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
>>> +
>>> +#define BQ27XXX_DM_SZ        32
>>> +
>>> +/**
>>> + * struct bq27xxx_dm_buf - chip data memory buffer
>>> + * @class: data memory subclass_id
>>> + * @block: data memory block number
>>> + * @data: data from/for the block
>>> + * @has_data: true if data has been filled by read
>>> + * @dirty: true if data has changed since last read/write
>>> + *
>>> + * Encapsulates info required to manage chip data memory blocks.
>>> + */
>>> +struct bq27xxx_dm_buf {
>>> +     u8 class;
>>> +     u8 block;
>>> +     u8 data[BQ27XXX_DM_SZ];
>>> +     bool has_data, dirty;
>>> +};
>>> +
>>> +
>>>  static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
>>>  {
>>>       struct bq27xxx_device_info *di;
>>> @@ -864,6 +930,193 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in
>>>       return ret;
>>>  }
>>>
>>> +static int bq27xxx_battery_seal(struct bq27xxx_device_info *di)
>>> +{
>>> +     int ret;
>>> +
>>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_SEALED, false);
>>> +     if (ret < 0) {
>>> +             dev_err(di->dev, "bus error on seal: %d\n", ret);
>>> +             return ret;
>>> +     }
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int bq27xxx_battery_unseal(struct bq27xxx_device_info *di)
>>> +{
>>> +     int ret;
>>> +
>>> +     if (di->unseal_key == 0) {
>>> +             dev_err(di->dev, "unseal failed due to missing key\n");
>>> +             return -EINVAL;
>>> +     }
>>> +
>>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)(di->unseal_key >> 16), false);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)di->unseal_key, false);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     return 0;
>>> +
>>> +out:
>>> +     dev_err(di->dev, "bus error on unseal: %d\n", 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->data[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;
>>> +
>>> +     buf->has_data = false;
>>> +
>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     BQ27XXX_MSLEEP(1);
>>> +
>>> +     ret = bq27xxx_read_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     ret = bq27xxx_read(di, BQ27XXX_DM_CKSUM, true);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {
>>> +             ret = -EINVAL;
>>> +             goto out;
>>> +     }
>>> +
>>> +     buf->has_data = true;
>>> +     buf->dirty = false;
>>> +
>>> +     return 0;
>>> +
>>> +out:
>>> +     dev_err(di->dev, "bus error reading chip memory: %d\n", ret);
>>> +     return ret;
>>> +}
>>> +
>>> +static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
>>
>> Why do you pass in a flag but treat it like a bool? This whole function
>> needs to be re-factored.
> 
> How's this look?
> 

Better, how about we store the mask at the start, might improve
readability, something like this would be nice:

static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info
*di, bool active)
{
	const int limit = 100;
	int ret, try = 0;
	u16 command = active ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET;

	ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, command, false);
	if (ret < 0)
		return ret;

	do {
		BQ27XXX_MSLEEP(25);
		ret = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false);
		if (ret < 0)
			return ret;

		if (try++ > limit) {
			dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", active);
			return -EINVAL;
		}
	} while (!!(ret & BQ27XXX_FLAG_CFGUP) != active);

	return 0;
}

> 
> static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info
> *di, bool active)
> {
>         const int limit = 100;
>         int ret, try = limit;
> 
>         ret = bq27xxx_write(di, BQ27XXX_REG_CTRL,
>                             active ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET,
>                             false);
>         if (ret < 0)
>                 return ret;
> 
>         do {
>                 BQ27XXX_MSLEEP(25);
>                 ret = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false);
>                 if (ret < 0)
>                         return ret;
>         } while (!!(ret & BQ27XXX_FLAG_CFGUP) != active && --try);
> 
>         if (!try) {
>                 dev_err(di->dev, "timed out waiting for cfgupdate flag
> %d\n", active);
>                 return -EINVAL;
>         }
> 
>         if (limit - try > 3)
>                 dev_warn(di->dev, "cfgupdate %d, retries %d\n",
> active, limit - try);
> 
>         return 0;
> }
> 
> static inline int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di)
> {
>         int ret = bq27xxx_battery_cfgupdate_priv(di, true);
>         if (ret < 0 && ret != -EINVAL)
>                 dev_err(di->dev, "bus error on set_cfgupdate: %d\n", ret);
> 
>         return ret;
> }
> 
> static inline int bq27xxx_battery_soft_reset(struct bq27xxx_device_info *di)
> {
>         int ret = bq27xxx_battery_cfgupdate_priv(di, false);
>         if (ret < 0 && ret != -EINVAL)
>                 dev_err(di->dev, "bus error on soft_reset: %d\n", ret);
> 
>         return ret;
> }
> 
> 
>>> +{
>>> +     const int limit = 100;
>>> +     int ret, try = limit;
>>> +
>>> +     ret = bq27xxx_write(di, 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 (limit-try > 3)
>>> +             dev_warn(di->dev, "cfgupdate %d, retries %d\n", !!state, limit-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 */
>>
>> Group? This is a single chip ID.
>>
>>> +     int ret;
>>> +
>>> +     if (!buf->dirty)
>>> +             return 0;
>>> +
>>> +     if (cfgup) {
>>> +             ret = bq27xxx_battery_set_cfgupdate(di, BQ27XXX_FLAG_CFGUP);
>>> +             if (ret < 0)
>>> +                     return ret;
>>> +     }
>>> +
>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CTRL, 0, true);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     BQ27XXX_MSLEEP(1);
>>> +
>>> +     ret = bq27xxx_write_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CKSUM,
>>> +                         bq27xxx_battery_checksum_dm_block(buf), true);
>>> +     if (ret < 0)
>>> +             goto out;
>>> +
>>> +     /* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM
>>> +      * corruption on the '425 chip (and perhaps others), which can damage
>>> +      * the chip. See TI bqtool for what not to do:
>>> +      * http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
>>> +      */
>>> +
>>
>> Again, this is not needed, I'm sorry you fried your chip somehow but
>> this program is not incorrect, it is used by our customers all the time
>> and does not fry chips, drop this comment.
>>
>>> +     if (cfgup) {
>>> +             BQ27XXX_MSLEEP(1);
>>> +             ret = bq27xxx_battery_set_cfgupdate(di, 0);
>>> +             if (ret < 0)
>>> +                     return ret;
>>> +     } else {
>>> +             BQ27XXX_MSLEEP(100); /* flash DM updates in <100ms */
>>> +     }
>>> +
>>> +     buf->dirty = false;
>>> +
>>> +     return 0;
>>> +
>>> +out:
>>> +     if (cfgup)
>>> +             bq27xxx_battery_set_cfgupdate(di, 0);
>>> +
>>> +     dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
>>> +     return ret;
>>> +}
>>> +
>>>  /*
>>>   * Return the battery State-of-Charge
>>>   * Or < 0 if something fails.
>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>> index c3369fa..b1defb8 100644
>>> --- a/include/linux/power/bq27xxx_battery.h
>>> +++ b/include/linux/power/bq27xxx_battery.h
>>> @@ -64,6 +64,7 @@ struct bq27xxx_device_info {
>>>       int id;
>>>       enum bq27xxx_chip chip;
>>>       const char *name;
>>> +     u32 unseal_key;
>>>       struct bq27xxx_access_methods bus;
>>>       struct bq27xxx_reg_cache cache;
>>>       int charge_design_full;
>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support
  2017-05-05 15:40       ` Andrew F. Davis
@ 2017-05-05 18:44         ` Liam Breck
  0 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-05 18:44 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Matt Ranostay, Liam Breck

On Fri, May 5, 2017 at 8:40 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/05/2017 07:45 AM, Liam Breck wrote:
>> On Thu, May 4, 2017 at 9:44 AM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>
>>>> Add these to enable read/write of chip data memory RAM/NVM/flash:
>>>>   bq27xxx_battery_seal()
>>>>   bq27xxx_battery_unseal()
>>>>   bq27xxx_battery_set_cfgupdate()
>>>>   bq27xxx_battery_read_dm_block()
>>>>   bq27xxx_battery_write_dm_block()
>>>>   bq27xxx_battery_checksum_dm_block()
>>>>
>>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>> ---
>>>>  drivers/power/supply/bq27xxx_battery.c | 253 +++++++++++++++++++++++++++++++++
>>>>  include/linux/power/bq27xxx_battery.h  |   1 +
>>>>  2 files changed, 254 insertions(+)
>>>>
>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>> index a11dfad..8ab184c 100644
>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>> @@ -5,6 +5,7 @@
>>>>   * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
>>>>   * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
>>>>   * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
>>>> + * Copyright (C) 2017 Liam Breck <kernel@networkimprov.net>
>>>>   *
>>>>   * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
>>>>   *
>>>> @@ -65,6 +66,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)
>>>> @@ -78,6 +80,12 @@
>>>>  #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_RESET                        0x41
>>>> +
>>>>  #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 */
>>>> @@ -108,9 +116,21 @@ enum bq27xxx_reg_index {
>>>>       BQ27XXX_REG_SOC,        /* State-of-Charge */
>>>>       BQ27XXX_REG_DCAP,       /* Design Capacity */
>>>>       BQ27XXX_REG_AP,         /* Average Power */
>>>> +     BQ27XXX_DM_CTRL,        /* Block Data Control */
>>>> +     BQ27XXX_DM_CLASS,       /* Data Class */
>>>> +     BQ27XXX_DM_BLOCK,       /* Data Block */
>>>> +     BQ27XXX_DM_DATA,        /* Block Data */
>>>> +     BQ27XXX_DM_CKSUM,       /* Block Data Checksum */
>>>>       BQ27XXX_REG_MAX,        /* sentinel */
>>>>  };
>>>>
>>>> +#define BQ27XXX_DM_REG_ROWS \
>>>> +     [BQ27XXX_DM_CTRL] = 0x61,  \
>>>> +     [BQ27XXX_DM_CLASS] = 0x3e, \
>>>> +     [BQ27XXX_DM_BLOCK] = 0x3f, \
>>>> +     [BQ27XXX_DM_DATA] = 0x40,  \
>>>> +     [BQ27XXX_DM_CKSUM] = 0x60
>>>> +
>>>>  /* Register mappings */
>>>>  static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>       [BQ27000] = {
>>>> @@ -131,6 +151,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,
>>>> @@ -150,6 +175,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,
>>>>       },
>>>>       [BQ2750X] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -169,6 +199,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ2751X] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -188,6 +219,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x20,
>>>>               [BQ27XXX_REG_DCAP] = 0x2e,
>>>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27500] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -207,6 +239,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>>               [BQ27XXX_REG_AP] = 0x24,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27510G1] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -226,6 +259,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>>               [BQ27XXX_REG_AP] = 0x24,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27510G2] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -245,6 +279,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>>               [BQ27XXX_REG_AP] = 0x24,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27510G3] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -264,6 +299,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x20,
>>>>               [BQ27XXX_REG_DCAP] = 0x2e,
>>>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27520G1] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -283,6 +319,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>>               [BQ27XXX_REG_AP] = 0x24,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27520G2] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -302,6 +339,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>>               [BQ27XXX_REG_AP] = 0x24,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27520G3] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -321,6 +359,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>>               [BQ27XXX_REG_AP] = 0x24,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27520G4] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -340,6 +379,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x20,
>>>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>>>               [BQ27XXX_REG_AP] = INVALID_REG_ADDR,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27530] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -359,6 +399,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>>>               [BQ27XXX_REG_AP] = 0x24,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27541] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -378,6 +419,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>>               [BQ27XXX_REG_AP] = 0x24,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27545] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -397,6 +439,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x2c,
>>>>               [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR,
>>>>               [BQ27XXX_REG_AP] = 0x24,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>       [BQ27421] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>> @@ -416,6 +459,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>               [BQ27XXX_REG_SOC] = 0x1c,
>>>>               [BQ27XXX_REG_DCAP] = 0x3c,
>>>>               [BQ27XXX_REG_AP] = 0x18,
>>>> +             BQ27XXX_DM_REG_ROWS,
>>>>       },
>>>>  };
>>>>
>>>> @@ -757,6 +801,28 @@ static struct {
>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>
>>>> +#define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500)
>>>> +
>>>> +#define BQ27XXX_DM_SZ        32
>>>> +
>>>> +/**
>>>> + * struct bq27xxx_dm_buf - chip data memory buffer
>>>> + * @class: data memory subclass_id
>>>> + * @block: data memory block number
>>>> + * @data: data from/for the block
>>>> + * @has_data: true if data has been filled by read
>>>> + * @dirty: true if data has changed since last read/write
>>>> + *
>>>> + * Encapsulates info required to manage chip data memory blocks.
>>>> + */
>>>> +struct bq27xxx_dm_buf {
>>>> +     u8 class;
>>>> +     u8 block;
>>>> +     u8 data[BQ27XXX_DM_SZ];
>>>> +     bool has_data, dirty;
>>>> +};
>>>> +
>>>> +
>>>>  static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
>>>>  {
>>>>       struct bq27xxx_device_info *di;
>>>> @@ -864,6 +930,193 @@ static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_in
>>>>       return ret;
>>>>  }
>>>>
>>>> +static int bq27xxx_battery_seal(struct bq27xxx_device_info *di)
>>>> +{
>>>> +     int ret;
>>>> +
>>>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_SEALED, false);
>>>> +     if (ret < 0) {
>>>> +             dev_err(di->dev, "bus error on seal: %d\n", ret);
>>>> +             return ret;
>>>> +     }
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int bq27xxx_battery_unseal(struct bq27xxx_device_info *di)
>>>> +{
>>>> +     int ret;
>>>> +
>>>> +     if (di->unseal_key == 0) {
>>>> +             dev_err(di->dev, "unseal failed due to missing key\n");
>>>> +             return -EINVAL;
>>>> +     }
>>>> +
>>>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)(di->unseal_key >> 16), false);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)di->unseal_key, false);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     return 0;
>>>> +
>>>> +out:
>>>> +     dev_err(di->dev, "bus error on unseal: %d\n", 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->data[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;
>>>> +
>>>> +     buf->has_data = false;
>>>> +
>>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     BQ27XXX_MSLEEP(1);
>>>> +
>>>> +     ret = bq27xxx_read_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     ret = bq27xxx_read(di, BQ27XXX_DM_CKSUM, true);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) {
>>>> +             ret = -EINVAL;
>>>> +             goto out;
>>>> +     }
>>>> +
>>>> +     buf->has_data = true;
>>>> +     buf->dirty = false;
>>>> +
>>>> +     return 0;
>>>> +
>>>> +out:
>>>> +     dev_err(di->dev, "bus error reading chip memory: %d\n", ret);
>>>> +     return ret;
>>>> +}
>>>> +
>>>> +static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
>>>
>>> Why do you pass in a flag but treat it like a bool? This whole function
>>> needs to be re-factored.
>>
>> How's this look?
>>
>
> Better, how about we store the mask at the start, might improve
> readability, something like this would be nice:

Sure, will do.

> static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info
> *di, bool active)
> {
>         const int limit = 100;
>         int ret, try = 0;
>         u16 command = active ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET;
>
>         ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, command, false);
>         if (ret < 0)
>                 return ret;
>
>         do {
>                 BQ27XXX_MSLEEP(25);
>                 ret = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false);
>                 if (ret < 0)
>                         return ret;
>
>                 if (try++ > limit) {
>                         dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", active);
>                         return -EINVAL;
>                 }
>         } while (!!(ret & BQ27XXX_FLAG_CFGUP) != active);
>
>         return 0;
> }
>
>>
>> static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info
>> *di, bool active)
>> {
>>         const int limit = 100;
>>         int ret, try = limit;
>>
>>         ret = bq27xxx_write(di, BQ27XXX_REG_CTRL,
>>                             active ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET,
>>                             false);
>>         if (ret < 0)
>>                 return ret;
>>
>>         do {
>>                 BQ27XXX_MSLEEP(25);
>>                 ret = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false);
>>                 if (ret < 0)
>>                         return ret;
>>         } while (!!(ret & BQ27XXX_FLAG_CFGUP) != active && --try);
>>
>>         if (!try) {
>>                 dev_err(di->dev, "timed out waiting for cfgupdate flag
>> %d\n", active);
>>                 return -EINVAL;
>>         }
>>
>>         if (limit - try > 3)
>>                 dev_warn(di->dev, "cfgupdate %d, retries %d\n",
>> active, limit - try);
>>
>>         return 0;
>> }
>>
>> static inline int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di)
>> {
>>         int ret = bq27xxx_battery_cfgupdate_priv(di, true);
>>         if (ret < 0 && ret != -EINVAL)
>>                 dev_err(di->dev, "bus error on set_cfgupdate: %d\n", ret);
>>
>>         return ret;
>> }
>>
>> static inline int bq27xxx_battery_soft_reset(struct bq27xxx_device_info *di)
>> {
>>         int ret = bq27xxx_battery_cfgupdate_priv(di, false);
>>         if (ret < 0 && ret != -EINVAL)
>>                 dev_err(di->dev, "bus error on soft_reset: %d\n", ret);
>>
>>         return ret;
>> }
>>
>>
>>>> +{
>>>> +     const int limit = 100;
>>>> +     int ret, try = limit;
>>>> +
>>>> +     ret = bq27xxx_write(di, 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 (limit-try > 3)
>>>> +             dev_warn(di->dev, "cfgupdate %d, retries %d\n", !!state, limit-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 */
>>>
>>> Group? This is a single chip ID.
>>>
>>>> +     int ret;
>>>> +
>>>> +     if (!buf->dirty)
>>>> +             return 0;
>>>> +
>>>> +     if (cfgup) {
>>>> +             ret = bq27xxx_battery_set_cfgupdate(di, BQ27XXX_FLAG_CFGUP);
>>>> +             if (ret < 0)
>>>> +                     return ret;
>>>> +     }
>>>> +
>>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CTRL, 0, true);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     BQ27XXX_MSLEEP(1);
>>>> +
>>>> +     ret = bq27xxx_write_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     ret = bq27xxx_write(di, BQ27XXX_DM_CKSUM,
>>>> +                         bq27xxx_battery_checksum_dm_block(buf), true);
>>>> +     if (ret < 0)
>>>> +             goto out;
>>>> +
>>>> +     /* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM
>>>> +      * corruption on the '425 chip (and perhaps others), which can damage
>>>> +      * the chip. See TI bqtool for what not to do:
>>>> +      * http://git.ti.com/bms-linux/bqtool/blobs/master/gauge.c#line328
>>>> +      */
>>>> +
>>>
>>> Again, this is not needed, I'm sorry you fried your chip somehow but
>>> this program is not incorrect, it is used by our customers all the time
>>> and does not fry chips, drop this comment.
>>>
>>>> +     if (cfgup) {
>>>> +             BQ27XXX_MSLEEP(1);
>>>> +             ret = bq27xxx_battery_set_cfgupdate(di, 0);
>>>> +             if (ret < 0)
>>>> +                     return ret;
>>>> +     } else {
>>>> +             BQ27XXX_MSLEEP(100); /* flash DM updates in <100ms */
>>>> +     }
>>>> +
>>>> +     buf->dirty = false;
>>>> +
>>>> +     return 0;
>>>> +
>>>> +out:
>>>> +     if (cfgup)
>>>> +             bq27xxx_battery_set_cfgupdate(di, 0);
>>>> +
>>>> +     dev_err(di->dev, "bus error writing chip memory: %d\n", ret);
>>>> +     return ret;
>>>> +}
>>>> +
>>>>  /*
>>>>   * Return the battery State-of-Charge
>>>>   * Or < 0 if something fails.
>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>> index c3369fa..b1defb8 100644
>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>> @@ -64,6 +64,7 @@ struct bq27xxx_device_info {
>>>>       int id;
>>>>       enum bq27xxx_chip chip;
>>>>       const char *name;
>>>> +     u32 unseal_key;
>>>>       struct bq27xxx_access_methods bus;
>>>>       struct bq27xxx_reg_cache cache;
>>>>       int charge_design_full;
>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-04 17:00   ` Andrew F. Davis
  2017-05-04 19:12     ` Liam Breck
@ 2017-05-05 19:31     ` Liam Breck
  2017-05-05 19:45       ` Andrew F. Davis
  1 sibling, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-05 19:31 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/04/2017 01:18 AM, Liam Breck wrote:
>> From: Liam Breck <kernel@networkimprov.net>
>>
>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>
>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>> and data memory register tables.
>>
>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>> ---
>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>> index 06f15da..0aecd41 100644
>> --- a/drivers/power/supply/bq27xxx_battery.c
>> +++ b/drivers/power/supply/bq27xxx_battery.c
>> @@ -58,7 +58,7 @@
>>
>>  #include <linux/power/bq27xxx_battery.h>
>>
>> -#define DRIVER_VERSION               "1.2.0"
>> +#define DRIVER_VERSION               "1.3.0"
>>
>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>
>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>       [BQ27XXX_DM_CKSUM] = 0x60
>>
>>  /* Register mappings */
>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>       [BQ27000] = {
>>               [BQ27XXX_REG_CTRL] = 0x00,
>>               [BQ27XXX_REG_TEMP] = 0x06,
>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>  static struct {
>>       enum power_supply_property *props;
>>       size_t size;
>> -} bq27xxx_battery_props[] = {
>> +} bq27xxx_battery_props[BQ27MAX] = {
>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>> @@ -798,6 +798,33 @@ static struct {
>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>  };
>>
>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>> +     [BQ27000]   = BQ27000,
>> +     [BQ27010]   = BQ27010,
>> +     [BQ2750X]   = BQ2750X,
>> +     [BQ2751X]   = BQ2751X,
>> +     [BQ2752X]   = BQ2751X,
>> +     [BQ27500]   = BQ27500,
>> +     [BQ27510G1] = BQ27510G1,
>> +     [BQ27510G2] = BQ27510G2,
>> +     [BQ27510G3] = BQ27510G3,
>> +     [BQ27520G1] = BQ27520G1,
>> +     [BQ27520G2] = BQ27520G2,
>> +     [BQ27520G3] = BQ27520G3,
>> +     [BQ27520G4] = BQ27520G4,
>> +     [BQ27530]   = BQ27530,
>> +     [BQ27531]   = BQ27530,
>> +     [BQ27541]   = BQ27541,
>> +     [BQ27542]   = BQ27541,
>> +     [BQ27546]   = BQ27541,
>> +     [BQ27742]   = BQ27541,
>> +     [BQ27545]   = BQ27545,
>> +     [BQ27421]   = BQ27421,
>> +     [BQ27425]   = BQ27421,
>> +     [BQ27441]   = BQ27421,
>> +     [BQ27621]   = BQ27421,
>> +};
>> +
>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>  static LIST_HEAD(bq27xxx_battery_devices);
>>
>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>> +     [BQ27500] = bq27500_dm_regs,
>> +     [BQ27545] = bq27545_dm_regs,
>> +     [BQ27421] = bq27421_dm_regs,
>> +     [BQ27425] = bq27425_dm_regs,
>> +     [BQ27441] = bq27421_dm_regs,
>> +     [BQ27621] = bq27621_dm_regs,
>> +};
>> +
>> +static u32 bq27xxx_unseal_keys[] = {
>> +     [BQ27500] = 0x04143672,
>> +     [BQ27545] = 0x04143672,
>> +     [BQ27421] = 0x80008000,
>> +     [BQ27425] = 0x04143672,
>> +     [BQ27441] = 0x80008000,
>> +     [BQ27621] = 0x80008000,
>> +};
>> +
>>
>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>  static bool bq27xxx_dt_to_nvm = true;
>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>               .drv_data = di,
>>       };
>>
>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>> +
>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>> +     di->chip = bq27xxx_chips[di->chip];
>
> NACK, this is a mess, you should not be using a table to change what
> chip was passed in, it may be needed later. The chip is still the same,
> it should have the same one correct ID, use a different index or array
> if you would like, but this is very hacky.

The only way I see to make the I2C subsystem deliver multiple IDs for
a device is to treat i2c_device_id.driver_data as a u16[2] instead of
its normal u32. What do you think of that?


> Just stop trying to hack around it, add the extra tables, even if they
> are clones, so we can be done with this series already. I'm sure you
> want that more than you want this "clever" work-around, right?
>
> Also fix all the checkpatch --strict warnings.
>
>> +
>> +     di->regs = bq27xxx_regs[di->chip];
>> +
>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>       mutex_init(&di->lock);
>> -     di->regs = bq27xxx_regs[di->chip];
>>
>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>       if (!psy_desc)
>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>> index a597221..0b11ed4 100644
>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>       { "bq27210", BQ27010 },
>>       { "bq27500", BQ2750X },
>>       { "bq27510", BQ2751X },
>> -     { "bq27520", BQ2751X },
>> +     { "bq27520", BQ2752X },
>>       { "bq27500-1", BQ27500 },
>>       { "bq27510g1", BQ27510G1 },
>>       { "bq27510g2", BQ27510G2 },
>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>       { "bq27520g3", BQ27520G3 },
>>       { "bq27520g4", BQ27520G4 },
>>       { "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);
>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>> index 11e1168..543c10e 100644
>> --- a/include/linux/power/bq27xxx_battery.h
>> +++ b/include/linux/power/bq27xxx_battery.h
>> @@ -2,6 +2,8 @@
>>  #define __LINUX_BQ27X00_BATTERY_H__
>>
>>  enum bq27xxx_chip {
>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>> +     /* and map to themselves in bq27xxx_chips[]             */
>>       BQ27000 = 1, /* bq27000, bq27200 */
>>       BQ27010, /* bq27010, bq27210 */
>>       BQ2750X, /* bq27500 deprecated alias */
>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>       BQ27545, /* bq27545 */
>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>> +     BQ27MAX,
>> +
>> +     /* these map to above in bq27xxx_chips[] */
>> +     BQ2752X, /* deprecated alias */
>> +     BQ27531,
>> +     BQ27542,
>> +     BQ27546,
>> +     BQ27742,
>> +     BQ27425,
>> +     BQ27441,
>> +     BQ27621,
>>  };
>>
>>  /**
>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-05 19:31     ` Liam Breck
@ 2017-05-05 19:45       ` Andrew F. Davis
  2017-05-05 20:14         ` Liam Breck
  2017-05-08  6:40         ` Liam Breck
  0 siblings, 2 replies; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-05 19:45 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/05/2017 02:31 PM, Liam Breck wrote:
> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>> From: Liam Breck <kernel@networkimprov.net>
>>>
>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>
>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>> and data memory register tables.
>>>
>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>> ---
>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>> index 06f15da..0aecd41 100644
>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>> @@ -58,7 +58,7 @@
>>>
>>>  #include <linux/power/bq27xxx_battery.h>
>>>
>>> -#define DRIVER_VERSION               "1.2.0"
>>> +#define DRIVER_VERSION               "1.3.0"
>>>
>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>
>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>
>>>  /* Register mappings */
>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>       [BQ27000] = {
>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>  static struct {
>>>       enum power_supply_property *props;
>>>       size_t size;
>>> -} bq27xxx_battery_props[] = {
>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>> @@ -798,6 +798,33 @@ static struct {
>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>  };
>>>
>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>> +     [BQ27000]   = BQ27000,
>>> +     [BQ27010]   = BQ27010,
>>> +     [BQ2750X]   = BQ2750X,
>>> +     [BQ2751X]   = BQ2751X,
>>> +     [BQ2752X]   = BQ2751X,
>>> +     [BQ27500]   = BQ27500,
>>> +     [BQ27510G1] = BQ27510G1,
>>> +     [BQ27510G2] = BQ27510G2,
>>> +     [BQ27510G3] = BQ27510G3,
>>> +     [BQ27520G1] = BQ27520G1,
>>> +     [BQ27520G2] = BQ27520G2,
>>> +     [BQ27520G3] = BQ27520G3,
>>> +     [BQ27520G4] = BQ27520G4,
>>> +     [BQ27530]   = BQ27530,
>>> +     [BQ27531]   = BQ27530,
>>> +     [BQ27541]   = BQ27541,
>>> +     [BQ27542]   = BQ27541,
>>> +     [BQ27546]   = BQ27541,
>>> +     [BQ27742]   = BQ27541,
>>> +     [BQ27545]   = BQ27545,
>>> +     [BQ27421]   = BQ27421,
>>> +     [BQ27425]   = BQ27421,
>>> +     [BQ27441]   = BQ27421,
>>> +     [BQ27621]   = BQ27421,
>>> +};
>>> +
>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>
>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>> +     [BQ27500] = bq27500_dm_regs,
>>> +     [BQ27545] = bq27545_dm_regs,
>>> +     [BQ27421] = bq27421_dm_regs,
>>> +     [BQ27425] = bq27425_dm_regs,
>>> +     [BQ27441] = bq27421_dm_regs,
>>> +     [BQ27621] = bq27621_dm_regs,
>>> +};
>>> +
>>> +static u32 bq27xxx_unseal_keys[] = {
>>> +     [BQ27500] = 0x04143672,
>>> +     [BQ27545] = 0x04143672,
>>> +     [BQ27421] = 0x80008000,
>>> +     [BQ27425] = 0x04143672,
>>> +     [BQ27441] = 0x80008000,
>>> +     [BQ27621] = 0x80008000,
>>> +};
>>> +
>>>
>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>  static bool bq27xxx_dt_to_nvm = true;
>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>               .drv_data = di,
>>>       };
>>>
>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>> +
>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>> +     di->chip = bq27xxx_chips[di->chip];
>>
>> NACK, this is a mess, you should not be using a table to change what
>> chip was passed in, it may be needed later. The chip is still the same,
>> it should have the same one correct ID, use a different index or array
>> if you would like, but this is very hacky.
> 
> The only way I see to make the I2C subsystem deliver multiple IDs for
> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
> its normal u32. What do you think of that?
> 

Why would it need multiple IDs for one device? Just pass in the one
correct device ID that it is. No reason to make this so complicated.
>From the one ID you can then use tables to lookup any other info about
that device, you don't have to have ever ID populated in every table,
you can even have a table of tables if you would like:

static const struct chip_lookup lookup_table = {
	[bq27425] = {
		.regs = &bq27xxx_regs[bq27425],
		.dm_regs = &bq27xxx_dm_regs[bq274xx],
		.unseal_key = INVALID_FOR_THIS_DEVICE,
	},
	[bq27343] = {
...

Not sure if that is valid C but I think you can get the idea.

> 
>> Just stop trying to hack around it, add the extra tables, even if they
>> are clones, so we can be done with this series already. I'm sure you
>> want that more than you want this "clever" work-around, right?
>>
>> Also fix all the checkpatch --strict warnings.
>>
>>> +
>>> +     di->regs = bq27xxx_regs[di->chip];
>>> +
>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>       mutex_init(&di->lock);
>>> -     di->regs = bq27xxx_regs[di->chip];
>>>
>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>       if (!psy_desc)
>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>> index a597221..0b11ed4 100644
>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>       { "bq27210", BQ27010 },
>>>       { "bq27500", BQ2750X },
>>>       { "bq27510", BQ2751X },
>>> -     { "bq27520", BQ2751X },
>>> +     { "bq27520", BQ2752X },
>>>       { "bq27500-1", BQ27500 },
>>>       { "bq27510g1", BQ27510G1 },
>>>       { "bq27510g2", BQ27510G2 },
>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>       { "bq27520g3", BQ27520G3 },
>>>       { "bq27520g4", BQ27520G4 },
>>>       { "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);
>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>> index 11e1168..543c10e 100644
>>> --- a/include/linux/power/bq27xxx_battery.h
>>> +++ b/include/linux/power/bq27xxx_battery.h
>>> @@ -2,6 +2,8 @@
>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>
>>>  enum bq27xxx_chip {
>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>       BQ27010, /* bq27010, bq27210 */
>>>       BQ2750X, /* bq27500 deprecated alias */
>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>       BQ27545, /* bq27545 */
>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>> +     BQ27MAX,
>>> +
>>> +     /* these map to above in bq27xxx_chips[] */
>>> +     BQ2752X, /* deprecated alias */
>>> +     BQ27531,
>>> +     BQ27542,
>>> +     BQ27546,
>>> +     BQ27742,
>>> +     BQ27425,
>>> +     BQ27441,
>>> +     BQ27621,
>>>  };
>>>
>>>  /**
>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-05 19:45       ` Andrew F. Davis
@ 2017-05-05 20:14         ` Liam Breck
  2017-05-05 20:44           ` Andrew F. Davis
  2017-05-08  6:40         ` Liam Breck
  1 sibling, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-05 20:14 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/05/2017 02:31 PM, Liam Breck wrote:
>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>
>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>
>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>> and data memory register tables.
>>>>
>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>> ---
>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>
>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>> index 06f15da..0aecd41 100644
>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>> @@ -58,7 +58,7 @@
>>>>
>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>
>>>> -#define DRIVER_VERSION               "1.2.0"
>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>
>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>
>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>
>>>>  /* Register mappings */
>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>       [BQ27000] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>  static struct {
>>>>       enum power_supply_property *props;
>>>>       size_t size;
>>>> -} bq27xxx_battery_props[] = {
>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>> @@ -798,6 +798,33 @@ static struct {
>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>  };
>>>>
>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>> +     [BQ27000]   = BQ27000,
>>>> +     [BQ27010]   = BQ27010,
>>>> +     [BQ2750X]   = BQ2750X,
>>>> +     [BQ2751X]   = BQ2751X,
>>>> +     [BQ2752X]   = BQ2751X,
>>>> +     [BQ27500]   = BQ27500,
>>>> +     [BQ27510G1] = BQ27510G1,
>>>> +     [BQ27510G2] = BQ27510G2,
>>>> +     [BQ27510G3] = BQ27510G3,
>>>> +     [BQ27520G1] = BQ27520G1,
>>>> +     [BQ27520G2] = BQ27520G2,
>>>> +     [BQ27520G3] = BQ27520G3,
>>>> +     [BQ27520G4] = BQ27520G4,
>>>> +     [BQ27530]   = BQ27530,
>>>> +     [BQ27531]   = BQ27530,
>>>> +     [BQ27541]   = BQ27541,
>>>> +     [BQ27542]   = BQ27541,
>>>> +     [BQ27546]   = BQ27541,
>>>> +     [BQ27742]   = BQ27541,
>>>> +     [BQ27545]   = BQ27545,
>>>> +     [BQ27421]   = BQ27421,
>>>> +     [BQ27425]   = BQ27421,
>>>> +     [BQ27441]   = BQ27421,
>>>> +     [BQ27621]   = BQ27421,
>>>> +};
>>>> +
>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>
>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>> +     [BQ27500] = bq27500_dm_regs,
>>>> +     [BQ27545] = bq27545_dm_regs,
>>>> +     [BQ27421] = bq27421_dm_regs,
>>>> +     [BQ27425] = bq27425_dm_regs,
>>>> +     [BQ27441] = bq27421_dm_regs,
>>>> +     [BQ27621] = bq27621_dm_regs,
>>>> +};
>>>> +
>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>> +     [BQ27500] = 0x04143672,
>>>> +     [BQ27545] = 0x04143672,
>>>> +     [BQ27421] = 0x80008000,
>>>> +     [BQ27425] = 0x04143672,
>>>> +     [BQ27441] = 0x80008000,
>>>> +     [BQ27621] = 0x80008000,
>>>> +};
>>>> +
>>>>
>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>               .drv_data = di,
>>>>       };
>>>>
>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>> +
>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>
>>> NACK, this is a mess, you should not be using a table to change what
>>> chip was passed in, it may be needed later. The chip is still the same,
>>> it should have the same one correct ID, use a different index or array
>>> if you would like, but this is very hacky.
>>
>> The only way I see to make the I2C subsystem deliver multiple IDs for
>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>> its normal u32. What do you think of that?
>>
>
> Why would it need multiple IDs for one device? Just pass in the one
> correct device ID that it is. No reason to make this so complicated.

Take a look at bq27xxx_i2c_id_table[] here:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/drivers/power/supply/bq27xxx_battery_i2c.c?h=linux-4.11.y#n148

Notice how this table maps certain chips to the same IDs. I am going
to preserve that scheme, as changing it is outside the scope of this
series.

So the only question is how to deliver the "real" ID to the driver. In
v13, I change the I2C table to deliver real-ID, and replicate the
mapping of the orig I2C table in bq27xxx_chips[]. Now I propose to
make the I2C table carry two values, chip-ID and real-ID. Then we can
drop bq27xxx_chips[].

Hope that clarifies the issue...

> From the one ID you can then use tables to lookup any other info about
> that device, you don't have to have ever ID populated in every table,
> you can even have a table of tables if you would like:
>
> static const struct chip_lookup lookup_table = {
>         [bq27425] = {
>                 .regs = &bq27xxx_regs[bq27425],
>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>         },
>         [bq27343] = {
> ...
>
> Not sure if that is valid C but I think you can get the idea.
>
>>
>>> Just stop trying to hack around it, add the extra tables, even if they
>>> are clones, so we can be done with this series already. I'm sure you
>>> want that more than you want this "clever" work-around, right?
>>>
>>> Also fix all the checkpatch --strict warnings.
>>>
>>>> +
>>>> +     di->regs = bq27xxx_regs[di->chip];
>>>> +
>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>       mutex_init(&di->lock);
>>>> -     di->regs = bq27xxx_regs[di->chip];
>>>>
>>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>>       if (!psy_desc)
>>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>> index a597221..0b11ed4 100644
>>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>       { "bq27210", BQ27010 },
>>>>       { "bq27500", BQ2750X },
>>>>       { "bq27510", BQ2751X },
>>>> -     { "bq27520", BQ2751X },
>>>> +     { "bq27520", BQ2752X },
>>>>       { "bq27500-1", BQ27500 },
>>>>       { "bq27510g1", BQ27510G1 },
>>>>       { "bq27510g2", BQ27510G2 },
>>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>       { "bq27520g3", BQ27520G3 },
>>>>       { "bq27520g4", BQ27520G4 },
>>>>       { "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);
>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>> index 11e1168..543c10e 100644
>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>> @@ -2,6 +2,8 @@
>>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>>
>>>>  enum bq27xxx_chip {
>>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>>       BQ27010, /* bq27010, bq27210 */
>>>>       BQ2750X, /* bq27500 deprecated alias */
>>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>>       BQ27545, /* bq27545 */
>>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>>> +     BQ27MAX,
>>>> +
>>>> +     /* these map to above in bq27xxx_chips[] */
>>>> +     BQ2752X, /* deprecated alias */
>>>> +     BQ27531,
>>>> +     BQ27542,
>>>> +     BQ27546,
>>>> +     BQ27742,
>>>> +     BQ27425,
>>>> +     BQ27441,
>>>> +     BQ27621,
>>>>  };
>>>>
>>>>  /**
>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-05 20:14         ` Liam Breck
@ 2017-05-05 20:44           ` Andrew F. Davis
  2017-05-05 20:55             ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-05 20:44 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/05/2017 03:14 PM, Liam Breck wrote:
> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>
>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>
>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>> and data memory register tables.
>>>>>
>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>> ---
>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>
>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>> index 06f15da..0aecd41 100644
>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>> @@ -58,7 +58,7 @@
>>>>>
>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>
>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>
>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>
>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>
>>>>>  /* Register mappings */
>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>       [BQ27000] = {
>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>  static struct {
>>>>>       enum power_supply_property *props;
>>>>>       size_t size;
>>>>> -} bq27xxx_battery_props[] = {
>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>  };
>>>>>
>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>> +     [BQ27000]   = BQ27000,
>>>>> +     [BQ27010]   = BQ27010,
>>>>> +     [BQ2750X]   = BQ2750X,
>>>>> +     [BQ2751X]   = BQ2751X,
>>>>> +     [BQ2752X]   = BQ2751X,
>>>>> +     [BQ27500]   = BQ27500,
>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>> +     [BQ27530]   = BQ27530,
>>>>> +     [BQ27531]   = BQ27530,
>>>>> +     [BQ27541]   = BQ27541,
>>>>> +     [BQ27542]   = BQ27541,
>>>>> +     [BQ27546]   = BQ27541,
>>>>> +     [BQ27742]   = BQ27541,
>>>>> +     [BQ27545]   = BQ27545,
>>>>> +     [BQ27421]   = BQ27421,
>>>>> +     [BQ27425]   = BQ27421,
>>>>> +     [BQ27441]   = BQ27421,
>>>>> +     [BQ27621]   = BQ27421,
>>>>> +};
>>>>> +
>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>
>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>> +};
>>>>> +
>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>> +     [BQ27500] = 0x04143672,
>>>>> +     [BQ27545] = 0x04143672,
>>>>> +     [BQ27421] = 0x80008000,
>>>>> +     [BQ27425] = 0x04143672,
>>>>> +     [BQ27441] = 0x80008000,
>>>>> +     [BQ27621] = 0x80008000,
>>>>> +};
>>>>> +
>>>>>
>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>               .drv_data = di,
>>>>>       };
>>>>>
>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>> +
>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>
>>>> NACK, this is a mess, you should not be using a table to change what
>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>> it should have the same one correct ID, use a different index or array
>>>> if you would like, but this is very hacky.
>>>
>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>> its normal u32. What do you think of that?
>>>
>>
>> Why would it need multiple IDs for one device? Just pass in the one
>> correct device ID that it is. No reason to make this so complicated.
> 
> Take a look at bq27xxx_i2c_id_table[] here:
> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/drivers/power/supply/bq27xxx_battery_i2c.c?h=linux-4.11.y#n148
> 
> Notice how this table maps certain chips to the same IDs. I am going
> to preserve that scheme, as changing it is outside the scope of this
> series.
> 

You can't just say doing something the right is "outside the scope of
this series" then hack something together...

Fixing this should be trivial anyway, add the new IDs, pass the real IDs
in, then add the translation table so you don't have to add any new
entries to bq27xxx_regs.

> So the only question is how to deliver the "real" ID to the driver. In
> v13, I change the I2C table to deliver real-ID, and replicate the
> mapping of the orig I2C table in bq27xxx_chips[]. Now I propose to
> make the I2C table carry two values, chip-ID and real-ID. Then we can
> drop bq27xxx_chips[].
> 
> Hope that clarifies the issue...
> 
>> From the one ID you can then use tables to lookup any other info about
>> that device, you don't have to have ever ID populated in every table,
>> you can even have a table of tables if you would like:
>>
>> static const struct chip_lookup lookup_table = {
>>         [bq27425] = {
>>                 .regs = &bq27xxx_regs[bq27425],
>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>         },
>>         [bq27343] = {
>> ...
>>
>> Not sure if that is valid C but I think you can get the idea.
>>
>>>
>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>> are clones, so we can be done with this series already. I'm sure you
>>>> want that more than you want this "clever" work-around, right?
>>>>
>>>> Also fix all the checkpatch --strict warnings.
>>>>
>>>>> +
>>>>> +     di->regs = bq27xxx_regs[di->chip];
>>>>> +
>>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>>       mutex_init(&di->lock);
>>>>> -     di->regs = bq27xxx_regs[di->chip];
>>>>>
>>>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>>>       if (!psy_desc)
>>>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>> index a597221..0b11ed4 100644
>>>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>       { "bq27210", BQ27010 },
>>>>>       { "bq27500", BQ2750X },
>>>>>       { "bq27510", BQ2751X },
>>>>> -     { "bq27520", BQ2751X },
>>>>> +     { "bq27520", BQ2752X },
>>>>>       { "bq27500-1", BQ27500 },
>>>>>       { "bq27510g1", BQ27510G1 },
>>>>>       { "bq27510g2", BQ27510G2 },
>>>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>       { "bq27520g3", BQ27520G3 },
>>>>>       { "bq27520g4", BQ27520G4 },
>>>>>       { "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);
>>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>>> index 11e1168..543c10e 100644
>>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>>> @@ -2,6 +2,8 @@
>>>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>>>
>>>>>  enum bq27xxx_chip {
>>>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>>>       BQ27010, /* bq27010, bq27210 */
>>>>>       BQ2750X, /* bq27500 deprecated alias */
>>>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>>>       BQ27545, /* bq27545 */
>>>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>>>> +     BQ27MAX,
>>>>> +
>>>>> +     /* these map to above in bq27xxx_chips[] */
>>>>> +     BQ2752X, /* deprecated alias */
>>>>> +     BQ27531,
>>>>> +     BQ27542,
>>>>> +     BQ27546,
>>>>> +     BQ27742,
>>>>> +     BQ27425,
>>>>> +     BQ27441,
>>>>> +     BQ27621,
>>>>>  };
>>>>>
>>>>>  /**
>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-05 20:44           ` Andrew F. Davis
@ 2017-05-05 20:55             ` Liam Breck
  2017-05-05 21:04               ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-05 20:55 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Fri, May 5, 2017 at 1:44 PM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/05/2017 03:14 PM, Liam Breck wrote:
>> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>
>>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>>
>>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>>> and data memory register tables.
>>>>>>
>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>> ---
>>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>> index 06f15da..0aecd41 100644
>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>> @@ -58,7 +58,7 @@
>>>>>>
>>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>>
>>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>>
>>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>>
>>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>>
>>>>>>  /* Register mappings */
>>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>>       [BQ27000] = {
>>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>>  static struct {
>>>>>>       enum power_supply_property *props;
>>>>>>       size_t size;
>>>>>> -} bq27xxx_battery_props[] = {
>>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>>  };
>>>>>>
>>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>>> +     [BQ27000]   = BQ27000,
>>>>>> +     [BQ27010]   = BQ27010,
>>>>>> +     [BQ2750X]   = BQ2750X,
>>>>>> +     [BQ2751X]   = BQ2751X,
>>>>>> +     [BQ2752X]   = BQ2751X,
>>>>>> +     [BQ27500]   = BQ27500,
>>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>>> +     [BQ27530]   = BQ27530,
>>>>>> +     [BQ27531]   = BQ27530,
>>>>>> +     [BQ27541]   = BQ27541,
>>>>>> +     [BQ27542]   = BQ27541,
>>>>>> +     [BQ27546]   = BQ27541,
>>>>>> +     [BQ27742]   = BQ27541,
>>>>>> +     [BQ27545]   = BQ27545,
>>>>>> +     [BQ27421]   = BQ27421,
>>>>>> +     [BQ27425]   = BQ27421,
>>>>>> +     [BQ27441]   = BQ27421,
>>>>>> +     [BQ27621]   = BQ27421,
>>>>>> +};
>>>>>> +
>>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>
>>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>>> +};
>>>>>> +
>>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>>> +     [BQ27500] = 0x04143672,
>>>>>> +     [BQ27545] = 0x04143672,
>>>>>> +     [BQ27421] = 0x80008000,
>>>>>> +     [BQ27425] = 0x04143672,
>>>>>> +     [BQ27441] = 0x80008000,
>>>>>> +     [BQ27621] = 0x80008000,
>>>>>> +};
>>>>>> +
>>>>>>
>>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>>               .drv_data = di,
>>>>>>       };
>>>>>>
>>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>> +
>>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>>
>>>>> NACK, this is a mess, you should not be using a table to change what
>>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>>> it should have the same one correct ID, use a different index or array
>>>>> if you would like, but this is very hacky.
>>>>
>>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>>> its normal u32. What do you think of that?
>>>>
>>>
>>> Why would it need multiple IDs for one device? Just pass in the one
>>> correct device ID that it is. No reason to make this so complicated.
>>
>> Take a look at bq27xxx_i2c_id_table[] here:
>> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/drivers/power/supply/bq27xxx_battery_i2c.c?h=linux-4.11.y#n148
>>
>> Notice how this table maps certain chips to the same IDs. I am going
>> to preserve that scheme, as changing it is outside the scope of this
>> series.
>>
>
> You can't just say doing something the right is "outside the scope of
> this series" then hack something together...
>
> Fixing this should be trivial anyway, add the new IDs, pass the real IDs
> in, then add the translation table so you don't have to add any new
> entries to bq27xxx_regs.

That is *precisely* what I do in v13. Except I don't store real-ID in
a di field because there isn't a use for it. Add that later if you
need it.

bq27xxx_chips[] is the translation table. However we could unify that
with the I2C table by placing two values in its driver_data field, and
I think that's cleaner.


>> So the only question is how to deliver the "real" ID to the driver. In
>> v13, I change the I2C table to deliver real-ID, and replicate the
>> mapping of the orig I2C table in bq27xxx_chips[]. Now I propose to
>> make the I2C table carry two values, chip-ID and real-ID. Then we can
>> drop bq27xxx_chips[].
>>
>> Hope that clarifies the issue...
>>
>>> From the one ID you can then use tables to lookup any other info about
>>> that device, you don't have to have ever ID populated in every table,
>>> you can even have a table of tables if you would like:
>>>
>>> static const struct chip_lookup lookup_table = {
>>>         [bq27425] = {
>>>                 .regs = &bq27xxx_regs[bq27425],
>>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>>         },
>>>         [bq27343] = {
>>> ...
>>>
>>> Not sure if that is valid C but I think you can get the idea.
>>>
>>>>
>>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>>> are clones, so we can be done with this series already. I'm sure you
>>>>> want that more than you want this "clever" work-around, right?
>>>>>
>>>>> Also fix all the checkpatch --strict warnings.
>>>>>
>>>>>> +
>>>>>> +     di->regs = bq27xxx_regs[di->chip];
>>>>>> +
>>>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>>>       mutex_init(&di->lock);
>>>>>> -     di->regs = bq27xxx_regs[di->chip];
>>>>>>
>>>>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>>>>       if (!psy_desc)
>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>> index a597221..0b11ed4 100644
>>>>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>       { "bq27210", BQ27010 },
>>>>>>       { "bq27500", BQ2750X },
>>>>>>       { "bq27510", BQ2751X },
>>>>>> -     { "bq27520", BQ2751X },
>>>>>> +     { "bq27520", BQ2752X },
>>>>>>       { "bq27500-1", BQ27500 },
>>>>>>       { "bq27510g1", BQ27510G1 },
>>>>>>       { "bq27510g2", BQ27510G2 },
>>>>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>       { "bq27520g3", BQ27520G3 },
>>>>>>       { "bq27520g4", BQ27520G4 },
>>>>>>       { "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);
>>>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>>>> index 11e1168..543c10e 100644
>>>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>>>> @@ -2,6 +2,8 @@
>>>>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>>>>
>>>>>>  enum bq27xxx_chip {
>>>>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>>>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>>>>       BQ27010, /* bq27010, bq27210 */
>>>>>>       BQ2750X, /* bq27500 deprecated alias */
>>>>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>>>>       BQ27545, /* bq27545 */
>>>>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>>>>> +     BQ27MAX,
>>>>>> +
>>>>>> +     /* these map to above in bq27xxx_chips[] */
>>>>>> +     BQ2752X, /* deprecated alias */
>>>>>> +     BQ27531,
>>>>>> +     BQ27542,
>>>>>> +     BQ27546,
>>>>>> +     BQ27742,
>>>>>> +     BQ27425,
>>>>>> +     BQ27441,
>>>>>> +     BQ27621,
>>>>>>  };
>>>>>>
>>>>>>  /**
>>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-05 20:55             ` Liam Breck
@ 2017-05-05 21:04               ` Andrew F. Davis
  2017-05-05 21:27                 ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-05 21:04 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/05/2017 03:55 PM, Liam Breck wrote:
> On Fri, May 5, 2017 at 1:44 PM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/05/2017 03:14 PM, Liam Breck wrote:
>>> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>
>>>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>>>
>>>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>>>> and data memory register tables.
>>>>>>>
>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>> ---
>>>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>> index 06f15da..0aecd41 100644
>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>> @@ -58,7 +58,7 @@
>>>>>>>
>>>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>>>
>>>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>>>
>>>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>>>
>>>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>>>
>>>>>>>  /* Register mappings */
>>>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>>>       [BQ27000] = {
>>>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>>>  static struct {
>>>>>>>       enum power_supply_property *props;
>>>>>>>       size_t size;
>>>>>>> -} bq27xxx_battery_props[] = {
>>>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>>>  };
>>>>>>>
>>>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>>>> +     [BQ27000]   = BQ27000,
>>>>>>> +     [BQ27010]   = BQ27010,
>>>>>>> +     [BQ2750X]   = BQ2750X,
>>>>>>> +     [BQ2751X]   = BQ2751X,
>>>>>>> +     [BQ2752X]   = BQ2751X,
>>>>>>> +     [BQ27500]   = BQ27500,
>>>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>>>> +     [BQ27530]   = BQ27530,
>>>>>>> +     [BQ27531]   = BQ27530,
>>>>>>> +     [BQ27541]   = BQ27541,
>>>>>>> +     [BQ27542]   = BQ27541,
>>>>>>> +     [BQ27546]   = BQ27541,
>>>>>>> +     [BQ27742]   = BQ27541,
>>>>>>> +     [BQ27545]   = BQ27545,
>>>>>>> +     [BQ27421]   = BQ27421,
>>>>>>> +     [BQ27425]   = BQ27421,
>>>>>>> +     [BQ27441]   = BQ27421,
>>>>>>> +     [BQ27621]   = BQ27421,
>>>>>>> +};
>>>>>>> +
>>>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>
>>>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>>>> +};
>>>>>>> +
>>>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>>>> +     [BQ27500] = 0x04143672,
>>>>>>> +     [BQ27545] = 0x04143672,
>>>>>>> +     [BQ27421] = 0x80008000,
>>>>>>> +     [BQ27425] = 0x04143672,
>>>>>>> +     [BQ27441] = 0x80008000,
>>>>>>> +     [BQ27621] = 0x80008000,
>>>>>>> +};
>>>>>>> +
>>>>>>>
>>>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>>>               .drv_data = di,
>>>>>>>       };
>>>>>>>
>>>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>>> +
>>>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>>>
>>>>>> NACK, this is a mess, you should not be using a table to change what
>>>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>>>> it should have the same one correct ID, use a different index or array
>>>>>> if you would like, but this is very hacky.
>>>>>
>>>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>>>> its normal u32. What do you think of that?
>>>>>
>>>>
>>>> Why would it need multiple IDs for one device? Just pass in the one
>>>> correct device ID that it is. No reason to make this so complicated.
>>>
>>> Take a look at bq27xxx_i2c_id_table[] here:
>>> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/drivers/power/supply/bq27xxx_battery_i2c.c?h=linux-4.11.y#n148
>>>
>>> Notice how this table maps certain chips to the same IDs. I am going
>>> to preserve that scheme, as changing it is outside the scope of this
>>> series.
>>>
>>
>> You can't just say doing something the right is "outside the scope of
>> this series" then hack something together...
>>
>> Fixing this should be trivial anyway, add the new IDs, pass the real IDs
>> in, then add the translation table so you don't have to add any new
>> entries to bq27xxx_regs.
> 
> That is *precisely* what I do in v13. Except I don't store real-ID in
> a di field because there isn't a use for it. Add that later if you
> need it.
> 

The first two yes, but it's the type of translation that doesn't look
good, we should go from lookup_table[realID]->whatever_values. With this
we are mapping realID -> fakeID then later whatever_values_table[fakeID].

So if you barrow the "struct chip_lookup lookup_table" below then we end
up with only two mapping types (table_lookup and values tables) and no
translations needed.

> bq27xxx_chips[] is the translation table. However we could unify that
> with the I2C table by placing two values in its driver_data field, and
> I think that's cleaner.
> 
> 
>>> So the only question is how to deliver the "real" ID to the driver. In
>>> v13, I change the I2C table to deliver real-ID, and replicate the
>>> mapping of the orig I2C table in bq27xxx_chips[]. Now I propose to
>>> make the I2C table carry two values, chip-ID and real-ID. Then we can
>>> drop bq27xxx_chips[].
>>>
>>> Hope that clarifies the issue...
>>>
>>>> From the one ID you can then use tables to lookup any other info about
>>>> that device, you don't have to have ever ID populated in every table,
>>>> you can even have a table of tables if you would like:
>>>>
>>>> static const struct chip_lookup lookup_table = {
>>>>         [bq27425] = {
>>>>                 .regs = &bq27xxx_regs[bq27425],
>>>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>>>         },
>>>>         [bq27343] = {
>>>> ...
>>>>
>>>> Not sure if that is valid C but I think you can get the idea.
>>>>
>>>>>
>>>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>>>> are clones, so we can be done with this series already. I'm sure you
>>>>>> want that more than you want this "clever" work-around, right?
>>>>>>
>>>>>> Also fix all the checkpatch --strict warnings.
>>>>>>
>>>>>>> +
>>>>>>> +     di->regs = bq27xxx_regs[di->chip];
>>>>>>> +
>>>>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>>>>       mutex_init(&di->lock);
>>>>>>> -     di->regs = bq27xxx_regs[di->chip];
>>>>>>>
>>>>>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>>>>>       if (!psy_desc)
>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>> index a597221..0b11ed4 100644
>>>>>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>>       { "bq27210", BQ27010 },
>>>>>>>       { "bq27500", BQ2750X },
>>>>>>>       { "bq27510", BQ2751X },
>>>>>>> -     { "bq27520", BQ2751X },
>>>>>>> +     { "bq27520", BQ2752X },
>>>>>>>       { "bq27500-1", BQ27500 },
>>>>>>>       { "bq27510g1", BQ27510G1 },
>>>>>>>       { "bq27510g2", BQ27510G2 },
>>>>>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>>       { "bq27520g3", BQ27520G3 },
>>>>>>>       { "bq27520g4", BQ27520G4 },
>>>>>>>       { "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);
>>>>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>>>>> index 11e1168..543c10e 100644
>>>>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>>>>> @@ -2,6 +2,8 @@
>>>>>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>>>>>
>>>>>>>  enum bq27xxx_chip {
>>>>>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>>>>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>>>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>>>>>       BQ27010, /* bq27010, bq27210 */
>>>>>>>       BQ2750X, /* bq27500 deprecated alias */
>>>>>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>>>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>>>>>       BQ27545, /* bq27545 */
>>>>>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>>>>>> +     BQ27MAX,
>>>>>>> +
>>>>>>> +     /* these map to above in bq27xxx_chips[] */
>>>>>>> +     BQ2752X, /* deprecated alias */
>>>>>>> +     BQ27531,
>>>>>>> +     BQ27542,
>>>>>>> +     BQ27546,
>>>>>>> +     BQ27742,
>>>>>>> +     BQ27425,
>>>>>>> +     BQ27441,
>>>>>>> +     BQ27621,
>>>>>>>  };
>>>>>>>
>>>>>>>  /**
>>>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-05 21:04               ` Andrew F. Davis
@ 2017-05-05 21:27                 ` Liam Breck
  2017-05-05 21:29                   ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-05 21:27 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Fri, May 5, 2017 at 2:04 PM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/05/2017 03:55 PM, Liam Breck wrote:
>> On Fri, May 5, 2017 at 1:44 PM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/05/2017 03:14 PM, Liam Breck wrote:
>>>> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>>>>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>>>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>>
>>>>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>>>>
>>>>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>>>>> and data memory register tables.
>>>>>>>>
>>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>>> ---
>>>>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>> index 06f15da..0aecd41 100644
>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>> @@ -58,7 +58,7 @@
>>>>>>>>
>>>>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>>>>
>>>>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>>>>
>>>>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>>>>
>>>>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>>>>
>>>>>>>>  /* Register mappings */
>>>>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>>>>       [BQ27000] = {
>>>>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>>>>  static struct {
>>>>>>>>       enum power_supply_property *props;
>>>>>>>>       size_t size;
>>>>>>>> -} bq27xxx_battery_props[] = {
>>>>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>>>>  };
>>>>>>>>
>>>>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>>>>> +     [BQ27000]   = BQ27000,
>>>>>>>> +     [BQ27010]   = BQ27010,
>>>>>>>> +     [BQ2750X]   = BQ2750X,
>>>>>>>> +     [BQ2751X]   = BQ2751X,
>>>>>>>> +     [BQ2752X]   = BQ2751X,
>>>>>>>> +     [BQ27500]   = BQ27500,
>>>>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>>>>> +     [BQ27530]   = BQ27530,
>>>>>>>> +     [BQ27531]   = BQ27530,
>>>>>>>> +     [BQ27541]   = BQ27541,
>>>>>>>> +     [BQ27542]   = BQ27541,
>>>>>>>> +     [BQ27546]   = BQ27541,
>>>>>>>> +     [BQ27742]   = BQ27541,
>>>>>>>> +     [BQ27545]   = BQ27545,
>>>>>>>> +     [BQ27421]   = BQ27421,
>>>>>>>> +     [BQ27425]   = BQ27421,
>>>>>>>> +     [BQ27441]   = BQ27421,
>>>>>>>> +     [BQ27621]   = BQ27421,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>>
>>>>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>>>>> +     [BQ27500] = 0x04143672,
>>>>>>>> +     [BQ27545] = 0x04143672,
>>>>>>>> +     [BQ27421] = 0x80008000,
>>>>>>>> +     [BQ27425] = 0x04143672,
>>>>>>>> +     [BQ27441] = 0x80008000,
>>>>>>>> +     [BQ27621] = 0x80008000,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>>
>>>>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>>>>               .drv_data = di,
>>>>>>>>       };
>>>>>>>>
>>>>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>>>> +
>>>>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>>>>
>>>>>>> NACK, this is a mess, you should not be using a table to change what
>>>>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>>>>> it should have the same one correct ID, use a different index or array
>>>>>>> if you would like, but this is very hacky.
>>>>>>
>>>>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>>>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>>>>> its normal u32. What do you think of that?
>>>>>>
>>>>>
>>>>> Why would it need multiple IDs for one device? Just pass in the one
>>>>> correct device ID that it is. No reason to make this so complicated.
>>>>
>>>> Take a look at bq27xxx_i2c_id_table[] here:
>>>> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/drivers/power/supply/bq27xxx_battery_i2c.c?h=linux-4.11.y#n148
>>>>
>>>> Notice how this table maps certain chips to the same IDs. I am going
>>>> to preserve that scheme, as changing it is outside the scope of this
>>>> series.
>>>>
>>>
>>> You can't just say doing something the right is "outside the scope of
>>> this series" then hack something together...
>>>
>>> Fixing this should be trivial anyway, add the new IDs, pass the real IDs
>>> in, then add the translation table so you don't have to add any new
>>> entries to bq27xxx_regs.
>>
>> That is *precisely* what I do in v13. Except I don't store real-ID in
>> a di field because there isn't a use for it. Add that later if you
>> need it.
>>
>
> The first two yes, but it's the type of translation that doesn't look
> good, we should go from lookup_table[realID]->whatever_values. With this
> we are mapping realID -> fakeID then later whatever_values_table[fakeID].
>
> So if you barrow the "struct chip_lookup lookup_table" below then we end
> up with only two mapping types (table_lookup and values tables) and no
> translations needed.

If we deliver two values in I2C driver_data, the lookup code will be
this, and we don't need an extra table:

       di->unseal_key = bq27xxx_unseal_keys[di->real_chip];
       di->dm_regs = bq27xxx_dm_regs[di->real_chip];

       di->regs = bq27xxx_regs[di->chip];


>> bq27xxx_chips[] is the translation table. However we could unify that
>> with the I2C table by placing two values in its driver_data field, and
>> I think that's cleaner.
>>
>>
>>>> So the only question is how to deliver the "real" ID to the driver. In
>>>> v13, I change the I2C table to deliver real-ID, and replicate the
>>>> mapping of the orig I2C table in bq27xxx_chips[]. Now I propose to
>>>> make the I2C table carry two values, chip-ID and real-ID. Then we can
>>>> drop bq27xxx_chips[].
>>>>
>>>> Hope that clarifies the issue...
>>>>
>>>>> From the one ID you can then use tables to lookup any other info about
>>>>> that device, you don't have to have ever ID populated in every table,
>>>>> you can even have a table of tables if you would like:
>>>>>
>>>>> static const struct chip_lookup lookup_table = {
>>>>>         [bq27425] = {
>>>>>                 .regs = &bq27xxx_regs[bq27425],
>>>>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>>>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>>>>         },
>>>>>         [bq27343] = {
>>>>> ...
>>>>>
>>>>> Not sure if that is valid C but I think you can get the idea.
>>>>>
>>>>>>
>>>>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>>>>> are clones, so we can be done with this series already. I'm sure you
>>>>>>> want that more than you want this "clever" work-around, right?
>>>>>>>
>>>>>>> Also fix all the checkpatch --strict warnings.
>>>>>>>
>>>>>>>> +
>>>>>>>> +     di->regs = bq27xxx_regs[di->chip];
>>>>>>>> +
>>>>>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>>>>>       mutex_init(&di->lock);
>>>>>>>> -     di->regs = bq27xxx_regs[di->chip];
>>>>>>>>
>>>>>>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>>>>>>       if (!psy_desc)
>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>>> index a597221..0b11ed4 100644
>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>>>       { "bq27210", BQ27010 },
>>>>>>>>       { "bq27500", BQ2750X },
>>>>>>>>       { "bq27510", BQ2751X },
>>>>>>>> -     { "bq27520", BQ2751X },
>>>>>>>> +     { "bq27520", BQ2752X },
>>>>>>>>       { "bq27500-1", BQ27500 },
>>>>>>>>       { "bq27510g1", BQ27510G1 },
>>>>>>>>       { "bq27510g2", BQ27510G2 },
>>>>>>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>>>       { "bq27520g3", BQ27520G3 },
>>>>>>>>       { "bq27520g4", BQ27520G4 },
>>>>>>>>       { "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);
>>>>>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>>>>>> index 11e1168..543c10e 100644
>>>>>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>>>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>>>>>> @@ -2,6 +2,8 @@
>>>>>>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>>>>>>
>>>>>>>>  enum bq27xxx_chip {
>>>>>>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>>>>>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>>>>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>>>>>>       BQ27010, /* bq27010, bq27210 */
>>>>>>>>       BQ2750X, /* bq27500 deprecated alias */
>>>>>>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>>>>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>>>>>>       BQ27545, /* bq27545 */
>>>>>>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>>>>>>> +     BQ27MAX,
>>>>>>>> +
>>>>>>>> +     /* these map to above in bq27xxx_chips[] */
>>>>>>>> +     BQ2752X, /* deprecated alias */
>>>>>>>> +     BQ27531,
>>>>>>>> +     BQ27542,
>>>>>>>> +     BQ27546,
>>>>>>>> +     BQ27742,
>>>>>>>> +     BQ27425,
>>>>>>>> +     BQ27441,
>>>>>>>> +     BQ27621,
>>>>>>>>  };
>>>>>>>>
>>>>>>>>  /**
>>>>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-05 21:27                 ` Liam Breck
@ 2017-05-05 21:29                   ` Andrew F. Davis
  2017-05-05 21:38                     ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-05 21:29 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/05/2017 04:27 PM, Liam Breck wrote:
> On Fri, May 5, 2017 at 2:04 PM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/05/2017 03:55 PM, Liam Breck wrote:
>>> On Fri, May 5, 2017 at 1:44 PM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/05/2017 03:14 PM, Liam Breck wrote:
>>>>> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>>>>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>>>
>>>>>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>>>>>
>>>>>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>>>>>> and data memory register tables.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>>>> ---
>>>>>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>> index 06f15da..0aecd41 100644
>>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>> @@ -58,7 +58,7 @@
>>>>>>>>>
>>>>>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>>>>>
>>>>>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>>>>>
>>>>>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>>>>>
>>>>>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>>>>>
>>>>>>>>>  /* Register mappings */
>>>>>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>>>>>       [BQ27000] = {
>>>>>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>>>>>  static struct {
>>>>>>>>>       enum power_supply_property *props;
>>>>>>>>>       size_t size;
>>>>>>>>> -} bq27xxx_battery_props[] = {
>>>>>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>>>>>  };
>>>>>>>>>
>>>>>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>>>>>> +     [BQ27000]   = BQ27000,
>>>>>>>>> +     [BQ27010]   = BQ27010,
>>>>>>>>> +     [BQ2750X]   = BQ2750X,
>>>>>>>>> +     [BQ2751X]   = BQ2751X,
>>>>>>>>> +     [BQ2752X]   = BQ2751X,
>>>>>>>>> +     [BQ27500]   = BQ27500,
>>>>>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>>>>>> +     [BQ27530]   = BQ27530,
>>>>>>>>> +     [BQ27531]   = BQ27530,
>>>>>>>>> +     [BQ27541]   = BQ27541,
>>>>>>>>> +     [BQ27542]   = BQ27541,
>>>>>>>>> +     [BQ27546]   = BQ27541,
>>>>>>>>> +     [BQ27742]   = BQ27541,
>>>>>>>>> +     [BQ27545]   = BQ27545,
>>>>>>>>> +     [BQ27421]   = BQ27421,
>>>>>>>>> +     [BQ27425]   = BQ27421,
>>>>>>>>> +     [BQ27441]   = BQ27421,
>>>>>>>>> +     [BQ27621]   = BQ27421,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>>>
>>>>>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>>>>>> +     [BQ27500] = 0x04143672,
>>>>>>>>> +     [BQ27545] = 0x04143672,
>>>>>>>>> +     [BQ27421] = 0x80008000,
>>>>>>>>> +     [BQ27425] = 0x04143672,
>>>>>>>>> +     [BQ27441] = 0x80008000,
>>>>>>>>> +     [BQ27621] = 0x80008000,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>>
>>>>>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>>>>>               .drv_data = di,
>>>>>>>>>       };
>>>>>>>>>
>>>>>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>>>>> +
>>>>>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>>>>>
>>>>>>>> NACK, this is a mess, you should not be using a table to change what
>>>>>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>>>>>> it should have the same one correct ID, use a different index or array
>>>>>>>> if you would like, but this is very hacky.
>>>>>>>
>>>>>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>>>>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>>>>>> its normal u32. What do you think of that?
>>>>>>>
>>>>>>
>>>>>> Why would it need multiple IDs for one device? Just pass in the one
>>>>>> correct device ID that it is. No reason to make this so complicated.
>>>>>
>>>>> Take a look at bq27xxx_i2c_id_table[] here:
>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/drivers/power/supply/bq27xxx_battery_i2c.c?h=linux-4.11.y#n148
>>>>>
>>>>> Notice how this table maps certain chips to the same IDs. I am going
>>>>> to preserve that scheme, as changing it is outside the scope of this
>>>>> series.
>>>>>
>>>>
>>>> You can't just say doing something the right is "outside the scope of
>>>> this series" then hack something together...
>>>>
>>>> Fixing this should be trivial anyway, add the new IDs, pass the real IDs
>>>> in, then add the translation table so you don't have to add any new
>>>> entries to bq27xxx_regs.
>>>
>>> That is *precisely* what I do in v13. Except I don't store real-ID in
>>> a di field because there isn't a use for it. Add that later if you
>>> need it.
>>>
>>
>> The first two yes, but it's the type of translation that doesn't look
>> good, we should go from lookup_table[realID]->whatever_values. With this
>> we are mapping realID -> fakeID then later whatever_values_table[fakeID].
>>
>> So if you barrow the "struct chip_lookup lookup_table" below then we end
>> up with only two mapping types (table_lookup and values tables) and no
>> translations needed.
> 
> If we deliver two values in I2C driver_data, the lookup code will be
> this, and we don't need an extra table:
> 

Sure, but why should the I2C driver have to know anything about how the
core works or what tables it does and does not have index IDs for? It
should only pass in the real ID.

>        di->unseal_key = bq27xxx_unseal_keys[di->real_chip];
>        di->dm_regs = bq27xxx_dm_regs[di->real_chip];
> 
>        di->regs = bq27xxx_regs[di->chip];
> 
> 
>>> bq27xxx_chips[] is the translation table. However we could unify that
>>> with the I2C table by placing two values in its driver_data field, and
>>> I think that's cleaner.
>>>
>>>
>>>>> So the only question is how to deliver the "real" ID to the driver. In
>>>>> v13, I change the I2C table to deliver real-ID, and replicate the
>>>>> mapping of the orig I2C table in bq27xxx_chips[]. Now I propose to
>>>>> make the I2C table carry two values, chip-ID and real-ID. Then we can
>>>>> drop bq27xxx_chips[].
>>>>>
>>>>> Hope that clarifies the issue...
>>>>>
>>>>>> From the one ID you can then use tables to lookup any other info about
>>>>>> that device, you don't have to have ever ID populated in every table,
>>>>>> you can even have a table of tables if you would like:
>>>>>>
>>>>>> static const struct chip_lookup lookup_table = {
>>>>>>         [bq27425] = {
>>>>>>                 .regs = &bq27xxx_regs[bq27425],
>>>>>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>>>>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>>>>>         },
>>>>>>         [bq27343] = {
>>>>>> ...
>>>>>>
>>>>>> Not sure if that is valid C but I think you can get the idea.
>>>>>>
>>>>>>>
>>>>>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>>>>>> are clones, so we can be done with this series already. I'm sure you
>>>>>>>> want that more than you want this "clever" work-around, right?
>>>>>>>>
>>>>>>>> Also fix all the checkpatch --strict warnings.
>>>>>>>>
>>>>>>>>> +
>>>>>>>>> +     di->regs = bq27xxx_regs[di->chip];
>>>>>>>>> +
>>>>>>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>>>>>>       mutex_init(&di->lock);
>>>>>>>>> -     di->regs = bq27xxx_regs[di->chip];
>>>>>>>>>
>>>>>>>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>>>>>>>       if (!psy_desc)
>>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>>>> index a597221..0b11ed4 100644
>>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>>>>       { "bq27210", BQ27010 },
>>>>>>>>>       { "bq27500", BQ2750X },
>>>>>>>>>       { "bq27510", BQ2751X },
>>>>>>>>> -     { "bq27520", BQ2751X },
>>>>>>>>> +     { "bq27520", BQ2752X },
>>>>>>>>>       { "bq27500-1", BQ27500 },
>>>>>>>>>       { "bq27510g1", BQ27510G1 },
>>>>>>>>>       { "bq27510g2", BQ27510G2 },
>>>>>>>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>>>>       { "bq27520g3", BQ27520G3 },
>>>>>>>>>       { "bq27520g4", BQ27520G4 },
>>>>>>>>>       { "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);
>>>>>>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>>>>>>> index 11e1168..543c10e 100644
>>>>>>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>>>>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>>>>>>> @@ -2,6 +2,8 @@
>>>>>>>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>>>>>>>
>>>>>>>>>  enum bq27xxx_chip {
>>>>>>>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>>>>>>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>>>>>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>>>>>>>       BQ27010, /* bq27010, bq27210 */
>>>>>>>>>       BQ2750X, /* bq27500 deprecated alias */
>>>>>>>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>>>>>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>>>>>>>       BQ27545, /* bq27545 */
>>>>>>>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>>>>>>>> +     BQ27MAX,
>>>>>>>>> +
>>>>>>>>> +     /* these map to above in bq27xxx_chips[] */
>>>>>>>>> +     BQ2752X, /* deprecated alias */
>>>>>>>>> +     BQ27531,
>>>>>>>>> +     BQ27542,
>>>>>>>>> +     BQ27546,
>>>>>>>>> +     BQ27742,
>>>>>>>>> +     BQ27425,
>>>>>>>>> +     BQ27441,
>>>>>>>>> +     BQ27621,
>>>>>>>>>  };
>>>>>>>>>
>>>>>>>>>  /**
>>>>>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-05 21:29                   ` Andrew F. Davis
@ 2017-05-05 21:38                     ` Liam Breck
  0 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-05 21:38 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Fri, May 5, 2017 at 2:29 PM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/05/2017 04:27 PM, Liam Breck wrote:
>> On Fri, May 5, 2017 at 2:04 PM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/05/2017 03:55 PM, Liam Breck wrote:
>>>> On Fri, May 5, 2017 at 1:44 PM, Andrew F. Davis <afd@ti.com> wrote:
>>>>> On 05/05/2017 03:14 PM, Liam Breck wrote:
>>>>>> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>>>>>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>>>>
>>>>>>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>>>>>>
>>>>>>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>>>>>>> and data memory register tables.
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>>>>> ---
>>>>>>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>>> index 06f15da..0aecd41 100644
>>>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>>> @@ -58,7 +58,7 @@
>>>>>>>>>>
>>>>>>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>>>>>>
>>>>>>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>>>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>>>>>>
>>>>>>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>>>>>>
>>>>>>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>>>>>>
>>>>>>>>>>  /* Register mappings */
>>>>>>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>>>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>>>>>>       [BQ27000] = {
>>>>>>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>>>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>>>>>>  static struct {
>>>>>>>>>>       enum power_supply_property *props;
>>>>>>>>>>       size_t size;
>>>>>>>>>> -} bq27xxx_battery_props[] = {
>>>>>>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>>>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>>>>>>  };
>>>>>>>>>>
>>>>>>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>>>>>>> +     [BQ27000]   = BQ27000,
>>>>>>>>>> +     [BQ27010]   = BQ27010,
>>>>>>>>>> +     [BQ2750X]   = BQ2750X,
>>>>>>>>>> +     [BQ2751X]   = BQ2751X,
>>>>>>>>>> +     [BQ2752X]   = BQ2751X,
>>>>>>>>>> +     [BQ27500]   = BQ27500,
>>>>>>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>>>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>>>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>>>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>>>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>>>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>>>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>>>>>>> +     [BQ27530]   = BQ27530,
>>>>>>>>>> +     [BQ27531]   = BQ27530,
>>>>>>>>>> +     [BQ27541]   = BQ27541,
>>>>>>>>>> +     [BQ27542]   = BQ27541,
>>>>>>>>>> +     [BQ27546]   = BQ27541,
>>>>>>>>>> +     [BQ27742]   = BQ27541,
>>>>>>>>>> +     [BQ27545]   = BQ27545,
>>>>>>>>>> +     [BQ27421]   = BQ27421,
>>>>>>>>>> +     [BQ27425]   = BQ27421,
>>>>>>>>>> +     [BQ27441]   = BQ27421,
>>>>>>>>>> +     [BQ27621]   = BQ27421,
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>>>>
>>>>>>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>>>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>>>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>>>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>>>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>>>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>>>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>>>>>>> +     [BQ27500] = 0x04143672,
>>>>>>>>>> +     [BQ27545] = 0x04143672,
>>>>>>>>>> +     [BQ27421] = 0x80008000,
>>>>>>>>>> +     [BQ27425] = 0x04143672,
>>>>>>>>>> +     [BQ27441] = 0x80008000,
>>>>>>>>>> +     [BQ27621] = 0x80008000,
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>>
>>>>>>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>>>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>>>>>>               .drv_data = di,
>>>>>>>>>>       };
>>>>>>>>>>
>>>>>>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>>>>>> +
>>>>>>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>>>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>>>>>>
>>>>>>>>> NACK, this is a mess, you should not be using a table to change what
>>>>>>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>>>>>>> it should have the same one correct ID, use a different index or array
>>>>>>>>> if you would like, but this is very hacky.
>>>>>>>>
>>>>>>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>>>>>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>>>>>>> its normal u32. What do you think of that?
>>>>>>>>
>>>>>>>
>>>>>>> Why would it need multiple IDs for one device? Just pass in the one
>>>>>>> correct device ID that it is. No reason to make this so complicated.
>>>>>>
>>>>>> Take a look at bq27xxx_i2c_id_table[] here:
>>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/drivers/power/supply/bq27xxx_battery_i2c.c?h=linux-4.11.y#n148
>>>>>>
>>>>>> Notice how this table maps certain chips to the same IDs. I am going
>>>>>> to preserve that scheme, as changing it is outside the scope of this
>>>>>> series.
>>>>>>
>>>>>
>>>>> You can't just say doing something the right is "outside the scope of
>>>>> this series" then hack something together...
>>>>>
>>>>> Fixing this should be trivial anyway, add the new IDs, pass the real IDs
>>>>> in, then add the translation table so you don't have to add any new
>>>>> entries to bq27xxx_regs.
>>>>
>>>> That is *precisely* what I do in v13. Except I don't store real-ID in
>>>> a di field because there isn't a use for it. Add that later if you
>>>> need it.
>>>>
>>>
>>> The first two yes, but it's the type of translation that doesn't look
>>> good, we should go from lookup_table[realID]->whatever_values. With this
>>> we are mapping realID -> fakeID then later whatever_values_table[fakeID].
>>>
>>> So if you barrow the "struct chip_lookup lookup_table" below then we end
>>> up with only two mapping types (table_lookup and values tables) and no
>>> translations needed.
>>
>> If we deliver two values in I2C driver_data, the lookup code will be
>> this, and we don't need an extra table:
>>
>
> Sure, but why should the I2C driver have to know anything about how the
> core works or what tables it does and does not have index IDs for? It
> should only pass in the real ID.

It's already mapping certain IDs to others. We need to leave that as
is. Remember, IDs are not just table indexes, they also select
behavior, so di->chip has to keep its current value.

It's easy to extend it to deliver a real-ID along with the orig value.
That will simplify the patch.




>>        di->unseal_key = bq27xxx_unseal_keys[di->real_chip];
>>        di->dm_regs = bq27xxx_dm_regs[di->real_chip];
>>
>>        di->regs = bq27xxx_regs[di->chip];
>>
>>
>>>> bq27xxx_chips[] is the translation table. However we could unify that
>>>> with the I2C table by placing two values in its driver_data field, and
>>>> I think that's cleaner.
>>>>
>>>>
>>>>>> So the only question is how to deliver the "real" ID to the driver. In
>>>>>> v13, I change the I2C table to deliver real-ID, and replicate the
>>>>>> mapping of the orig I2C table in bq27xxx_chips[]. Now I propose to
>>>>>> make the I2C table carry two values, chip-ID and real-ID. Then we can
>>>>>> drop bq27xxx_chips[].
>>>>>>
>>>>>> Hope that clarifies the issue...
>>>>>>
>>>>>>> From the one ID you can then use tables to lookup any other info about
>>>>>>> that device, you don't have to have ever ID populated in every table,
>>>>>>> you can even have a table of tables if you would like:
>>>>>>>
>>>>>>> static const struct chip_lookup lookup_table = {
>>>>>>>         [bq27425] = {
>>>>>>>                 .regs = &bq27xxx_regs[bq27425],
>>>>>>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>>>>>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>>>>>>         },
>>>>>>>         [bq27343] = {
>>>>>>> ...
>>>>>>>
>>>>>>> Not sure if that is valid C but I think you can get the idea.
>>>>>>>
>>>>>>>>
>>>>>>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>>>>>>> are clones, so we can be done with this series already. I'm sure you
>>>>>>>>> want that more than you want this "clever" work-around, right?
>>>>>>>>>
>>>>>>>>> Also fix all the checkpatch --strict warnings.
>>>>>>>>>
>>>>>>>>>> +
>>>>>>>>>> +     di->regs = bq27xxx_regs[di->chip];
>>>>>>>>>> +
>>>>>>>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>>>>>>>       mutex_init(&di->lock);
>>>>>>>>>> -     di->regs = bq27xxx_regs[di->chip];
>>>>>>>>>>
>>>>>>>>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>>>>>>>>       if (!psy_desc)
>>>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>>>>> index a597221..0b11ed4 100644
>>>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>>>>>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>>>>>       { "bq27210", BQ27010 },
>>>>>>>>>>       { "bq27500", BQ2750X },
>>>>>>>>>>       { "bq27510", BQ2751X },
>>>>>>>>>> -     { "bq27520", BQ2751X },
>>>>>>>>>> +     { "bq27520", BQ2752X },
>>>>>>>>>>       { "bq27500-1", BQ27500 },
>>>>>>>>>>       { "bq27510g1", BQ27510G1 },
>>>>>>>>>>       { "bq27510g2", BQ27510G2 },
>>>>>>>>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>>>>>>       { "bq27520g3", BQ27520G3 },
>>>>>>>>>>       { "bq27520g4", BQ27520G4 },
>>>>>>>>>>       { "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);
>>>>>>>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>>>>>>>> index 11e1168..543c10e 100644
>>>>>>>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>>>>>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>>>>>>>> @@ -2,6 +2,8 @@
>>>>>>>>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>>>>>>>>
>>>>>>>>>>  enum bq27xxx_chip {
>>>>>>>>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>>>>>>>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>>>>>>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>>>>>>>>       BQ27010, /* bq27010, bq27210 */
>>>>>>>>>>       BQ2750X, /* bq27500 deprecated alias */
>>>>>>>>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>>>>>>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>>>>>>>>       BQ27545, /* bq27545 */
>>>>>>>>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>>>>>>>>> +     BQ27MAX,
>>>>>>>>>> +
>>>>>>>>>> +     /* these map to above in bq27xxx_chips[] */
>>>>>>>>>> +     BQ2752X, /* deprecated alias */
>>>>>>>>>> +     BQ27531,
>>>>>>>>>> +     BQ27542,
>>>>>>>>>> +     BQ27546,
>>>>>>>>>> +     BQ27742,
>>>>>>>>>> +     BQ27425,
>>>>>>>>>> +     BQ27441,
>>>>>>>>>> +     BQ27621,
>>>>>>>>>>  };
>>>>>>>>>>
>>>>>>>>>>  /**
>>>>>>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-04 18:40     ` Liam Breck
@ 2017-05-08  6:16       ` Liam Breck
  2017-05-08 14:54         ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-08  6:16 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Matt Ranostay, Liam Breck

On Thu, May 4, 2017 at 11:40 AM, Liam Breck <liam@networkimprov.net> wrote:
> On Thu, May 4, 2017 at 9:52 AM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>> From: Liam Breck <kernel@networkimprov.net>
>>>
>>> Previously there was no way to configure these chips in the event that the
>>> defaults didn't match the battery in question.
>>>
>>> For chips with RAM data memory (and also those with flash/NVM data memory
>>> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
>>> set module param dt_monitored_battery_updates_nvm=0) we now call
>>> power_supply_get_battery_info(), check its values, and write battery
>>> properties to chip data memory if there is a dm_regs table for the chip.
>>>
>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>> ---
>>>  drivers/power/supply/Kconfig           |   9 ++
>>>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>>>  include/linux/power/bq27xxx_battery.h  |   2 +
>>>  3 files changed, 209 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>>> index 76806a0..85e2fb2 100644
>>> --- a/drivers/power/supply/Kconfig
>>> +++ b/drivers/power/supply/Kconfig
>>> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>>>         Say Y here to enable support for batteries with BQ27xxx chips
>>>         connected over an I2C bus.
>>>
>>> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
>>> +     bool "BQ27xxx support for update of NVM/flash data memory"
>>> +     depends on BATTERY_BQ27XXX_I2C
>>> +     help
>>> +       Say Y here to enable devicetree monitored-battery config to update
>>> +       NVM/flash data memory. Only enable this option for devices with a
>>> +       fuel gauge mounted on the circuit board, and a battery that cannot
>>> +       be replaced with one of a different type.
>>> +
>>>  config BATTERY_DA9030
>>>       tristate "DA9030 battery driver"
>>>       depends on PMIC_DA903X
>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>> index 8ab184c..06f15da 100644
>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>>>
>>>  #define BQ27XXX_DM_SZ        32
>>>
>>> +struct bq27xxx_dm_reg {
>>> +     u8 subclass_id;
>>> +     u8 offset;
>>> +     u8 bytes;
>>> +     u16 min, max;
>>> +};
>>> +
>>>  /**
>>>   * struct bq27xxx_dm_buf - chip data memory buffer
>>>   * @class: data memory subclass_id
>>> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>>>       bool has_data, dirty;
>>>  };
>>>
>>> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
>>> +     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
>>> +     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
>>> +     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>>> +};
>>> +
>>> +
>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>> +static bool bq27xxx_dt_to_nvm = true;
>>> +
>>> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
>>> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
>>> +     "Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
>>
>> As before, the default should not be y, this is a rare case and I can't
>> see it being useful or wanted by anyone but device manufacturers. I
>> don't want everyones chip's factory programmed NVM overwritten by
>> accident when someone compiles and ships a kernel with
>> BATTERY_BQ27XXX_DT_UPDATES_NVM=y
>
> Right, the point of the config option is to let a device vendor ship a
> kernel + dtb which can field-upgrade NVM. (Setting the option does
> nothing absent the necessary dtb.)
>
> Module params are for end-user config; we can't require a device
> vendor to ship /etc/modprobe.d/xyz. And we certainly don't want a
> kernel package update to defeat the end-user config of
> dt_monitored_battery_updates_nvm=0 !!
>
> I believe Sebastian agrees, given that he queued this patch :-)

I clarified the rationale for module param default =1 above; could you ack?

That prevents this scenario:
1) user changes battery type, sets dt_monitored_battery_updates_nvm=0
2) vendor ships kernel package with dtb update and
dt_monitored_battery_updates_nvm=1
3) gauge stops working correctly


>>> +#else
>>> +static bool bq27xxx_dt_to_nvm = false;
>>> +#endif
>>>
>>>  static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
>>>  {
>>> @@ -1019,6 +1063,51 @@ static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
>>>       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->has_data)
>>> +             return;
>>> +
>>> +     if (be16_to_cpup(prev) == val) {
>>> +             dev_info(di->dev, "%s has %u\n", str, val);
>>> +             return;
>>> +     }
>>> +
>>> +     if (!di->ram_chip && !bq27xxx_dt_to_nvm) {
>>> +             /* devicetree and NVM differ; defer to NVM */
>>> +             dev_warn(di->dev, "%s has %u; update to %u disallowed "
>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>> +                      "by dt_monitored_battery_updates_nvm=0"
>>> +#else
>>> +                      "for flash/NVM data memory"
>>> +#endif
>>> +                      "\n", str, be16_to_cpup(prev), val);
>>> +             return;
>>> +     }
>>> +
>>> +     dev_info(di->dev, "update %s to %u\n", str, val);
>>> +
>>> +     *prev = cpu_to_be16(val);
>>> +     buf->dirty = true;
>>> +}
>>> +
>>>  static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
>>>  {
>>>       const int limit = 100;
>>> @@ -1117,6 +1206,103 @@ static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
>>>       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);
>>> +     bool updated;
>>> +
>>> +     if (bq27xxx_battery_unseal(di) < 0)
>>> +             return;
>>> +
>>> +     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);
>>> +     }
>>> +
>>> +     updated = bd.dirty || bt.dirty;
>>> +
>>> +     bq27xxx_battery_write_dm_block(di, &bd);
>>> +     bq27xxx_battery_write_dm_block(di, &bt);
>>> +
>>> +     bq27xxx_battery_seal(di);
>>> +
>>> +     if (updated && di->chip != BQ27421) { /* not a cfgupdate chip, so reset */
>>> +             bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false);
>>> +             BQ27XXX_MSLEEP(300); /* reset time is not documented */
>>> +     }
>>> +     /* assume bq27xxx_battery_update() is called hereafter */
>>> +}
>>> +
>>> +static void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
>>> +{
>>> +     struct power_supply_battery_info info = {};
>>> +     unsigned int min, max;
>>> +
>>> +     if (power_supply_get_battery_info(di->bat, &info) < 0)
>>> +             return;
>>> +
>>> +     if (!di->dm_regs) {
>>> +             dev_warn(di->dev, "data memory update not supported for chip\n");
>>> +             return;
>>> +     }
>>> +
>>> +     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)
>>> +             bq27xxx_battery_set_config(di, &info);
>>> +}
>>> +
>>>  /*
>>>   * Return the battery State-of-Charge
>>>   * Or < 0 if something fails.
>>> @@ -1634,6 +1820,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;
>>> @@ -1667,7 +1860,10 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
>>>  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,
>>> +     };
>>>
>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>       mutex_init(&di->lock);
>>> @@ -1692,6 +1888,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);
>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>> index b1defb8..11e1168 100644
>>> --- a/include/linux/power/bq27xxx_battery.h
>>> +++ b/include/linux/power/bq27xxx_battery.h
>>> @@ -63,7 +63,9 @@ struct bq27xxx_device_info {
>>>       struct device *dev;
>>>       int id;
>>>       enum bq27xxx_chip chip;
>>> +     bool ram_chip;
>>>       const char *name;
>>> +     struct bq27xxx_dm_reg *dm_regs;
>>>       u32 unseal_key;
>>>       struct bq27xxx_access_methods bus;
>>>       struct bq27xxx_reg_cache cache;
>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode
  2017-05-04 16:38   ` Andrew F. Davis
@ 2017-05-08  6:18     ` Liam Breck
  2017-05-08 15:01       ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-08  6:18 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Thu, May 4, 2017 at 9:38 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/04/2017 01:18 AM, Liam Breck wrote:
>> From: Liam Breck <kernel@networkimprov.net>
>>
>> We tie multiple chips to unique register maps. When supporting a new chip,
>> it's easy to add a duplicate map by mistake.
>>
>> In debug mode we now scan the register maps for duplicates.
>>
>
> Debugging stuff doesn't need to go upstream.

Since we're keeping a dupeless reg table, please ack this so folks
adding chips avoid adding dupes as Chris did.

I don't have to mention there's tons of debug code upstream :-)


>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>> ---
>>  drivers/power/supply/bq27xxx_battery.c | 21 +++++++++++++++++++++
>>  1 file changed, 21 insertions(+)
>>
>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>> index 0aecd41..97c646c 100644
>> --- a/drivers/power/supply/bq27xxx_battery.c
>> +++ b/drivers/power/supply/bq27xxx_battery.c
>> @@ -1932,6 +1932,25 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
>>       schedule_delayed_work(&di->work, 0);
>>  }
>>
>> +#ifdef DEBUG
>> +static void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di)
>> +{
>> +     const size_t max = ARRAY_SIZE(bq27xxx_regs);
>> +     int a, b;
>> +
>> +     for (a = 1; a < max-1; a++) {
>> +             for (b = a+1; b < max; b++) {
>> +                     if (!memcmp(bq27xxx_regs[a], bq27xxx_regs[b],
>> +                                 sizeof(bq27xxx_regs[0])))
>> +                             dev_warn(di->dev,
>> +                                     "bq27xxx_regs[%d] & [%d] are identical\n", a, b);
>> +             }
>> +     }
>> +}
>> +#else
>> +static inline void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di) {}
>> +#endif
>> +
>>  int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>  {
>>       struct power_supply_desc *psy_desc;
>> @@ -1940,6 +1959,8 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>               .drv_data = di,
>>       };
>>
>> +     bq27xxx_battery_dbg_regs_dupes(di);
>> +
>>       di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>
>>       di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-05 19:45       ` Andrew F. Davis
  2017-05-05 20:14         ` Liam Breck
@ 2017-05-08  6:40         ` Liam Breck
  2017-05-08 15:00           ` Andrew F. Davis
  1 sibling, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-08  6:40 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/05/2017 02:31 PM, Liam Breck wrote:
>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>
>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>
>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>> and data memory register tables.
>>>>
>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>> ---
>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>
>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>> index 06f15da..0aecd41 100644
>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>> @@ -58,7 +58,7 @@
>>>>
>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>
>>>> -#define DRIVER_VERSION               "1.2.0"
>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>
>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>
>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>
>>>>  /* Register mappings */
>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>       [BQ27000] = {
>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>  static struct {
>>>>       enum power_supply_property *props;
>>>>       size_t size;
>>>> -} bq27xxx_battery_props[] = {
>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>> @@ -798,6 +798,33 @@ static struct {
>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>  };
>>>>
>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>> +     [BQ27000]   = BQ27000,
>>>> +     [BQ27010]   = BQ27010,
>>>> +     [BQ2750X]   = BQ2750X,
>>>> +     [BQ2751X]   = BQ2751X,
>>>> +     [BQ2752X]   = BQ2751X,
>>>> +     [BQ27500]   = BQ27500,
>>>> +     [BQ27510G1] = BQ27510G1,
>>>> +     [BQ27510G2] = BQ27510G2,
>>>> +     [BQ27510G3] = BQ27510G3,
>>>> +     [BQ27520G1] = BQ27520G1,
>>>> +     [BQ27520G2] = BQ27520G2,
>>>> +     [BQ27520G3] = BQ27520G3,
>>>> +     [BQ27520G4] = BQ27520G4,
>>>> +     [BQ27530]   = BQ27530,
>>>> +     [BQ27531]   = BQ27530,
>>>> +     [BQ27541]   = BQ27541,
>>>> +     [BQ27542]   = BQ27541,
>>>> +     [BQ27546]   = BQ27541,
>>>> +     [BQ27742]   = BQ27541,
>>>> +     [BQ27545]   = BQ27545,
>>>> +     [BQ27421]   = BQ27421,
>>>> +     [BQ27425]   = BQ27421,
>>>> +     [BQ27441]   = BQ27421,
>>>> +     [BQ27621]   = BQ27421,
>>>> +};
>>>> +
>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>
>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>> +     [BQ27500] = bq27500_dm_regs,
>>>> +     [BQ27545] = bq27545_dm_regs,
>>>> +     [BQ27421] = bq27421_dm_regs,
>>>> +     [BQ27425] = bq27425_dm_regs,
>>>> +     [BQ27441] = bq27421_dm_regs,
>>>> +     [BQ27621] = bq27621_dm_regs,
>>>> +};
>>>> +
>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>> +     [BQ27500] = 0x04143672,
>>>> +     [BQ27545] = 0x04143672,
>>>> +     [BQ27421] = 0x80008000,
>>>> +     [BQ27425] = 0x04143672,
>>>> +     [BQ27441] = 0x80008000,
>>>> +     [BQ27621] = 0x80008000,
>>>> +};
>>>> +
>>>>
>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>               .drv_data = di,
>>>>       };
>>>>
>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>> +
>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>
>>> NACK, this is a mess, you should not be using a table to change what
>>> chip was passed in, it may be needed later. The chip is still the same,
>>> it should have the same one correct ID, use a different index or array
>>> if you would like, but this is very hacky.
>>
>> The only way I see to make the I2C subsystem deliver multiple IDs for
>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>> its normal u32. What do you think of that?
>>
>
> Why would it need multiple IDs for one device? Just pass in the one
> correct device ID that it is. No reason to make this so complicated.
> From the one ID you can then use tables to lookup any other info about
> that device, you don't have to have ever ID populated in every table,
> you can even have a table of tables if you would like:
>
> static const struct chip_lookup lookup_table = {
>         [bq27425] = {
>                 .regs = &bq27xxx_regs[bq27425],
>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>         },
>         [bq27343] = {
> ...
>
> Not sure if that is valid C but I think you can get the idea.

I considered a master lookup_table, but its ref to
bq27xxx_regs[fake-ID] duplicates the mapping of real-ID to di->chip.
The latter is still necessary as di->chip is used to select
conditional behaviors; we can't change its value in this patch.

So instead lets amend the I2C table to carry both its original value
(fake-ID) and the real-ID. That looks like:

static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
    /* dest.    di->real_chip       di->chip      */
    { "bq27200",   (BQ27000   << 16) |  BQ27000   },
    { "bq27210",   (BQ27010   << 16) |  BQ27010   },
    ...
    { "bq27441",   (BQ27441   << 16) |  BQ27421   },
    { "bq27621",   (BQ27621   << 16) |  BQ27421   },
    {},
};

In probe, retrieve two values:

    di->real_chip = id->driver_data >> 16;
    di->chip = (u16) id->driver_data;

In setup, use two values:

    di->unseal_key = bq27xxx_unseal_keys[di->real_chip];
    di->dm_regs = bq27xxx_dm_regs[di->real_chip];
    di->regs = bq27xxx_regs[di->chip]; // unchanged from orig src

That yields the most compact implementation of this patch, and you get
di->real_chip in the bargain :-)


>>> Just stop trying to hack around it, add the extra tables, even if they
>>> are clones, so we can be done with this series already. I'm sure you
>>> want that more than you want this "clever" work-around, right?
>>>
>>> Also fix all the checkpatch --strict warnings.
>>>
>>>> +
>>>> +     di->regs = bq27xxx_regs[di->chip];
>>>> +
>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>       mutex_init(&di->lock);
>>>> -     di->regs = bq27xxx_regs[di->chip];
>>>>
>>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>>       if (!psy_desc)
>>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>> index a597221..0b11ed4 100644
>>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>       { "bq27210", BQ27010 },
>>>>       { "bq27500", BQ2750X },
>>>>       { "bq27510", BQ2751X },
>>>> -     { "bq27520", BQ2751X },
>>>> +     { "bq27520", BQ2752X },
>>>>       { "bq27500-1", BQ27500 },
>>>>       { "bq27510g1", BQ27510G1 },
>>>>       { "bq27510g2", BQ27510G2 },
>>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>       { "bq27520g3", BQ27520G3 },
>>>>       { "bq27520g4", BQ27520G4 },
>>>>       { "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);
>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>> index 11e1168..543c10e 100644
>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>> @@ -2,6 +2,8 @@
>>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>>
>>>>  enum bq27xxx_chip {
>>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>>       BQ27010, /* bq27010, bq27210 */
>>>>       BQ2750X, /* bq27500 deprecated alias */
>>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>>       BQ27545, /* bq27545 */
>>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>>> +     BQ27MAX,
>>>> +
>>>> +     /* these map to above in bq27xxx_chips[] */
>>>> +     BQ2752X, /* deprecated alias */
>>>> +     BQ27531,
>>>> +     BQ27542,
>>>> +     BQ27546,
>>>> +     BQ27742,
>>>> +     BQ27425,
>>>> +     BQ27441,
>>>> +     BQ27621,
>>>>  };
>>>>
>>>>  /**
>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-08  6:16       ` Liam Breck
@ 2017-05-08 14:54         ` Andrew F. Davis
  2017-05-08 18:39           ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-08 14:54 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Matt Ranostay, Liam Breck

On 05/08/2017 01:16 AM, Liam Breck wrote:
> On Thu, May 4, 2017 at 11:40 AM, Liam Breck <liam@networkimprov.net> wrote:
>> On Thu, May 4, 2017 at 9:52 AM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>
>>>> Previously there was no way to configure these chips in the event that the
>>>> defaults didn't match the battery in question.
>>>>
>>>> For chips with RAM data memory (and also those with flash/NVM data memory
>>>> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
>>>> set module param dt_monitored_battery_updates_nvm=0) we now call
>>>> power_supply_get_battery_info(), check its values, and write battery
>>>> properties to chip data memory if there is a dm_regs table for the chip.
>>>>
>>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>> ---
>>>>  drivers/power/supply/Kconfig           |   9 ++
>>>>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>>>>  include/linux/power/bq27xxx_battery.h  |   2 +
>>>>  3 files changed, 209 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>>>> index 76806a0..85e2fb2 100644
>>>> --- a/drivers/power/supply/Kconfig
>>>> +++ b/drivers/power/supply/Kconfig
>>>> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>>>>         Say Y here to enable support for batteries with BQ27xxx chips
>>>>         connected over an I2C bus.
>>>>
>>>> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>> +     bool "BQ27xxx support for update of NVM/flash data memory"
>>>> +     depends on BATTERY_BQ27XXX_I2C
>>>> +     help
>>>> +       Say Y here to enable devicetree monitored-battery config to update
>>>> +       NVM/flash data memory. Only enable this option for devices with a
>>>> +       fuel gauge mounted on the circuit board, and a battery that cannot
>>>> +       be replaced with one of a different type.
>>>> +
>>>>  config BATTERY_DA9030
>>>>       tristate "DA9030 battery driver"
>>>>       depends on PMIC_DA903X
>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>> index 8ab184c..06f15da 100644
>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>>>>
>>>>  #define BQ27XXX_DM_SZ        32
>>>>
>>>> +struct bq27xxx_dm_reg {
>>>> +     u8 subclass_id;
>>>> +     u8 offset;
>>>> +     u8 bytes;
>>>> +     u16 min, max;
>>>> +};
>>>> +
>>>>  /**
>>>>   * struct bq27xxx_dm_buf - chip data memory buffer
>>>>   * @class: data memory subclass_id
>>>> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>>>>       bool has_data, dirty;
>>>>  };
>>>>
>>>> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
>>>> +     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
>>>> +     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
>>>> +     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>>>> +};
>>>> +
>>>> +
>>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>> +static bool bq27xxx_dt_to_nvm = true;
>>>> +
>>>> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
>>>> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
>>>> +     "Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
>>>
>>> As before, the default should not be y, this is a rare case and I can't
>>> see it being useful or wanted by anyone but device manufacturers. I
>>> don't want everyones chip's factory programmed NVM overwritten by
>>> accident when someone compiles and ships a kernel with
>>> BATTERY_BQ27XXX_DT_UPDATES_NVM=y
>>
>> Right, the point of the config option is to let a device vendor ship a
>> kernel + dtb which can field-upgrade NVM. (Setting the option does
>> nothing absent the necessary dtb.)
>>
>> Module params are for end-user config; we can't require a device
>> vendor to ship /etc/modprobe.d/xyz. And we certainly don't want a
>> kernel package update to defeat the end-user config of
>> dt_monitored_battery_updates_nvm=0 !!
>>
>> I believe Sebastian agrees, given that he queued this patch :-)
> 
> I clarified the rationale for module param default =1 above; could you ack?
> 
> That prevents this scenario:
> 1) user changes battery type, sets dt_monitored_battery_updates_nvm=0
> 2) vendor ships kernel package with dtb update and
> dt_monitored_battery_updates_nvm=1
> 3) gauge stops working correctly
> 

Leaving it =1 will encourage this situation, not prevent it. Updating
NVM is a non-standard operation for these parts. It should only be done
once ideally. It is nice being able to update the NVM, and we have
user-space tools for this, but this is a dangerous operation, improperly
programming can brick the chip, as you have found out.

If you want to add this function into the kernel driver that is fine,
but you *cannot* have this be the default, it needs to be a hidden away
option for people who know what they are doing, else you will end up
accidentally causing damage to countless users' hardware.

> 
>>>> +#else
>>>> +static bool bq27xxx_dt_to_nvm = false;
>>>> +#endif
>>>>
>>>>  static int poll_interval_param_set(const char *val, const struct kernel_param *kp)
>>>>  {
>>>> @@ -1019,6 +1063,51 @@ static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di,
>>>>       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->has_data)
>>>> +             return;
>>>> +
>>>> +     if (be16_to_cpup(prev) == val) {
>>>> +             dev_info(di->dev, "%s has %u\n", str, val);
>>>> +             return;
>>>> +     }
>>>> +
>>>> +     if (!di->ram_chip && !bq27xxx_dt_to_nvm) {
>>>> +             /* devicetree and NVM differ; defer to NVM */
>>>> +             dev_warn(di->dev, "%s has %u; update to %u disallowed "
>>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>> +                      "by dt_monitored_battery_updates_nvm=0"
>>>> +#else
>>>> +                      "for flash/NVM data memory"
>>>> +#endif
>>>> +                      "\n", str, be16_to_cpup(prev), val);
>>>> +             return;
>>>> +     }
>>>> +
>>>> +     dev_info(di->dev, "update %s to %u\n", str, val);
>>>> +
>>>> +     *prev = cpu_to_be16(val);
>>>> +     buf->dirty = true;
>>>> +}
>>>> +
>>>>  static int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di, u16 state)
>>>>  {
>>>>       const int limit = 100;
>>>> @@ -1117,6 +1206,103 @@ static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
>>>>       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);
>>>> +     bool updated;
>>>> +
>>>> +     if (bq27xxx_battery_unseal(di) < 0)
>>>> +             return;
>>>> +
>>>> +     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);
>>>> +     }
>>>> +
>>>> +     updated = bd.dirty || bt.dirty;
>>>> +
>>>> +     bq27xxx_battery_write_dm_block(di, &bd);
>>>> +     bq27xxx_battery_write_dm_block(di, &bt);
>>>> +
>>>> +     bq27xxx_battery_seal(di);
>>>> +
>>>> +     if (updated && di->chip != BQ27421) { /* not a cfgupdate chip, so reset */
>>>> +             bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false);
>>>> +             BQ27XXX_MSLEEP(300); /* reset time is not documented */
>>>> +     }
>>>> +     /* assume bq27xxx_battery_update() is called hereafter */
>>>> +}
>>>> +
>>>> +static void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
>>>> +{
>>>> +     struct power_supply_battery_info info = {};
>>>> +     unsigned int min, max;
>>>> +
>>>> +     if (power_supply_get_battery_info(di->bat, &info) < 0)
>>>> +             return;
>>>> +
>>>> +     if (!di->dm_regs) {
>>>> +             dev_warn(di->dev, "data memory update not supported for chip\n");
>>>> +             return;
>>>> +     }
>>>> +
>>>> +     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)
>>>> +             bq27xxx_battery_set_config(di, &info);
>>>> +}
>>>> +
>>>>  /*
>>>>   * Return the battery State-of-Charge
>>>>   * Or < 0 if something fails.
>>>> @@ -1634,6 +1820,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;
>>>> @@ -1667,7 +1860,10 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
>>>>  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,
>>>> +     };
>>>>
>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>       mutex_init(&di->lock);
>>>> @@ -1692,6 +1888,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);
>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>> index b1defb8..11e1168 100644
>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>> @@ -63,7 +63,9 @@ struct bq27xxx_device_info {
>>>>       struct device *dev;
>>>>       int id;
>>>>       enum bq27xxx_chip chip;
>>>> +     bool ram_chip;
>>>>       const char *name;
>>>> +     struct bq27xxx_dm_reg *dm_regs;
>>>>       u32 unseal_key;
>>>>       struct bq27xxx_access_methods bus;
>>>>       struct bq27xxx_reg_cache cache;
>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-08  6:40         ` Liam Breck
@ 2017-05-08 15:00           ` Andrew F. Davis
  2017-05-08 19:02             ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-08 15:00 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/08/2017 01:40 AM, Liam Breck wrote:
> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>
>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>
>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>> and data memory register tables.
>>>>>
>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>> ---
>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>
>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>> index 06f15da..0aecd41 100644
>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>> @@ -58,7 +58,7 @@
>>>>>
>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>
>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>
>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>
>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>
>>>>>  /* Register mappings */
>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>       [BQ27000] = {
>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>  static struct {
>>>>>       enum power_supply_property *props;
>>>>>       size_t size;
>>>>> -} bq27xxx_battery_props[] = {
>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>  };
>>>>>
>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>> +     [BQ27000]   = BQ27000,
>>>>> +     [BQ27010]   = BQ27010,
>>>>> +     [BQ2750X]   = BQ2750X,
>>>>> +     [BQ2751X]   = BQ2751X,
>>>>> +     [BQ2752X]   = BQ2751X,
>>>>> +     [BQ27500]   = BQ27500,
>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>> +     [BQ27530]   = BQ27530,
>>>>> +     [BQ27531]   = BQ27530,
>>>>> +     [BQ27541]   = BQ27541,
>>>>> +     [BQ27542]   = BQ27541,
>>>>> +     [BQ27546]   = BQ27541,
>>>>> +     [BQ27742]   = BQ27541,
>>>>> +     [BQ27545]   = BQ27545,
>>>>> +     [BQ27421]   = BQ27421,
>>>>> +     [BQ27425]   = BQ27421,
>>>>> +     [BQ27441]   = BQ27421,
>>>>> +     [BQ27621]   = BQ27421,
>>>>> +};
>>>>> +
>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>
>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>> +};
>>>>> +
>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>> +     [BQ27500] = 0x04143672,
>>>>> +     [BQ27545] = 0x04143672,
>>>>> +     [BQ27421] = 0x80008000,
>>>>> +     [BQ27425] = 0x04143672,
>>>>> +     [BQ27441] = 0x80008000,
>>>>> +     [BQ27621] = 0x80008000,
>>>>> +};
>>>>> +
>>>>>
>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>               .drv_data = di,
>>>>>       };
>>>>>
>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>> +
>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>
>>>> NACK, this is a mess, you should not be using a table to change what
>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>> it should have the same one correct ID, use a different index or array
>>>> if you would like, but this is very hacky.
>>>
>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>> its normal u32. What do you think of that?
>>>
>>
>> Why would it need multiple IDs for one device? Just pass in the one
>> correct device ID that it is. No reason to make this so complicated.
>> From the one ID you can then use tables to lookup any other info about
>> that device, you don't have to have ever ID populated in every table,
>> you can even have a table of tables if you would like:
>>
>> static const struct chip_lookup lookup_table = {
>>         [bq27425] = {
>>                 .regs = &bq27xxx_regs[bq27425],
>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>         },
>>         [bq27343] = {
>> ...
>>
>> Not sure if that is valid C but I think you can get the idea.
> 
> I considered a master lookup_table, but its ref to
> bq27xxx_regs[fake-ID] duplicates the mapping of real-ID to di->chip.
> The latter is still necessary as di->chip is used to select
> conditional behaviors; we can't change its value in this patch.
> 

Sure we can, in fact you could add the conditional behavior flags to the
master lookup_table and cleanup all the current switch-case checks we do
now.

> So instead lets amend the I2C table to carry both its original value
> (fake-ID) and the real-ID. That looks like:
> 
> static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>     /* dest.    di->real_chip       di->chip      */
>     { "bq27200",   (BQ27000   << 16) |  BQ27000   },
>     { "bq27210",   (BQ27010   << 16) |  BQ27010   },
>     ...
>     { "bq27441",   (BQ27441   << 16) |  BQ27421   },
>     { "bq27621",   (BQ27621   << 16) |  BQ27421   },
>     {},
> };
> 
> In probe, retrieve two values:
> 
>     di->real_chip = id->driver_data >> 16;
>     di->chip = (u16) id->driver_data;
> 

NAK, I'm sure you can see how hacky this is right? This doesn't give us
anything that the old table didn't. And it fails to correct the issue
with the tables: We have two chip IDs still!

Try the lookup_table again, send be what you have and I can help get
everything else working if you have any problems with the conditional
behavior cleanups.

> In setup, use two values:
> 
>     di->unseal_key = bq27xxx_unseal_keys[di->real_chip];
>     di->dm_regs = bq27xxx_dm_regs[di->real_chip];
>     di->regs = bq27xxx_regs[di->chip]; // unchanged from orig src
> 
> That yields the most compact implementation of this patch, and you get
> di->real_chip in the bargain :-)
> 
> 
>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>> are clones, so we can be done with this series already. I'm sure you
>>>> want that more than you want this "clever" work-around, right?
>>>>
>>>> Also fix all the checkpatch --strict warnings.
>>>>
>>>>> +
>>>>> +     di->regs = bq27xxx_regs[di->chip];
>>>>> +
>>>>>       INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>>>>>       mutex_init(&di->lock);
>>>>> -     di->regs = bq27xxx_regs[di->chip];
>>>>>
>>>>>       psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>>>>>       if (!psy_desc)
>>>>> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>> index a597221..0b11ed4 100644
>>>>> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
>>>>> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>       { "bq27210", BQ27010 },
>>>>>       { "bq27500", BQ2750X },
>>>>>       { "bq27510", BQ2751X },
>>>>> -     { "bq27520", BQ2751X },
>>>>> +     { "bq27520", BQ2752X },
>>>>>       { "bq27500-1", BQ27500 },
>>>>>       { "bq27510g1", BQ27510G1 },
>>>>>       { "bq27510g2", BQ27510G2 },
>>>>> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>       { "bq27520g3", BQ27520G3 },
>>>>>       { "bq27520g4", BQ27520G4 },
>>>>>       { "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);
>>>>> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
>>>>> index 11e1168..543c10e 100644
>>>>> --- a/include/linux/power/bq27xxx_battery.h
>>>>> +++ b/include/linux/power/bq27xxx_battery.h
>>>>> @@ -2,6 +2,8 @@
>>>>>  #define __LINUX_BQ27X00_BATTERY_H__
>>>>>
>>>>>  enum bq27xxx_chip {
>>>>> +     /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
>>>>> +     /* and map to themselves in bq27xxx_chips[]             */
>>>>>       BQ27000 = 1, /* bq27000, bq27200 */
>>>>>       BQ27010, /* bq27010, bq27210 */
>>>>>       BQ2750X, /* bq27500 deprecated alias */
>>>>> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>>>>>       BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>>>>>       BQ27545, /* bq27545 */
>>>>>       BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
>>>>> +     BQ27MAX,
>>>>> +
>>>>> +     /* these map to above in bq27xxx_chips[] */
>>>>> +     BQ2752X, /* deprecated alias */
>>>>> +     BQ27531,
>>>>> +     BQ27542,
>>>>> +     BQ27546,
>>>>> +     BQ27742,
>>>>> +     BQ27425,
>>>>> +     BQ27441,
>>>>> +     BQ27621,
>>>>>  };
>>>>>
>>>>>  /**
>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode
  2017-05-08  6:18     ` Liam Breck
@ 2017-05-08 15:01       ` Andrew F. Davis
  2017-05-08 19:07         ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-08 15:01 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/08/2017 01:18 AM, Liam Breck wrote:
> On Thu, May 4, 2017 at 9:38 AM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>> From: Liam Breck <kernel@networkimprov.net>
>>>
>>> We tie multiple chips to unique register maps. When supporting a new chip,
>>> it's easy to add a duplicate map by mistake.
>>>
>>> In debug mode we now scan the register maps for duplicates.
>>>
>>
>> Debugging stuff doesn't need to go upstream.
> 
> Since we're keeping a dupeless reg table, please ack this so folks
> adding chips avoid adding dupes as Chris did.
> 
> I don't have to mention there's tons of debug code upstream :-)
> 

If you want it then make it into a tool that can go into scripts/ or
tools/, it doesn't need to be inline cluttering up the source.

> 
>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>> ---
>>>  drivers/power/supply/bq27xxx_battery.c | 21 +++++++++++++++++++++
>>>  1 file changed, 21 insertions(+)
>>>
>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>> index 0aecd41..97c646c 100644
>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>> @@ -1932,6 +1932,25 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
>>>       schedule_delayed_work(&di->work, 0);
>>>  }
>>>
>>> +#ifdef DEBUG
>>> +static void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di)
>>> +{
>>> +     const size_t max = ARRAY_SIZE(bq27xxx_regs);
>>> +     int a, b;
>>> +
>>> +     for (a = 1; a < max-1; a++) {
>>> +             for (b = a+1; b < max; b++) {
>>> +                     if (!memcmp(bq27xxx_regs[a], bq27xxx_regs[b],
>>> +                                 sizeof(bq27xxx_regs[0])))
>>> +                             dev_warn(di->dev,
>>> +                                     "bq27xxx_regs[%d] & [%d] are identical\n", a, b);
>>> +             }
>>> +     }
>>> +}
>>> +#else
>>> +static inline void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di) {}
>>> +#endif
>>> +
>>>  int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>  {
>>>       struct power_supply_desc *psy_desc;
>>> @@ -1940,6 +1959,8 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>               .drv_data = di,
>>>       };
>>>
>>> +     bq27xxx_battery_dbg_regs_dupes(di);
>>> +
>>>       di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>
>>>       di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-08 14:54         ` Andrew F. Davis
@ 2017-05-08 18:39           ` Liam Breck
  2017-05-08 18:42             ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-08 18:39 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Mon, May 8, 2017 at 7:54 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/08/2017 01:16 AM, Liam Breck wrote:
>> On Thu, May 4, 2017 at 11:40 AM, Liam Breck <liam@networkimprov.net> wrote:
>>> On Thu, May 4, 2017 at 9:52 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>
>>>>> Previously there was no way to configure these chips in the event that the
>>>>> defaults didn't match the battery in question.
>>>>>
>>>>> For chips with RAM data memory (and also those with flash/NVM data memory
>>>>> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
>>>>> set module param dt_monitored_battery_updates_nvm=0) we now call
>>>>> power_supply_get_battery_info(), check its values, and write battery
>>>>> properties to chip data memory if there is a dm_regs table for the chip.
>>>>>
>>>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>> ---
>>>>>  drivers/power/supply/Kconfig           |   9 ++
>>>>>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>>>>>  include/linux/power/bq27xxx_battery.h  |   2 +
>>>>>  3 files changed, 209 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>>>>> index 76806a0..85e2fb2 100644
>>>>> --- a/drivers/power/supply/Kconfig
>>>>> +++ b/drivers/power/supply/Kconfig
>>>>> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>>>>>         Say Y here to enable support for batteries with BQ27xxx chips
>>>>>         connected over an I2C bus.
>>>>>
>>>>> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>> +     bool "BQ27xxx support for update of NVM/flash data memory"
>>>>> +     depends on BATTERY_BQ27XXX_I2C
>>>>> +     help
>>>>> +       Say Y here to enable devicetree monitored-battery config to update
>>>>> +       NVM/flash data memory. Only enable this option for devices with a
>>>>> +       fuel gauge mounted on the circuit board, and a battery that cannot
>>>>> +       be replaced with one of a different type.
>>>>> +
>>>>>  config BATTERY_DA9030
>>>>>       tristate "DA9030 battery driver"
>>>>>       depends on PMIC_DA903X
>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>> index 8ab184c..06f15da 100644
>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>>>>>
>>>>>  #define BQ27XXX_DM_SZ        32
>>>>>
>>>>> +struct bq27xxx_dm_reg {
>>>>> +     u8 subclass_id;
>>>>> +     u8 offset;
>>>>> +     u8 bytes;
>>>>> +     u16 min, max;
>>>>> +};
>>>>> +
>>>>>  /**
>>>>>   * struct bq27xxx_dm_buf - chip data memory buffer
>>>>>   * @class: data memory subclass_id
>>>>> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>>>>>       bool has_data, dirty;
>>>>>  };
>>>>>
>>>>> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
>>>>> +     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
>>>>> +     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
>>>>> +     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>>>>> +};
>>>>> +
>>>>> +
>>>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>> +static bool bq27xxx_dt_to_nvm = true;
>>>>> +
>>>>> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
>>>>> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
>>>>> +     "Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
>>>>
>>>> As before, the default should not be y, this is a rare case and I can't
>>>> see it being useful or wanted by anyone but device manufacturers. I
>>>> don't want everyones chip's factory programmed NVM overwritten by
>>>> accident when someone compiles and ships a kernel with
>>>> BATTERY_BQ27XXX_DT_UPDATES_NVM=y
>>>
>>> Right, the point of the config option is to let a device vendor ship a
>>> kernel + dtb which can field-upgrade NVM. (Setting the option does
>>> nothing absent the necessary dtb.)
>>>
>>> Module params are for end-user config; we can't require a device
>>> vendor to ship /etc/modprobe.d/xyz. And we certainly don't want a
>>> kernel package update to defeat the end-user config of
>>> dt_monitored_battery_updates_nvm=0 !!
>>>
>>> I believe Sebastian agrees, given that he queued this patch :-)
>>
>> I clarified the rationale for module param default =1 above; could you ack?
>>
>> That prevents this scenario:
>> 1) user changes battery type, sets dt_monitored_battery_updates_nvm=0
>> 2) vendor ships kernel package with dtb update and
>> dt_monitored_battery_updates_nvm=1
>> 3) gauge stops working correctly
>>
>
> Leaving it =1 will encourage this situation, not prevent it. Updating
> NVM is a non-standard operation for these parts. It should only be done
> once ideally. It is nice being able to update the NVM, and we have
> user-space tools for this, but this is a dangerous operation, improperly
> programming can brick the chip, as you have found out.
>
> If you want to add this function into the kernel driver that is fine,
> but you *cannot* have this be the default, it needs to be a hidden away
> option for people who know what they are doing, else you will end up
> accidentally causing damage to countless users' hardware.

I don't think you followed my logic.... It *is* hidden behind a
dedicated kernel config option which only device vendors (and
tinkerers :-) would use. A kernel package with that option and
suitable dtb has to perform the update without manipulation of the
module param. The module param is to let the user prevent any future
update by such a kernel package, since only he knows that he changed
the battery type.

What is your evidence for the assertion of "encourage this situation"?

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-08 18:39           ` Liam Breck
@ 2017-05-08 18:42             ` Andrew F. Davis
  2017-05-08 19:31               ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-08 18:42 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/08/2017 01:39 PM, Liam Breck wrote:
> On Mon, May 8, 2017 at 7:54 AM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/08/2017 01:16 AM, Liam Breck wrote:
>>> On Thu, May 4, 2017 at 11:40 AM, Liam Breck <liam@networkimprov.net> wrote:
>>>> On Thu, May 4, 2017 at 9:52 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>
>>>>>> Previously there was no way to configure these chips in the event that the
>>>>>> defaults didn't match the battery in question.
>>>>>>
>>>>>> For chips with RAM data memory (and also those with flash/NVM data memory
>>>>>> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
>>>>>> set module param dt_monitored_battery_updates_nvm=0) we now call
>>>>>> power_supply_get_battery_info(), check its values, and write battery
>>>>>> properties to chip data memory if there is a dm_regs table for the chip.
>>>>>>
>>>>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>> ---
>>>>>>  drivers/power/supply/Kconfig           |   9 ++
>>>>>>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>>>>>>  include/linux/power/bq27xxx_battery.h  |   2 +
>>>>>>  3 files changed, 209 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>>>>>> index 76806a0..85e2fb2 100644
>>>>>> --- a/drivers/power/supply/Kconfig
>>>>>> +++ b/drivers/power/supply/Kconfig
>>>>>> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>>>>>>         Say Y here to enable support for batteries with BQ27xxx chips
>>>>>>         connected over an I2C bus.
>>>>>>
>>>>>> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>> +     bool "BQ27xxx support for update of NVM/flash data memory"
>>>>>> +     depends on BATTERY_BQ27XXX_I2C
>>>>>> +     help
>>>>>> +       Say Y here to enable devicetree monitored-battery config to update
>>>>>> +       NVM/flash data memory. Only enable this option for devices with a
>>>>>> +       fuel gauge mounted on the circuit board, and a battery that cannot
>>>>>> +       be replaced with one of a different type.
>>>>>> +
>>>>>>  config BATTERY_DA9030
>>>>>>       tristate "DA9030 battery driver"
>>>>>>       depends on PMIC_DA903X
>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>> index 8ab184c..06f15da 100644
>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>
>>>>>>  #define BQ27XXX_DM_SZ        32
>>>>>>
>>>>>> +struct bq27xxx_dm_reg {
>>>>>> +     u8 subclass_id;
>>>>>> +     u8 offset;
>>>>>> +     u8 bytes;
>>>>>> +     u16 min, max;
>>>>>> +};
>>>>>> +
>>>>>>  /**
>>>>>>   * struct bq27xxx_dm_buf - chip data memory buffer
>>>>>>   * @class: data memory subclass_id
>>>>>> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>>>>>>       bool has_data, dirty;
>>>>>>  };
>>>>>>
>>>>>> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
>>>>>> +     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
>>>>>> +     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
>>>>>> +     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>>>>>> +};
>>>>>> +
>>>>>> +
>>>>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>> +static bool bq27xxx_dt_to_nvm = true;
>>>>>> +
>>>>>> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
>>>>>> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
>>>>>> +     "Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
>>>>>
>>>>> As before, the default should not be y, this is a rare case and I can't
>>>>> see it being useful or wanted by anyone but device manufacturers. I
>>>>> don't want everyones chip's factory programmed NVM overwritten by
>>>>> accident when someone compiles and ships a kernel with
>>>>> BATTERY_BQ27XXX_DT_UPDATES_NVM=y
>>>>
>>>> Right, the point of the config option is to let a device vendor ship a
>>>> kernel + dtb which can field-upgrade NVM. (Setting the option does
>>>> nothing absent the necessary dtb.)
>>>>
>>>> Module params are for end-user config; we can't require a device
>>>> vendor to ship /etc/modprobe.d/xyz. And we certainly don't want a
>>>> kernel package update to defeat the end-user config of
>>>> dt_monitored_battery_updates_nvm=0 !!
>>>>
>>>> I believe Sebastian agrees, given that he queued this patch :-)
>>>
>>> I clarified the rationale for module param default =1 above; could you ack?
>>>
>>> That prevents this scenario:
>>> 1) user changes battery type, sets dt_monitored_battery_updates_nvm=0
>>> 2) vendor ships kernel package with dtb update and
>>> dt_monitored_battery_updates_nvm=1
>>> 3) gauge stops working correctly
>>>
>>
>> Leaving it =1 will encourage this situation, not prevent it. Updating
>> NVM is a non-standard operation for these parts. It should only be done
>> once ideally. It is nice being able to update the NVM, and we have
>> user-space tools for this, but this is a dangerous operation, improperly
>> programming can brick the chip, as you have found out.
>>
>> If you want to add this function into the kernel driver that is fine,
>> but you *cannot* have this be the default, it needs to be a hidden away
>> option for people who know what they are doing, else you will end up
>> accidentally causing damage to countless users' hardware.
> 
> I don't think you followed my logic.... It *is* hidden behind a
> dedicated kernel config option which only device vendors (and
> tinkerers :-) would use. A kernel package with that option and
> suitable dtb has to perform the update without manipulation of the
> module param. The module param is to let the user prevent any future
> update by such a kernel package, since only he knows that he changed
> the battery type.
> 
> What is your evidence for the assertion of "encourage this situation"?
> 

It is the default value, what more evidence do you want? Someone should
have to enable the functionality in Kconfig *and* enable it as a
module_param. Leaving either on by default will cause it to be
accidentally left enabled.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-08 15:00           ` Andrew F. Davis
@ 2017-05-08 19:02             ` Liam Breck
  2017-05-08 19:09               ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-08 19:02 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Mon, May 8, 2017 at 8:00 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/08/2017 01:40 AM, Liam Breck wrote:
>> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>
>>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>>
>>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>>> and data memory register tables.
>>>>>>
>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>> ---
>>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>> index 06f15da..0aecd41 100644
>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>> @@ -58,7 +58,7 @@
>>>>>>
>>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>>
>>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>>
>>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>>
>>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>>
>>>>>>  /* Register mappings */
>>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>>       [BQ27000] = {
>>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>>  static struct {
>>>>>>       enum power_supply_property *props;
>>>>>>       size_t size;
>>>>>> -} bq27xxx_battery_props[] = {
>>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>>  };
>>>>>>
>>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>>> +     [BQ27000]   = BQ27000,
>>>>>> +     [BQ27010]   = BQ27010,
>>>>>> +     [BQ2750X]   = BQ2750X,
>>>>>> +     [BQ2751X]   = BQ2751X,
>>>>>> +     [BQ2752X]   = BQ2751X,
>>>>>> +     [BQ27500]   = BQ27500,
>>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>>> +     [BQ27530]   = BQ27530,
>>>>>> +     [BQ27531]   = BQ27530,
>>>>>> +     [BQ27541]   = BQ27541,
>>>>>> +     [BQ27542]   = BQ27541,
>>>>>> +     [BQ27546]   = BQ27541,
>>>>>> +     [BQ27742]   = BQ27541,
>>>>>> +     [BQ27545]   = BQ27545,
>>>>>> +     [BQ27421]   = BQ27421,
>>>>>> +     [BQ27425]   = BQ27421,
>>>>>> +     [BQ27441]   = BQ27421,
>>>>>> +     [BQ27621]   = BQ27421,
>>>>>> +};
>>>>>> +
>>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>
>>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>>> +};
>>>>>> +
>>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>>> +     [BQ27500] = 0x04143672,
>>>>>> +     [BQ27545] = 0x04143672,
>>>>>> +     [BQ27421] = 0x80008000,
>>>>>> +     [BQ27425] = 0x04143672,
>>>>>> +     [BQ27441] = 0x80008000,
>>>>>> +     [BQ27621] = 0x80008000,
>>>>>> +};
>>>>>> +
>>>>>>
>>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>>               .drv_data = di,
>>>>>>       };
>>>>>>
>>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>> +
>>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>>
>>>>> NACK, this is a mess, you should not be using a table to change what
>>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>>> it should have the same one correct ID, use a different index or array
>>>>> if you would like, but this is very hacky.
>>>>
>>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>>> its normal u32. What do you think of that?
>>>>
>>>
>>> Why would it need multiple IDs for one device? Just pass in the one
>>> correct device ID that it is. No reason to make this so complicated.
>>> From the one ID you can then use tables to lookup any other info about
>>> that device, you don't have to have ever ID populated in every table,
>>> you can even have a table of tables if you would like:
>>>
>>> static const struct chip_lookup lookup_table = {
>>>         [bq27425] = {
>>>                 .regs = &bq27xxx_regs[bq27425],
>>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>>         },
>>>         [bq27343] = {
>>> ...
>>>
>>> Not sure if that is valid C but I think you can get the idea.
>>
>> I considered a master lookup_table, but its ref to
>> bq27xxx_regs[fake-ID] duplicates the mapping of real-ID to di->chip.
>> The latter is still necessary as di->chip is used to select
>> conditional behaviors; we can't change its value in this patch.
>>
>
> Sure we can, in fact you could add the conditional behavior flags to the
> master lookup_table and cleanup all the current switch-case checks we do
> now.

You are proposing a significant change to the ID handling, which is
fine, but I don't wish to code that. Accept this minimal patch to
enable DM update, and then alter the ID logic when you have time in a
future patch.


>> So instead lets amend the I2C table to carry both its original value
>> (fake-ID) and the real-ID. That looks like:
>>
>> static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>     /* dest.    di->real_chip       di->chip      */
>>     { "bq27200",   (BQ27000   << 16) |  BQ27000   },
>>     { "bq27210",   (BQ27010   << 16) |  BQ27010   },
>>     ...
>>     { "bq27441",   (BQ27441   << 16) |  BQ27421   },
>>     { "bq27621",   (BQ27621   << 16) |  BQ27421   },
>>     {},
>> };
>>
>> In probe, retrieve two values:
>>
>>     di->real_chip = id->driver_data >> 16;
>>     di->chip = (u16) id->driver_data;
>>
>
> NAK, I'm sure you can see how hacky this is right? This doesn't give us
> anything that the old table didn't. And it fails to correct the issue
> with the tables: We have two chip IDs still!

I'm sorry you don't like the extra ID, but you're the party
responsible for (if not the author of) the fake-ID scheme :-)


> Try the lookup_table again, send be what you have and I can help get
> everything else working if you have any problems with the conditional
> behavior cleanups.
>
>> In setup, use two values:
>>
>>     di->unseal_key = bq27xxx_unseal_keys[di->real_chip];
>>     di->dm_regs = bq27xxx_dm_regs[di->real_chip];
>>     di->regs = bq27xxx_regs[di->chip]; // unchanged from orig src
>>
>> That yields the most compact implementation of this patch, and you get
>> di->real_chip in the bargain :-)
>>
>>
>>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>>> are clones, so we can be done with this series already. I'm sure you
>>>>> want that more than you want this "clever" work-around, right?
>>>>>
>>>>> Also fix all the checkpatch --strict warnings.
>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode
  2017-05-08 15:01       ` Andrew F. Davis
@ 2017-05-08 19:07         ` Liam Breck
  2017-05-08 19:12           ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-08 19:07 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Mon, May 8, 2017 at 8:01 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/08/2017 01:18 AM, Liam Breck wrote:
>> On Thu, May 4, 2017 at 9:38 AM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>
>>>> We tie multiple chips to unique register maps. When supporting a new chip,
>>>> it's easy to add a duplicate map by mistake.
>>>>
>>>> In debug mode we now scan the register maps for duplicates.
>>>>
>>>
>>> Debugging stuff doesn't need to go upstream.
>>
>> Since we're keeping a dupeless reg table, please ack this so folks
>> adding chips avoid adding dupes as Chris did.
>>
>> I don't have to mention there's tons of debug code upstream :-)
>>
>
> If you want it then make it into a tool that can go into scripts/ or
> tools/, it doesn't need to be inline cluttering up the source.

This code needs to read module static data. How would it work in an
external file?



>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>> ---
>>>>  drivers/power/supply/bq27xxx_battery.c | 21 +++++++++++++++++++++
>>>>  1 file changed, 21 insertions(+)
>>>>
>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>> index 0aecd41..97c646c 100644
>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>> @@ -1932,6 +1932,25 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
>>>>       schedule_delayed_work(&di->work, 0);
>>>>  }
>>>>
>>>> +#ifdef DEBUG
>>>> +static void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di)
>>>> +{
>>>> +     const size_t max = ARRAY_SIZE(bq27xxx_regs);
>>>> +     int a, b;
>>>> +
>>>> +     for (a = 1; a < max-1; a++) {
>>>> +             for (b = a+1; b < max; b++) {
>>>> +                     if (!memcmp(bq27xxx_regs[a], bq27xxx_regs[b],
>>>> +                                 sizeof(bq27xxx_regs[0])))
>>>> +                             dev_warn(di->dev,
>>>> +                                     "bq27xxx_regs[%d] & [%d] are identical\n", a, b);
>>>> +             }
>>>> +     }
>>>> +}
>>>> +#else
>>>> +static inline void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di) {}
>>>> +#endif
>>>> +
>>>>  int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>  {
>>>>       struct power_supply_desc *psy_desc;
>>>> @@ -1940,6 +1959,8 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>               .drv_data = di,
>>>>       };
>>>>
>>>> +     bq27xxx_battery_dbg_regs_dupes(di);
>>>> +
>>>>       di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>
>>>>       di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-08 19:02             ` Liam Breck
@ 2017-05-08 19:09               ` Andrew F. Davis
  2017-05-08 20:01                 ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-08 19:09 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/08/2017 02:02 PM, Liam Breck wrote:
> On Mon, May 8, 2017 at 8:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/08/2017 01:40 AM, Liam Breck wrote:
>>> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>
>>>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>>>
>>>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>>>> and data memory register tables.
>>>>>>>
>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>> ---
>>>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>> index 06f15da..0aecd41 100644
>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>> @@ -58,7 +58,7 @@
>>>>>>>
>>>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>>>
>>>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>>>
>>>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>>>
>>>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>>>
>>>>>>>  /* Register mappings */
>>>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>>>       [BQ27000] = {
>>>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>>>  static struct {
>>>>>>>       enum power_supply_property *props;
>>>>>>>       size_t size;
>>>>>>> -} bq27xxx_battery_props[] = {
>>>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>>>  };
>>>>>>>
>>>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>>>> +     [BQ27000]   = BQ27000,
>>>>>>> +     [BQ27010]   = BQ27010,
>>>>>>> +     [BQ2750X]   = BQ2750X,
>>>>>>> +     [BQ2751X]   = BQ2751X,
>>>>>>> +     [BQ2752X]   = BQ2751X,
>>>>>>> +     [BQ27500]   = BQ27500,
>>>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>>>> +     [BQ27530]   = BQ27530,
>>>>>>> +     [BQ27531]   = BQ27530,
>>>>>>> +     [BQ27541]   = BQ27541,
>>>>>>> +     [BQ27542]   = BQ27541,
>>>>>>> +     [BQ27546]   = BQ27541,
>>>>>>> +     [BQ27742]   = BQ27541,
>>>>>>> +     [BQ27545]   = BQ27545,
>>>>>>> +     [BQ27421]   = BQ27421,
>>>>>>> +     [BQ27425]   = BQ27421,
>>>>>>> +     [BQ27441]   = BQ27421,
>>>>>>> +     [BQ27621]   = BQ27421,
>>>>>>> +};
>>>>>>> +
>>>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>
>>>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>>>> +};
>>>>>>> +
>>>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>>>> +     [BQ27500] = 0x04143672,
>>>>>>> +     [BQ27545] = 0x04143672,
>>>>>>> +     [BQ27421] = 0x80008000,
>>>>>>> +     [BQ27425] = 0x04143672,
>>>>>>> +     [BQ27441] = 0x80008000,
>>>>>>> +     [BQ27621] = 0x80008000,
>>>>>>> +};
>>>>>>> +
>>>>>>>
>>>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>>>               .drv_data = di,
>>>>>>>       };
>>>>>>>
>>>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>>> +
>>>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>>>
>>>>>> NACK, this is a mess, you should not be using a table to change what
>>>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>>>> it should have the same one correct ID, use a different index or array
>>>>>> if you would like, but this is very hacky.
>>>>>
>>>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>>>> its normal u32. What do you think of that?
>>>>>
>>>>
>>>> Why would it need multiple IDs for one device? Just pass in the one
>>>> correct device ID that it is. No reason to make this so complicated.
>>>> From the one ID you can then use tables to lookup any other info about
>>>> that device, you don't have to have ever ID populated in every table,
>>>> you can even have a table of tables if you would like:
>>>>
>>>> static const struct chip_lookup lookup_table = {
>>>>         [bq27425] = {
>>>>                 .regs = &bq27xxx_regs[bq27425],
>>>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>>>         },
>>>>         [bq27343] = {
>>>> ...
>>>>
>>>> Not sure if that is valid C but I think you can get the idea.
>>>
>>> I considered a master lookup_table, but its ref to
>>> bq27xxx_regs[fake-ID] duplicates the mapping of real-ID to di->chip.
>>> The latter is still necessary as di->chip is used to select
>>> conditional behaviors; we can't change its value in this patch.
>>>
>>
>> Sure we can, in fact you could add the conditional behavior flags to the
>> master lookup_table and cleanup all the current switch-case checks we do
>> now.
> 
> You are proposing a significant change to the ID handling, which is
> fine, but I don't wish to code that. Accept this minimal patch to
> enable DM update, and then alter the ID logic when you have time in a
> future patch.
> 

Doesn't work like that, you can't just hack something together and hope
someone else will fix it later. If you want to change something you
should make it right the first time. We don't need DM update, but if you
would like it then you need to fix the problems it will create.

> 
>>> So instead lets amend the I2C table to carry both its original value
>>> (fake-ID) and the real-ID. That looks like:
>>>
>>> static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>     /* dest.    di->real_chip       di->chip      */
>>>     { "bq27200",   (BQ27000   << 16) |  BQ27000   },
>>>     { "bq27210",   (BQ27010   << 16) |  BQ27010   },
>>>     ...
>>>     { "bq27441",   (BQ27441   << 16) |  BQ27421   },
>>>     { "bq27621",   (BQ27621   << 16) |  BQ27421   },
>>>     {},
>>> };
>>>
>>> In probe, retrieve two values:
>>>
>>>     di->real_chip = id->driver_data >> 16;
>>>     di->chip = (u16) id->driver_data;
>>>
>>
>> NAK, I'm sure you can see how hacky this is right? This doesn't give us
>> anything that the old table didn't. And it fails to correct the issue
>> with the tables: We have two chip IDs still!
> 
> I'm sorry you don't like the extra ID, but you're the party
> responsible for (if not the author of) the fake-ID scheme :-)
> 

It has worked fine until now, your additions require a different scheme,
hacking around the old one is not a workable solution.

> 
>> Try the lookup_table again, send be what you have and I can help get
>> everything else working if you have any problems with the conditional
>> behavior cleanups.
>>
>>> In setup, use two values:
>>>
>>>     di->unseal_key = bq27xxx_unseal_keys[di->real_chip];
>>>     di->dm_regs = bq27xxx_dm_regs[di->real_chip];
>>>     di->regs = bq27xxx_regs[di->chip]; // unchanged from orig src
>>>
>>> That yields the most compact implementation of this patch, and you get
>>> di->real_chip in the bargain :-)
>>>
>>>
>>>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>>>> are clones, so we can be done with this series already. I'm sure you
>>>>>> want that more than you want this "clever" work-around, right?
>>>>>>
>>>>>> Also fix all the checkpatch --strict warnings.
>>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode
  2017-05-08 19:07         ` Liam Breck
@ 2017-05-08 19:12           ` Andrew F. Davis
  2017-05-08 20:08             ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-08 19:12 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/08/2017 02:07 PM, Liam Breck wrote:
> On Mon, May 8, 2017 at 8:01 AM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/08/2017 01:18 AM, Liam Breck wrote:
>>> On Thu, May 4, 2017 at 9:38 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>
>>>>> We tie multiple chips to unique register maps. When supporting a new chip,
>>>>> it's easy to add a duplicate map by mistake.
>>>>>
>>>>> In debug mode we now scan the register maps for duplicates.
>>>>>
>>>>
>>>> Debugging stuff doesn't need to go upstream.
>>>
>>> Since we're keeping a dupeless reg table, please ack this so folks
>>> adding chips avoid adding dupes as Chris did.
>>>
>>> I don't have to mention there's tons of debug code upstream :-)
>>>
>>
>> If you want it then make it into a tool that can go into scripts/ or
>> tools/, it doesn't need to be inline cluttering up the source.
> 
> This code needs to read module static data. How would it work in an
> external file?
> 

If you are creating an external checking tool it can just ignore
'static' scope definitions when it is parsing this file.

> 
> 
>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>> ---
>>>>>  drivers/power/supply/bq27xxx_battery.c | 21 +++++++++++++++++++++
>>>>>  1 file changed, 21 insertions(+)
>>>>>
>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>> index 0aecd41..97c646c 100644
>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>> @@ -1932,6 +1932,25 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
>>>>>       schedule_delayed_work(&di->work, 0);
>>>>>  }
>>>>>
>>>>> +#ifdef DEBUG
>>>>> +static void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di)
>>>>> +{
>>>>> +     const size_t max = ARRAY_SIZE(bq27xxx_regs);
>>>>> +     int a, b;
>>>>> +
>>>>> +     for (a = 1; a < max-1; a++) {
>>>>> +             for (b = a+1; b < max; b++) {
>>>>> +                     if (!memcmp(bq27xxx_regs[a], bq27xxx_regs[b],
>>>>> +                                 sizeof(bq27xxx_regs[0])))
>>>>> +                             dev_warn(di->dev,
>>>>> +                                     "bq27xxx_regs[%d] & [%d] are identical\n", a, b);
>>>>> +             }
>>>>> +     }
>>>>> +}
>>>>> +#else
>>>>> +static inline void bq27xxx_battery_dbg_regs_dupes(struct bq27xxx_device_info *di) {}
>>>>> +#endif
>>>>> +
>>>>>  int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>  {
>>>>>       struct power_supply_desc *psy_desc;
>>>>> @@ -1940,6 +1959,8 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>               .drv_data = di,
>>>>>       };
>>>>>
>>>>> +     bq27xxx_battery_dbg_regs_dupes(di);
>>>>> +
>>>>>       di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>
>>>>>       di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-08 18:42             ` Andrew F. Davis
@ 2017-05-08 19:31               ` Liam Breck
  2017-05-08 19:50                 ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-08 19:31 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Mon, May 8, 2017 at 11:42 AM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/08/2017 01:39 PM, Liam Breck wrote:
>> On Mon, May 8, 2017 at 7:54 AM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/08/2017 01:16 AM, Liam Breck wrote:
>>>> On Thu, May 4, 2017 at 11:40 AM, Liam Breck <liam@networkimprov.net> wrote:
>>>>> On Thu, May 4, 2017 at 9:52 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>
>>>>>>> Previously there was no way to configure these chips in the event that the
>>>>>>> defaults didn't match the battery in question.
>>>>>>>
>>>>>>> For chips with RAM data memory (and also those with flash/NVM data memory
>>>>>>> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
>>>>>>> set module param dt_monitored_battery_updates_nvm=0) we now call
>>>>>>> power_supply_get_battery_info(), check its values, and write battery
>>>>>>> properties to chip data memory if there is a dm_regs table for the chip.
>>>>>>>
>>>>>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>> ---
>>>>>>>  drivers/power/supply/Kconfig           |   9 ++
>>>>>>>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>>>>>>>  include/linux/power/bq27xxx_battery.h  |   2 +
>>>>>>>  3 files changed, 209 insertions(+), 1 deletion(-)
>>>>>>>
>>>>>>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>>>>>>> index 76806a0..85e2fb2 100644
>>>>>>> --- a/drivers/power/supply/Kconfig
>>>>>>> +++ b/drivers/power/supply/Kconfig
>>>>>>> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>>>>>>>         Say Y here to enable support for batteries with BQ27xxx chips
>>>>>>>         connected over an I2C bus.
>>>>>>>
>>>>>>> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>> +     bool "BQ27xxx support for update of NVM/flash data memory"
>>>>>>> +     depends on BATTERY_BQ27XXX_I2C
>>>>>>> +     help
>>>>>>> +       Say Y here to enable devicetree monitored-battery config to update
>>>>>>> +       NVM/flash data memory. Only enable this option for devices with a
>>>>>>> +       fuel gauge mounted on the circuit board, and a battery that cannot
>>>>>>> +       be replaced with one of a different type.
>>>>>>> +
>>>>>>>  config BATTERY_DA9030
>>>>>>>       tristate "DA9030 battery driver"
>>>>>>>       depends on PMIC_DA903X
>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>> index 8ab184c..06f15da 100644
>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>
>>>>>>>  #define BQ27XXX_DM_SZ        32
>>>>>>>
>>>>>>> +struct bq27xxx_dm_reg {
>>>>>>> +     u8 subclass_id;
>>>>>>> +     u8 offset;
>>>>>>> +     u8 bytes;
>>>>>>> +     u16 min, max;
>>>>>>> +};
>>>>>>> +
>>>>>>>  /**
>>>>>>>   * struct bq27xxx_dm_buf - chip data memory buffer
>>>>>>>   * @class: data memory subclass_id
>>>>>>> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>>>>>>>       bool has_data, dirty;
>>>>>>>  };
>>>>>>>
>>>>>>> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
>>>>>>> +     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
>>>>>>> +     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
>>>>>>> +     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>>>>>>> +};
>>>>>>> +
>>>>>>> +
>>>>>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>> +static bool bq27xxx_dt_to_nvm = true;
>>>>>>> +
>>>>>>> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
>>>>>>> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
>>>>>>> +     "Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
>>>>>>
>>>>>> As before, the default should not be y, this is a rare case and I can't
>>>>>> see it being useful or wanted by anyone but device manufacturers. I
>>>>>> don't want everyones chip's factory programmed NVM overwritten by
>>>>>> accident when someone compiles and ships a kernel with
>>>>>> BATTERY_BQ27XXX_DT_UPDATES_NVM=y
>>>>>
>>>>> Right, the point of the config option is to let a device vendor ship a
>>>>> kernel + dtb which can field-upgrade NVM. (Setting the option does
>>>>> nothing absent the necessary dtb.)
>>>>>
>>>>> Module params are for end-user config; we can't require a device
>>>>> vendor to ship /etc/modprobe.d/xyz. And we certainly don't want a
>>>>> kernel package update to defeat the end-user config of
>>>>> dt_monitored_battery_updates_nvm=0 !!
>>>>>
>>>>> I believe Sebastian agrees, given that he queued this patch :-)
>>>>
>>>> I clarified the rationale for module param default =1 above; could you ack?
>>>>
>>>> That prevents this scenario:
>>>> 1) user changes battery type, sets dt_monitored_battery_updates_nvm=0
>>>> 2) vendor ships kernel package with dtb update and
>>>> dt_monitored_battery_updates_nvm=1
>>>> 3) gauge stops working correctly
>>>>
>>>
>>> Leaving it =1 will encourage this situation, not prevent it. Updating
>>> NVM is a non-standard operation for these parts. It should only be done
>>> once ideally. It is nice being able to update the NVM, and we have
>>> user-space tools for this, but this is a dangerous operation, improperly
>>> programming can brick the chip, as you have found out.
>>>
>>> If you want to add this function into the kernel driver that is fine,
>>> but you *cannot* have this be the default, it needs to be a hidden away
>>> option for people who know what they are doing, else you will end up
>>> accidentally causing damage to countless users' hardware.
>>
>> I don't think you followed my logic.... It *is* hidden behind a
>> dedicated kernel config option which only device vendors (and
>> tinkerers :-) would use. A kernel package with that option and
>> suitable dtb has to perform the update without manipulation of the
>> module param. The module param is to let the user prevent any future
>> update by such a kernel package, since only he knows that he changed
>> the battery type.
>>
>> What is your evidence for the assertion of "encourage this situation"?
>>
>
> It is the default value, what more evidence do you want? Someone should
> have to enable the functionality in Kconfig *and* enable it as a
> module_param. Leaving either on by default will cause it to be
> accidentally left enabled.

We could add a second config option to eliminate the possibility of
the first one being set by mistake.

You can't trivially enable a config option. If you set it, you'd
obviously set the module param if that were necessary, so that's no
extra protection against "accidentally left enabled". (And the config
option does nothing without a suitable dtb.)

My scenario is a clear and likely threat. You haven't described a
threat scenario.

The docs for the config option describe its correct use, and I will
mention the risk of overwriting a smart battery. No general purpose
distro will enable it.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-08 19:31               ` Liam Breck
@ 2017-05-08 19:50                 ` Andrew F. Davis
  2017-05-08 20:34                   ` Liam Breck
  0 siblings, 1 reply; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-08 19:50 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/08/2017 02:31 PM, Liam Breck wrote:
> On Mon, May 8, 2017 at 11:42 AM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/08/2017 01:39 PM, Liam Breck wrote:
>>> On Mon, May 8, 2017 at 7:54 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/08/2017 01:16 AM, Liam Breck wrote:
>>>>> On Thu, May 4, 2017 at 11:40 AM, Liam Breck <liam@networkimprov.net> wrote:
>>>>>> On Thu, May 4, 2017 at 9:52 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>>
>>>>>>>> Previously there was no way to configure these chips in the event that the
>>>>>>>> defaults didn't match the battery in question.
>>>>>>>>
>>>>>>>> For chips with RAM data memory (and also those with flash/NVM data memory
>>>>>>>> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
>>>>>>>> set module param dt_monitored_battery_updates_nvm=0) we now call
>>>>>>>> power_supply_get_battery_info(), check its values, and write battery
>>>>>>>> properties to chip data memory if there is a dm_regs table for the chip.
>>>>>>>>
>>>>>>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>>> ---
>>>>>>>>  drivers/power/supply/Kconfig           |   9 ++
>>>>>>>>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>>>>>>>>  include/linux/power/bq27xxx_battery.h  |   2 +
>>>>>>>>  3 files changed, 209 insertions(+), 1 deletion(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>>>>>>>> index 76806a0..85e2fb2 100644
>>>>>>>> --- a/drivers/power/supply/Kconfig
>>>>>>>> +++ b/drivers/power/supply/Kconfig
>>>>>>>> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>>>>>>>>         Say Y here to enable support for batteries with BQ27xxx chips
>>>>>>>>         connected over an I2C bus.
>>>>>>>>
>>>>>>>> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>> +     bool "BQ27xxx support for update of NVM/flash data memory"
>>>>>>>> +     depends on BATTERY_BQ27XXX_I2C
>>>>>>>> +     help
>>>>>>>> +       Say Y here to enable devicetree monitored-battery config to update
>>>>>>>> +       NVM/flash data memory. Only enable this option for devices with a
>>>>>>>> +       fuel gauge mounted on the circuit board, and a battery that cannot
>>>>>>>> +       be replaced with one of a different type.
>>>>>>>> +
>>>>>>>>  config BATTERY_DA9030
>>>>>>>>       tristate "DA9030 battery driver"
>>>>>>>>       depends on PMIC_DA903X
>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>> index 8ab184c..06f15da 100644
>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>>
>>>>>>>>  #define BQ27XXX_DM_SZ        32
>>>>>>>>
>>>>>>>> +struct bq27xxx_dm_reg {
>>>>>>>> +     u8 subclass_id;
>>>>>>>> +     u8 offset;
>>>>>>>> +     u8 bytes;
>>>>>>>> +     u16 min, max;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>>  /**
>>>>>>>>   * struct bq27xxx_dm_buf - chip data memory buffer
>>>>>>>>   * @class: data memory subclass_id
>>>>>>>> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>>>>>>>>       bool has_data, dirty;
>>>>>>>>  };
>>>>>>>>
>>>>>>>> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
>>>>>>>> +     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
>>>>>>>> +     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
>>>>>>>> +     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>> +static bool bq27xxx_dt_to_nvm = true;
>>>>>>>> +
>>>>>>>> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
>>>>>>>> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
>>>>>>>> +     "Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
>>>>>>>
>>>>>>> As before, the default should not be y, this is a rare case and I can't
>>>>>>> see it being useful or wanted by anyone but device manufacturers. I
>>>>>>> don't want everyones chip's factory programmed NVM overwritten by
>>>>>>> accident when someone compiles and ships a kernel with
>>>>>>> BATTERY_BQ27XXX_DT_UPDATES_NVM=y
>>>>>>
>>>>>> Right, the point of the config option is to let a device vendor ship a
>>>>>> kernel + dtb which can field-upgrade NVM. (Setting the option does
>>>>>> nothing absent the necessary dtb.)
>>>>>>
>>>>>> Module params are for end-user config; we can't require a device
>>>>>> vendor to ship /etc/modprobe.d/xyz. And we certainly don't want a
>>>>>> kernel package update to defeat the end-user config of
>>>>>> dt_monitored_battery_updates_nvm=0 !!
>>>>>>
>>>>>> I believe Sebastian agrees, given that he queued this patch :-)
>>>>>
>>>>> I clarified the rationale for module param default =1 above; could you ack?
>>>>>
>>>>> That prevents this scenario:
>>>>> 1) user changes battery type, sets dt_monitored_battery_updates_nvm=0
>>>>> 2) vendor ships kernel package with dtb update and
>>>>> dt_monitored_battery_updates_nvm=1
>>>>> 3) gauge stops working correctly
>>>>>
>>>>
>>>> Leaving it =1 will encourage this situation, not prevent it. Updating
>>>> NVM is a non-standard operation for these parts. It should only be done
>>>> once ideally. It is nice being able to update the NVM, and we have
>>>> user-space tools for this, but this is a dangerous operation, improperly
>>>> programming can brick the chip, as you have found out.
>>>>
>>>> If you want to add this function into the kernel driver that is fine,
>>>> but you *cannot* have this be the default, it needs to be a hidden away
>>>> option for people who know what they are doing, else you will end up
>>>> accidentally causing damage to countless users' hardware.
>>>
>>> I don't think you followed my logic.... It *is* hidden behind a
>>> dedicated kernel config option which only device vendors (and
>>> tinkerers :-) would use. A kernel package with that option and
>>> suitable dtb has to perform the update without manipulation of the
>>> module param. The module param is to let the user prevent any future
>>> update by such a kernel package, since only he knows that he changed
>>> the battery type.
>>>
>>> What is your evidence for the assertion of "encourage this situation"?
>>>
>>
>> It is the default value, what more evidence do you want? Someone should
>> have to enable the functionality in Kconfig *and* enable it as a
>> module_param. Leaving either on by default will cause it to be
>> accidentally left enabled.
> 
> We could add a second config option to eliminate the possibility of
> the first one being set by mistake.
> 
> You can't trivially enable a config option. If you set it, you'd
> obviously set the module param if that were necessary, so that's no
> extra protection against "accidentally left enabled". (And the config
> option does nothing without a suitable dtb.)
> 

Why would you "obviously set the module param"? If this config option is
enabled then you still have to set the module param to make this write
to your device's NVM, that is two things vs one. The people who use
kernels often don't build them. Both should need to be set to update the
devices NVM.

> My scenario is a clear and likely threat. You haven't described a
> threat scenario.
> 

Easy, kernel is built with the config option enabled and their DT has
invalid option for their battery. Now everyone bricks their hardware.

Vs. your three step situation that the two people who will ever use this
will never actually find themselves in, that results in a minor
inconvenience as they have to turn a module param back off.

Lets take the safe route and leave this default off.

> The docs for the config option describe its correct use, and I will
> mention the risk of overwriting a smart battery. No general purpose
> distro will enable it.
> 

How can you know this, I'm pretty sure Ubuntu ships with a randconfig
kernel :)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-08 19:09               ` Andrew F. Davis
@ 2017-05-08 20:01                 ` Liam Breck
  2017-05-09 16:20                   ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-08 20:01 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Mon, May 8, 2017 at 12:09 PM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/08/2017 02:02 PM, Liam Breck wrote:
>> On Mon, May 8, 2017 at 8:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/08/2017 01:40 AM, Liam Breck wrote:
>>>> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>>>>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>>>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>>
>>>>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>>>>
>>>>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>>>>> and data memory register tables.
>>>>>>>>
>>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>>> ---
>>>>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>> index 06f15da..0aecd41 100644
>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>> @@ -58,7 +58,7 @@
>>>>>>>>
>>>>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>>>>
>>>>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>>>>
>>>>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>>>>
>>>>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>>>>
>>>>>>>>  /* Register mappings */
>>>>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>>>>       [BQ27000] = {
>>>>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>>>>  static struct {
>>>>>>>>       enum power_supply_property *props;
>>>>>>>>       size_t size;
>>>>>>>> -} bq27xxx_battery_props[] = {
>>>>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>>>>  };
>>>>>>>>
>>>>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>>>>> +     [BQ27000]   = BQ27000,
>>>>>>>> +     [BQ27010]   = BQ27010,
>>>>>>>> +     [BQ2750X]   = BQ2750X,
>>>>>>>> +     [BQ2751X]   = BQ2751X,
>>>>>>>> +     [BQ2752X]   = BQ2751X,
>>>>>>>> +     [BQ27500]   = BQ27500,
>>>>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>>>>> +     [BQ27530]   = BQ27530,
>>>>>>>> +     [BQ27531]   = BQ27530,
>>>>>>>> +     [BQ27541]   = BQ27541,
>>>>>>>> +     [BQ27542]   = BQ27541,
>>>>>>>> +     [BQ27546]   = BQ27541,
>>>>>>>> +     [BQ27742]   = BQ27541,
>>>>>>>> +     [BQ27545]   = BQ27545,
>>>>>>>> +     [BQ27421]   = BQ27421,
>>>>>>>> +     [BQ27425]   = BQ27421,
>>>>>>>> +     [BQ27441]   = BQ27421,
>>>>>>>> +     [BQ27621]   = BQ27421,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>>
>>>>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>>>>> +     [BQ27500] = 0x04143672,
>>>>>>>> +     [BQ27545] = 0x04143672,
>>>>>>>> +     [BQ27421] = 0x80008000,
>>>>>>>> +     [BQ27425] = 0x04143672,
>>>>>>>> +     [BQ27441] = 0x80008000,
>>>>>>>> +     [BQ27621] = 0x80008000,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>>
>>>>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>>>>               .drv_data = di,
>>>>>>>>       };
>>>>>>>>
>>>>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>>>> +
>>>>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>>>>
>>>>>>> NACK, this is a mess, you should not be using a table to change what
>>>>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>>>>> it should have the same one correct ID, use a different index or array
>>>>>>> if you would like, but this is very hacky.
>>>>>>
>>>>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>>>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>>>>> its normal u32. What do you think of that?
>>>>>>
>>>>>
>>>>> Why would it need multiple IDs for one device? Just pass in the one
>>>>> correct device ID that it is. No reason to make this so complicated.
>>>>> From the one ID you can then use tables to lookup any other info about
>>>>> that device, you don't have to have ever ID populated in every table,
>>>>> you can even have a table of tables if you would like:
>>>>>
>>>>> static const struct chip_lookup lookup_table = {
>>>>>         [bq27425] = {
>>>>>                 .regs = &bq27xxx_regs[bq27425],
>>>>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>>>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>>>>         },
>>>>>         [bq27343] = {
>>>>> ...
>>>>>
>>>>> Not sure if that is valid C but I think you can get the idea.
>>>>
>>>> I considered a master lookup_table, but its ref to
>>>> bq27xxx_regs[fake-ID] duplicates the mapping of real-ID to di->chip.
>>>> The latter is still necessary as di->chip is used to select
>>>> conditional behaviors; we can't change its value in this patch.
>>>>
>>>
>>> Sure we can, in fact you could add the conditional behavior flags to the
>>> master lookup_table and cleanup all the current switch-case checks we do
>>> now.
>>
>> You are proposing a significant change to the ID handling, which is
>> fine, but I don't wish to code that. Accept this minimal patch to
>> enable DM update, and then alter the ID logic when you have time in a
>> future patch.
>>
>
> Doesn't work like that, you can't just hack something together and hope
> someone else will fix it later. If you want to change something you
> should make it right the first time. We don't need DM update, but if you
> would like it then you need to fix the problems it will create.

You do indeed need DM update for the RAM-only chips; they expect to be
configured on boot, as I documented previously.

Adding real-ID to the I2C table and using it in *exactly two lines* of
setup() is a minimal workaround for a pre-existing design flaw. You
have a concept for fixing it, so you should code it. I gracefully
decline.

I have labored on this patchset for some 19 revisions. Sebastian seems
to think that's enough, as he queued most of the series last week even
tho you hadn't acked it.



>>>> So instead lets amend the I2C table to carry both its original value
>>>> (fake-ID) and the real-ID. That looks like:
>>>>
>>>> static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>     /* dest.    di->real_chip       di->chip      */
>>>>     { "bq27200",   (BQ27000   << 16) |  BQ27000   },
>>>>     { "bq27210",   (BQ27010   << 16) |  BQ27010   },
>>>>     ...
>>>>     { "bq27441",   (BQ27441   << 16) |  BQ27421   },
>>>>     { "bq27621",   (BQ27621   << 16) |  BQ27421   },
>>>>     {},
>>>> };
>>>>
>>>> In probe, retrieve two values:
>>>>
>>>>     di->real_chip = id->driver_data >> 16;
>>>>     di->chip = (u16) id->driver_data;
>>>>
>>>
>>> NAK, I'm sure you can see how hacky this is right? This doesn't give us
>>> anything that the old table didn't. And it fails to correct the issue
>>> with the tables: We have two chip IDs still!
>>
>> I'm sorry you don't like the extra ID, but you're the party
>> responsible for (if not the author of) the fake-ID scheme :-)
>>
>
> It has worked fine until now, your additions require a different scheme,
> hacking around the old one is not a workable solution.
>
>>
>>> Try the lookup_table again, send be what you have and I can help get
>>> everything else working if you have any problems with the conditional
>>> behavior cleanups.
>>>
>>>> In setup, use two values:
>>>>
>>>>     di->unseal_key = bq27xxx_unseal_keys[di->real_chip];
>>>>     di->dm_regs = bq27xxx_dm_regs[di->real_chip];
>>>>     di->regs = bq27xxx_regs[di->chip]; // unchanged from orig src
>>>>
>>>> That yields the most compact implementation of this patch, and you get
>>>> di->real_chip in the bargain :-)
>>>>
>>>>
>>>>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>>>>> are clones, so we can be done with this series already. I'm sure you
>>>>>>> want that more than you want this "clever" work-around, right?
>>>>>>>
>>>>>>> Also fix all the checkpatch --strict warnings.
>>>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode
  2017-05-08 19:12           ` Andrew F. Davis
@ 2017-05-08 20:08             ` Liam Breck
  0 siblings, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-08 20:08 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Mon, May 8, 2017 at 12:12 PM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/08/2017 02:07 PM, Liam Breck wrote:
>> On Mon, May 8, 2017 at 8:01 AM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/08/2017 01:18 AM, Liam Breck wrote:
>>>> On Thu, May 4, 2017 at 9:38 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>
>>>>>> We tie multiple chips to unique register maps. When supporting a new chip,
>>>>>> it's easy to add a duplicate map by mistake.
>>>>>>
>>>>>> In debug mode we now scan the register maps for duplicates.
>>>>>>
>>>>>
>>>>> Debugging stuff doesn't need to go upstream.
>>>>
>>>> Since we're keeping a dupeless reg table, please ack this so folks
>>>> adding chips avoid adding dupes as Chris did.
>>>>
>>>> I don't have to mention there's tons of debug code upstream :-)
>>>>
>>>
>>> If you want it then make it into a tool that can go into scripts/ or
>>> tools/, it doesn't need to be inline cluttering up the source.
>>
>> This code needs to read module static data. How would it work in an
>> external file?
>>
>
> If you are creating an external checking tool it can just ignore
> 'static' scope definitions when it is parsing this file.

Can you point to an example?

Is it a program with #include .../bq27xxx_battery.c and a main() that
runs the dupe check? I won't parse the file since the compiler does
that so remarkably well.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-08 19:50                 ` Andrew F. Davis
@ 2017-05-08 20:34                   ` Liam Breck
  2017-05-09 16:06                     ` Andrew F. Davis
  0 siblings, 1 reply; 52+ messages in thread
From: Liam Breck @ 2017-05-08 20:34 UTC (permalink / raw)
  To: Andrew F. Davis; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On Mon, May 8, 2017 at 12:50 PM, Andrew F. Davis <afd@ti.com> wrote:
> On 05/08/2017 02:31 PM, Liam Breck wrote:
>> On Mon, May 8, 2017 at 11:42 AM, Andrew F. Davis <afd@ti.com> wrote:
>>> On 05/08/2017 01:39 PM, Liam Breck wrote:
>>>> On Mon, May 8, 2017 at 7:54 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>> On 05/08/2017 01:16 AM, Liam Breck wrote:
>>>>>> On Thu, May 4, 2017 at 11:40 AM, Liam Breck <liam@networkimprov.net> wrote:
>>>>>>> On Thu, May 4, 2017 at 9:52 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>>>
>>>>>>>>> Previously there was no way to configure these chips in the event that the
>>>>>>>>> defaults didn't match the battery in question.
>>>>>>>>>
>>>>>>>>> For chips with RAM data memory (and also those with flash/NVM data memory
>>>>>>>>> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
>>>>>>>>> set module param dt_monitored_battery_updates_nvm=0) we now call
>>>>>>>>> power_supply_get_battery_info(), check its values, and write battery
>>>>>>>>> properties to chip data memory if there is a dm_regs table for the chip.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>>>> ---
>>>>>>>>>  drivers/power/supply/Kconfig           |   9 ++
>>>>>>>>>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>>>>>>>>>  include/linux/power/bq27xxx_battery.h  |   2 +
>>>>>>>>>  3 files changed, 209 insertions(+), 1 deletion(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>>>>>>>>> index 76806a0..85e2fb2 100644
>>>>>>>>> --- a/drivers/power/supply/Kconfig
>>>>>>>>> +++ b/drivers/power/supply/Kconfig
>>>>>>>>> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>>>>>>>>>         Say Y here to enable support for batteries with BQ27xxx chips
>>>>>>>>>         connected over an I2C bus.
>>>>>>>>>
>>>>>>>>> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>>> +     bool "BQ27xxx support for update of NVM/flash data memory"
>>>>>>>>> +     depends on BATTERY_BQ27XXX_I2C
>>>>>>>>> +     help
>>>>>>>>> +       Say Y here to enable devicetree monitored-battery config to update
>>>>>>>>> +       NVM/flash data memory. Only enable this option for devices with a
>>>>>>>>> +       fuel gauge mounted on the circuit board, and a battery that cannot
>>>>>>>>> +       be replaced with one of a different type.
>>>>>>>>> +
>>>>>>>>>  config BATTERY_DA9030
>>>>>>>>>       tristate "DA9030 battery driver"
>>>>>>>>>       depends on PMIC_DA903X
>>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>> index 8ab184c..06f15da 100644
>>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>>>
>>>>>>>>>  #define BQ27XXX_DM_SZ        32
>>>>>>>>>
>>>>>>>>> +struct bq27xxx_dm_reg {
>>>>>>>>> +     u8 subclass_id;
>>>>>>>>> +     u8 offset;
>>>>>>>>> +     u8 bytes;
>>>>>>>>> +     u16 min, max;
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>>  /**
>>>>>>>>>   * struct bq27xxx_dm_buf - chip data memory buffer
>>>>>>>>>   * @class: data memory subclass_id
>>>>>>>>> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>>>>>>>>>       bool has_data, dirty;
>>>>>>>>>  };
>>>>>>>>>
>>>>>>>>> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
>>>>>>>>> +     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
>>>>>>>>> +     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
>>>>>>>>> +     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>>> +static bool bq27xxx_dt_to_nvm = true;
>>>>>>>>> +
>>>>>>>>> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
>>>>>>>>> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
>>>>>>>>> +     "Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
>>>>>>>>
>>>>>>>> As before, the default should not be y, this is a rare case and I can't
>>>>>>>> see it being useful or wanted by anyone but device manufacturers. I
>>>>>>>> don't want everyones chip's factory programmed NVM overwritten by
>>>>>>>> accident when someone compiles and ships a kernel with
>>>>>>>> BATTERY_BQ27XXX_DT_UPDATES_NVM=y
>>>>>>>
>>>>>>> Right, the point of the config option is to let a device vendor ship a
>>>>>>> kernel + dtb which can field-upgrade NVM. (Setting the option does
>>>>>>> nothing absent the necessary dtb.)
>>>>>>>
>>>>>>> Module params are for end-user config; we can't require a device
>>>>>>> vendor to ship /etc/modprobe.d/xyz. And we certainly don't want a
>>>>>>> kernel package update to defeat the end-user config of
>>>>>>> dt_monitored_battery_updates_nvm=0 !!
>>>>>>>
>>>>>>> I believe Sebastian agrees, given that he queued this patch :-)
>>>>>>
>>>>>> I clarified the rationale for module param default =1 above; could you ack?
>>>>>>
>>>>>> That prevents this scenario:
>>>>>> 1) user changes battery type, sets dt_monitored_battery_updates_nvm=0
>>>>>> 2) vendor ships kernel package with dtb update and
>>>>>> dt_monitored_battery_updates_nvm=1
>>>>>> 3) gauge stops working correctly
>>>>>>
>>>>>
>>>>> Leaving it =1 will encourage this situation, not prevent it. Updating
>>>>> NVM is a non-standard operation for these parts. It should only be done
>>>>> once ideally. It is nice being able to update the NVM, and we have
>>>>> user-space tools for this, but this is a dangerous operation, improperly
>>>>> programming can brick the chip, as you have found out.
>>>>>
>>>>> If you want to add this function into the kernel driver that is fine,
>>>>> but you *cannot* have this be the default, it needs to be a hidden away
>>>>> option for people who know what they are doing, else you will end up
>>>>> accidentally causing damage to countless users' hardware.
>>>>
>>>> I don't think you followed my logic.... It *is* hidden behind a
>>>> dedicated kernel config option which only device vendors (and
>>>> tinkerers :-) would use. A kernel package with that option and
>>>> suitable dtb has to perform the update without manipulation of the
>>>> module param. The module param is to let the user prevent any future
>>>> update by such a kernel package, since only he knows that he changed
>>>> the battery type.
>>>>
>>>> What is your evidence for the assertion of "encourage this situation"?
>>>>
>>>
>>> It is the default value, what more evidence do you want? Someone should
>>> have to enable the functionality in Kconfig *and* enable it as a
>>> module_param. Leaving either on by default will cause it to be
>>> accidentally left enabled.
>>
>> We could add a second config option to eliminate the possibility of
>> the first one being set by mistake.
>>
>> You can't trivially enable a config option. If you set it, you'd
>> obviously set the module param if that were necessary, so that's no
>> extra protection against "accidentally left enabled". (And the config
>> option does nothing without a suitable dtb.)
>>
>
> Why would you "obviously set the module param"? If this config option is
> enabled then you still have to set the module param to make this write
> to your device's NVM, that is two things vs one. The people who use
> kernels often don't build them. Both should need to be set to update the
> devices NVM.

The target of this config option is device vendors. They would
obviously set the module param when setting the config option to
field-upgrade NVM.

>> My scenario is a clear and likely threat. You haven't described a
>> threat scenario.
>>
>
> Easy, kernel is built with the config option enabled and their DT has
> invalid option for their battery. Now everyone bricks their hardware.

A device vendor could misconfigure their hw, sure. They would also fix
it in an update. That's not a threat. In what scenario does someone
other than the vendor or tinkering user misconfigure the gauge?

> Vs. your three step situation that the two people who will ever use this
> will never actually find themselves in, that results in a minor
> inconvenience as they have to turn a module param back off.

I don't think you followed the scenario. User resetting the param =0
after a vendor update sets =1 would not fix the NVM misconfig caused
by the update! The whole point of user setting =0 is to prevent that
update.

> Lets take the safe route and leave this default off.

I offered you a safe route: two config options.

>> The docs for the config option describe its correct use, and I will
>> mention the risk of overwriting a smart battery. No general purpose
>> distro will enable it.
>>
>
> How can you know this, I'm pretty sure Ubuntu ships with a randconfig
> kernel :)

And that includes a rand dtb? :-p

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support
  2017-05-08 20:34                   ` Liam Breck
@ 2017-05-09 16:06                     ` Andrew F. Davis
  0 siblings, 0 replies; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-09 16:06 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/08/2017 03:34 PM, Liam Breck wrote:
> On Mon, May 8, 2017 at 12:50 PM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/08/2017 02:31 PM, Liam Breck wrote:
>>> On Mon, May 8, 2017 at 11:42 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/08/2017 01:39 PM, Liam Breck wrote:
>>>>> On Mon, May 8, 2017 at 7:54 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>> On 05/08/2017 01:16 AM, Liam Breck wrote:
>>>>>>> On Thu, May 4, 2017 at 11:40 AM, Liam Breck <liam@networkimprov.net> wrote:
>>>>>>>> On Thu, May 4, 2017 at 9:52 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>>>>
>>>>>>>>>> Previously there was no way to configure these chips in the event that the
>>>>>>>>>> defaults didn't match the battery in question.
>>>>>>>>>>
>>>>>>>>>> For chips with RAM data memory (and also those with flash/NVM data memory
>>>>>>>>>> if CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is defined and the user has not
>>>>>>>>>> set module param dt_monitored_battery_updates_nvm=0) we now call
>>>>>>>>>> power_supply_get_battery_info(), check its values, and write battery
>>>>>>>>>> properties to chip data memory if there is a dm_regs table for the chip.
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
>>>>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>>>>> ---
>>>>>>>>>>  drivers/power/supply/Kconfig           |   9 ++
>>>>>>>>>>  drivers/power/supply/bq27xxx_battery.c | 199 ++++++++++++++++++++++++++++++++-
>>>>>>>>>>  include/linux/power/bq27xxx_battery.h  |   2 +
>>>>>>>>>>  3 files changed, 209 insertions(+), 1 deletion(-)
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>>>>>>>>>> index 76806a0..85e2fb2 100644
>>>>>>>>>> --- a/drivers/power/supply/Kconfig
>>>>>>>>>> +++ b/drivers/power/supply/Kconfig
>>>>>>>>>> @@ -178,6 +178,15 @@ config BATTERY_BQ27XXX_I2C
>>>>>>>>>>         Say Y here to enable support for batteries with BQ27xxx chips
>>>>>>>>>>         connected over an I2C bus.
>>>>>>>>>>
>>>>>>>>>> +config BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>>>> +     bool "BQ27xxx support for update of NVM/flash data memory"
>>>>>>>>>> +     depends on BATTERY_BQ27XXX_I2C
>>>>>>>>>> +     help
>>>>>>>>>> +       Say Y here to enable devicetree monitored-battery config to update
>>>>>>>>>> +       NVM/flash data memory. Only enable this option for devices with a
>>>>>>>>>> +       fuel gauge mounted on the circuit board, and a battery that cannot
>>>>>>>>>> +       be replaced with one of a different type.
>>>>>>>>>> +
>>>>>>>>>>  config BATTERY_DA9030
>>>>>>>>>>       tristate "DA9030 battery driver"
>>>>>>>>>>       depends on PMIC_DA903X
>>>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>>> index 8ab184c..06f15da 100644
>>>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>>> @@ -805,6 +805,13 @@ static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>>>>
>>>>>>>>>>  #define BQ27XXX_DM_SZ        32
>>>>>>>>>>
>>>>>>>>>> +struct bq27xxx_dm_reg {
>>>>>>>>>> +     u8 subclass_id;
>>>>>>>>>> +     u8 offset;
>>>>>>>>>> +     u8 bytes;
>>>>>>>>>> +     u16 min, max;
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>>  /**
>>>>>>>>>>   * struct bq27xxx_dm_buf - chip data memory buffer
>>>>>>>>>>   * @class: data memory subclass_id
>>>>>>>>>> @@ -822,6 +829,43 @@ struct bq27xxx_dm_buf {
>>>>>>>>>>       bool has_data, dirty;
>>>>>>>>>>  };
>>>>>>>>>>
>>>>>>>>>> +#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->data + 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 * const bq27xxx_dm_reg_name[] = {
>>>>>>>>>> +     [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
>>>>>>>>>> +     [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
>>>>>>>>>> +     [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +
>>>>>>>>>> +#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>>>> +static bool bq27xxx_dt_to_nvm = true;
>>>>>>>>>> +
>>>>>>>>>> +module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444);
>>>>>>>>>> +MODULE_PARM_DESC(dt_monitored_battery_updates_nvm,
>>>>>>>>>> +     "Devicetree monitored-battery config updates NVM/flash data memory, if present. Default is 1/y.");
>>>>>>>>>
>>>>>>>>> As before, the default should not be y, this is a rare case and I can't
>>>>>>>>> see it being useful or wanted by anyone but device manufacturers. I
>>>>>>>>> don't want everyones chip's factory programmed NVM overwritten by
>>>>>>>>> accident when someone compiles and ships a kernel with
>>>>>>>>> BATTERY_BQ27XXX_DT_UPDATES_NVM=y
>>>>>>>>
>>>>>>>> Right, the point of the config option is to let a device vendor ship a
>>>>>>>> kernel + dtb which can field-upgrade NVM. (Setting the option does
>>>>>>>> nothing absent the necessary dtb.)
>>>>>>>>
>>>>>>>> Module params are for end-user config; we can't require a device
>>>>>>>> vendor to ship /etc/modprobe.d/xyz. And we certainly don't want a
>>>>>>>> kernel package update to defeat the end-user config of
>>>>>>>> dt_monitored_battery_updates_nvm=0 !!
>>>>>>>>
>>>>>>>> I believe Sebastian agrees, given that he queued this patch :-)
>>>>>>>
>>>>>>> I clarified the rationale for module param default =1 above; could you ack?
>>>>>>>
>>>>>>> That prevents this scenario:
>>>>>>> 1) user changes battery type, sets dt_monitored_battery_updates_nvm=0
>>>>>>> 2) vendor ships kernel package with dtb update and
>>>>>>> dt_monitored_battery_updates_nvm=1
>>>>>>> 3) gauge stops working correctly
>>>>>>>
>>>>>>
>>>>>> Leaving it =1 will encourage this situation, not prevent it. Updating
>>>>>> NVM is a non-standard operation for these parts. It should only be done
>>>>>> once ideally. It is nice being able to update the NVM, and we have
>>>>>> user-space tools for this, but this is a dangerous operation, improperly
>>>>>> programming can brick the chip, as you have found out.
>>>>>>
>>>>>> If you want to add this function into the kernel driver that is fine,
>>>>>> but you *cannot* have this be the default, it needs to be a hidden away
>>>>>> option for people who know what they are doing, else you will end up
>>>>>> accidentally causing damage to countless users' hardware.
>>>>>
>>>>> I don't think you followed my logic.... It *is* hidden behind a
>>>>> dedicated kernel config option which only device vendors (and
>>>>> tinkerers :-) would use. A kernel package with that option and
>>>>> suitable dtb has to perform the update without manipulation of the
>>>>> module param. The module param is to let the user prevent any future
>>>>> update by such a kernel package, since only he knows that he changed
>>>>> the battery type.
>>>>>
>>>>> What is your evidence for the assertion of "encourage this situation"?
>>>>>
>>>>
>>>> It is the default value, what more evidence do you want? Someone should
>>>> have to enable the functionality in Kconfig *and* enable it as a
>>>> module_param. Leaving either on by default will cause it to be
>>>> accidentally left enabled.
>>>
>>> We could add a second config option to eliminate the possibility of
>>> the first one being set by mistake.
>>>
>>> You can't trivially enable a config option. If you set it, you'd
>>> obviously set the module param if that were necessary, so that's no
>>> extra protection against "accidentally left enabled". (And the config
>>> option does nothing without a suitable dtb.)
>>>
>>
>> Why would you "obviously set the module param"? If this config option is
>> enabled then you still have to set the module param to make this write
>> to your device's NVM, that is two things vs one. The people who use
>> kernels often don't build them. Both should need to be set to update the
>> devices NVM.
> 
> The target of this config option is device vendors. They would
> obviously set the module param when setting the config option to
> field-upgrade NVM.
> 

Great, they we don't need to have it default =1 if they will obviously
set it, problem solved.

>>> My scenario is a clear and likely threat. You haven't described a
>>> threat scenario.
>>>
>>
>> Easy, kernel is built with the config option enabled and their DT has
>> invalid option for their battery. Now everyone bricks their hardware.
> 
> A device vendor could misconfigure their hw, sure. They would also fix
> it in an update. That's not a threat. In what scenario does someone
> other than the vendor or tinkering user misconfigure the gauge?
> 
>> Vs. your three step situation that the two people who will ever use this
>> will never actually find themselves in, that results in a minor
>> inconvenience as they have to turn a module param back off.
> 
> I don't think you followed the scenario. User resetting the param =0
> after a vendor update sets =1 would not fix the NVM misconfig caused
> by the update! The whole point of user setting =0 is to prevent that
> update.
> 

Updates are optional, you shouldn't have to manually prevent an update.

>> Lets take the safe route and leave this default off.
> 
> I offered you a safe route: two config options.
> 

How about a default off module param so we don't clutter the kconfig.

>>> The docs for the config option describe its correct use, and I will
>>> mention the risk of overwriting a smart battery. No general purpose
>>> distro will enable it.
>>>
>>
>> How can you know this, I'm pretty sure Ubuntu ships with a randconfig
>> kernel :)
> 
> And that includes a rand dtb? :-p
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-08 20:01                 ` Liam Breck
@ 2017-05-09 16:20                   ` Andrew F. Davis
  0 siblings, 0 replies; 52+ messages in thread
From: Andrew F. Davis @ 2017-05-09 16:20 UTC (permalink / raw)
  To: Liam Breck; +Cc: Sebastian Reichel, linux-pm, Liam Breck

On 05/08/2017 03:01 PM, Liam Breck wrote:
> On Mon, May 8, 2017 at 12:09 PM, Andrew F. Davis <afd@ti.com> wrote:
>> On 05/08/2017 02:02 PM, Liam Breck wrote:
>>> On Mon, May 8, 2017 at 8:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>> On 05/08/2017 01:40 AM, Liam Breck wrote:
>>>>> On Fri, May 5, 2017 at 12:45 PM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>> On 05/05/2017 02:31 PM, Liam Breck wrote:
>>>>>>> On Thu, May 4, 2017 at 10:00 AM, Andrew F. Davis <afd@ti.com> wrote:
>>>>>>>> On 05/04/2017 01:18 AM, Liam Breck wrote:
>>>>>>>>> From: Liam Breck <kernel@networkimprov.net>
>>>>>>>>>
>>>>>>>>> Support data memory update on BQ27500, 545, 425, 421, 441, 621.
>>>>>>>>>
>>>>>>>>> Create IDs for for previously unID'd chips, to index arrays for unseal keys
>>>>>>>>> and data memory register tables.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Liam Breck <kernel@networkimprov.net>
>>>>>>>>> ---
>>>>>>>>>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>>>>>>>>>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>>>>>>>>>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>>>>>>>>>  3 files changed, 107 insertions(+), 12 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>> index 06f15da..0aecd41 100644
>>>>>>>>> --- a/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>> +++ b/drivers/power/supply/bq27xxx_battery.c
>>>>>>>>> @@ -58,7 +58,7 @@
>>>>>>>>>
>>>>>>>>>  #include <linux/power/bq27xxx_battery.h>
>>>>>>>>>
>>>>>>>>> -#define DRIVER_VERSION               "1.2.0"
>>>>>>>>> +#define DRIVER_VERSION               "1.3.0"
>>>>>>>>>
>>>>>>>>>  #define BQ27XXX_MANUFACTURER "Texas Instruments"
>>>>>>>>>
>>>>>>>>> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>>>>>>>>>       [BQ27XXX_DM_CKSUM] = 0x60
>>>>>>>>>
>>>>>>>>>  /* Register mappings */
>>>>>>>>> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
>>>>>>>>> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>>>>>>>>>       [BQ27000] = {
>>>>>>>>>               [BQ27XXX_REG_CTRL] = 0x00,
>>>>>>>>>               [BQ27XXX_REG_TEMP] = 0x06,
>>>>>>>>> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>>>>>>>>>  static struct {
>>>>>>>>>       enum power_supply_property *props;
>>>>>>>>>       size_t size;
>>>>>>>>> -} bq27xxx_battery_props[] = {
>>>>>>>>> +} bq27xxx_battery_props[BQ27MAX] = {
>>>>>>>>>       BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>>>>>>>>>       BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>>>>>>>>>       BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
>>>>>>>>> @@ -798,6 +798,33 @@ static struct {
>>>>>>>>>       BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>>>>>>>>>  };
>>>>>>>>>
>>>>>>>>> +static enum bq27xxx_chip bq27xxx_chips[] = {
>>>>>>>>> +     [BQ27000]   = BQ27000,
>>>>>>>>> +     [BQ27010]   = BQ27010,
>>>>>>>>> +     [BQ2750X]   = BQ2750X,
>>>>>>>>> +     [BQ2751X]   = BQ2751X,
>>>>>>>>> +     [BQ2752X]   = BQ2751X,
>>>>>>>>> +     [BQ27500]   = BQ27500,
>>>>>>>>> +     [BQ27510G1] = BQ27510G1,
>>>>>>>>> +     [BQ27510G2] = BQ27510G2,
>>>>>>>>> +     [BQ27510G3] = BQ27510G3,
>>>>>>>>> +     [BQ27520G1] = BQ27520G1,
>>>>>>>>> +     [BQ27520G2] = BQ27520G2,
>>>>>>>>> +     [BQ27520G3] = BQ27520G3,
>>>>>>>>> +     [BQ27520G4] = BQ27520G4,
>>>>>>>>> +     [BQ27530]   = BQ27530,
>>>>>>>>> +     [BQ27531]   = BQ27530,
>>>>>>>>> +     [BQ27541]   = BQ27541,
>>>>>>>>> +     [BQ27542]   = BQ27541,
>>>>>>>>> +     [BQ27546]   = BQ27541,
>>>>>>>>> +     [BQ27742]   = BQ27541,
>>>>>>>>> +     [BQ27545]   = BQ27545,
>>>>>>>>> +     [BQ27421]   = BQ27421,
>>>>>>>>> +     [BQ27425]   = BQ27421,
>>>>>>>>> +     [BQ27441]   = BQ27421,
>>>>>>>>> +     [BQ27621]   = BQ27421,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>>  static DEFINE_MUTEX(bq27xxx_list_lock);
>>>>>>>>>  static LIST_HEAD(bq27xxx_battery_devices);
>>>>>>>>>
>>>>>>>>> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>>>>>>>>>       [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 struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
>>>>>>>>> +     [BQ27500] = bq27500_dm_regs,
>>>>>>>>> +     [BQ27545] = bq27545_dm_regs,
>>>>>>>>> +     [BQ27421] = bq27421_dm_regs,
>>>>>>>>> +     [BQ27425] = bq27425_dm_regs,
>>>>>>>>> +     [BQ27441] = bq27421_dm_regs,
>>>>>>>>> +     [BQ27621] = bq27621_dm_regs,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static u32 bq27xxx_unseal_keys[] = {
>>>>>>>>> +     [BQ27500] = 0x04143672,
>>>>>>>>> +     [BQ27545] = 0x04143672,
>>>>>>>>> +     [BQ27421] = 0x80008000,
>>>>>>>>> +     [BQ27425] = 0x04143672,
>>>>>>>>> +     [BQ27441] = 0x80008000,
>>>>>>>>> +     [BQ27621] = 0x80008000,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>>
>>>>>>>>>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>>>>>>>>>  static bool bq27xxx_dt_to_nvm = true;
>>>>>>>>> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>>>>>>>>>               .drv_data = di,
>>>>>>>>>       };
>>>>>>>>>
>>>>>>>>> +     di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
>>>>>>>>> +
>>>>>>>>> +     di->unseal_key = bq27xxx_unseal_keys[di->chip];
>>>>>>>>> +     di->dm_regs = bq27xxx_dm_regs[di->chip];
>>>>>>>>> +     di->chip = bq27xxx_chips[di->chip];
>>>>>>>>
>>>>>>>> NACK, this is a mess, you should not be using a table to change what
>>>>>>>> chip was passed in, it may be needed later. The chip is still the same,
>>>>>>>> it should have the same one correct ID, use a different index or array
>>>>>>>> if you would like, but this is very hacky.
>>>>>>>
>>>>>>> The only way I see to make the I2C subsystem deliver multiple IDs for
>>>>>>> a device is to treat i2c_device_id.driver_data as a u16[2] instead of
>>>>>>> its normal u32. What do you think of that?
>>>>>>>
>>>>>>
>>>>>> Why would it need multiple IDs for one device? Just pass in the one
>>>>>> correct device ID that it is. No reason to make this so complicated.
>>>>>> From the one ID you can then use tables to lookup any other info about
>>>>>> that device, you don't have to have ever ID populated in every table,
>>>>>> you can even have a table of tables if you would like:
>>>>>>
>>>>>> static const struct chip_lookup lookup_table = {
>>>>>>         [bq27425] = {
>>>>>>                 .regs = &bq27xxx_regs[bq27425],
>>>>>>                 .dm_regs = &bq27xxx_dm_regs[bq274xx],
>>>>>>                 .unseal_key = INVALID_FOR_THIS_DEVICE,
>>>>>>         },
>>>>>>         [bq27343] = {
>>>>>> ...
>>>>>>
>>>>>> Not sure if that is valid C but I think you can get the idea.
>>>>>
>>>>> I considered a master lookup_table, but its ref to
>>>>> bq27xxx_regs[fake-ID] duplicates the mapping of real-ID to di->chip.
>>>>> The latter is still necessary as di->chip is used to select
>>>>> conditional behaviors; we can't change its value in this patch.
>>>>>
>>>>
>>>> Sure we can, in fact you could add the conditional behavior flags to the
>>>> master lookup_table and cleanup all the current switch-case checks we do
>>>> now.
>>>
>>> You are proposing a significant change to the ID handling, which is
>>> fine, but I don't wish to code that. Accept this minimal patch to
>>> enable DM update, and then alter the ID logic when you have time in a
>>> future patch.
>>>
>>
>> Doesn't work like that, you can't just hack something together and hope
>> someone else will fix it later. If you want to change something you
>> should make it right the first time. We don't need DM update, but if you
>> would like it then you need to fix the problems it will create.
> 
> You do indeed need DM update for the RAM-only chips; they expect to be
> configured on boot, as I documented previously.
> 
> Adding real-ID to the I2C table and using it in *exactly two lines* of
> setup() is a minimal workaround for a pre-existing design flaw. You
> have a concept for fixing it, so you should code it. I gracefully
> decline.
> 

Just because it was done wrong before doesn't mean it should continue to
be done wrong.

> I have labored on this patchset for some 19 revisions. Sebastian seems
> to think that's enough, as he queued most of the series last week even
> tho you hadn't acked it.
> 

I know you said v1 came out in Jan, but I've only been looking at this
for one cycle, also you wouldn't be at v19 if you didn't push 2 series a
week, let each version sit on the list for a while to build up multiple
comments. Patch series version number is not a metric of quality or
"readiness".

+ queuing patches is not approval, it just sets it up for testing in
-next, nothing is final until Linus takes the pull request, and even
then there is always revert patches.

I've offered to work with you on this, if you would stop fighting every
minor suggestion I give we could get all this in this cycle.

I empathize with you, this is a very difficult driver with a lot of
legacy attached and more by-name supported devices than almost any other
driver I've seen, we have to get this right or it will negatively effect
a lot of people down the road.

> 
> 
>>>>> So instead lets amend the I2C table to carry both its original value
>>>>> (fake-ID) and the real-ID. That looks like:
>>>>>
>>>>> static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>>>>>     /* dest.    di->real_chip       di->chip      */
>>>>>     { "bq27200",   (BQ27000   << 16) |  BQ27000   },
>>>>>     { "bq27210",   (BQ27010   << 16) |  BQ27010   },
>>>>>     ...
>>>>>     { "bq27441",   (BQ27441   << 16) |  BQ27421   },
>>>>>     { "bq27621",   (BQ27621   << 16) |  BQ27421   },
>>>>>     {},
>>>>> };
>>>>>
>>>>> In probe, retrieve two values:
>>>>>
>>>>>     di->real_chip = id->driver_data >> 16;
>>>>>     di->chip = (u16) id->driver_data;
>>>>>
>>>>
>>>> NAK, I'm sure you can see how hacky this is right? This doesn't give us
>>>> anything that the old table didn't. And it fails to correct the issue
>>>> with the tables: We have two chip IDs still!
>>>
>>> I'm sorry you don't like the extra ID, but you're the party
>>> responsible for (if not the author of) the fake-ID scheme :-)
>>>
>>
>> It has worked fine until now, your additions require a different scheme,
>> hacking around the old one is not a workable solution.
>>
>>>
>>>> Try the lookup_table again, send be what you have and I can help get
>>>> everything else working if you have any problems with the conditional
>>>> behavior cleanups.
>>>>
>>>>> In setup, use two values:
>>>>>
>>>>>     di->unseal_key = bq27xxx_unseal_keys[di->real_chip];
>>>>>     di->dm_regs = bq27xxx_dm_regs[di->real_chip];
>>>>>     di->regs = bq27xxx_regs[di->chip]; // unchanged from orig src
>>>>>
>>>>> That yields the most compact implementation of this patch, and you get
>>>>> di->real_chip in the bargain :-)
>>>>>
>>>>>
>>>>>>>> Just stop trying to hack around it, add the extra tables, even if they
>>>>>>>> are clones, so we can be done with this series already. I'm sure you
>>>>>>>> want that more than you want this "clever" work-around, right?
>>>>>>>>
>>>>>>>> Also fix all the checkpatch --strict warnings.
>>>>>>>>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips
  2017-05-04  6:18 ` [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips Liam Breck
  2017-05-04 17:00   ` Andrew F. Davis
@ 2017-05-10  9:16   ` Liam Breck
  1 sibling, 0 replies; 52+ messages in thread
From: Liam Breck @ 2017-05-10  9:16 UTC (permalink / raw)
  To: Andrew F. Davis, linux-pm; +Cc: Liam Breck

Hi Andrew,

On Wed, May 3, 2017 at 11:18 PM, Liam Breck <liam@networkimprov.net> wrote:
> From: Liam Breck <kernel@networkimprov.net>
>
> Support data memory update on BQ27500, 545, 425, 421, 441, 621.

Re testing, I'll comment out code in this patch for chips I can't
test. We can let future users test chips they use and re-enable/insert
them. No need to make you test everything.

> Create IDs for for previously unID'd chips, to index arrays for unseal keys
> and data memory register tables.
>
> Signed-off-by: Liam Breck <kernel@networkimprov.net>
> ---
>  drivers/power/supply/bq27xxx_battery.c     | 90 ++++++++++++++++++++++++++++--
>  drivers/power/supply/bq27xxx_battery_i2c.c | 16 +++---
>  include/linux/power/bq27xxx_battery.h      | 13 +++++
>  3 files changed, 107 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
> index 06f15da..0aecd41 100644
> --- a/drivers/power/supply/bq27xxx_battery.c
> +++ b/drivers/power/supply/bq27xxx_battery.c
> @@ -58,7 +58,7 @@
>
>  #include <linux/power/bq27xxx_battery.h>
>
> -#define DRIVER_VERSION         "1.2.0"
> +#define DRIVER_VERSION         "1.3.0"
>
>  #define BQ27XXX_MANUFACTURER   "Texas Instruments"
>
> @@ -132,7 +132,7 @@ enum bq27xxx_reg_index {
>         [BQ27XXX_DM_CKSUM] = 0x60
>
>  /* Register mappings */
> -static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
> +static u8 bq27xxx_regs[BQ27MAX][BQ27XXX_REG_MAX] = {
>         [BQ27000] = {
>                 [BQ27XXX_REG_CTRL] = 0x00,
>                 [BQ27XXX_REG_TEMP] = 0x06,
> @@ -779,7 +779,7 @@ static enum power_supply_property bq27421_battery_props[] = {
>  static struct {
>         enum power_supply_property *props;
>         size_t size;
> -} bq27xxx_battery_props[] = {
> +} bq27xxx_battery_props[BQ27MAX] = {
>         BQ27XXX_PROP(BQ27000, bq27000_battery_props),
>         BQ27XXX_PROP(BQ27010, bq27010_battery_props),
>         BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
> @@ -798,6 +798,33 @@ static struct {
>         BQ27XXX_PROP(BQ27421, bq27421_battery_props),
>  };
>
> +static enum bq27xxx_chip bq27xxx_chips[] = {
> +       [BQ27000]   = BQ27000,
> +       [BQ27010]   = BQ27010,
> +       [BQ2750X]   = BQ2750X,
> +       [BQ2751X]   = BQ2751X,
> +       [BQ2752X]   = BQ2751X,
> +       [BQ27500]   = BQ27500,
> +       [BQ27510G1] = BQ27510G1,
> +       [BQ27510G2] = BQ27510G2,
> +       [BQ27510G3] = BQ27510G3,
> +       [BQ27520G1] = BQ27520G1,
> +       [BQ27520G2] = BQ27520G2,
> +       [BQ27520G3] = BQ27520G3,
> +       [BQ27520G4] = BQ27520G4,
> +       [BQ27530]   = BQ27530,
> +       [BQ27531]   = BQ27530,
> +       [BQ27541]   = BQ27541,
> +       [BQ27542]   = BQ27541,
> +       [BQ27546]   = BQ27541,
> +       [BQ27742]   = BQ27541,
> +       [BQ27545]   = BQ27545,
> +       [BQ27421]   = BQ27421,
> +       [BQ27425]   = BQ27421,
> +       [BQ27441]   = BQ27421,
> +       [BQ27621]   = BQ27421,
> +};
> +
>  static DEFINE_MUTEX(bq27xxx_list_lock);
>  static LIST_HEAD(bq27xxx_battery_devices);
>
> @@ -856,6 +883,54 @@ static const char * const bq27xxx_dm_reg_name[] = {
>         [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage",
>  };

Specifically...

#ifdef DEBUG here

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

#endif here, moving one table outside the ifdef.

> +static struct bq27xxx_dm_reg *bq27xxx_dm_regs[] = {
> +       [BQ27500] = bq27500_dm_regs,
> +       [BQ27545] = bq27545_dm_regs,
> +       [BQ27421] = bq27421_dm_regs,
> +       [BQ27425] = bq27425_dm_regs,
> +       [BQ27441] = bq27421_dm_regs,
> +       [BQ27621] = bq27621_dm_regs,
> +};
> +

And the same inside the above table.

> +static u32 bq27xxx_unseal_keys[] = {
> +       [BQ27500] = 0x04143672,
> +       [BQ27545] = 0x04143672,
> +       [BQ27421] = 0x80008000,
> +       [BQ27425] = 0x04143672,
> +       [BQ27441] = 0x80008000,
> +       [BQ27621] = 0x80008000,
> +};
> +
>
>  #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
>  static bool bq27xxx_dt_to_nvm = true;
> @@ -1865,9 +1940,16 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
>                 .drv_data = di,
>         };
>
> +       di->ram_chip = di->chip == BQ27421 || di->chip == BQ27441 || di->chip == BQ27621;
> +
> +       di->unseal_key = bq27xxx_unseal_keys[di->chip];
> +       di->dm_regs = bq27xxx_dm_regs[di->chip];
> +       di->chip = bq27xxx_chips[di->chip];
> +
> +       di->regs = bq27xxx_regs[di->chip];
> +
>         INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
>         mutex_init(&di->lock);
> -       di->regs = bq27xxx_regs[di->chip];
>
>         psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
>         if (!psy_desc)
> diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
> index a597221..0b11ed4 100644
> --- a/drivers/power/supply/bq27xxx_battery_i2c.c
> +++ b/drivers/power/supply/bq27xxx_battery_i2c.c
> @@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>         { "bq27210", BQ27010 },
>         { "bq27500", BQ2750X },
>         { "bq27510", BQ2751X },
> -       { "bq27520", BQ2751X },
> +       { "bq27520", BQ2752X },
>         { "bq27500-1", BQ27500 },
>         { "bq27510g1", BQ27510G1 },
>         { "bq27510g2", BQ27510G2 },
> @@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
>         { "bq27520g3", BQ27520G3 },
>         { "bq27520g4", BQ27520G4 },
>         { "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);
> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h
> index 11e1168..543c10e 100644
> --- a/include/linux/power/bq27xxx_battery.h
> +++ b/include/linux/power/bq27xxx_battery.h
> @@ -2,6 +2,8 @@
>  #define __LINUX_BQ27X00_BATTERY_H__
>
>  enum bq27xxx_chip {
> +       /* these index bq27xxx_regs[] & bq27xxx_battery_props[] */
> +       /* and map to themselves in bq27xxx_chips[]             */
>         BQ27000 = 1, /* bq27000, bq27200 */
>         BQ27010, /* bq27010, bq27210 */
>         BQ2750X, /* bq27500 deprecated alias */
> @@ -18,6 +20,17 @@ enum bq27xxx_chip {
>         BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
>         BQ27545, /* bq27545 */
>         BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
> +       BQ27MAX,
> +
> +       /* these map to above in bq27xxx_chips[] */
> +       BQ2752X, /* deprecated alias */
> +       BQ27531,
> +       BQ27542,
> +       BQ27546,
> +       BQ27742,
> +       BQ27425,
> +       BQ27441,
> +       BQ27621,
>  };
>
>  /**
> --
> 2.9.3
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2017-05-10  9:16 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-04  6:18 [PATCH v13 0/11] devicetree simple-battery and client in bq27xxx_battery Liam Breck
2017-05-04  6:18 ` [PATCH v13 01/11] devicetree: property-units: Add uWh and uAh units Liam Breck
2017-05-04  6:18   ` Liam Breck
2017-05-04  6:18 ` [PATCH v13 02/11] dt-bindings: power: supply: Add battery.txt with simple-battery binding Liam Breck
2017-05-04  6:18 ` [PATCH v13 03/11] power: supply: core: Add power_supply_battery_info and API Liam Breck
2017-05-04  6:18 ` [PATCH v13 04/11] power: supply: core: Add power_supply_prop_precharge Liam Breck
     [not found] ` <20170504061811.18107-1-liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
2017-05-04  6:18   ` [PATCH v13 05/11] dt-bindings: power: supply: bq27xxx: Add monitored-battery documentation Liam Breck
2017-05-04  6:18 ` [PATCH v13 06/11] power: supply: bq27xxx_battery: Add bulk transfer bus methods Liam Breck
2017-05-04  6:18 ` [PATCH v13 07/11] power: supply: bq27xxx_battery: Add chip data memory read/write support Liam Breck
2017-05-04 16:44   ` Andrew F. Davis
2017-05-04 18:07     ` Liam Breck
2017-05-05 12:45     ` Liam Breck
2017-05-05 15:40       ` Andrew F. Davis
2017-05-05 18:44         ` Liam Breck
2017-05-04  6:18 ` [PATCH v13 08/11] power: supply: bq27xxx_battery: Add power_supply_battery_info support Liam Breck
2017-05-04 16:52   ` Andrew F. Davis
2017-05-04 18:40     ` Liam Breck
2017-05-08  6:16       ` Liam Breck
2017-05-08 14:54         ` Andrew F. Davis
2017-05-08 18:39           ` Liam Breck
2017-05-08 18:42             ` Andrew F. Davis
2017-05-08 19:31               ` Liam Breck
2017-05-08 19:50                 ` Andrew F. Davis
2017-05-08 20:34                   ` Liam Breck
2017-05-09 16:06                     ` Andrew F. Davis
2017-05-04  6:18 ` [PATCH v13 09/11] power: supply: bq27xxx_battery: Enable data memory update for certain chips Liam Breck
2017-05-04 17:00   ` Andrew F. Davis
2017-05-04 19:12     ` Liam Breck
2017-05-05 19:31     ` Liam Breck
2017-05-05 19:45       ` Andrew F. Davis
2017-05-05 20:14         ` Liam Breck
2017-05-05 20:44           ` Andrew F. Davis
2017-05-05 20:55             ` Liam Breck
2017-05-05 21:04               ` Andrew F. Davis
2017-05-05 21:27                 ` Liam Breck
2017-05-05 21:29                   ` Andrew F. Davis
2017-05-05 21:38                     ` Liam Breck
2017-05-08  6:40         ` Liam Breck
2017-05-08 15:00           ` Andrew F. Davis
2017-05-08 19:02             ` Liam Breck
2017-05-08 19:09               ` Andrew F. Davis
2017-05-08 20:01                 ` Liam Breck
2017-05-09 16:20                   ` Andrew F. Davis
2017-05-10  9:16   ` Liam Breck
2017-05-04  6:18 ` [PATCH v13 10/11] power: supply: bq27xxx_battery: Flag identical register maps when in debug mode Liam Breck
2017-05-04 16:38   ` Andrew F. Davis
2017-05-08  6:18     ` Liam Breck
2017-05-08 15:01       ` Andrew F. Davis
2017-05-08 19:07         ` Liam Breck
2017-05-08 19:12           ` Andrew F. Davis
2017-05-08 20:08             ` Liam Breck
2017-05-04  6:18 ` [PATCH v13 11/11] power: supply: bq27xxx_battery: Remove duplicate register arrays Liam Breck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.