Re: [PATCH v5 4/6] power: supply: core: Add some helpers to use the battery OCV capacity table

2018-10-21 Thread Sebastian Reichel
Hi,

On Fri, Oct 19, 2018 at 06:53:13PM +0800, Baolin Wang wrote:
> We have introduced some battery properties to present the OCV table
> temperatures and OCV capacity table values. Thus this patch add OCV
> temperature and OCV table for battery information, as well as providing
> some helper functions to use the OCV capacity table for users.
> 
> Signed-off-by: Baolin Wang 
> Reviewed-by: Linus Walleij 
> ---

Looks good to me.

-- Sebastian

> Changes from v4:
>  - None.
> 
> Changes from v3:
>  - Split core modification into one separate patch.
>  - Rename ocv-capacity-table-temperatures to ocv-capacity-celsius.
> 
> Changes from v2:
>  - Use type __be32 to calculate the table length.
>  - Update error messages.
>  - Add some helper functions.
> 
> Changes from v1:
>  - New patch in v2.
> ---
>  drivers/power/supply/power_supply_core.c |  123 
> +-
>  include/linux/power_supply.h |   19 +
>  2 files changed, 141 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/power/supply/power_supply_core.c 
> b/drivers/power/supply/power_supply_core.c
> index 307e0995..58c4309 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -570,7 +570,7 @@ int power_supply_get_battery_info(struct power_supply 
> *psy,
>  {
>   struct device_node *battery_np;
>   const char *value;
> - int err;
> + int err, len, index;
>  
>   info->energy_full_design_uwh = -EINVAL;
>   info->charge_full_design_uah = -EINVAL;
> @@ -581,6 +581,12 @@ int power_supply_get_battery_info(struct power_supply 
> *psy,
>   info->constant_charge_voltage_max_uv = -EINVAL;
>   info->factory_internal_resistance_uohm  = -EINVAL;
>  
> + for (index = 0; index < POWER_SUPPLY_OCV_TEMP_MAX; index++) {
> + info->ocv_table[index]   = NULL;
> + info->ocv_temp[index]= -EINVAL;
> + info->ocv_table_size[index]  = -EINVAL;
> + }
> +
>   if (!psy->of_node) {
>   dev_warn(>dev, "%s currently only supports devicetree\n",
>__func__);
> @@ -620,10 +626,125 @@ int power_supply_get_battery_info(struct power_supply 
> *psy,
>   of_property_read_u32(battery_np, 
> "factory-internal-resistance-micro-ohms",
>>factory_internal_resistance_uohm);
>  
> + len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius");
> + if (len < 0 && len != -EINVAL) {
> + return len;
> + } else if (len > POWER_SUPPLY_OCV_TEMP_MAX) {
> + dev_err(>dev, "Too many temperature values\n");
> + return -EINVAL;
> + } else if (len > 0) {
> + of_property_read_u32_array(battery_np, "ocv-capacity-celsius",
> +info->ocv_temp, len);
> + }
> +
> + for (index = 0; index < len; index++) {
> + struct power_supply_battery_ocv_table *table;
> + char *propname;
> + const __be32 *list;
> + int i, tab_len, size;
> +
> + propname = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", 
> index);
> + list = of_get_property(battery_np, propname, );
> + if (!list || !size) {
> + dev_err(>dev, "failed to get %s\n", propname);
> + kfree(propname);
> + power_supply_put_battery_info(psy, info);
> + return -EINVAL;
> + }
> +
> + kfree(propname);
> + tab_len = size / (2 * sizeof(__be32));
> + info->ocv_table_size[index] = tab_len;
> +
> + table = info->ocv_table[index] =
> + devm_kzalloc(>dev, tab_len * sizeof(*table),
> +  GFP_KERNEL);
> + if (!info->ocv_table[index]) {
> + power_supply_put_battery_info(psy, info);
> + return -ENOMEM;
> + }
> +
> + for (i = 0; i < tab_len; i++) {
> + table[i].ocv = be32_to_cpu(*list++);
> + table[i].capacity = be32_to_cpu(*list++);
> + }
> + }
> +
>   return 0;
>  }
>  EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
>  
> +void power_supply_put_battery_info(struct power_supply *psy,
> +struct power_supply_battery_info *info)
> +{
> + int i;
> +
> + for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++)
> + kfree(info->ocv_table[i]);
> +}
> +EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
> +
> +int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
> + int table_len, int ocv)
> +{
> + int i, cap, tmp;
> +
> + for (i = 0; i < table_len; i++)
> + if (ocv > table[i].ocv)
> + break;
> +
> + if (i > 0 && i < table_len) {
> + tmp = (table[i - 1].capacity - 

Re: [PATCH v5 4/6] power: supply: core: Add some helpers to use the battery OCV capacity table

2018-10-21 Thread Sebastian Reichel
Hi,

On Fri, Oct 19, 2018 at 06:53:13PM +0800, Baolin Wang wrote:
> We have introduced some battery properties to present the OCV table
> temperatures and OCV capacity table values. Thus this patch add OCV
> temperature and OCV table for battery information, as well as providing
> some helper functions to use the OCV capacity table for users.
> 
> Signed-off-by: Baolin Wang 
> Reviewed-by: Linus Walleij 
> ---

Looks good to me.

-- Sebastian

> Changes from v4:
>  - None.
> 
> Changes from v3:
>  - Split core modification into one separate patch.
>  - Rename ocv-capacity-table-temperatures to ocv-capacity-celsius.
> 
> Changes from v2:
>  - Use type __be32 to calculate the table length.
>  - Update error messages.
>  - Add some helper functions.
> 
> Changes from v1:
>  - New patch in v2.
> ---
>  drivers/power/supply/power_supply_core.c |  123 
> +-
>  include/linux/power_supply.h |   19 +
>  2 files changed, 141 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/power/supply/power_supply_core.c 
> b/drivers/power/supply/power_supply_core.c
> index 307e0995..58c4309 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -570,7 +570,7 @@ int power_supply_get_battery_info(struct power_supply 
> *psy,
>  {
>   struct device_node *battery_np;
>   const char *value;
> - int err;
> + int err, len, index;
>  
>   info->energy_full_design_uwh = -EINVAL;
>   info->charge_full_design_uah = -EINVAL;
> @@ -581,6 +581,12 @@ int power_supply_get_battery_info(struct power_supply 
> *psy,
>   info->constant_charge_voltage_max_uv = -EINVAL;
>   info->factory_internal_resistance_uohm  = -EINVAL;
>  
> + for (index = 0; index < POWER_SUPPLY_OCV_TEMP_MAX; index++) {
> + info->ocv_table[index]   = NULL;
> + info->ocv_temp[index]= -EINVAL;
> + info->ocv_table_size[index]  = -EINVAL;
> + }
> +
>   if (!psy->of_node) {
>   dev_warn(>dev, "%s currently only supports devicetree\n",
>__func__);
> @@ -620,10 +626,125 @@ int power_supply_get_battery_info(struct power_supply 
> *psy,
>   of_property_read_u32(battery_np, 
> "factory-internal-resistance-micro-ohms",
>>factory_internal_resistance_uohm);
>  
> + len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius");
> + if (len < 0 && len != -EINVAL) {
> + return len;
> + } else if (len > POWER_SUPPLY_OCV_TEMP_MAX) {
> + dev_err(>dev, "Too many temperature values\n");
> + return -EINVAL;
> + } else if (len > 0) {
> + of_property_read_u32_array(battery_np, "ocv-capacity-celsius",
> +info->ocv_temp, len);
> + }
> +
> + for (index = 0; index < len; index++) {
> + struct power_supply_battery_ocv_table *table;
> + char *propname;
> + const __be32 *list;
> + int i, tab_len, size;
> +
> + propname = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", 
> index);
> + list = of_get_property(battery_np, propname, );
> + if (!list || !size) {
> + dev_err(>dev, "failed to get %s\n", propname);
> + kfree(propname);
> + power_supply_put_battery_info(psy, info);
> + return -EINVAL;
> + }
> +
> + kfree(propname);
> + tab_len = size / (2 * sizeof(__be32));
> + info->ocv_table_size[index] = tab_len;
> +
> + table = info->ocv_table[index] =
> + devm_kzalloc(>dev, tab_len * sizeof(*table),
> +  GFP_KERNEL);
> + if (!info->ocv_table[index]) {
> + power_supply_put_battery_info(psy, info);
> + return -ENOMEM;
> + }
> +
> + for (i = 0; i < tab_len; i++) {
> + table[i].ocv = be32_to_cpu(*list++);
> + table[i].capacity = be32_to_cpu(*list++);
> + }
> + }
> +
>   return 0;
>  }
>  EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
>  
> +void power_supply_put_battery_info(struct power_supply *psy,
> +struct power_supply_battery_info *info)
> +{
> + int i;
> +
> + for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++)
> + kfree(info->ocv_table[i]);
> +}
> +EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
> +
> +int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
> + int table_len, int ocv)
> +{
> + int i, cap, tmp;
> +
> + for (i = 0; i < table_len; i++)
> + if (ocv > table[i].ocv)
> + break;
> +
> + if (i > 0 && i < table_len) {
> + tmp = (table[i - 1].capacity - 

[PATCH v5 4/6] power: supply: core: Add some helpers to use the battery OCV capacity table

2018-10-19 Thread Baolin Wang
We have introduced some battery properties to present the OCV table
temperatures and OCV capacity table values. Thus this patch add OCV
temperature and OCV table for battery information, as well as providing
some helper functions to use the OCV capacity table for users.

Signed-off-by: Baolin Wang 
Reviewed-by: Linus Walleij 
---
Changes from v4:
 - None.

Changes from v3:
 - Split core modification into one separate patch.
 - Rename ocv-capacity-table-temperatures to ocv-capacity-celsius.

Changes from v2:
 - Use type __be32 to calculate the table length.
 - Update error messages.
 - Add some helper functions.

Changes from v1:
 - New patch in v2.
---
 drivers/power/supply/power_supply_core.c |  123 +-
 include/linux/power_supply.h |   19 +
 2 files changed, 141 insertions(+), 1 deletion(-)

diff --git a/drivers/power/supply/power_supply_core.c 
b/drivers/power/supply/power_supply_core.c
index 307e0995..58c4309 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -570,7 +570,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
 {
struct device_node *battery_np;
const char *value;
-   int err;
+   int err, len, index;
 
info->energy_full_design_uwh = -EINVAL;
info->charge_full_design_uah = -EINVAL;
@@ -581,6 +581,12 @@ int power_supply_get_battery_info(struct power_supply *psy,
info->constant_charge_voltage_max_uv = -EINVAL;
info->factory_internal_resistance_uohm  = -EINVAL;
 
+   for (index = 0; index < POWER_SUPPLY_OCV_TEMP_MAX; index++) {
+   info->ocv_table[index]   = NULL;
+   info->ocv_temp[index]= -EINVAL;
+   info->ocv_table_size[index]  = -EINVAL;
+   }
+
if (!psy->of_node) {
dev_warn(>dev, "%s currently only supports devicetree\n",
 __func__);
@@ -620,10 +626,125 @@ int power_supply_get_battery_info(struct power_supply 
*psy,
of_property_read_u32(battery_np, 
"factory-internal-resistance-micro-ohms",
 >factory_internal_resistance_uohm);
 
+   len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius");
+   if (len < 0 && len != -EINVAL) {
+   return len;
+   } else if (len > POWER_SUPPLY_OCV_TEMP_MAX) {
+   dev_err(>dev, "Too many temperature values\n");
+   return -EINVAL;
+   } else if (len > 0) {
+   of_property_read_u32_array(battery_np, "ocv-capacity-celsius",
+  info->ocv_temp, len);
+   }
+
+   for (index = 0; index < len; index++) {
+   struct power_supply_battery_ocv_table *table;
+   char *propname;
+   const __be32 *list;
+   int i, tab_len, size;
+
+   propname = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", 
index);
+   list = of_get_property(battery_np, propname, );
+   if (!list || !size) {
+   dev_err(>dev, "failed to get %s\n", propname);
+   kfree(propname);
+   power_supply_put_battery_info(psy, info);
+   return -EINVAL;
+   }
+
+   kfree(propname);
+   tab_len = size / (2 * sizeof(__be32));
+   info->ocv_table_size[index] = tab_len;
+
+   table = info->ocv_table[index] =
+   devm_kzalloc(>dev, tab_len * sizeof(*table),
+GFP_KERNEL);
+   if (!info->ocv_table[index]) {
+   power_supply_put_battery_info(psy, info);
+   return -ENOMEM;
+   }
+
+   for (i = 0; i < tab_len; i++) {
+   table[i].ocv = be32_to_cpu(*list++);
+   table[i].capacity = be32_to_cpu(*list++);
+   }
+   }
+
return 0;
 }
 EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
 
+void power_supply_put_battery_info(struct power_supply *psy,
+  struct power_supply_battery_info *info)
+{
+   int i;
+
+   for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++)
+   kfree(info->ocv_table[i]);
+}
+EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
+
+int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
+   int table_len, int ocv)
+{
+   int i, cap, tmp;
+
+   for (i = 0; i < table_len; i++)
+   if (ocv > table[i].ocv)
+   break;
+
+   if (i > 0 && i < table_len) {
+   tmp = (table[i - 1].capacity - table[i].capacity) *
+   (ocv - table[i].ocv);
+   tmp /= table[i - 1].ocv - table[i].ocv;
+   cap = tmp + table[i].capacity;
+   } else if (i == 0) {
+   cap = 

[PATCH v5 4/6] power: supply: core: Add some helpers to use the battery OCV capacity table

2018-10-19 Thread Baolin Wang
We have introduced some battery properties to present the OCV table
temperatures and OCV capacity table values. Thus this patch add OCV
temperature and OCV table for battery information, as well as providing
some helper functions to use the OCV capacity table for users.

Signed-off-by: Baolin Wang 
Reviewed-by: Linus Walleij 
---
Changes from v4:
 - None.

Changes from v3:
 - Split core modification into one separate patch.
 - Rename ocv-capacity-table-temperatures to ocv-capacity-celsius.

Changes from v2:
 - Use type __be32 to calculate the table length.
 - Update error messages.
 - Add some helper functions.

Changes from v1:
 - New patch in v2.
---
 drivers/power/supply/power_supply_core.c |  123 +-
 include/linux/power_supply.h |   19 +
 2 files changed, 141 insertions(+), 1 deletion(-)

diff --git a/drivers/power/supply/power_supply_core.c 
b/drivers/power/supply/power_supply_core.c
index 307e0995..58c4309 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -570,7 +570,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
 {
struct device_node *battery_np;
const char *value;
-   int err;
+   int err, len, index;
 
info->energy_full_design_uwh = -EINVAL;
info->charge_full_design_uah = -EINVAL;
@@ -581,6 +581,12 @@ int power_supply_get_battery_info(struct power_supply *psy,
info->constant_charge_voltage_max_uv = -EINVAL;
info->factory_internal_resistance_uohm  = -EINVAL;
 
+   for (index = 0; index < POWER_SUPPLY_OCV_TEMP_MAX; index++) {
+   info->ocv_table[index]   = NULL;
+   info->ocv_temp[index]= -EINVAL;
+   info->ocv_table_size[index]  = -EINVAL;
+   }
+
if (!psy->of_node) {
dev_warn(>dev, "%s currently only supports devicetree\n",
 __func__);
@@ -620,10 +626,125 @@ int power_supply_get_battery_info(struct power_supply 
*psy,
of_property_read_u32(battery_np, 
"factory-internal-resistance-micro-ohms",
 >factory_internal_resistance_uohm);
 
+   len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius");
+   if (len < 0 && len != -EINVAL) {
+   return len;
+   } else if (len > POWER_SUPPLY_OCV_TEMP_MAX) {
+   dev_err(>dev, "Too many temperature values\n");
+   return -EINVAL;
+   } else if (len > 0) {
+   of_property_read_u32_array(battery_np, "ocv-capacity-celsius",
+  info->ocv_temp, len);
+   }
+
+   for (index = 0; index < len; index++) {
+   struct power_supply_battery_ocv_table *table;
+   char *propname;
+   const __be32 *list;
+   int i, tab_len, size;
+
+   propname = kasprintf(GFP_KERNEL, "ocv-capacity-table-%d", 
index);
+   list = of_get_property(battery_np, propname, );
+   if (!list || !size) {
+   dev_err(>dev, "failed to get %s\n", propname);
+   kfree(propname);
+   power_supply_put_battery_info(psy, info);
+   return -EINVAL;
+   }
+
+   kfree(propname);
+   tab_len = size / (2 * sizeof(__be32));
+   info->ocv_table_size[index] = tab_len;
+
+   table = info->ocv_table[index] =
+   devm_kzalloc(>dev, tab_len * sizeof(*table),
+GFP_KERNEL);
+   if (!info->ocv_table[index]) {
+   power_supply_put_battery_info(psy, info);
+   return -ENOMEM;
+   }
+
+   for (i = 0; i < tab_len; i++) {
+   table[i].ocv = be32_to_cpu(*list++);
+   table[i].capacity = be32_to_cpu(*list++);
+   }
+   }
+
return 0;
 }
 EXPORT_SYMBOL_GPL(power_supply_get_battery_info);
 
+void power_supply_put_battery_info(struct power_supply *psy,
+  struct power_supply_battery_info *info)
+{
+   int i;
+
+   for (i = 0; i < POWER_SUPPLY_OCV_TEMP_MAX; i++)
+   kfree(info->ocv_table[i]);
+}
+EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
+
+int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
+   int table_len, int ocv)
+{
+   int i, cap, tmp;
+
+   for (i = 0; i < table_len; i++)
+   if (ocv > table[i].ocv)
+   break;
+
+   if (i > 0 && i < table_len) {
+   tmp = (table[i - 1].capacity - table[i].capacity) *
+   (ocv - table[i].ocv);
+   tmp /= table[i - 1].ocv - table[i].ocv;
+   cap = tmp + table[i].capacity;
+   } else if (i == 0) {
+   cap =