Implement a simple battery driver for monitoring voltage with the
netronix embedded controller found in certain ebook readers.
Signed-off-by: Josua Mayer <josua.mayer@jm0.eu>
---
drivers/mfd/ntxec.c | 1 +
drivers/power/supply/Kconfig | 9 ++++
drivers/power/supply/Makefile | 1 +
drivers/power/supply/ntxec-battery.c | 101 +++++++++++++++++++++++++++++++++++
4 files changed, 112 insertions(+)
diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
index 08c68de0f01bc..d5059b8862aa8 100644
--- a/drivers/mfd/ntxec.c
+++ b/drivers/mfd/ntxec.c
@@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
static const struct mfd_cell ntxec_subdev[] = {
{ .name = "ntxec-rtc" },
{ .name = "ntxec-pwm" },
+ { .name = "ntxec-battery" },
};
static const struct mfd_cell ntxec_subdev_pwm[] = {
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 92f9f7aae92f2..5674a23ba7bd6 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -1132,4 +1132,13 @@ config FUEL_GAUGE_MM8013
the state of charge, temperature, cycle count, actual and design
capacity, etc.
+config BATTERY_NTXEC
+ tristate "Battery driver for Netronix embedded controller"
+ depends on MFD_NTXEC
+ help
+ Say yes here to enable netronix ec battery monitoring driver.
+ It enables the monitoring battery voltage on certain e-book readers
+ using an embedded controller by ODM Netronix. Battery design
+ characteristics are read from Firmware Tables if available.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 4b79d5abc49a7..db6fc815f9da2 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -128,3 +128,4 @@ obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o
obj-$(CONFIG_BATTERY_UG3105) += ug3105_battery.o
obj-$(CONFIG_CHARGER_QCOM_SMB2) += qcom_smbx.o
obj-$(CONFIG_FUEL_GAUGE_MM8013) += mm8013.o
+obj-$(CONFIG_BATTERY_NTXEC) += ntxec-battery.o
diff --git a/drivers/power/supply/ntxec-battery.c b/drivers/power/supply/ntxec-battery.c
new file mode 100644
index 0000000000000..f49f0966d18dd
--- /dev/null
+++ b/drivers/power/supply/ntxec-battery.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * The Netronix embedded controller is a microcontroller found in some
+ * e-book readers designed by the original design manufacturer Netronix, Inc.
+ * It contains RTC, battery monitoring, system power management, and PWM
+ * functionality.
+ *
+ * This driver implements battery monitoring.
+ *
+ * Copyright 2021 Josua Mayer <josua.mayer@jm0.eu>
+ */
+
+#include <linux/mfd/ntxec.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+static const enum power_supply_property ntxec_battery_properties[] = {
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+struct ntxec_battery {
+ struct ntxec *ec;
+};
+
+#define NTXEC_REG_READ_BATTERY 0x41
+
+static int ntxec_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ntxec_battery *priv = power_supply_get_drvdata(psy);
+ int ret;
+ unsigned int value;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
+ if (ret < 0)
+ return ret;
+
+ /* ec value to microvolt conversion:
+ * vendor kernel source suggests linear behaviour from 3V to 4.2V
+ * with readings 767 to 1023; each increment represents 4687,5uV.
+ * adjust 3V boundary slightly to report exactly 4.2V when full.
+ */
+ val->intval = 2999872 + (value - 767) * 4688;
+ break;
+ default:
+ dev_err(&psy->dev, "%s: invalid property %u\n", __func__, psp);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct power_supply_desc ntxec_battery_desc = {
+ .name = "ec-battery",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = ntxec_battery_properties,
+ .get_property = ntxec_battery_get_property,
+ .num_properties = ARRAY_SIZE(ntxec_battery_properties),
+};
+
+static int ntxec_battery_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ntxec *ec = dev_get_drvdata(dev->parent);
+ struct power_supply_config psy_cfg = {};
+ struct ntxec_battery *priv;
+ struct power_supply *psy;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->ec = ec;
+ psy_cfg.drv_data = priv;
+ psy_cfg.fwnode = dev_fwnode(dev->parent);
+ psy_cfg.no_wakeup_source = true;
+ psy = devm_power_supply_register(dev, &ntxec_battery_desc, &psy_cfg);
+ if (IS_ERR(psy))
+ return PTR_ERR(psy);
+
+ return 0;
+}
+
+static struct platform_driver ntxec_battery_driver = {
+ .driver = {
+ .name = "ntxec-battery",
+ },
+ .probe = ntxec_battery_probe,
+};
+module_platform_driver(ntxec_battery_driver);
+
+MODULE_AUTHOR("Josua Mayer <josua.mayer@jm0.eu>");
+MODULE_DESCRIPTION("Battery driver for Netronix EC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ntxec-battery");
--
2.51.0
Hello!
Nice to see someone work on the Netronix EC :-)
On Sat, Dec 27, 2025 at 05:28:13PM +0100, Josua Mayer wrote:
> Implement a simple battery driver for monitoring voltage with the
> netronix embedded controller found in certain ebook readers.
>
> Signed-off-by: Josua Mayer <josua.mayer@jm0.eu>
> ---
> drivers/mfd/ntxec.c | 1 +
> drivers/power/supply/Kconfig | 9 ++++
> drivers/power/supply/Makefile | 1 +
> drivers/power/supply/ntxec-battery.c | 101 +++++++++++++++++++++++++++++++++++
> 4 files changed, 112 insertions(+)
>
> diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
> index 08c68de0f01bc..d5059b8862aa8 100644
> --- a/drivers/mfd/ntxec.c
> +++ b/drivers/mfd/ntxec.c
> @@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
> static const struct mfd_cell ntxec_subdev[] = {
> { .name = "ntxec-rtc" },
> { .name = "ntxec-pwm" },
> + { .name = "ntxec-battery" },
> };
>
> static const struct mfd_cell ntxec_subdev_pwm[] = {
> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index 92f9f7aae92f2..5674a23ba7bd6 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -1132,4 +1132,13 @@ config FUEL_GAUGE_MM8013
> the state of charge, temperature, cycle count, actual and design
> capacity, etc.
>
> +config BATTERY_NTXEC
> + tristate "Battery driver for Netronix embedded controller"
> + depends on MFD_NTXEC
> + help
> + Say yes here to enable netronix ec battery monitoring driver.
> + It enables the monitoring battery voltage on certain e-book readers
> + using an embedded controller by ODM Netronix. Battery design
> + characteristics are read from Firmware Tables if available.
What do you mean by Firmware Tables, and where does this happen?
(I guess it means devicetree/fwnode, but "git grep -i 'firmware tables'"
doesn't show many uses of that term)
> +
> endif # POWER_SUPPLY
> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
> index 4b79d5abc49a7..db6fc815f9da2 100644
> --- a/drivers/power/supply/Makefile
> +++ b/drivers/power/supply/Makefile
> @@ -128,3 +128,4 @@ obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o
> obj-$(CONFIG_BATTERY_UG3105) += ug3105_battery.o
> obj-$(CONFIG_CHARGER_QCOM_SMB2) += qcom_smbx.o
> obj-$(CONFIG_FUEL_GAUGE_MM8013) += mm8013.o
> +obj-$(CONFIG_BATTERY_NTXEC) += ntxec-battery.o
> diff --git a/drivers/power/supply/ntxec-battery.c b/drivers/power/supply/ntxec-battery.c
> new file mode 100644
> index 0000000000000..f49f0966d18dd
> --- /dev/null
> +++ b/drivers/power/supply/ntxec-battery.c
> @@ -0,0 +1,101 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * The Netronix embedded controller is a microcontroller found in some
> + * e-book readers designed by the original design manufacturer Netronix, Inc.
> + * It contains RTC, battery monitoring, system power management, and PWM
> + * functionality.
> + *
> + * This driver implements battery monitoring.
> + *
> + * Copyright 2021 Josua Mayer <josua.mayer@jm0.eu>
> + */
> +
> +#include <linux/mfd/ntxec.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +static const enum power_supply_property ntxec_battery_properties[] = {
> + POWER_SUPPLY_PROP_VOLTAGE_NOW,
> +};
> +
> +struct ntxec_battery {
> + struct ntxec *ec;
> +};
> +
> +#define NTXEC_REG_READ_BATTERY 0x41
> +
> +static int ntxec_battery_get_property(struct power_supply *psy,
> + enum power_supply_property psp,
> + union power_supply_propval *val)
> +{
> + struct ntxec_battery *priv = power_supply_get_drvdata(psy);
> + int ret;
> + unsigned int value;
> +
> + switch (psp) {
> + case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> + ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
> + if (ret < 0)
> + return ret;
> +
> + /* ec value to microvolt conversion:
> + * vendor kernel source suggests linear behaviour from 3V to 4.2V
> + * with readings 767 to 1023; each increment represents 4687,5uV.
> + * adjust 3V boundary slightly to report exactly 4.2V when full.
> + */
> + val->intval = 2999872 + (value - 767) * 4688;
> + break;
> + default:
> + dev_err(&psy->dev, "%s: invalid property %u\n", __func__, psp);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static const struct power_supply_desc ntxec_battery_desc = {
> + .name = "ec-battery",
> + .type = POWER_SUPPLY_TYPE_BATTERY,
> + .properties = ntxec_battery_properties,
> + .get_property = ntxec_battery_get_property,
> + .num_properties = ARRAY_SIZE(ntxec_battery_properties),
> +};
> +
> +static int ntxec_battery_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct ntxec *ec = dev_get_drvdata(dev->parent);
> + struct power_supply_config psy_cfg = {};
> + struct ntxec_battery *priv;
> + struct power_supply *psy;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->ec = ec;
> + psy_cfg.drv_data = priv;
> + psy_cfg.fwnode = dev_fwnode(dev->parent);
> + psy_cfg.no_wakeup_source = true;
> + psy = devm_power_supply_register(dev, &ntxec_battery_desc, &psy_cfg);
> + if (IS_ERR(psy))
> + return PTR_ERR(psy);
> +
> + return 0;
> +}
> +
> +static struct platform_driver ntxec_battery_driver = {
> + .driver = {
> + .name = "ntxec-battery",
> + },
> + .probe = ntxec_battery_probe,
> +};
> +module_platform_driver(ntxec_battery_driver);
> +
> +MODULE_AUTHOR("Josua Mayer <josua.mayer@jm0.eu>");
> +MODULE_DESCRIPTION("Battery driver for Netronix EC");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:ntxec-battery");
Thanks,
J. Neuschäfer
Am 28.12.25 um 18:56 schrieb J. Neuschäfer:
> Hello!
>
> Nice to see someone work on the Netronix EC :-)
>
> On Sat, Dec 27, 2025 at 05:28:13PM +0100, Josua Mayer wrote:
>> Implement a simple battery driver for monitoring voltage with the
>> netronix embedded controller found in certain ebook readers.
>>
>> Signed-off-by: Josua Mayer <josua.mayer@jm0.eu>
>> ---
>> drivers/mfd/ntxec.c | 1 +
>> drivers/power/supply/Kconfig | 9 ++++
>> drivers/power/supply/Makefile | 1 +
>> drivers/power/supply/ntxec-battery.c | 101 +++++++++++++++++++++++++++++++++++
>> 4 files changed, 112 insertions(+)
>>
>> diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
>> index 08c68de0f01bc..d5059b8862aa8 100644
>> --- a/drivers/mfd/ntxec.c
>> +++ b/drivers/mfd/ntxec.c
>> @@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
>> static const struct mfd_cell ntxec_subdev[] = {
>> { .name = "ntxec-rtc" },
>> { .name = "ntxec-pwm" },
>> + { .name = "ntxec-battery" },
>> };
>>
>> static const struct mfd_cell ntxec_subdev_pwm[] = {
>> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
>> index 92f9f7aae92f2..5674a23ba7bd6 100644
>> --- a/drivers/power/supply/Kconfig
>> +++ b/drivers/power/supply/Kconfig
>> @@ -1132,4 +1132,13 @@ config FUEL_GAUGE_MM8013
>> the state of charge, temperature, cycle count, actual and design
>> capacity, etc.
>>
>> +config BATTERY_NTXEC
>> + tristate "Battery driver for Netronix embedded controller"
>> + depends on MFD_NTXEC
>> + help
>> + Say yes here to enable netronix ec battery monitoring driver.
>> + It enables the monitoring battery voltage on certain e-book readers
>> + using an embedded controller by ODM Netronix. Battery design
>> + characteristics are read from Firmware Tables if available.
>
> What do you mean by Firmware Tables, and where does this happen?
Effectively I mean device-tree.
This happens in power-supply core automatically for type battery:
static struct power_supply *__must_check
__power_supply_register(struct device *parent,
const struct power_supply_desc *desc,
const struct power_supply_config *cfg)
{
...
/*
* Expose constant battery info, if it is available. While there are
* some chargers accessing constant battery data, we only want to
* expose battery data to userspace for battery devices.
*/
if (desc->type == POWER_SUPPLY_TYPE_BATTERY) {
rc = power_supply_get_battery_info(psy, &psy->battery_info);
if (rc && rc != -ENODEV && rc != -ENOENT)
goto check_supplies_failed;
}
...
}
This code particular is the reason I marked it optional in DT binding.
>
> (I guess it means devicetree/fwnode, but "git grep -i 'firmware tables'"
Yes, given that power_supply_get_battery_info uses fwnode_* functions.
> doesn't show many uses of that term)
I was struggling with the phrasing - can change to something better.
>
>> +
>> endif # POWER_SUPPLY
>> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
>> index 4b79d5abc49a7..db6fc815f9da2 100644
>> --- a/drivers/power/supply/Makefile
>> +++ b/drivers/power/supply/Makefile
>> @@ -128,3 +128,4 @@ obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o
>> obj-$(CONFIG_BATTERY_UG3105) += ug3105_battery.o
>> obj-$(CONFIG_CHARGER_QCOM_SMB2) += qcom_smbx.o
>> obj-$(CONFIG_FUEL_GAUGE_MM8013) += mm8013.o
>> +obj-$(CONFIG_BATTERY_NTXEC) += ntxec-battery.o
>> diff --git a/drivers/power/supply/ntxec-battery.c b/drivers/power/supply/ntxec-battery.c
>> new file mode 100644
>> index 0000000000000..f49f0966d18dd
>> --- /dev/null
>> +++ b/drivers/power/supply/ntxec-battery.c
>> @@ -0,0 +1,101 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * The Netronix embedded controller is a microcontroller found in some
>> + * e-book readers designed by the original design manufacturer Netronix, Inc.
>> + * It contains RTC, battery monitoring, system power management, and PWM
>> + * functionality.
>> + *
>> + * This driver implements battery monitoring.
>> + *
>> + * Copyright 2021 Josua Mayer <josua.mayer@jm0.eu>
>> + */
>> +
>> +#include <linux/mfd/ntxec.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/power_supply.h>
>> +#include <linux/property.h>
>> +#include <linux/regmap.h>
>> +
>> +static const enum power_supply_property ntxec_battery_properties[] = {
>> + POWER_SUPPLY_PROP_VOLTAGE_NOW,
>> +};
>> +
>> +struct ntxec_battery {
>> + struct ntxec *ec;
>> +};
>> +
>> +#define NTXEC_REG_READ_BATTERY 0x41
>> +
>> +static int ntxec_battery_get_property(struct power_supply *psy,
>> + enum power_supply_property psp,
>> + union power_supply_propval *val)
>> +{
>> + struct ntxec_battery *priv = power_supply_get_drvdata(psy);
>> + int ret;
>> + unsigned int value;
>> +
>> + switch (psp) {
>> + case POWER_SUPPLY_PROP_VOLTAGE_NOW:
>> + ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
>> + if (ret < 0)
>> + return ret;
>> +
>> + /* ec value to microvolt conversion:
>> + * vendor kernel source suggests linear behaviour from 3V to 4.2V
>> + * with readings 767 to 1023; each increment represents 4687,5uV.
>> + * adjust 3V boundary slightly to report exactly 4.2V when full.
>> + */
>> + val->intval = 2999872 + (value - 767) * 4688;
>> + break;
>> + default:
>> + dev_err(&psy->dev, "%s: invalid property %u\n", __func__, psp);
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct power_supply_desc ntxec_battery_desc = {
>> + .name = "ec-battery",
>> + .type = POWER_SUPPLY_TYPE_BATTERY,
>> + .properties = ntxec_battery_properties,
>> + .get_property = ntxec_battery_get_property,
>> + .num_properties = ARRAY_SIZE(ntxec_battery_properties),
>> +};
>> +
>> +static int ntxec_battery_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct ntxec *ec = dev_get_drvdata(dev->parent);
>> + struct power_supply_config psy_cfg = {};
>> + struct ntxec_battery *priv;
>> + struct power_supply *psy;
>> +
>> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> + if (!priv)
>> + return -ENOMEM;
>> +
>> + priv->ec = ec;
>> + psy_cfg.drv_data = priv;
>> + psy_cfg.fwnode = dev_fwnode(dev->parent);
>> + psy_cfg.no_wakeup_source = true;
>> + psy = devm_power_supply_register(dev, &ntxec_battery_desc, &psy_cfg);
>> + if (IS_ERR(psy))
>> + return PTR_ERR(psy);
>> +
>> + return 0;
>> +}
>> +
>> +static struct platform_driver ntxec_battery_driver = {
>> + .driver = {
>> + .name = "ntxec-battery",
>> + },
>> + .probe = ntxec_battery_probe,
>> +};
>> +module_platform_driver(ntxec_battery_driver);
>> +
>> +MODULE_AUTHOR("Josua Mayer <josua.mayer@jm0.eu>");
>> +MODULE_DESCRIPTION("Battery driver for Netronix EC");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("platform:ntxec-battery");
>
> Thanks,
> J. Neuschäfer
On Sat, 27 Dec 2025 17:28:13 +0100
Josua Mayer <josua.mayer@jm0.eu> wrote:
> Implement a simple battery driver for monitoring voltage with the
> netronix embedded controller found in certain ebook readers.
>
> Signed-off-by: Josua Mayer <josua.mayer@jm0.eu>
This also produces a value somehow depending on battery voltage
on the Tolino vision.
[...]
> diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
> index 08c68de0f01bc..d5059b8862aa8 100644
> --- a/drivers/mfd/ntxec.c
> +++ b/drivers/mfd/ntxec.c
> @@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
> static const struct mfd_cell ntxec_subdev[] = {
> { .name = "ntxec-rtc" },
> { .name = "ntxec-pwm" },
> + { .name = "ntxec-battery" },
> };
>
> static const struct mfd_cell ntxec_subdev_pwm[] = {
I think that should be a separate patch for mfd.
[...]
> + switch (psp) {
> + case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> + ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
> + if (ret < 0)
> + return ret;
> +
> + /* ec value to microvolt conversion:
> + * vendor kernel source suggests linear behaviour from 3V to 4.2V
> + * with readings 767 to 1023; each increment represents 4687,5uV.
> + * adjust 3V boundary slightly to report exactly 4.2V when full.
> + */
> + val->intval = 2999872 + (value - 767) * 4688;
> + break;
I find this code both in some kobo 2.6.35.3 code and on the tolino 3.0.35:
const unsigned short battGasgauge[] = {
// 3.0V, 3.1V, 3.2V, 3.3V, 3.4V, 3.5V, 3.6V, 3.7V, 3.8V, 3.9V, 4.0V, 4.1V, 4.2V,
// 743, 767, 791, 812, 835, 860, 885, 909, 935, 960, 985, 1010, 1023,
767, 791, 812, 833, 852, 877, 903, 928, 950, 979, 993, 1019, 1023,
};
This does not look very linear... We have offsets
24
21
21
19
25
26
25
22
29
14
26
4
Do you have something looking more sane?
No idea what should produce such flaky offsets besides of
improper measurements. At least that should be commented.
And why do these tables exist at all?
Hmm, the more weird thing is that these voltages are translated linearly
inot capacity. So maybe they are just adjusted to have the capacity look
more sane. That would explain the 4 units step between 4.1V and 4.2V.
Having linear adc result -> voltage and nonlinear voltage-> capcity would
make more sense.
looking at such code snippet like this:
case POWER_SUPPLY_PROP_CAPACITY:
if (POWER_SUPPLY_STATUS_NOT_CHARGING == g_ntx_bat_di->battery_status) {
val->intval = 100;
return 0;
}
value = ntx_up_battery_vol();
[...]
val->intval = 100 - ((4100000 - value)/7000);
I am wondering whether we should just return capacity that way without
calculating voltage...
Regards,
Andreas
Am 27.12.25 um 22:38 schrieb Andreas Kemnade:
> On Sat, 27 Dec 2025 17:28:13 +0100
> Josua Mayer <josua.mayer@jm0.eu> wrote:
>
>> Implement a simple battery driver for monitoring voltage with the
>> netronix embedded controller found in certain ebook readers.
>>
>> Signed-off-by: Josua Mayer <josua.mayer@jm0.eu>
>
> This also produces a value somehow depending on battery voltage
> on the Tolino vision.
Good!
> [...]
>> diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
>> index 08c68de0f01bc..d5059b8862aa8 100644
>> --- a/drivers/mfd/ntxec.c
>> +++ b/drivers/mfd/ntxec.c
>> @@ -139,6 +139,7 @@ static const struct regmap_config regmap_config = {
>> static const struct mfd_cell ntxec_subdev[] = {
>> { .name = "ntxec-rtc" },
>> { .name = "ntxec-pwm" },
>> + { .name = "ntxec-battery" },
>> };
>>
>> static const struct mfd_cell ntxec_subdev_pwm[] = {
>
> I think that should be a separate patch for mfd.
Okay
> [...]
>> + switch (psp) {
>> + case POWER_SUPPLY_PROP_VOLTAGE_NOW:
>> + ret = regmap_read(priv->ec->regmap, NTXEC_REG_READ_BATTERY, &value);
>> + if (ret < 0)
>> + return ret;
>> +
>> + /* ec value to microvolt conversion:
>> + * vendor kernel source suggests linear behaviour from 3V to 4.2V
>> + * with readings 767 to 1023; each increment represents 4687,5uV.
>> + * adjust 3V boundary slightly to report exactly 4.2V when full.
>> + */
>> + val->intval = 2999872 + (value - 767) * 4688;
>> + break;
> I find this code both in some kobo 2.6.35.3 code and on the tolino 3.0.35:
>
> const unsigned short battGasgauge[] = {
> // 3.0V, 3.1V, 3.2V, 3.3V, 3.4V, 3.5V, 3.6V, 3.7V, 3.8V, 3.9V, 4.0V, 4.1V, 4.2V,
> // 743, 767, 791, 812, 835, 860, 885, 909, 935, 960, 985, 1010, 1023,
> 767, 791, 812, 833, 852, 877, 903, 928, 950, 979, 993, 1019, 1023,
> };
>
> This does not look very linear... We have offsets
> 24
> 21
> 21
> 19
> 25
> 26
> 25
> 22
> 29
> 14
> 26
> 4
>
> Do you have something looking more sane?
No, I based on the same but simplified it.
> No idea what should produce such flaky offsets besides of
> improper measurements. At least that should be commented.
> And why do these tables exist at all?
>
> Hmm, the more weird thing is that these voltages are translated linearly
> inot capacity.
Indeed - this is why I decided on a linear relationship ...
matching minimal and maixmal voltage as close as possible.
> So maybe they are just adjusted to have the capacity look
> more sane. That would explain the 4 units step between 4.1V and 4.2V.
4.1 is the full voltage of the lion battery if charger was disconnected.
However 4.2 I think is the final voltage reached while charging.
> Having linear adc result -> voltage and nonlinear voltage-> capcity would
> make more sense.
Indeed.
But if it was intended as percentage, then why would he register not
just read from 0-100 :(
So I still guess it is some adc result.
>
> looking at such code snippet like this:
> case POWER_SUPPLY_PROP_CAPACITY:
> if (POWER_SUPPLY_STATUS_NOT_CHARGING == g_ntx_bat_di->battery_status) {
> val->intval = 100;
> return 0;
> }
> value = ntx_up_battery_vol();
> [...]
> val->intval = 100 - ((4100000 - value)/7000);
>
>
> I am wondering whether we should just return capacity that way without
> calculating voltage...
I suppose it depends on whether it is more likely that the ec provides
voltage, or a charge estimation.
br
Josua
© 2016 - 2026 Red Hat, Inc.