* [PATCH 0/2] power: supply: add charger for BD71828
@ 2025-08-16 19:19 Andreas Kemnade,,,
2025-08-16 19:19 ` [PATCH 1/2] mfd: bd71828, bd71815 prepare for power-supply support Andreas Kemnade,,,
2025-08-16 19:19 ` [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver Andreas Kemnade
0 siblings, 2 replies; 19+ messages in thread
From: Andreas Kemnade,,, @ 2025-08-16 19:19 UTC (permalink / raw)
To: Matti Vaittinen, Lee Jones, Sebastian Reichel
Cc: linux-kernel, linux-pm, Andreas Kemnade, Matti Vaittinen
Add basic charger which does just read out simple registers without
doing any sophisticated things.
This is a stripped down version of
https://lore.kernel.org/lkml/dbd97c1b0d715aa35a8b4d79741e433d97c562aa.1637061794.git.matti.vaittinen@fi.rohmeurope.com/
That version includes all the bells-and-whistles you might imagine
around coloumb counter handling and capacity measurement which includes
changes no the power supply core.
Rather do a step by step approach to keep that reviewable.
Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
---
Andreas Kemnade (1):
power: supply: Add bd718(15/28/78) charger driver
Matti Vaittinen (1):
mfd: bd71828, bd71815 prepare for power-supply support
drivers/mfd/rohm-bd71828.c | 44 +-
drivers/power/supply/Kconfig | 11 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/bd71828-power.c | 1144 ++++++++++++++++++++++++++++++++++
include/linux/mfd/rohm-bd71828.h | 65 ++
include/linux/mfd/rohm-generic.h | 2 +
6 files changed, 1258 insertions(+), 9 deletions(-)
---
base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
change-id: 20250816-bd71828-charger-9d187346f734
Best regards,
--
Andreas Kemnade,,, <andreas@kemnade.info>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 1/2] mfd: bd71828, bd71815 prepare for power-supply support
2025-08-16 19:19 [PATCH 0/2] power: supply: add charger for BD71828 Andreas Kemnade,,,
@ 2025-08-16 19:19 ` Andreas Kemnade,,,
2025-08-18 5:49 ` Matti Vaittinen
2025-08-16 19:19 ` [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver Andreas Kemnade
1 sibling, 1 reply; 19+ messages in thread
From: Andreas Kemnade,,, @ 2025-08-16 19:19 UTC (permalink / raw)
To: Matti Vaittinen, Lee Jones, Sebastian Reichel
Cc: linux-kernel, linux-pm, Andreas Kemnade, Matti Vaittinen
From: Matti Vaittinen <mazziesaccount@gmail.com>
Add core support for ROHM BD718(15/28/78) PMIC's charger blocks.
Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
---
drivers/mfd/rohm-bd71828.c | 44 +++++++++++++++++++++------
include/linux/mfd/rohm-bd71828.h | 65 ++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/rohm-generic.h | 2 ++
3 files changed, 102 insertions(+), 9 deletions(-)
diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c
index a14b7aa69c3c61d51f2aeeae9afdf222310d63e3..84a64c3b9c9f52e663855c89ed78ede9a7c21f55 100644
--- a/drivers/mfd/rohm-bd71828.c
+++ b/drivers/mfd/rohm-bd71828.c
@@ -45,8 +45,8 @@ static const struct resource bd71828_rtc_irqs[] = {
static const struct resource bd71815_power_irqs[] = {
DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"),
- DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-clps-out"),
- DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-dcin-clps-out"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-dcin-clps-in"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res"),
@@ -56,7 +56,7 @@ static const struct resource bd71815_power_irqs[] = {
DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res"),
- DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_DET, "bd71815-vsys-mon-det"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res"),
@@ -87,10 +87,10 @@ static const struct resource bd71815_power_irqs[] = {
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_DET, "bd71815-bat-oc2-det"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_RES, "bd71815-bat-oc3-res"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_DET, "bd71815-bat-oc3-det"),
- DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-bat-low-res"),
- DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-bat-low-det"),
- DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-bat-hi-res"),
- DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-bat-hi-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-temp-bat-low-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-temp-bat-low-det"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-temp-bat-hi-res"),
+ DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-temp-bat-hi-det"),
};
static const struct mfd_cell bd71815_mfd_cells[] = {
@@ -109,7 +109,30 @@ static const struct mfd_cell bd71815_mfd_cells[] = {
},
};
-static const struct mfd_cell bd71828_mfd_cells[] = {
+static const struct resource bd71828_power_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_CHG_TOPOFF_TO_DONE,
+ "bd71828-chg-done"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_DCIN_DET, "bd71828-pwr-dcin-in"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_DCIN_RMV, "bd71828-pwr-dcin-out"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_BAT_LOW_VOLT_RES,
+ "bd71828-vbat-normal"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_BAT_LOW_VOLT_DET, "bd71828-vbat-low"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_BAT_HI_DET, "bd71828-btemp-hi"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_BAT_HI_RES, "bd71828-btemp-cool"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_BAT_LOW_DET, "bd71828-btemp-lo"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_BAT_LOW_RES,
+ "bd71828-btemp-warm"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_CHIP_OVER_VF_DET,
+ "bd71828-temp-hi"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_CHIP_OVER_VF_RES,
+ "bd71828-temp-norm"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_CHIP_OVER_125_DET,
+ "bd71828-temp-125-over"),
+ DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_CHIP_OVER_125_RES,
+ "bd71828-temp-125-under"),
+};
+
+static struct mfd_cell bd71828_mfd_cells[] = {
{ .name = "bd71828-pmic", },
{ .name = "bd71828-gpio", },
{ .name = "bd71828-led", .of_compatible = "rohm,bd71828-leds" },
@@ -118,8 +141,11 @@ static const struct mfd_cell bd71828_mfd_cells[] = {
* BD70528 clock gate are the register address and mask.
*/
{ .name = "bd71828-clk", },
- { .name = "bd71827-power", },
{
+ .name = "bd71828-power",
+ .resources = bd71828_power_irqs,
+ .num_resources = ARRAY_SIZE(bd71828_power_irqs),
+ }, {
.name = "bd71828-rtc",
.resources = bd71828_rtc_irqs,
.num_resources = ARRAY_SIZE(bd71828_rtc_irqs),
diff --git a/include/linux/mfd/rohm-bd71828.h b/include/linux/mfd/rohm-bd71828.h
index ce786c96404a3dc9d5124ffbbd507df89ca0e5ba..a34991984caa8724e925f1c59de4bcfa543ae411 100644
--- a/include/linux/mfd/rohm-bd71828.h
+++ b/include/linux/mfd/rohm-bd71828.h
@@ -189,6 +189,71 @@ enum {
/* Charger/Battey */
#define BD71828_REG_CHG_STATE 0x65
#define BD71828_REG_CHG_FULL 0xd2
+#define BD71828_REG_CHG_EN 0x6F
+#define BD71828_REG_DCIN_STAT 0x68
+#define BD71828_MASK_DCIN_DET 0x01
+#define BD71828_REG_VDCIN_U 0x9c
+#define BD71828_MASK_CHG_EN 0x01
+#define BD71828_CHG_MASK_DCIN_U 0x0f
+#define BD71828_REG_BAT_STAT 0x67
+#define BD71828_REG_BAT_TEMP 0x6c
+#define BD71828_MASK_BAT_TEMP 0x07
+#define BD71828_BAT_TEMP_OPEN 0x07
+#define BD71828_MASK_BAT_DET 0x20
+#define BD71828_MASK_BAT_DET_DONE 0x10
+#define BD71828_REG_CHG_STATE 0x65
+#define BD71828_REG_VBAT_U 0x8c
+#define BD71828_MASK_VBAT_U 0x0f
+#define BD71828_REG_VBAT_REX_AVG_U 0x92
+
+#define BD71828_REG_OCV_PWRON_U 0x8A
+
+#define BD71828_REG_VBAT_MIN_AVG_U 0x8e
+#define BD71828_REG_VBAT_MIN_AVG_L 0x8f
+
+#define BD71828_REG_CC_CNT3 0xb5
+#define BD71828_REG_CC_CNT2 0xb6
+#define BD71828_REG_CC_CNT1 0xb7
+#define BD71828_REG_CC_CNT0 0xb8
+#define BD71828_REG_CC_CURCD_AVG_U 0xb2
+#define BD71828_MASK_CC_CURCD_AVG_U 0x3f
+#define BD71828_MASK_CC_CUR_DIR 0x80
+#define BD71828_REG_VM_BTMP_U 0xa1
+#define BD71828_REG_VM_BTMP_L 0xa2
+#define BD71828_MASK_VM_BTMP_U 0x0f
+#define BD71828_REG_COULOMB_CTRL 0xc4
+#define BD71828_REG_COULOMB_CTRL2 0xd2
+#define BD71828_MASK_REX_CC_CLR 0x01
+#define BD71828_MASK_FULL_CC_CLR 0x10
+#define BD71828_REG_CC_CNT_FULL3 0xbd
+#define BD71828_REG_CC_CNT_CHG3 0xc1
+
+#define BD71828_REG_VBAT_INITIAL1_U 0x86
+#define BD71828_REG_VBAT_INITIAL1_L 0x87
+
+#define BD71828_REG_VBAT_INITIAL2_U 0x88
+#define BD71828_REG_VBAT_INITIAL2_L 0x89
+
+#define BD71828_REG_IBAT_U 0xb0
+#define BD71828_REG_IBAT_L 0xb1
+
+#define BD71828_REG_IBAT_AVG_U 0xb2
+#define BD71828_REG_IBAT_AVG_L 0xb3
+
+#define BD71828_REG_VSYS_AVG_U 0x96
+#define BD71828_REG_VSYS_AVG_L 0x97
+#define BD71828_REG_VSYS_MIN_AVG_U 0x98
+#define BD71828_REG_VSYS_MIN_AVG_L 0x99
+#define BD71828_REG_CHG_SET1 0x75
+#define BD71828_REG_ALM_VBAT_LIMIT_U 0xaa
+#define BD71828_REG_BATCAP_MON_LIMIT_U 0xcc
+#define BD71828_REG_CONF 0x64
+
+#define BD71828_REG_DCIN_CLPS 0x71
+
+#define BD71828_REG_MEAS_CLEAR 0xaf
+
+
/* LEDs */
#define BD71828_REG_LED_CTRL 0x4A
diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h
index 579e8dcfcca41d2680283819684a1014617d0d4b..5e9d0da380ec0fc3245bee998c791a162a34e3fa 100644
--- a/include/linux/mfd/rohm-generic.h
+++ b/include/linux/mfd/rohm-generic.h
@@ -13,9 +13,11 @@ enum rohm_chip_type {
ROHM_CHIP_TYPE_BD9574,
ROHM_CHIP_TYPE_BD9576,
ROHM_CHIP_TYPE_BD71815,
+ ROHM_CHIP_TYPE_BD71827,
ROHM_CHIP_TYPE_BD71828,
ROHM_CHIP_TYPE_BD71837,
ROHM_CHIP_TYPE_BD71847,
+ ROHM_CHIP_TYPE_BD71878,
ROHM_CHIP_TYPE_BD96801,
ROHM_CHIP_TYPE_BD96802,
ROHM_CHIP_TYPE_BD96805,
--
2.39.5
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-16 19:19 [PATCH 0/2] power: supply: add charger for BD71828 Andreas Kemnade,,,
2025-08-16 19:19 ` [PATCH 1/2] mfd: bd71828, bd71815 prepare for power-supply support Andreas Kemnade,,,
@ 2025-08-16 19:19 ` Andreas Kemnade
2025-08-17 5:58 ` Krzysztof Kozlowski
` (3 more replies)
1 sibling, 4 replies; 19+ messages in thread
From: Andreas Kemnade @ 2025-08-16 19:19 UTC (permalink / raw)
To: Matti Vaittinen, Lee Jones, Sebastian Reichel
Cc: linux-kernel, linux-pm, Andreas Kemnade
Add charger driver for ROHM BD718(15/28/78) PMIC charger block.
It is a stripped down version of the driver here:
https://lore.kernel.org/lkml/dbd97c1b0d715aa35a8b4d79741e433d97c562aa.1637061794.git.matti.vaittinen@fi.rohmeurope.com/
For the ease of review and to do a step-by-step approach remove all the
coloumb counter related stuff and do not sneak in BD71827 support.
Changes besides that:
Replace the custom property by a standard one and do not use megaohms
for the current sense resistor.
Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
---
drivers/power/supply/Kconfig | 11 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/bd71828-power.c | 1144 ++++++++++++++++++++++++++++++++++
3 files changed, 1156 insertions(+)
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 79ddb006e2dad6bf96b71ed570a37c006b5f9433..f3429f0aecf5a17fbaa52ee76899657181429a48 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -974,6 +974,17 @@ config CHARGER_UCS1002
Say Y to enable support for Microchip UCS1002 Programmable
USB Port Power Controller with Charger Emulation.
+config CHARGER_BD71828
+ tristate "Power-supply driver for ROHM BD71828 and BD71815 PMIC"
+ depends on MFD_ROHM_BD71828
+ select POWER_SIMPLE_GAUGE
+ help
+ Say Y here to enable support for charger, battery and fuel gauge
+ in ROHM BD71815, BD71817, ROHM BD71828 power management
+ ICs. This driver gets various bits of information about battery
+ and charger states and also implements fuel gauge based on
+ coulomb counters on PMIC.
+
config CHARGER_BD99954
tristate "ROHM bd99954 charger driver"
depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index f943c9150b326d41ff241f82610f70298635eb08..c6520a11f021c872f01250ae54eb4c63018cd428 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -113,6 +113,7 @@ obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
obj-$(CONFIG_FUEL_GAUGE_STC3117) += stc3117_fuel_gauge.o
obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
+obj-$(CONFIG_CHARGER_BD71828) += bd71828-power.o
obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o
obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
diff --git a/drivers/power/supply/bd71828-power.c b/drivers/power/supply/bd71828-power.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2686c7eadf0515856d60123f57bca59b33bbd10
--- /dev/null
+++ b/drivers/power/supply/bd71828-power.c
@@ -0,0 +1,1144 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * bd71828-power.c
+ * @file ROHM BD71815, BD71828 and BD71878 Charger driver
+ *
+ * Copyright 2021.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/rohm-bd71815.h>
+#include <linux/mfd/rohm-bd71828.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+/* common defines */
+#define BD7182x_MASK_VBAT_U 0x1f
+#define BD7182x_MASK_VDCIN_U 0x0f
+#define BD7182x_MASK_IBAT_U 0x3f
+#define BD7182x_MASK_CURDIR_DISCHG 0x80
+#define BD7182x_MASK_CC_CCNTD_HI 0x0FFF
+#define BD7182x_MASK_CC_CCNTD 0x0FFFFFFF
+#define BD7182x_MASK_CHG_STATE 0x7f
+#define BD7182x_MASK_CC_FULL_CLR 0x10
+#define BD7182x_MASK_BAT_TEMP 0x07
+#define BD7182x_MASK_DCIN_DET BIT(0)
+#define BD7182x_MASK_CONF_PON BIT(0)
+#define BD71815_MASK_CONF_XSTB BIT(1)
+#define BD7182x_MASK_BAT_STAT 0x3f
+#define BD7182x_MASK_DCIN_STAT 0x07
+
+#define BD7182x_MASK_CCNTRST 0x80
+#define BD7182x_MASK_CCNTENB 0x40
+#define BD7182x_MASK_CCCALIB 0x20
+#define BD7182x_MASK_WDT_AUTO 0x40
+#define BD7182x_MASK_VBAT_ALM_LIMIT_U 0x01
+#define BD7182x_MASK_CHG_EN 0x01
+
+#define BD7182x_DCIN_COLLAPSE_DEFAULT 0x36
+
+/* Measured min and max value clear bits */
+#define BD718XX_MASK_VSYS_MIN_AVG_CLR 0x10
+
+#define JITTER_DEFAULT 3000
+#define MAX_CURRENT_DEFAULT 890000 /* uA */
+#define AC_NAME "bd71828_ac"
+#define BAT_NAME "bd71828_bat"
+
+/*
+ * VBAT Low voltage detection Threshold
+ * 0x00D4*16mV = 212*0.016 = 3.392v
+ */
+#define VBAT_LOW_TH 0x00D4
+
+#define THR_RELAX_CURRENT_DEFAULT 5 /* mA */
+#define THR_RELAX_TIME_DEFAULT (60 * 60) /* sec. */
+
+#define DGRD_CYC_CAP_DEFAULT 88 /* 1 micro Ah */
+
+#define DGRD_TEMP_H_DEFAULT 450 /* 0.1 degrees C */
+#define DGRD_TEMP_M_DEFAULT 250 /* 0.1 degrees C */
+#define DGRD_TEMP_L_DEFAULT 50 /* 0.1 degrees C */
+#define DGRD_TEMP_VL_DEFAULT 0 /* 0.1 degrees C */
+
+#define SOC_EST_MAX_NUM_DEFAULT 5
+#define PWRCTRL_NORMAL 0x22
+#define PWRCTRL_RESET 0x23
+
+/*
+ * Originally we relied upon a fixed size table of OCV and VDR params.
+ * However the exising linux power-supply batinfo interface for getting the OCV
+ * values from DT does not have fixed amount of OCV values. Thus we use fixed
+ * parameter amount only for values provided as module params - and use this
+ * only as maximum number of parameters when values come from DT.
+ */
+#define NUM_BAT_PARAMS 23
+#define MAX_NUM_VDR_VALUES NUM_BAT_PARAMS
+
+struct pwr_regs {
+ int used_init_regs;
+ u8 vbat_init;
+ u8 vbat_init2;
+ u8 vbat_init3;
+ u8 vbat_avg;
+ u8 ibat;
+ u8 ibat_avg;
+ u8 meas_clear;
+ u8 vsys_min_avg;
+ u8 btemp_vth;
+ u8 chg_state;
+ u8 coulomb3;
+ u8 coulomb2;
+ u8 coulomb1;
+ u8 coulomb0;
+ u8 coulomb_ctrl;
+ u8 vbat_rex_avg;
+ u8 coulomb_full3;
+ u8 cc_full_clr;
+ u8 coulomb_chg3;
+ u8 bat_temp;
+ u8 dcin_stat;
+ u8 dcin_collapse_limit;
+ u8 chg_set1;
+ u8 chg_en;
+ u8 vbat_alm_limit_u;
+ u8 batcap_mon_limit_u;
+ u8 conf;
+ u8 vdcin;
+};
+
+static const struct pwr_regs pwr_regs_bd71828 = {
+ .vbat_init = BD71828_REG_VBAT_INITIAL1_U,
+ .vbat_init2 = BD71828_REG_VBAT_INITIAL2_U,
+ .vbat_init3 = BD71828_REG_OCV_PWRON_U,
+ .used_init_regs = 3,
+ .vbat_avg = BD71828_REG_VBAT_U,
+ .ibat = BD71828_REG_IBAT_U,
+ .ibat_avg = BD71828_REG_IBAT_AVG_U,
+ .meas_clear = BD71828_REG_MEAS_CLEAR,
+ .vsys_min_avg = BD71828_REG_VSYS_MIN_AVG_U,
+ .btemp_vth = BD71828_REG_VM_BTMP_U,
+ .chg_state = BD71828_REG_CHG_STATE,
+ .coulomb3 = BD71828_REG_CC_CNT3,
+ .coulomb2 = BD71828_REG_CC_CNT2,
+ .coulomb1 = BD71828_REG_CC_CNT1,
+ .coulomb0 = BD71828_REG_CC_CNT0,
+ .coulomb_ctrl = BD71828_REG_COULOMB_CTRL,
+ .vbat_rex_avg = BD71828_REG_VBAT_REX_AVG_U,
+ .coulomb_full3 = BD71828_REG_CC_CNT_FULL3,
+ .cc_full_clr = BD71828_REG_COULOMB_CTRL2,
+ .coulomb_chg3 = BD71828_REG_CC_CNT_CHG3,
+ .bat_temp = BD71828_REG_BAT_TEMP,
+ .dcin_stat = BD71828_REG_DCIN_STAT,
+ .dcin_collapse_limit = BD71828_REG_DCIN_CLPS,
+ .chg_set1 = BD71828_REG_CHG_SET1,
+ .chg_en = BD71828_REG_CHG_EN,
+ .vbat_alm_limit_u = BD71828_REG_ALM_VBAT_LIMIT_U,
+ .batcap_mon_limit_u = BD71828_REG_BATCAP_MON_LIMIT_U,
+ .conf = BD71828_REG_CONF,
+ .vdcin = BD71828_REG_VDCIN_U,
+};
+
+static const struct pwr_regs pwr_regs_bd71815 = {
+ .vbat_init = BD71815_REG_VM_OCV_PRE_U,
+ .vbat_init2 = BD71815_REG_VM_OCV_PST_U,
+ .used_init_regs = 2,
+ .vbat_avg = BD71815_REG_VM_SA_VBAT_U,
+ /* BD71815 does not have separate current and current avg */
+ .ibat = BD71815_REG_CC_CURCD_U,
+ .ibat_avg = BD71815_REG_CC_CURCD_U,
+
+ .meas_clear = BD71815_REG_VM_SA_MINMAX_CLR,
+ .vsys_min_avg = BD71815_REG_VM_SA_VSYS_MIN_U,
+ .btemp_vth = BD71815_REG_VM_BTMP,
+ .chg_state = BD71815_REG_CHG_STATE,
+ .coulomb3 = BD71815_REG_CC_CCNTD_3,
+ .coulomb2 = BD71815_REG_CC_CCNTD_2,
+ .coulomb1 = BD71815_REG_CC_CCNTD_1,
+ .coulomb0 = BD71815_REG_CC_CCNTD_0,
+ .coulomb_ctrl = BD71815_REG_CC_CTRL,
+ .vbat_rex_avg = BD71815_REG_REX_SA_VBAT_U,
+ .coulomb_full3 = BD71815_REG_FULL_CCNTD_3,
+ .cc_full_clr = BD71815_REG_FULL_CTRL,
+ .coulomb_chg3 = BD71815_REG_CCNTD_CHG_3,
+ .bat_temp = BD71815_REG_BAT_TEMP,
+ .dcin_stat = BD71815_REG_DCIN_STAT,
+ .dcin_collapse_limit = BD71815_REG_DCIN_CLPS,
+ .chg_set1 = BD71815_REG_CHG_SET1,
+ .chg_en = BD71815_REG_CHG_SET1,
+ .vbat_alm_limit_u = BD71815_REG_ALM_VBAT_TH_U,
+ .batcap_mon_limit_u = BD71815_REG_CC_BATCAP1_TH_U,
+ .conf = BD71815_REG_CONF,
+
+ .vdcin = BD71815_REG_VM_DCIN_U,
+};
+
+struct bd71828_power {
+ struct regmap *regmap;
+ enum rohm_chip_type chip_type;
+ struct device *dev;
+ struct power_supply *ac;
+ struct power_supply *bat;
+
+ const struct pwr_regs *regs;
+ /* Reg val to uA */
+ int curr_factor;
+ int rsens;
+ int (*get_temp)(struct bd71828_power *pwr, int *temp);
+ int (*bat_inserted)(struct bd71828_power *pwr);
+};
+
+static int bd7182x_write16(struct bd71828_power *pwr, int reg, uint16_t val)
+{
+ __be16 tmp;
+
+ tmp = cpu_to_be16(val);
+
+ return regmap_bulk_write(pwr->regmap, reg, &tmp, sizeof(tmp));
+}
+
+static int bd7182x_read16_himask(struct bd71828_power *pwr, int reg, int himask,
+ uint16_t *val)
+{
+ struct regmap *regmap = pwr->regmap;
+ int ret;
+ __be16 rvals;
+ u8 *tmp = (u8 *) &rvals;
+
+ ret = regmap_bulk_read(regmap, reg, &rvals, sizeof(*val));
+ if (!ret) {
+ *tmp &= himask;
+ *val = be16_to_cpu(rvals);
+ }
+ return ret;
+}
+
+static int bd71828_get_vbat(struct bd71828_power *pwr, int *vcell)
+{
+ uint16_t tmp_vcell;
+ int ret;
+
+ ret = bd7182x_read16_himask(pwr, pwr->regs->vbat_avg,
+ BD7182x_MASK_VBAT_U, &tmp_vcell);
+ if (ret)
+ dev_err(pwr->dev, "Failed to read battery average voltage\n");
+ else
+ *vcell = ((int)tmp_vcell) * 1000;
+
+ return ret;
+}
+
+static int bd71828_get_current_ds_adc(struct bd71828_power *pwr, int *curr, int *curr_avg)
+{
+ __be16 tmp_curr;
+ char *tmp = (char *)&tmp_curr;
+ int dir = 1;
+ int regs[] = { pwr->regs->ibat, pwr->regs->ibat_avg };
+ int *vals[] = { curr, curr_avg };
+ int ret, i;
+
+ for (dir = 1, i = 0; i < ARRAY_SIZE(regs); i++) {
+ ret = regmap_bulk_read(pwr->regmap, regs[i], &tmp_curr,
+ sizeof(tmp_curr));
+ if (ret)
+ break;
+
+ if (*tmp & BD7182x_MASK_CURDIR_DISCHG)
+ dir = -1;
+
+ *tmp &= BD7182x_MASK_IBAT_U;
+ tmp_curr = be16_to_cpu(tmp_curr);
+
+ *vals[i] = dir * ((int)tmp_curr) * pwr->curr_factor;
+ }
+
+ return ret;
+}
+
+/* Unit is tenths of degree C */
+static int bd71815_get_temp(struct bd71828_power *pwr, int *temp)
+{
+ struct regmap *regmap = pwr->regmap;
+ int ret;
+ int t;
+
+ ret = regmap_read(regmap, pwr->regs->btemp_vth, &t);
+ t = 200 - t;
+
+ if (ret || t > 200) {
+ dev_err(pwr->dev, "Failed to read battery temperature\n");
+ *temp = 2000;
+ } else {
+ *temp = t * 10;
+ }
+
+ return ret;
+}
+
+/* Unit is tenths of degree C */
+static int bd71828_get_temp(struct bd71828_power *pwr, int *temp)
+{
+ uint16_t t;
+ int ret;
+ int tmp = 200 * 10000;
+
+ ret = bd7182x_read16_himask(pwr, pwr->regs->btemp_vth,
+ BD71828_MASK_VM_BTMP_U, &t);
+ if (ret || t > 3200)
+ dev_err(pwr->dev,
+ "Failed to read system min average voltage\n");
+
+ tmp -= 625ULL * (unsigned int)t;
+ *temp = tmp / 1000;
+
+ return ret;
+}
+
+static int bd71828_charge_status(struct bd71828_power *pwr,
+ int *s, int *h)
+{
+ unsigned int state;
+ int status, health;
+ int ret = 1;
+
+ ret = regmap_read(pwr->regmap, pwr->regs->chg_state, &state);
+ if (ret)
+ dev_err(pwr->dev, "charger status reading failed (%d)\n", ret);
+
+ state &= BD7182x_MASK_CHG_STATE;
+
+ dev_dbg(pwr->dev, "CHG_STATE %d\n", state);
+
+ switch (state) {
+ case 0x00:
+ ret = 0;
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
+ health = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x0E:
+ status = POWER_SUPPLY_STATUS_CHARGING;
+ health = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case 0x0F:
+ ret = 0;
+ status = POWER_SUPPLY_STATUS_FULL;
+ health = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ ret = 0;
+ status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ health = POWER_SUPPLY_HEALTH_OVERHEAT;
+ break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x40:
+ ret = 0;
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
+ health = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case 0x7f:
+ default:
+ ret = 0;
+ status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ health = POWER_SUPPLY_HEALTH_DEAD;
+ break;
+ }
+
+ if (s)
+ *s = status;
+ if (h)
+ *h = health;
+
+ return ret;
+}
+
+static int get_chg_online(struct bd71828_power *pwr, int *chg_online)
+{
+ int r, ret;
+
+ ret = regmap_read(pwr->regmap, pwr->regs->dcin_stat, &r);
+ if (ret) {
+ dev_err(pwr->dev, "Failed to read DCIN status\n");
+ return ret;
+ }
+ *chg_online = ((r & BD7182x_MASK_DCIN_DET) != 0);
+
+ return 0;
+}
+
+static int get_bat_online(struct bd71828_power *pwr, int *bat_online)
+{
+ int r, ret;
+
+#define BAT_OPEN 0x7
+ ret = regmap_read(pwr->regmap, pwr->regs->bat_temp, &r);
+ if (ret) {
+ dev_err(pwr->dev, "Failed to read battery temperature\n");
+ return ret;
+ }
+ *bat_online = ((r & BD7182x_MASK_BAT_TEMP) != BAT_OPEN);
+
+ return 0;
+}
+
+static int bd71828_bat_inserted(struct bd71828_power *pwr)
+{
+ int ret, val;
+
+ ret = regmap_read(pwr->regmap, pwr->regs->conf, &val);
+ if (ret) {
+ dev_err(pwr->dev, "Failed to read CONF register\n");
+ return 0;
+ }
+ ret = val & BD7182x_MASK_CONF_PON;
+
+ if (ret)
+ regmap_update_bits(pwr->regmap, pwr->regs->conf,
+ BD7182x_MASK_CONF_PON, 0);
+
+ return ret;
+}
+
+static int bd71815_bat_inserted(struct bd71828_power *pwr)
+{
+ int ret, val;
+
+ ret = regmap_read(pwr->regmap, pwr->regs->conf, &val);
+ if (ret) {
+ dev_err(pwr->dev, "Failed to read CONF register\n");
+ return ret;
+ }
+
+ ret = !(val & BD71815_MASK_CONF_XSTB);
+ if (ret)
+ regmap_write(pwr->regmap, pwr->regs->conf, val |
+ BD71815_MASK_CONF_XSTB);
+
+ return ret;
+}
+
+static int bd71828_init_hardware(struct bd71828_power *pwr)
+{
+ int ret;
+
+ /* TODO: Collapse limit should come from device-tree ? */
+ ret = regmap_write(pwr->regmap, pwr->regs->dcin_collapse_limit,
+ BD7182x_DCIN_COLLAPSE_DEFAULT);
+ if (ret) {
+ dev_err(pwr->dev, "Failed to write DCIN collapse limit\n");
+ return ret;
+ }
+
+ ret = pwr->bat_inserted(pwr);
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+
+ /* WDT_FST auto set */
+ ret = regmap_update_bits(pwr->regmap, pwr->regs->chg_set1,
+ BD7182x_MASK_WDT_AUTO,
+ BD7182x_MASK_WDT_AUTO);
+ if (ret)
+ return ret;
+
+ ret = bd7182x_write16(pwr, pwr->regs->vbat_alm_limit_u,
+ VBAT_LOW_TH);
+ if (ret)
+ return ret;
+
+ /*
+ * On BD71815 "we mask the power-state" from relax detection.
+ * I am unsure what the impact of the power-state would be if
+ * we didn't - but this is what the vendor driver did - and
+ * that driver has been used in few projects so I just assume
+ * this is needed.
+ */
+ if (pwr->chip_type == ROHM_CHIP_TYPE_BD71815) {
+ ret = regmap_set_bits(pwr->regmap,
+ BD71815_REG_REX_CTRL_1,
+ REX_PMU_STATE_MASK);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int bd71828_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct bd71828_power *pwr = dev_get_drvdata(psy->dev.parent);
+ u32 vot;
+ uint16_t tmp;
+ int online;
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = get_chg_online(pwr, &online);
+ if (!ret)
+ val->intval = online;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ ret = bd7182x_read16_himask(pwr, pwr->regs->vdcin,
+ BD7182x_MASK_VDCIN_U, &tmp);
+ if (ret)
+ return ret;
+
+ vot = tmp;
+ /* 5 milli volt steps */
+ val->intval = 5000 * vot;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bd71828_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct bd71828_power *pwr = dev_get_drvdata(psy->dev.parent);
+ int ret = 0;
+ int status, health, tmp, curr, curr_avg, chg_en;
+
+ if (psp == POWER_SUPPLY_PROP_STATUS || psp == POWER_SUPPLY_PROP_HEALTH
+ || psp == POWER_SUPPLY_PROP_CHARGE_TYPE)
+ ret = bd71828_charge_status(pwr, &status, &health);
+ else if (psp == POWER_SUPPLY_PROP_CURRENT_AVG ||
+ psp == POWER_SUPPLY_PROP_CURRENT_NOW)
+ ret = bd71828_get_current_ds_adc(pwr, &curr, &curr_avg);
+ if (ret)
+ return ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = status;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = health;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ if (status == POWER_SUPPLY_STATUS_CHARGING)
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ else
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ ret = get_bat_online(pwr, &tmp);
+ if (!ret)
+ val->intval = tmp;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ ret = bd71828_get_vbat(pwr, &tmp);
+ val->intval = tmp;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ val->intval = curr_avg;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = curr;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = MAX_CURRENT_DEFAULT;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ ret = pwr->get_temp(pwr, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ ret = regmap_read(pwr->regmap, pwr->regs->chg_en, &chg_en);
+ if (ret)
+ return ret;
+
+ val->intval = (chg_en & BD7182x_MASK_CHG_EN) ?
+ POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO :
+ POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int bd71828_battery_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct bd71828_power *pwr = dev_get_drvdata(psy->dev.parent);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ if (val->intval == POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO)
+ ret = regmap_update_bits(pwr->regmap, pwr->regs->chg_en,
+ BD7182x_MASK_CHG_EN,
+ BD7182x_MASK_CHG_EN);
+ else
+ ret = regmap_update_bits(pwr->regmap, pwr->regs->chg_en,
+ BD7182x_MASK_CHG_EN,
+ 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int bd71828_battery_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+/** @brief ac properties */
+static const enum power_supply_property bd71828_charger_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+static const enum power_supply_property bd71828_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
+};
+
+/** @brief powers supplied by bd71828_ac */
+static char *bd71828_ac_supplied_to[] = {
+ BAT_NAME,
+};
+
+static const struct power_supply_desc bd71828_ac_desc = {
+ .name = AC_NAME,
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = bd71828_charger_props,
+ .num_properties = ARRAY_SIZE(bd71828_charger_props),
+ .get_property = bd71828_charger_get_property,
+};
+
+static const struct power_supply_desc bd71828_bat_desc = {
+ .name = BAT_NAME,
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .charge_behaviours = BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) |
+ BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE),
+ .properties = bd71828_battery_props,
+ .num_properties = ARRAY_SIZE(bd71828_battery_props),
+ .get_property = bd71828_battery_get_property,
+ .set_property = bd71828_battery_set_property,
+ .property_is_writeable = bd71828_battery_property_is_writeable,
+};
+
+#define RSENS_CURR 10000000LLU
+
+#define BD_ISR_NAME(name) \
+bd7181x_##name##_isr
+
+#define BD_ISR_BAT(name, print, run_gauge) \
+static irqreturn_t BD_ISR_NAME(name)(int irq, void *data) \
+{ \
+ struct bd71828_power *pwr = (struct bd71828_power *)data; \
+ \
+ dev_dbg(pwr->dev, "%s\n", print); \
+ power_supply_changed(pwr->bat); \
+ \
+ return IRQ_HANDLED; \
+}
+
+#define BD_ISR_AC(name, print, run_gauge) \
+static irqreturn_t BD_ISR_NAME(name)(int irq, void *data) \
+{ \
+ struct bd71828_power *pwr = (struct bd71828_power *)data; \
+ \
+ power_supply_changed(pwr->ac); \
+ dev_dbg(pwr->dev, "%s\n", print); \
+ power_supply_changed(pwr->bat); \
+ \
+ return IRQ_HANDLED; \
+}
+
+#define BD_ISR_DUMMY(name, print) \
+static irqreturn_t BD_ISR_NAME(name)(int irq, void *data) \
+{ \
+ struct bd71828_power *pwr = (struct bd71828_power *)data; \
+ \
+ dev_dbg(pwr->dev, "%s\n", print); \
+ \
+ return IRQ_HANDLED; \
+}
+
+BD_ISR_BAT(chg_state_changed, "CHG state changed", true)
+/* DCIN voltage changes */
+BD_ISR_AC(dcin_removed, "DCIN removed", true)
+BD_ISR_AC(clps_out, "DCIN voltage back to normal", true)
+BD_ISR_AC(clps_in, "DCIN voltage collapsed", false)
+BD_ISR_AC(dcin_ovp_res, "DCIN voltage normal", true)
+BD_ISR_AC(dcin_ovp_det, "DCIN OVER VOLTAGE", true)
+
+BD_ISR_DUMMY(dcin_mon_det, "DCIN voltage below threshold")
+BD_ISR_DUMMY(dcin_mon_res, "DCIN voltage above threshold")
+
+BD_ISR_DUMMY(vsys_uv_res, "VSYS under-voltage cleared")
+BD_ISR_DUMMY(vsys_uv_det, "VSYS under-voltage")
+BD_ISR_DUMMY(vsys_low_res, "'VSYS low' cleared")
+BD_ISR_DUMMY(vsys_low_det, "VSYS low")
+BD_ISR_DUMMY(vsys_mon_res, "VSYS mon - resumed")
+BD_ISR_DUMMY(vsys_mon_det, "VSYS mon - detected")
+BD_ISR_BAT(chg_wdg_temp, "charger temperature watchdog triggered", true)
+BD_ISR_BAT(chg_wdg, "charging watchdog triggered", true)
+BD_ISR_BAT(bat_removed, "Battery removed", true)
+BD_ISR_BAT(bat_det, "Battery detected", true)
+/* TODO: Verify the meaning of these interrupts */
+BD_ISR_BAT(rechg_det, "Recharging", true)
+BD_ISR_BAT(rechg_res, "Recharge ending", true)
+BD_ISR_DUMMY(temp_transit, "Temperature transition")
+BD_ISR_BAT(therm_rmv, "bd71815-therm-rmv", false)
+BD_ISR_BAT(therm_det, "bd71815-therm-det", true)
+BD_ISR_BAT(bat_dead, "bd71815-bat-dead", false)
+BD_ISR_BAT(bat_short_res, "bd71815-bat-short-res", true)
+BD_ISR_BAT(bat_short, "bd71815-bat-short-det", false)
+BD_ISR_BAT(bat_low_res, "bd71815-bat-low-res", true)
+BD_ISR_BAT(bat_low, "bd71815-bat-low-det", true)
+BD_ISR_BAT(bat_ov_res, "bd71815-bat-over-res", true)
+/* What should we do here? */
+BD_ISR_BAT(bat_ov, "bd71815-bat-over-det", false)
+BD_ISR_BAT(bat_mon_res, "bd71815-bat-mon-res", true)
+BD_ISR_BAT(bat_mon, "bd71815-bat-mon-det", true)
+BD_ISR_BAT(bat_cc_mon, "bd71815-bat-cc-mon2", false)
+BD_ISR_BAT(bat_oc1_res, "bd71815-bat-oc1-res", true)
+BD_ISR_BAT(bat_oc1, "bd71815-bat-oc1-det", false)
+BD_ISR_BAT(bat_oc2_res, "bd71815-bat-oc2-res", true)
+BD_ISR_BAT(bat_oc2, "bd71815-bat-oc2-det", false)
+BD_ISR_BAT(bat_oc3_res, "bd71815-bat-oc3-res", true)
+BD_ISR_BAT(bat_oc3, "bd71815-bat-oc3-det", false)
+BD_ISR_BAT(temp_bat_low_res, "bd71815-temp-bat-low-res", true)
+BD_ISR_BAT(temp_bat_low, "bd71815-temp-bat-low-det", true)
+BD_ISR_BAT(temp_bat_hi_res, "bd71815-temp-bat-hi-res", true)
+BD_ISR_BAT(temp_bat_hi, "bd71815-temp-bat-hi-det", true)
+
+static irqreturn_t bd7182x_dcin_removed(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ power_supply_changed(pwr->ac);
+ dev_dbg(pwr->dev, "DCIN removed\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd718x7_chg_done(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ power_supply_changed(pwr->bat);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd7182x_dcin_detected(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "DCIN inserted\n");
+ power_supply_changed(pwr->ac);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_vbat_low_res(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "VBAT LOW Resumed\n");
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_vbat_low_det(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "VBAT LOW Detected\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_temp_bat_hi_det(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_warn(pwr->dev, "Overtemp Detected\n");
+ power_supply_changed(pwr->bat);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_temp_bat_hi_res(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "Overtemp Resumed\n");
+ power_supply_changed(pwr->bat);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_temp_bat_low_det(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "Lowtemp Detected\n");
+ power_supply_changed(pwr->bat);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_temp_bat_low_res(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "Lowtemp Resumed\n");
+ power_supply_changed(pwr->bat);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_temp_vf_det(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "VF Detected\n");
+ power_supply_changed(pwr->bat);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_temp_vf_res(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "VF Resumed\n");
+ power_supply_changed(pwr->bat);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_temp_vf125_det(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "VF125 Detected\n");
+ power_supply_changed(pwr->bat);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd71828_temp_vf125_res(int irq, void *data)
+{
+ struct bd71828_power *pwr = (struct bd71828_power *)data;
+
+ dev_dbg(pwr->dev, "VF125 Resumed\n");
+ power_supply_changed(pwr->bat);
+
+ return IRQ_HANDLED;
+}
+
+struct bd7182x_irq_res {
+ const char *name;
+ irq_handler_t handler;
+};
+
+#define BDIRQ(na, hn) { .name = (na), .handler = (hn) }
+
+static int bd7182x_get_irqs(struct platform_device *pdev,
+ struct bd71828_power *pwr)
+{
+ int i, irq, ret;
+ static const struct bd7182x_irq_res bd71815_irqs[] = {
+ BDIRQ("bd71815-dcin-rmv", BD_ISR_NAME(dcin_removed)),
+ BDIRQ("bd71815-dcin-clps-out", BD_ISR_NAME(clps_out)),
+ BDIRQ("bd71815-dcin-clps-in", BD_ISR_NAME(clps_in)),
+ BDIRQ("bd71815-dcin-ovp-res", BD_ISR_NAME(dcin_ovp_res)),
+ BDIRQ("bd71815-dcin-ovp-det", BD_ISR_NAME(dcin_ovp_det)),
+ BDIRQ("bd71815-dcin-mon-res", BD_ISR_NAME(dcin_mon_res)),
+ BDIRQ("bd71815-dcin-mon-det", BD_ISR_NAME(dcin_mon_det)),
+
+ BDIRQ("bd71815-vsys-uv-res", BD_ISR_NAME(vsys_uv_res)),
+ BDIRQ("bd71815-vsys-uv-det", BD_ISR_NAME(vsys_uv_det)),
+ BDIRQ("bd71815-vsys-low-res", BD_ISR_NAME(vsys_low_res)),
+ BDIRQ("bd71815-vsys-low-det", BD_ISR_NAME(vsys_low_det)),
+ BDIRQ("bd71815-vsys-mon-res", BD_ISR_NAME(vsys_mon_res)),
+ BDIRQ("bd71815-vsys-mon-det", BD_ISR_NAME(vsys_mon_det)),
+ BDIRQ("bd71815-chg-wdg-temp", BD_ISR_NAME(chg_wdg_temp)),
+ BDIRQ("bd71815-chg-wdg", BD_ISR_NAME(chg_wdg)),
+ BDIRQ("bd71815-rechg-det", BD_ISR_NAME(rechg_det)),
+ BDIRQ("bd71815-rechg-res", BD_ISR_NAME(rechg_res)),
+ BDIRQ("bd71815-ranged-temp-transit", BD_ISR_NAME(temp_transit)),
+ BDIRQ("bd71815-chg-state-change", BD_ISR_NAME(chg_state_changed)),
+ BDIRQ("bd71815-bat-temp-normal", bd71828_temp_bat_hi_res),
+ BDIRQ("bd71815-bat-temp-erange", bd71828_temp_bat_hi_det),
+ BDIRQ("bd71815-bat-rmv", BD_ISR_NAME(bat_removed)),
+ BDIRQ("bd71815-bat-det", BD_ISR_NAME(bat_det)),
+
+ /* Add ISRs for these */
+ BDIRQ("bd71815-therm-rmv", BD_ISR_NAME(therm_rmv)),
+ BDIRQ("bd71815-therm-det", BD_ISR_NAME(therm_det)),
+ BDIRQ("bd71815-bat-dead", BD_ISR_NAME(bat_dead)),
+ BDIRQ("bd71815-bat-short-res", BD_ISR_NAME(bat_short_res)),
+ BDIRQ("bd71815-bat-short-det", BD_ISR_NAME(bat_short)),
+ BDIRQ("bd71815-bat-low-res", BD_ISR_NAME(bat_low_res)),
+ BDIRQ("bd71815-bat-low-det", BD_ISR_NAME(bat_low)),
+ BDIRQ("bd71815-bat-over-res", BD_ISR_NAME(bat_ov_res)),
+ BDIRQ("bd71815-bat-over-det", BD_ISR_NAME(bat_ov)),
+ BDIRQ("bd71815-bat-mon-res", BD_ISR_NAME(bat_mon_res)),
+ BDIRQ("bd71815-bat-mon-det", BD_ISR_NAME(bat_mon)),
+ /* cc-mon 1 & 3 ? */
+ BDIRQ("bd71815-bat-cc-mon2", BD_ISR_NAME(bat_cc_mon)),
+ BDIRQ("bd71815-bat-oc1-res", BD_ISR_NAME(bat_oc1_res)),
+ BDIRQ("bd71815-bat-oc1-det", BD_ISR_NAME(bat_oc1)),
+ BDIRQ("bd71815-bat-oc2-res", BD_ISR_NAME(bat_oc2_res)),
+ BDIRQ("bd71815-bat-oc2-det", BD_ISR_NAME(bat_oc2)),
+ BDIRQ("bd71815-bat-oc3-res", BD_ISR_NAME(bat_oc3_res)),
+ BDIRQ("bd71815-bat-oc3-det", BD_ISR_NAME(bat_oc3)),
+ BDIRQ("bd71815-temp-bat-low-res", BD_ISR_NAME(temp_bat_low_res)),
+ BDIRQ("bd71815-temp-bat-low-det", BD_ISR_NAME(temp_bat_low)),
+ BDIRQ("bd71815-temp-bat-hi-res", BD_ISR_NAME(temp_bat_hi_res)),
+ BDIRQ("bd71815-temp-bat-hi-det", BD_ISR_NAME(temp_bat_hi)),
+ /*
+ * TODO: add rest of the IRQs and re-check the handling.
+ * Check the bd71815-bat-cc-mon1, bd71815-bat-cc-mon3,
+ * bd71815-bat-low-res, bd71815-bat-low-det,
+ * bd71815-bat-hi-res, bd71815-bat-hi-det.
+ */
+ };
+ static const struct bd7182x_irq_res bd71828_irqs[] = {
+ BDIRQ("bd71828-chg-done", bd718x7_chg_done),
+ BDIRQ("bd71828-pwr-dcin-in", bd7182x_dcin_detected),
+ BDIRQ("bd71828-pwr-dcin-out", bd7182x_dcin_removed),
+ BDIRQ("bd71828-vbat-normal", bd71828_vbat_low_res),
+ BDIRQ("bd71828-vbat-low", bd71828_vbat_low_det),
+ BDIRQ("bd71828-btemp-hi", bd71828_temp_bat_hi_det),
+ BDIRQ("bd71828-btemp-cool", bd71828_temp_bat_hi_res),
+ BDIRQ("bd71828-btemp-lo", bd71828_temp_bat_low_det),
+ BDIRQ("bd71828-btemp-warm", bd71828_temp_bat_low_res),
+ BDIRQ("bd71828-temp-hi", bd71828_temp_vf_det),
+ BDIRQ("bd71828-temp-norm", bd71828_temp_vf_res),
+ BDIRQ("bd71828-temp-125-over", bd71828_temp_vf125_det),
+ BDIRQ("bd71828-temp-125-under", bd71828_temp_vf125_res),
+ };
+ int num_irqs;
+ const struct bd7182x_irq_res *irqs;
+
+
+ switch (pwr->chip_type) {
+ case ROHM_CHIP_TYPE_BD71828:
+ irqs = &bd71828_irqs[0];
+ num_irqs = ARRAY_SIZE(bd71828_irqs);
+ break;
+ case ROHM_CHIP_TYPE_BD71815:
+ irqs = &bd71815_irqs[0];
+ num_irqs = ARRAY_SIZE(bd71815_irqs);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_irqs; i++) {
+ irq = platform_get_irq_byname(pdev, irqs[i].name);
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ irqs[i].handler, 0,
+ irqs[i].name, pwr);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+#define RSENS_DEFAULT_30MOHM 30000 /* 30 mOhm in uOhms*/
+
+static int bd7182x_get_rsens(struct bd71828_power *pwr)
+{
+ u64 tmp = RSENS_CURR;
+ int rsens_ohm = RSENS_DEFAULT_30MOHM;
+ struct fwnode_handle *node = NULL;
+
+ if (pwr->dev->parent)
+ node = dev_fwnode(pwr->dev->parent);
+
+ if (node) {
+ int ret;
+ uint32_t rs;
+
+ ret = fwnode_property_read_u32(node,
+ "rohm,charger-sense-resistor-micro-ohms",
+ &rs);
+ if (ret) {
+ if (ret == -EINVAL) {
+ rs = RSENS_DEFAULT_30MOHM;
+ } else {
+ dev_err(pwr->dev, "Bad RSENS dt property\n");
+ return ret;
+ }
+ }
+ if (!rs) {
+ dev_err(pwr->dev, "Bad RSENS value\n");
+ return -EINVAL;
+ }
+
+ rsens_ohm = (int)rs;
+ }
+
+ /* Reg val to uA */
+ do_div(tmp, rsens_ohm);
+
+ pwr->curr_factor = tmp;
+ pwr->rsens = rsens_ohm;
+ dev_dbg(pwr->dev, "Setting rsens to %u micro ohm\n", pwr->rsens);
+ dev_dbg(pwr->dev, "Setting curr-factor to %u\n", pwr->curr_factor);
+ return 0;
+}
+
+static int bd71828_power_probe(struct platform_device *pdev)
+{
+ struct bd71828_power *pwr;
+ struct power_supply_config ac_cfg = {};
+ struct power_supply_config bat_cfg = {};
+ int ret;
+ struct regmap *regmap;
+
+ regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!regmap) {
+ dev_err(&pdev->dev, "No parent regmap\n");
+ return -EINVAL;
+ }
+
+ pwr = devm_kzalloc(&pdev->dev, sizeof(*pwr), GFP_KERNEL);
+ if (!pwr)
+ return -ENOMEM;
+
+ pwr->regmap = regmap;
+ pwr->dev = &pdev->dev;
+ pwr->chip_type = platform_get_device_id(pdev)->driver_data;
+
+ switch (pwr->chip_type) {
+ case ROHM_CHIP_TYPE_BD71828:
+ pwr->bat_inserted = bd71828_bat_inserted;
+ pwr->get_temp = bd71828_get_temp;
+ pwr->regs = &pwr_regs_bd71828;
+ dev_dbg(pwr->dev, "Found ROHM BD71828\n");
+ break;
+ case ROHM_CHIP_TYPE_BD71815:
+ pwr->bat_inserted = bd71815_bat_inserted;
+ pwr->get_temp = bd71815_get_temp;
+ pwr->regs = &pwr_regs_bd71815;
+ dev_dbg(pwr->dev, "Found ROHM BD71815\n");
+ break;
+ default:
+ dev_err(pwr->dev, "Unknown PMIC\n");
+ return -EINVAL;
+ }
+
+ ret = bd7182x_get_rsens(pwr);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "sense resistor missing\n");
+
+ dev_set_drvdata(&pdev->dev, pwr);
+ bd71828_init_hardware(pwr);
+
+ bat_cfg.drv_data = pwr;
+ bat_cfg.fwnode = dev_fwnode(&pdev->dev);
+
+ ac_cfg.supplied_to = bd71828_ac_supplied_to;
+ ac_cfg.num_supplicants = ARRAY_SIZE(bd71828_ac_supplied_to);
+ ac_cfg.drv_data = pwr;
+
+ pwr->ac = devm_power_supply_register(&pdev->dev, &bd71828_ac_desc,
+ &ac_cfg);
+ if (IS_ERR(pwr->ac)) {
+ return dev_err_probe(&pdev->dev, PTR_ERR(pwr->ac),
+ "failed to register ac\n");
+ }
+
+ pwr->bat = devm_power_supply_register(&pdev->dev, &bd71828_bat_desc,
+ &bat_cfg);
+ if (IS_ERR(pwr->bat)) {
+ return dev_err_probe(&pdev->dev, PTR_ERR(pwr->bat),
+ "failed to register bat\n");
+ }
+
+ ret = bd7182x_get_irqs(pdev, pwr);
+ if (ret) {
+ return dev_err_probe(&pdev->dev, ret, "failed to request IRQs");
+ };
+
+ /* Configure wakeup capable */
+ device_set_wakeup_capable(pwr->dev, 1);
+ device_set_wakeup_enable(pwr->dev, 1);
+
+ return 0;
+}
+
+static const struct platform_device_id bd71828_charger_id[] = {
+ { "bd71815-power", ROHM_CHIP_TYPE_BD71815 },
+ { "bd71828-power", ROHM_CHIP_TYPE_BD71828 },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, bd71828_charger_id);
+
+static struct platform_driver bd71828_power_driver = {
+ .driver = {
+ .name = "bd718xx-power",
+ },
+ .probe = bd71828_power_probe,
+ .id_table = bd71828_charger_id,
+};
+
+module_platform_driver(bd71828_power_driver);
+MODULE_ALIAS("platform:bd718xx-power");
+
+MODULE_AUTHOR("Cong Pham <cpham2403@gmail.com>");
+MODULE_DESCRIPTION("ROHM BD718(15/17/28/78) PMIC Battery Charger driver");
+MODULE_LICENSE("GPL");
--
2.39.5
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-16 19:19 ` [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver Andreas Kemnade
@ 2025-08-17 5:58 ` Krzysztof Kozlowski
2025-08-17 8:11 ` Andreas Kemnade
2025-08-17 21:33 ` kernel test robot
` (2 subsequent siblings)
3 siblings, 1 reply; 19+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-17 5:58 UTC (permalink / raw)
To: Andreas Kemnade, Matti Vaittinen, Lee Jones, Sebastian Reichel
Cc: linux-kernel, linux-pm
On 16/08/2025 21:19, Andreas Kemnade wrote:
> Add charger driver for ROHM BD718(15/28/78) PMIC charger block.
> It is a stripped down version of the driver here:
> https://lore.kernel.org/lkml/dbd97c1b0d715aa35a8b4d79741e433d97c562aa.1637061794.git.matti.vaittinen@fi.rohmeurope.com/
Why are you duplicating the driver? Why original cannot be used?
...
> +
> +#define RSENS_DEFAULT_30MOHM 30000 /* 30 mOhm in uOhms*/
> +
> +static int bd7182x_get_rsens(struct bd71828_power *pwr)
> +{
> + u64 tmp = RSENS_CURR;
> + int rsens_ohm = RSENS_DEFAULT_30MOHM;
> + struct fwnode_handle *node = NULL;
> +
> + if (pwr->dev->parent)
> + node = dev_fwnode(pwr->dev->parent);
> +
> + if (node) {
> + int ret;
> + uint32_t rs;
> +
> + ret = fwnode_property_read_u32(node,
> + "rohm,charger-sense-resistor-micro-ohms",
Hm? Are you writing ACPI or DT driver?
> + &rs);
> + if (ret) {
> + if (ret == -EINVAL) {
> + rs = RSENS_DEFAULT_30MOHM;
> + } else {
> + dev_err(pwr->dev, "Bad RSENS dt property\n");
> + return ret;
> + }
> + }
> + if (!rs) {
> + dev_err(pwr->dev, "Bad RSENS value\n");
> + return -EINVAL;
> + }
> +
> + rsens_ohm = (int)rs;
> + }
> +
> + /* Reg val to uA */
> + do_div(tmp, rsens_ohm);
> +
> + pwr->curr_factor = tmp;
> + pwr->rsens = rsens_ohm;
> + dev_dbg(pwr->dev, "Setting rsens to %u micro ohm\n", pwr->rsens);
> + dev_dbg(pwr->dev, "Setting curr-factor to %u\n", pwr->curr_factor);
> + return 0;
> +}
> +
> +static int bd71828_power_probe(struct platform_device *pdev)
> +{
> + struct bd71828_power *pwr;
> + struct power_supply_config ac_cfg = {};
> + struct power_supply_config bat_cfg = {};
> + int ret;
> + struct regmap *regmap;
> +
> + regmap = dev_get_regmap(pdev->dev.parent, NULL);
> + if (!regmap) {
> + dev_err(&pdev->dev, "No parent regmap\n");
> + return -EINVAL;
> + }
> +
> + pwr = devm_kzalloc(&pdev->dev, sizeof(*pwr), GFP_KERNEL);
> + if (!pwr)
> + return -ENOMEM;
> +
> + pwr->regmap = regmap;
> + pwr->dev = &pdev->dev;
> + pwr->chip_type = platform_get_device_id(pdev)->driver_data;
> +
> + switch (pwr->chip_type) {
> + case ROHM_CHIP_TYPE_BD71828:
> + pwr->bat_inserted = bd71828_bat_inserted;
> + pwr->get_temp = bd71828_get_temp;
> + pwr->regs = &pwr_regs_bd71828;
> + dev_dbg(pwr->dev, "Found ROHM BD71828\n");
This is pretty useless debug. You do not use here autodetection, so
there is no "found" case. It's straightforward bind.
> + break;
> + case ROHM_CHIP_TYPE_BD71815:
> + pwr->bat_inserted = bd71815_bat_inserted;
> + pwr->get_temp = bd71815_get_temp;
> + pwr->regs = &pwr_regs_bd71815;
> + dev_dbg(pwr->dev, "Found ROHM BD71815\n");
Same here, drop.
> + break;
> + default:
> + dev_err(pwr->dev, "Unknown PMIC\n");
> + return -EINVAL;
> + }
> +
> + ret = bd7182x_get_rsens(pwr);
> + if (ret)
> + return dev_err_probe(&pdev->dev, ret, "sense resistor missing\n");
> +
> + dev_set_drvdata(&pdev->dev, pwr);
> + bd71828_init_hardware(pwr);
> +
> + bat_cfg.drv_data = pwr;
> + bat_cfg.fwnode = dev_fwnode(&pdev->dev);
> +
> + ac_cfg.supplied_to = bd71828_ac_supplied_to;
> + ac_cfg.num_supplicants = ARRAY_SIZE(bd71828_ac_supplied_to);
> + ac_cfg.drv_data = pwr;
> +
> + pwr->ac = devm_power_supply_register(&pdev->dev, &bd71828_ac_desc,
> + &ac_cfg);
> + if (IS_ERR(pwr->ac)) {
> + return dev_err_probe(&pdev->dev, PTR_ERR(pwr->ac),
> + "failed to register ac\n");
> + }
> +
> + pwr->bat = devm_power_supply_register(&pdev->dev, &bd71828_bat_desc,
> + &bat_cfg);
> + if (IS_ERR(pwr->bat)) {
> + return dev_err_probe(&pdev->dev, PTR_ERR(pwr->bat),
> + "failed to register bat\n");
> + }
> +
> + ret = bd7182x_get_irqs(pdev, pwr);
> + if (ret) {
Please run scripts/checkpatch.pl on the patches and fix reported
warnings. After that, run also 'scripts/checkpatch.pl --strict' on the
patches and (probably) fix more warnings. Some warnings can be ignored,
especially from --strict run, but the code here looks like it needs a
fix. Feel free to get in touch if the warning is not clear.
Drop {}
This applies to other places as well.
> + return dev_err_probe(&pdev->dev, ret, "failed to request IRQs");
> + };
> +
> + /* Configure wakeup capable */
> + device_set_wakeup_capable(pwr->dev, 1);
> + device_set_wakeup_enable(pwr->dev, 1);
> +
> + return 0;
> +}
> +
> +static const struct platform_device_id bd71828_charger_id[] = {
> + { "bd71815-power", ROHM_CHIP_TYPE_BD71815 },
> + { "bd71828-power", ROHM_CHIP_TYPE_BD71828 },
> + { },
> +};
> +MODULE_DEVICE_TABLE(platform, bd71828_charger_id);
> +
> +static struct platform_driver bd71828_power_driver = {
> + .driver = {
> + .name = "bd718xx-power",
> + },
> + .probe = bd71828_power_probe,
> + .id_table = bd71828_charger_id,
> +};
> +
> +module_platform_driver(bd71828_power_driver);
> +MODULE_ALIAS("platform:bd718xx-power");
Drop module alias, incorrect name anyway and you already have proper
aliases from table.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-17 5:58 ` Krzysztof Kozlowski
@ 2025-08-17 8:11 ` Andreas Kemnade
2025-08-17 8:13 ` Krzysztof Kozlowski
0 siblings, 1 reply; 19+ messages in thread
From: Andreas Kemnade @ 2025-08-17 8:11 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Matti Vaittinen, Lee Jones, Sebastian Reichel, linux-kernel,
linux-pm
Am Sun, 17 Aug 2025 07:58:35 +0200
schrieb Krzysztof Kozlowski <krzk@kernel.org>:
> On 16/08/2025 21:19, Andreas Kemnade wrote:
> > Add charger driver for ROHM BD718(15/28/78) PMIC charger block.
> > It is a stripped down version of the driver here:
> > https://lore.kernel.org/lkml/dbd97c1b0d715aa35a8b4d79741e433d97c562aa.1637061794.git.matti.vaittinen@fi.rohmeurope.com/
>
> Why are you duplicating the driver? Why original cannot be used?
>
>
I am not duplicating the driver. That patch series never went in. I am
stripping it down to let things go in step by step. I have also talked
with Sebastian about this. And he also prefers a step by step approach
to have it more easily reviewed.
I also do not have the infrastructure to test things like capacity
degradation over time. There is non-trivial rebasing work involved, so
I even do not feel confident submitting such at all.
> ...
>
> > +
> > +#define RSENS_DEFAULT_30MOHM 30000 /* 30 mOhm in uOhms*/
> > +
> > +static int bd7182x_get_rsens(struct bd71828_power *pwr)
> > +{
> > + u64 tmp = RSENS_CURR;
> > + int rsens_ohm = RSENS_DEFAULT_30MOHM;
> > + struct fwnode_handle *node = NULL;
> > +
> > + if (pwr->dev->parent)
> > + node = dev_fwnode(pwr->dev->parent);
> > +
> > + if (node) {
> > + int ret;
> > + uint32_t rs;
> > +
> > + ret = fwnode_property_read_u32(node,
> > + "rohm,charger-sense-resistor-micro-ohms",
>
> Hm? Are you writing ACPI or DT driver?
>
I am writing a driver for a platform device which gets information via
dt properties. The property is defined in
Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
[...]
> > + pwr->bat = devm_power_supply_register(&pdev->dev, &bd71828_bat_desc,
> > + &bat_cfg);
> > + if (IS_ERR(pwr->bat)) {
> > + return dev_err_probe(&pdev->dev, PTR_ERR(pwr->bat),
> > + "failed to register bat\n");
> > + }
> > +
> > + ret = bd7182x_get_irqs(pdev, pwr);
> > + if (ret) {
>
> Please run scripts/checkpatch.pl on the patches and fix reported
> warnings. After that, run also 'scripts/checkpatch.pl --strict' on the
> patches and (probably) fix more warnings. Some warnings can be ignored,
> especially from --strict run, but the code here looks like it needs a
> fix. Feel free to get in touch if the warning is not clear.
>
> Drop {}
>
> This applies to other places as well.
>
ok, I have forgotten the --strict. And {} around multiline things do
not trigger anything at my brain, even if it just a single statement.
BTW: Is there any way to mark warnings as handled if they can be
ignored, so that I do not see them in subsequent submissions?
Regards,
Andreas
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-17 8:11 ` Andreas Kemnade
@ 2025-08-17 8:13 ` Krzysztof Kozlowski
2025-08-18 6:34 ` Matti Vaittinen
0 siblings, 1 reply; 19+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-17 8:13 UTC (permalink / raw)
To: Andreas Kemnade
Cc: Matti Vaittinen, Lee Jones, Sebastian Reichel, linux-kernel,
linux-pm
On 17/08/2025 10:11, Andreas Kemnade wrote:
> Am Sun, 17 Aug 2025 07:58:35 +0200
> schrieb Krzysztof Kozlowski <krzk@kernel.org>:
>
>> On 16/08/2025 21:19, Andreas Kemnade wrote:
>>> Add charger driver for ROHM BD718(15/28/78) PMIC charger block.
>>> It is a stripped down version of the driver here:
>>> https://lore.kernel.org/lkml/dbd97c1b0d715aa35a8b4d79741e433d97c562aa.1637061794.git.matti.vaittinen@fi.rohmeurope.com/
>>
>> Why are you duplicating the driver? Why original cannot be used?
>>
>>
> I am not duplicating the driver. That patch series never went in. I am
> stripping it down to let things go in step by step. I have also talked
> with Sebastian about this. And he also prefers a step by step approach
> to have it more easily reviewed.
> I also do not have the infrastructure to test things like capacity
> degradation over time. There is non-trivial rebasing work involved, so
> I even do not feel confident submitting such at all.
OK, but if you refer to other work, then also please explain why this is
stripped down.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-16 19:19 ` [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver Andreas Kemnade
2025-08-17 5:58 ` Krzysztof Kozlowski
@ 2025-08-17 21:33 ` kernel test robot
2025-08-18 10:33 ` Matti Vaittinen
2025-08-19 6:14 ` Dan Carpenter
3 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2025-08-17 21:33 UTC (permalink / raw)
To: Andreas Kemnade, Matti Vaittinen, Matti Vaittinen, Lee Jones,
Sebastian Reichel
Cc: oe-kbuild-all, linux-kernel, linux-pm, Andreas Kemnade
Hi Andreas,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 8f5ae30d69d7543eee0d70083daf4de8fe15d585]
url: https://github.com/intel-lab-lkp/linux/commits/Andreas-Kemnade/mfd-bd71828-bd71815-prepare-for-power-supply-support/20250817-032146
base: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
patch link: https://lore.kernel.org/r/20250816-bd71828-charger-v1-2-71b11bde5c73%40kemnade.info
patch subject: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
config: m68k-randconfig-r111-20250818 (https://download.01.org/0day-ci/archive/20250818/202508180501.24kGNF9b-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 12.5.0
reproduce: (https://download.01.org/0day-ci/archive/20250818/202508180501.24kGNF9b-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508180501.24kGNF9b-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/power/supply/bd71828-power.c:257:26: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __be16 [addressable] [usertype] tmp_curr @@ got unsigned short [usertype] @@
drivers/power/supply/bd71828-power.c:257:26: sparse: expected restricted __be16 [addressable] [usertype] tmp_curr
drivers/power/supply/bd71828-power.c:257:26: sparse: got unsigned short [usertype]
>> drivers/power/supply/bd71828-power.c:259:36: sparse: sparse: cast from restricted __be16
vim +257 drivers/power/supply/bd71828-power.c
237
238 static int bd71828_get_current_ds_adc(struct bd71828_power *pwr, int *curr, int *curr_avg)
239 {
240 __be16 tmp_curr;
241 char *tmp = (char *)&tmp_curr;
242 int dir = 1;
243 int regs[] = { pwr->regs->ibat, pwr->regs->ibat_avg };
244 int *vals[] = { curr, curr_avg };
245 int ret, i;
246
247 for (dir = 1, i = 0; i < ARRAY_SIZE(regs); i++) {
248 ret = regmap_bulk_read(pwr->regmap, regs[i], &tmp_curr,
249 sizeof(tmp_curr));
250 if (ret)
251 break;
252
253 if (*tmp & BD7182x_MASK_CURDIR_DISCHG)
254 dir = -1;
255
256 *tmp &= BD7182x_MASK_IBAT_U;
> 257 tmp_curr = be16_to_cpu(tmp_curr);
258
> 259 *vals[i] = dir * ((int)tmp_curr) * pwr->curr_factor;
260 }
261
262 return ret;
263 }
264
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] mfd: bd71828, bd71815 prepare for power-supply support
2025-08-16 19:19 ` [PATCH 1/2] mfd: bd71828, bd71815 prepare for power-supply support Andreas Kemnade,,,
@ 2025-08-18 5:49 ` Matti Vaittinen
2025-08-18 6:44 ` Andreas Kemnade
0 siblings, 1 reply; 19+ messages in thread
From: Matti Vaittinen @ 2025-08-18 5:49 UTC (permalink / raw)
To: Andreas Kemnade,,,, Lee Jones, Sebastian Reichel; +Cc: linux-kernel, linux-pm
Thanks a ton for picking up from where I left it Andreas! :) I _really_
do love seeing this proceeding. This has haunted me and I actually still
have a JIRA item pending for this work - although that's one of those
items which might never get done - I just couldn't delete it after
putting quite bit of effort to this :(
I hope that effort benefits someone!
Just one comment:
On 16/08/2025 22:19, Andreas Kemnade,,, wrote:
> From: Matti Vaittinen <mazziesaccount@gmail.com>
>
> Add core support for ROHM BD718(15/28/78) PMIC's charger blocks.
>
> Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
> Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
> ---
> drivers/mfd/rohm-bd71828.c | 44 +++++++++++++++++++++------
> include/linux/mfd/rohm-bd71828.h | 65 ++++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/rohm-generic.h | 2 ++
> 3 files changed, 102 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c
> index a14b7aa69c3c61d51f2aeeae9afdf222310d63e3..84a64c3b9c9f52e663855c89ed78ede9a7c21f55 100644
> --- a/drivers/mfd/rohm-bd71828.c
> +++ b/drivers/mfd/rohm-bd71828.c
> @@ -45,8 +45,8 @@ static const struct resource bd71828_rtc_irqs[] = {
>
> static const struct resource bd71815_power_irqs[] = {
> DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"),
> - DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-clps-out"),
> - DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in"),
> + DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-dcin-clps-out"),
> + DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-dcin-clps-in"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res"),
> @@ -56,7 +56,7 @@ static const struct resource bd71815_power_irqs[] = {
> DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res"),
> - DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det"),
> + DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_DET, "bd71815-vsys-mon-det"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res"),
> @@ -87,10 +87,10 @@ static const struct resource bd71815_power_irqs[] = {
> DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_DET, "bd71815-bat-oc2-det"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_RES, "bd71815-bat-oc3-res"),
> DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_DET, "bd71815-bat-oc3-det"),
> - DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-bat-low-res"),
> - DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-bat-low-det"),
> - DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-bat-hi-res"),
> - DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-bat-hi-det"),
> + DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-temp-bat-low-res"),
> + DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-temp-bat-low-det"),
> + DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-temp-bat-hi-res"),
> + DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-temp-bat-hi-det"),
> };
>
> static const struct mfd_cell bd71815_mfd_cells[] = {
> @@ -109,7 +109,30 @@ static const struct mfd_cell bd71815_mfd_cells[] = {
> },
> };
>
> -static const struct mfd_cell bd71828_mfd_cells[] = {
> +static const struct resource bd71828_power_irqs[] = {
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_CHG_TOPOFF_TO_DONE,
> + "bd71828-chg-done"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_DCIN_DET, "bd71828-pwr-dcin-in"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_DCIN_RMV, "bd71828-pwr-dcin-out"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_BAT_LOW_VOLT_RES,
> + "bd71828-vbat-normal"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_BAT_LOW_VOLT_DET, "bd71828-vbat-low"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_BAT_HI_DET, "bd71828-btemp-hi"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_BAT_HI_RES, "bd71828-btemp-cool"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_BAT_LOW_DET, "bd71828-btemp-lo"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_BAT_LOW_RES,
> + "bd71828-btemp-warm"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_CHIP_OVER_VF_DET,
> + "bd71828-temp-hi"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_CHIP_OVER_VF_RES,
> + "bd71828-temp-norm"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_CHIP_OVER_125_DET,
> + "bd71828-temp-125-over"),
> + DEFINE_RES_IRQ_NAMED(BD71828_INT_TEMP_CHIP_OVER_125_RES,
> + "bd71828-temp-125-under"),
> +};
> +
> +static struct mfd_cell bd71828_mfd_cells[] = {
> { .name = "bd71828-pmic", },
> { .name = "bd71828-gpio", },
> { .name = "bd71828-led", .of_compatible = "rohm,bd71828-leds" },
> @@ -118,8 +141,11 @@ static const struct mfd_cell bd71828_mfd_cells[] = {
> * BD70528 clock gate are the register address and mask.
> */
> { .name = "bd71828-clk", },
> - { .name = "bd71827-power", },
> {
> + .name = "bd71828-power",
> + .resources = bd71828_power_irqs,
> + .num_resources = ARRAY_SIZE(bd71828_power_irqs),
> + }, {
> .name = "bd71828-rtc",
> .resources = bd71828_rtc_irqs,
> .num_resources = ARRAY_SIZE(bd71828_rtc_irqs),
> diff --git a/include/linux/mfd/rohm-bd71828.h b/include/linux/mfd/rohm-bd71828.h
> index ce786c96404a3dc9d5124ffbbd507df89ca0e5ba..a34991984caa8724e925f1c59de4bcfa543ae411 100644
> --- a/include/linux/mfd/rohm-bd71828.h
> +++ b/include/linux/mfd/rohm-bd71828.h
> @@ -189,6 +189,71 @@ enum {
> /* Charger/Battey */
> #define BD71828_REG_CHG_STATE 0x65
> #define BD71828_REG_CHG_FULL 0xd2
> +#define BD71828_REG_CHG_EN 0x6F
> +#define BD71828_REG_DCIN_STAT 0x68
> +#define BD71828_MASK_DCIN_DET 0x01
> +#define BD71828_REG_VDCIN_U 0x9c
> +#define BD71828_MASK_CHG_EN 0x01
> +#define BD71828_CHG_MASK_DCIN_U 0x0f
> +#define BD71828_REG_BAT_STAT 0x67
> +#define BD71828_REG_BAT_TEMP 0x6c
> +#define BD71828_MASK_BAT_TEMP 0x07
> +#define BD71828_BAT_TEMP_OPEN 0x07
> +#define BD71828_MASK_BAT_DET 0x20
> +#define BD71828_MASK_BAT_DET_DONE 0x10
> +#define BD71828_REG_CHG_STATE 0x65
> +#define BD71828_REG_VBAT_U 0x8c
> +#define BD71828_MASK_VBAT_U 0x0f
> +#define BD71828_REG_VBAT_REX_AVG_U 0x92
> +
> +#define BD71828_REG_OCV_PWRON_U 0x8A
> +
> +#define BD71828_REG_VBAT_MIN_AVG_U 0x8e
> +#define BD71828_REG_VBAT_MIN_AVG_L 0x8f
> +
> +#define BD71828_REG_CC_CNT3 0xb5
> +#define BD71828_REG_CC_CNT2 0xb6
> +#define BD71828_REG_CC_CNT1 0xb7
> +#define BD71828_REG_CC_CNT0 0xb8
> +#define BD71828_REG_CC_CURCD_AVG_U 0xb2
> +#define BD71828_MASK_CC_CURCD_AVG_U 0x3f
> +#define BD71828_MASK_CC_CUR_DIR 0x80
> +#define BD71828_REG_VM_BTMP_U 0xa1
> +#define BD71828_REG_VM_BTMP_L 0xa2
> +#define BD71828_MASK_VM_BTMP_U 0x0f
> +#define BD71828_REG_COULOMB_CTRL 0xc4
> +#define BD71828_REG_COULOMB_CTRL2 0xd2
> +#define BD71828_MASK_REX_CC_CLR 0x01
> +#define BD71828_MASK_FULL_CC_CLR 0x10
> +#define BD71828_REG_CC_CNT_FULL3 0xbd
> +#define BD71828_REG_CC_CNT_CHG3 0xc1
> +
> +#define BD71828_REG_VBAT_INITIAL1_U 0x86
> +#define BD71828_REG_VBAT_INITIAL1_L 0x87
> +
> +#define BD71828_REG_VBAT_INITIAL2_U 0x88
> +#define BD71828_REG_VBAT_INITIAL2_L 0x89
> +
> +#define BD71828_REG_IBAT_U 0xb0
> +#define BD71828_REG_IBAT_L 0xb1
> +
> +#define BD71828_REG_IBAT_AVG_U 0xb2
> +#define BD71828_REG_IBAT_AVG_L 0xb3
> +
> +#define BD71828_REG_VSYS_AVG_U 0x96
> +#define BD71828_REG_VSYS_AVG_L 0x97
> +#define BD71828_REG_VSYS_MIN_AVG_U 0x98
> +#define BD71828_REG_VSYS_MIN_AVG_L 0x99
> +#define BD71828_REG_CHG_SET1 0x75
> +#define BD71828_REG_ALM_VBAT_LIMIT_U 0xaa
> +#define BD71828_REG_BATCAP_MON_LIMIT_U 0xcc
> +#define BD71828_REG_CONF 0x64
> +
> +#define BD71828_REG_DCIN_CLPS 0x71
> +
> +#define BD71828_REG_MEAS_CLEAR 0xaf
> +
> +
>
> /* LEDs */
> #define BD71828_REG_LED_CTRL 0x4A
> diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h
> index 579e8dcfcca41d2680283819684a1014617d0d4b..5e9d0da380ec0fc3245bee998c791a162a34e3fa 100644
> --- a/include/linux/mfd/rohm-generic.h
> +++ b/include/linux/mfd/rohm-generic.h
> @@ -13,9 +13,11 @@ enum rohm_chip_type {
> ROHM_CHIP_TYPE_BD9574,
> ROHM_CHIP_TYPE_BD9576,
> ROHM_CHIP_TYPE_BD71815,
> + ROHM_CHIP_TYPE_BD71827,
Reading you drop the BD71827 support (which sounds like the right thing
to do) - do we still need this?
> ROHM_CHIP_TYPE_BD71828,
> ROHM_CHIP_TYPE_BD71837,
> ROHM_CHIP_TYPE_BD71847,
> + ROHM_CHIP_TYPE_BD71878,
> ROHM_CHIP_TYPE_BD96801,
> ROHM_CHIP_TYPE_BD96802,
> ROHM_CHIP_TYPE_BD96805,
>
Yours,
-- Matti
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-17 8:13 ` Krzysztof Kozlowski
@ 2025-08-18 6:34 ` Matti Vaittinen
2025-08-18 8:36 ` Andreas Kemnade
0 siblings, 1 reply; 19+ messages in thread
From: Matti Vaittinen @ 2025-08-18 6:34 UTC (permalink / raw)
To: Krzysztof Kozlowski, Andreas Kemnade
Cc: Lee Jones, Sebastian Reichel, linux-kernel, linux-pm
On 17/08/2025 11:13, Krzysztof Kozlowski wrote:
> On 17/08/2025 10:11, Andreas Kemnade wrote:
>> Am Sun, 17 Aug 2025 07:58:35 +0200
>> schrieb Krzysztof Kozlowski <krzk@kernel.org>:
>>
>>> On 16/08/2025 21:19, Andreas Kemnade wrote:
>>>> Add charger driver for ROHM BD718(15/28/78) PMIC charger block.
>>>> It is a stripped down version of the driver here:
>>>> https://lore.kernel.org/lkml/dbd97c1b0d715aa35a8b4d79741e433d97c562aa.1637061794.git.matti.vaittinen@fi.rohmeurope.com/
>>>
>>> Why are you duplicating the driver? Why original cannot be used?
>>>
>>>
>> I am not duplicating the driver. That patch series never went in. I am
>> stripping it down to let things go in step by step. I have also talked
>> with Sebastian about this. And he also prefers a step by step approach
>> to have it more easily reviewed.
>> I also do not have the infrastructure to test things like capacity
>> degradation over time. There is non-trivial rebasing work involved, so
>> I even do not feel confident submitting such at all.
>
>
> OK, but if you refer to other work, then also please explain why this is
> stripped down.
First of all, thanks a ton Andreas for continuing this work which I
never managed to finish!
Battery fuel-gauging with coulomb-counter is hard. I believe we can get
some results with the original RFC code - but it requires quite a bit of
effort. AFAIR, there are (at least) 4 "pain-points".
1. Lack of persistent storage for charging cycles. For proper
fuel-gauging, we would need information about battery aging. The PMIC
has nothing to store the charging cycle counter when power is cut.
That'd require some user-space solution which could store the cycle
information in a persistent storage && tell it to the driver at
start-up. I don't know if there is open-source userspace solution for this.
2. Battery parameters. This is the real problem. In order to make the
fuel-gauging work, the driver needs proper battery information. I wrote
the original driver to be able to retrieve the data from a
static-battery DT node - but I have a feeling the device-vendor using
this PMIC provided battery-info via module parameters. I am not sure if
those parameters can be recovered - and as Andreas said, defining them
is not easy task. By minimum we would need the OCV-tables and some aging
+ temperature degradation effects (or VDR-tables which ROHM uses for
it's zero-correction algorithm - but AFAIR, defining those VDR tables is
not widely known information).
3. ADC offset. The coulomb-counter operates by measuring and integrating
voltage-drop over known Rsense resistor. If (when) the ADC has some
measurement offset, it will produce a systematic error which accumulates
over time. Hence a calibration is required. The BD718[15/28] have an ADC
calibration routine, but AFAIR, there was some limitations. I don't
remember all the dirty details, but it probably didn't work too well if
current consumption was varying during the calibration(?). I think
running the calibration is not supported by the driver.
4. Maintaining all this. The fuel-gauging is maths which uses quite a
few of battery parameters. Pinpointing an error from parameters,
algorithm(s) or hardware is far from trivial because errors can specific
to the very battery/system they were detected at.
There are probably more problems (some of which I have forgotten, and
some of which I haven't even hit yet).
TLDR; It'd be hard to do accurate fuel-gauging without proper battery
information and some extra work. We could probably get some rough
estimates about the capacity - but implementing it only makes sense if
there is someone really using it. Charger control on the other hand
makes some sense. [It at least allows Andreas to charge his eReader
using solar-power when on a biking hiking! How cool is that? ;)]
So, dropping fuel-gauge (for now), and upstreaming the rest seems like a
very good approach to me.
Thanks for CC'in me Andreas. I don't have much time to work on this (as
I never do), but please keep me in loop and let me know if I can help...
I can at very least review things :)
Thanks again for working with this!
(Ps. Are you joining ELCE in Amsterdam? It'd be nice to see you there if
you do).
Yours,
-- Matti
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] mfd: bd71828, bd71815 prepare for power-supply support
2025-08-18 5:49 ` Matti Vaittinen
@ 2025-08-18 6:44 ` Andreas Kemnade
0 siblings, 0 replies; 19+ messages in thread
From: Andreas Kemnade @ 2025-08-18 6:44 UTC (permalink / raw)
To: Matti Vaittinen; +Cc: Lee Jones, Sebastian Reichel, linux-kernel, linux-pm
Hi Matti,
Am Mon, 18 Aug 2025 08:49:27 +0300
schrieb Matti Vaittinen <mazziesaccount@gmail.com>:
> > diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h
> > index 579e8dcfcca41d2680283819684a1014617d0d4b..5e9d0da380ec0fc3245bee998c791a162a34e3fa 100644
> > --- a/include/linux/mfd/rohm-generic.h
> > +++ b/include/linux/mfd/rohm-generic.h
> > @@ -13,9 +13,11 @@ enum rohm_chip_type {
> > ROHM_CHIP_TYPE_BD9574,
> > ROHM_CHIP_TYPE_BD9576,
> > ROHM_CHIP_TYPE_BD71815,
> > + ROHM_CHIP_TYPE_BD71827,
>
> Reading you drop the BD71827 support (which sounds like the right thing
> to do) - do we still need this?
we do not. It just flipped through in all that harmless devices.
Regards,
Andreas
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-18 6:34 ` Matti Vaittinen
@ 2025-08-18 8:36 ` Andreas Kemnade
2025-08-18 9:32 ` Matti Vaittinen
2025-08-18 10:09 ` Matti Vaittinen
0 siblings, 2 replies; 19+ messages in thread
From: Andreas Kemnade @ 2025-08-18 8:36 UTC (permalink / raw)
To: Matti Vaittinen
Cc: Krzysztof Kozlowski, Lee Jones, Sebastian Reichel, linux-kernel,
linux-pm
Hi Matti,
Am Mon, 18 Aug 2025 09:34:02 +0300
schrieb Matti Vaittinen <mazziesaccount@gmail.com>:
> On 17/08/2025 11:13, Krzysztof Kozlowski wrote:
> > On 17/08/2025 10:11, Andreas Kemnade wrote:
> >> Am Sun, 17 Aug 2025 07:58:35 +0200
> >> schrieb Krzysztof Kozlowski <krzk@kernel.org>:
> >>
> >>> On 16/08/2025 21:19, Andreas Kemnade wrote:
> >>>> Add charger driver for ROHM BD718(15/28/78) PMIC charger block.
> >>>> It is a stripped down version of the driver here:
> >>>> https://lore.kernel.org/lkml/dbd97c1b0d715aa35a8b4d79741e433d97c562aa.1637061794.git.matti.vaittinen@fi.rohmeurope.com/
> >>>
> >>> Why are you duplicating the driver? Why original cannot be used?
> >>>
> >>>
> >> I am not duplicating the driver. That patch series never went in. I am
> >> stripping it down to let things go in step by step. I have also talked
> >> with Sebastian about this. And he also prefers a step by step approach
> >> to have it more easily reviewed.
> >> I also do not have the infrastructure to test things like capacity
> >> degradation over time. There is non-trivial rebasing work involved, so
> >> I even do not feel confident submitting such at all.
> >
> >
> > OK, but if you refer to other work, then also please explain why this is
> > stripped down.
>
> First of all, thanks a ton Andreas for continuing this work which I
> never managed to finish!
>
> Battery fuel-gauging with coulomb-counter is hard. I believe we can get
> some results with the original RFC code - but it requires quite a bit of
> effort. AFAIR, there are (at least) 4 "pain-points".
>
Newest rebase I have is for 6.15. Yes, capacity calculation is hard.
Even the ugly-patched Kobo vendor driver has some surprises. It once
says battery is empty, then I put in charger, rebooted into debian,
Vbat = 4.1V even with charger detached.
I think the fuel-gauging stuff itself should go in a step by step
approach. I am wondering how sophisticated other drivers and hardware
are.
The rn5t618/rc5t619 mainline driver just uses raw coloumb counter
values and there is no compensation for anything. Some hardware does
more sophisticated things itself.
> 1. Lack of persistent storage for charging cycles. For proper
> fuel-gauging, we would need information about battery aging. The PMIC
> has nothing to store the charging cycle counter when power is cut.
> That'd require some user-space solution which could store the cycle
> information in a persistent storage && tell it to the driver at
> start-up. I don't know if there is open-source userspace solution for this.
>
I do not think so, and you will have trouble if you have dual-boot or
from some alternative boot media involved. The BQ27000 stuff has afaik
hw calculation of battery capacity to deal with this.
> 2. Battery parameters. This is the real problem. In order to make the
> fuel-gauging work, the driver needs proper battery information. I wrote
> the original driver to be able to retrieve the data from a
> static-battery DT node - but I have a feeling the device-vendor using
> this PMIC provided battery-info via module parameters. I am not sure if
> those parameters can be recovered - and as Andreas said, defining them
> is not easy task. By minimum we would need the OCV-tables and some aging
> + temperature degradation effects (or VDR-tables which ROHM uses for
> it's zero-correction algorithm - but AFAIR, defining those VDR tables is
> not widely known information).
>
Kobo kernels have these tables as part of the driver, the right one is
selected via an index in the NTX_HWCONFIG blob provided by the
bootloader to the kernel. So that is not necessarily a problem. It
could be translated into dt.
static int ocv_table_28_PR284983N[23] = {
//4200000, 4162288, 4110762, 4066502, 4025265, 3988454, 3955695, 3926323, 3900244, 3876035, 3834038, 3809386, 3794093, 3782718, 3774483, 3768044, 3748158, 3728750, 3704388, 3675577, 3650676, 3463852, 2768530
4200000, 4166349, 4114949, 4072016, 4031575, 3995353, 3963956, 3935650, 3910161, 3883395, 3845310, 3817535, 3801354, 3789708, 3781393, 3774994, 3765230, 3749035, 3726707, 3699147, 3671953, 3607301, 3148394
};
static int vdr_table_h_28_PR284983N[23] = {
//100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108, 108, 109, 110, 112, 124, 157, 786
100, 100, 101, 102, 102, 105, 106, 107, 112, 108, 108, 105, 105, 108, 110, 110, 110, 111, 112, 114, 120, 131, 620
};
static int vdr_table_m_28_PR284983N[23] = {
//100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 102, 100, 100, 102, 103, 103, 105, 108, 112, 124, 157, 586
100, 100, 103, 106, 110, 114, 115, 119, 122, 122, 115, 113, 112, 114, 117, 124, 126, 123, 122, 126, 140, 156, 558
};
static int vdr_table_l_28_PR284983N[23] = {
//100, 100, 103, 105, 110, 110, 113, 112, 112, 112, 105, 110, 110, 111, 122, 131, 138, 143, 150, 166, 242, 354, 357
100, 100, 105, 110, 114, 117, 121, 125, 126, 122, 116, 114, 115, 118, 124, 132, 140, 148, 156, 170, 210, 355, 579
};
static int vdr_table_vl_28_PR284983N[23] = {
//100, 100, 103, 106, 108, 111, 114, 117, 118, 115, 108, 106, 108, 113, 115, 114, 118, 125, 144, 159, 204, 361, 874
100, 100, 109, 115, 118, 123, 127, 130, 140, 139, 134, 130, 128, 138, 140, 150, 154, 164, 178, 204, 271, 362, 352
};
> 3. ADC offset. The coulomb-counter operates by measuring and integrating
> voltage-drop over known Rsense resistor. If (when) the ADC has some
> measurement offset, it will produce a systematic error which accumulates
> over time. Hence a calibration is required. The BD718[15/28] have an ADC
> calibration routine, but AFAIR, there was some limitations. I don't
> remember all the dirty details, but it probably didn't work too well if
> current consumption was varying during the calibration(?). I think
> running the calibration is not supported by the driver.
>
Yes, that is a pain.
[...]
> TLDR; It'd be hard to do accurate fuel-gauging without proper
battery
> information and some extra work. We could probably get some rough
> estimates about the capacity - but implementing it only makes sense if
> there is someone really using it. Charger control on the other hand
> makes some sense. [It at least allows Andreas to charge his eReader
> using solar-power when on a biking hiking! How cool is that? ;)]
>
And using a hub dynamo.
For now I have a user space script to help me, probably moving that into
input_current_limit.
But it is really nice to see if things are charging or are discharging
unusually fast.
It is a pity that such power sources are not taken into consideration
in standards or charges much. Around 20 year ago or something, I could
just attach a Thinkpad to a solar panel, there was a smooth transition
between discharging a litte (displaying battery discharging time in
weeks) and more ore less charging. Today often the recommendation is to
put somehow another battery in between. But that is technically
somehow nonsense. You need a buffer for power and another one in the
row.
Regards,
Andreas
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-18 8:36 ` Andreas Kemnade
@ 2025-08-18 9:32 ` Matti Vaittinen
2025-08-20 16:05 ` Andreas Kemnade
2025-08-18 10:09 ` Matti Vaittinen
1 sibling, 1 reply; 19+ messages in thread
From: Matti Vaittinen @ 2025-08-18 9:32 UTC (permalink / raw)
To: Andreas Kemnade
Cc: Krzysztof Kozlowski, Lee Jones, Sebastian Reichel, linux-kernel,
linux-pm
On 18/08/2025 11:36, Andreas Kemnade wrote:
> Hi Matti,
>
> Am Mon, 18 Aug 2025 09:34:02 +0300
> schrieb Matti Vaittinen <mazziesaccount@gmail.com>:
>
>> On 17/08/2025 11:13, Krzysztof Kozlowski wrote:
>>> On 17/08/2025 10:11, Andreas Kemnade wrote:
>>>> Am Sun, 17 Aug 2025 07:58:35 +0200
>>>> schrieb Krzysztof Kozlowski <krzk@kernel.org>:
>>>>
>>>>> On 16/08/2025 21:19, Andreas Kemnade wrote:
>>>>>> Add charger driver for ROHM BD718(15/28/78) PMIC charger block.
>>>>>> It is a stripped down version of the driver here:
>>>>>> https://lore.kernel.org/lkml/dbd97c1b0d715aa35a8b4d79741e433d97c562aa.1637061794.git.matti.vaittinen@fi.rohmeurope.com/
>>>>>
>>>>> Why are you duplicating the driver? Why original cannot be used?
>>>>>
>>>>>
>>>> I am not duplicating the driver. That patch series never went in. I am
>>>> stripping it down to let things go in step by step. I have also talked
>>>> with Sebastian about this. And he also prefers a step by step approach
>>>> to have it more easily reviewed.
>>>> I also do not have the infrastructure to test things like capacity
>>>> degradation over time. There is non-trivial rebasing work involved, so
>>>> I even do not feel confident submitting such at all.
>>>
>>>
>>> OK, but if you refer to other work, then also please explain why this is
>>> stripped down.
>>
>> First of all, thanks a ton Andreas for continuing this work which I
>> never managed to finish!
>>
>> Battery fuel-gauging with coulomb-counter is hard. I believe we can get
>> some results with the original RFC code - but it requires quite a bit of
>> effort. AFAIR, there are (at least) 4 "pain-points".
>>
> Newest rebase I have is for 6.15. Yes, capacity calculation is hard.
> Even the ugly-patched Kobo vendor driver has some surprises. It once
> says battery is empty, then I put in charger, rebooted into debian,
> Vbat = 4.1V even with charger detached.
:/
> I think the fuel-gauging stuff itself should go in a step by step
> approach.
I agree.
> I am wondering how sophisticated other drivers and hardware
> are.
I have no deep knowledge on this (either). I remember having some
(email) discussions with Linus W about Samsung's chargers / batteries...
My understanding is that there are very different levels of
"sophistication", both in HW and in SW. I really find this fascinating.
Unfortunately, there has also been infamous exploding batteries and
other less pleasant events. Hence this is also slightly dangerous area.
> The rn5t618/rc5t619 mainline driver just uses raw coloumb counter
> values and there is no compensation for anything. Some hardware does
> more sophisticated things itself.
Yes.
>> 1. Lack of persistent storage for charging cycles. For proper
>> fuel-gauging, we would need information about battery aging. The PMIC
>> has nothing to store the charging cycle counter when power is cut.
>> That'd require some user-space solution which could store the cycle
>> information in a persistent storage && tell it to the driver at
>> start-up. I don't know if there is open-source userspace solution for this.
>>
> I do not think so, and you will have trouble if you have dual-boot or
> from some alternative boot media involved.
I didn't even think about it. So, even with persistent PMIC areas, if
software is doing the charging count book-keeping, it won't be great for
a generic design. (May work Ok with an embedded device which is likely
to not get booted with other flavours of software).
> The BQ27000 stuff has afaik
> hw calculation of battery capacity to deal with this.
>
>> 2. Battery parameters. This is the real problem. In order to make the
>> fuel-gauging work, the driver needs proper battery information. I wrote
>> the original driver to be able to retrieve the data from a
>> static-battery DT node - but I have a feeling the device-vendor using
>> this PMIC provided battery-info via module parameters. I am not sure if
>> those parameters can be recovered - and as Andreas said, defining them
>> is not easy task. By minimum we would need the OCV-tables and some aging
>> + temperature degradation effects (or VDR-tables which ROHM uses for
>> it's zero-correction algorithm - but AFAIR, defining those VDR tables is
>> not widely known information).
>>
> Kobo kernels have these tables as part of the driver, the right one is
> selected via an index in the NTX_HWCONFIG blob provided by the
> bootloader to the kernel. So that is not necessarily a problem. It
> could be translated into dt.
>
> static int ocv_table_28_PR284983N[23] = {
> //4200000, 4162288, 4110762, 4066502, 4025265, 3988454, 3955695, 3926323, 3900244, 3876035, 3834038, 3809386, 3794093, 3782718, 3774483, 3768044, 3748158, 3728750, 3704388, 3675577, 3650676, 3463852, 2768530
> 4200000, 4166349, 4114949, 4072016, 4031575, 3995353, 3963956, 3935650, 3910161, 3883395, 3845310, 3817535, 3801354, 3789708, 3781393, 3774994, 3765230, 3749035, 3726707, 3699147, 3671953, 3607301, 3148394
> };
>
> static int vdr_table_h_28_PR284983N[23] = {
> //100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108, 108, 109, 110, 112, 124, 157, 786
> 100, 100, 101, 102, 102, 105, 106, 107, 112, 108, 108, 105, 105, 108, 110, 110, 110, 111, 112, 114, 120, 131, 620
> };
>
> static int vdr_table_m_28_PR284983N[23] = {
> //100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 102, 100, 100, 102, 103, 103, 105, 108, 112, 124, 157, 586
> 100, 100, 103, 106, 110, 114, 115, 119, 122, 122, 115, 113, 112, 114, 117, 124, 126, 123, 122, 126, 140, 156, 558
> };
>
> static int vdr_table_l_28_PR284983N[23] = {
> //100, 100, 103, 105, 110, 110, 113, 112, 112, 112, 105, 110, 110, 111, 122, 131, 138, 143, 150, 166, 242, 354, 357
> 100, 100, 105, 110, 114, 117, 121, 125, 126, 122, 116, 114, 115, 118, 124, 132, 140, 148, 156, 170, 210, 355, 579
> };
>
> static int vdr_table_vl_28_PR284983N[23] = {
> //100, 100, 103, 106, 108, 111, 114, 117, 118, 115, 108, 106, 108, 113, 115, 114, 118, 125, 144, 159, 204, 361, 874
> 100, 100, 109, 115, 118, 123, 127, 130, 140, 139, 134, 130, 128, 138, 140, 150, 154, 164, 178, 204, 271, 362, 352
> };
Oh, good. If we can get the right battery parameters from the vendor
driver, then the main problem gets solved. Although, multiple sets of
different VDR tables probably means, that there are variants with
different types of battery out there. I assume the bootloader can
somehow detect the battery type to provide the correct blob?
>
>> 3. ADC offset. The coulomb-counter operates by measuring and integrating
>> voltage-drop over known Rsense resistor. If (when) the ADC has some
>> measurement offset, it will produce a systematic error which accumulates
>> over time. Hence a calibration is required. The BD718[15/28] have an ADC
>> calibration routine, but AFAIR, there was some limitations. I don't
>> remember all the dirty details, but it probably didn't work too well if
>> current consumption was varying during the calibration(?). I think
>> running the calibration is not supported by the driver.
>>
> Yes, that is a pain.
I am pretty sure I can dig the registers which initiate the ADC
calibration, but I don't have real devices with real battery to test it.
I can try to find that information if if you wish to experiment with it
though...
...The BD718xx had a magic "test register area" - where this calibration
stuff (amongst other, very hazardous things) resides. Problem is that
this "test register area" is implemented in a way, that it is behind
another I2C slave address, which can be enabled by a magic write
sequence. Enabling it from a generically usable driver can't really be
done. It would be hazardous if there was another device in the I2C with
the same slave address as the "test register area".
> [...]
>> TLDR; It'd be hard to do accurate fuel-gauging without proper
> battery
>> information and some extra work. We could probably get some rough
>> estimates about the capacity - but implementing it only makes sense if
>> there is someone really using it. Charger control on the other hand
>> makes some sense. [It at least allows Andreas to charge his eReader
>> using solar-power when on a biking hiking! How cool is that? ;)]
>>
> And using a hub dynamo.
> For now I have a user space script to help me, probably moving that into
> input_current_limit.
Sounds good to me.
> But it is really nice to see if things are charging or are discharging
> unusually fast.
> It is a pity that such power sources are not taken into consideration
> in standards or charges much. Around 20 year ago or something, I could
> just attach a Thinkpad to a solar panel, there was a smooth transition
> between discharging a litte (displaying battery discharging time in
> weeks) and more ore less charging. Today often the recommendation is to
> put somehow another battery in between. But that is technically
> somehow nonsense. You need a buffer for power and another one in the
> row.
Yours,
-- Matti
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-18 8:36 ` Andreas Kemnade
2025-08-18 9:32 ` Matti Vaittinen
@ 2025-08-18 10:09 ` Matti Vaittinen
1 sibling, 0 replies; 19+ messages in thread
From: Matti Vaittinen @ 2025-08-18 10:09 UTC (permalink / raw)
To: Andreas Kemnade
Cc: Krzysztof Kozlowski, Lee Jones, Sebastian Reichel, linux-kernel,
linux-pm
On 18/08/2025 11:36, Andreas Kemnade wrote:
> Hi Matti,
>
> Am Mon, 18 Aug 2025 09:34:02 +0300
> schrieb Matti Vaittinen <mazziesaccount@gmail.com>:
>
>> On 17/08/2025 11:13, Krzysztof Kozlowski wrote:
>>> On 17/08/2025 10:11, Andreas Kemnade wrote:
>>>> Am Sun, 17 Aug 2025 07:58:35 +0200
>>>> schrieb Krzysztof Kozlowski <krzk@kernel.org>:
>>>>
>>>>> On 16/08/2025 21:19, Andreas Kemnade wrote:
> Newest rebase I have is for 6.15. Yes, capacity calculation is hard.
Just a thing to note. I've drafted some support for another variant, on
top of the v6.6. Just pushed the latest version of that to:
https://github.com/M-Vaittinen/linux/tree/bd72720-on-6.6-rohmpower
It may have something useful for you (or then it doesn't). Following
could perhaps be checked:
8c00ee888283 ("regulator: bd71828: Use platform device id")
0ba48e3a48d4 ("mfd: bd71828: Add IPRE register")
f6caf815fc2f ("power: supply: bd71828: Support setting trickle charge
current")
56197c1819e5 ("dt-bindings: Add trickle-charge upper limit")
af7500d7f278 ("mfd: bd71828: Definition for fast charge term current
register")
98401932fb75 ("mfd: bd71815: Add EXTMOS_EN mask")
e508c94159d8 ("mfd: bd71828: Add charge profile control masks")
e751bf502e29 ("power: supply: bd71828: Support setting charging profiles")
AND
b84792488191 ("power: supply: bd71827-power: Fix pre- and trickle charge
currents")
2f952952cecd ("power: supply: bd71827-charger: Fix print")
These hopefully are already done:
c4fe777755ef ("power: supply: bd71828: Fix Rsense resistor value")
34d9261706b2 ("dt-bindings: mfd: bd71828: Fix sense resistor values")
Rest may be just noise related to this new IC.
Yours,
-- Matti
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-16 19:19 ` [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver Andreas Kemnade
2025-08-17 5:58 ` Krzysztof Kozlowski
2025-08-17 21:33 ` kernel test robot
@ 2025-08-18 10:33 ` Matti Vaittinen
2025-08-18 15:07 ` Andreas Kemnade
2025-08-19 6:14 ` Dan Carpenter
3 siblings, 1 reply; 19+ messages in thread
From: Matti Vaittinen @ 2025-08-18 10:33 UTC (permalink / raw)
To: Andreas Kemnade, Lee Jones, Sebastian Reichel; +Cc: linux-kernel, linux-pm
On 16/08/2025 22:19, Andreas Kemnade wrote:
> Add charger driver for ROHM BD718(15/28/78) PMIC charger block.
> It is a stripped down version of the driver here:
> https://lore.kernel.org/lkml/dbd97c1b0d715aa35a8b4d79741e433d97c562aa.1637061794.git.matti.vaittinen@fi.rohmeurope.com/
>
> For the ease of review and to do a step-by-step approach remove all the
> coloumb counter related stuff and do not sneak in BD71827 support.
>
> Changes besides that:
> Replace the custom property by a standard one and do not use megaohms
> for the current sense resistor.
>
> Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
> ---
> drivers/power/supply/Kconfig | 11 +
> drivers/power/supply/Makefile | 1 +
> drivers/power/supply/bd71828-power.c | 1144 ++++++++++++++++++++++++++++++++++
> 3 files changed, 1156 insertions(+)
>
> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index 79ddb006e2dad6bf96b71ed570a37c006b5f9433..f3429f0aecf5a17fbaa52ee76899657181429a48 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -974,6 +974,17 @@ config CHARGER_UCS1002
> Say Y to enable support for Microchip UCS1002 Programmable
> USB Port Power Controller with Charger Emulation.
>
> +config CHARGER_BD71828
> + tristate "Power-supply driver for ROHM BD71828 and BD71815 PMIC"
> + depends on MFD_ROHM_BD71828
> + select POWER_SIMPLE_GAUGE
> + help
> + Say Y here to enable support for charger, battery and fuel gauge
Maybe drop the fuel-gauge?
> + in ROHM BD71815, BD71817, ROHM BD71828 power management
> + ICs. This driver gets various bits of information about battery
> + and charger states and also implements fuel gauge based on
> + coulomb counters on PMIC.
> +
> config CHARGER_BD99954
> tristate "ROHM bd99954 charger driver"
> depends on I2C
> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
> index f943c9150b326d41ff241f82610f70298635eb08..c6520a11f021c872f01250ae54eb4c63018cd428 100644
> --- a/drivers/power/supply/Makefile
> +++ b/drivers/power/supply/Makefile
> @@ -113,6 +113,7 @@ obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
> obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
> obj-$(CONFIG_FUEL_GAUGE_STC3117) += stc3117_fuel_gauge.o
> obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
> +obj-$(CONFIG_CHARGER_BD71828) += bd71828-power.o
> obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o
> obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
> obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
> diff --git a/drivers/power/supply/bd71828-power.c b/drivers/power/supply/bd71828-power.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..f2686c7eadf0515856d60123f57bca59b33bbd10
> --- /dev/null
> +++ b/drivers/power/supply/bd71828-power.c
> @@ -0,0 +1,1144 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * bd71828-power.c
> + * @file ROHM BD71815, BD71828 and BD71878 Charger driver
> + *
> + * Copyright 2021.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/rohm-bd71815.h>
> +#include <linux/mfd/rohm-bd71828.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +
> +/* common defines */
> +#define BD7182x_MASK_VBAT_U 0x1f
> +#define BD7182x_MASK_VDCIN_U 0x0f
> +#define BD7182x_MASK_IBAT_U 0x3f
> +#define BD7182x_MASK_CURDIR_DISCHG 0x80
> +#define BD7182x_MASK_CC_CCNTD_HI 0x0FFF
> +#define BD7182x_MASK_CC_CCNTD 0x0FFFFFFF
> +#define BD7182x_MASK_CHG_STATE 0x7f
> +#define BD7182x_MASK_CC_FULL_CLR 0x10
> +#define BD7182x_MASK_BAT_TEMP 0x07
> +#define BD7182x_MASK_DCIN_DET BIT(0)
> +#define BD7182x_MASK_CONF_PON BIT(0)
> +#define BD71815_MASK_CONF_XSTB BIT(1)
> +#define BD7182x_MASK_BAT_STAT 0x3f
> +#define BD7182x_MASK_DCIN_STAT 0x07
> +
> +#define BD7182x_MASK_CCNTRST 0x80
> +#define BD7182x_MASK_CCNTENB 0x40
> +#define BD7182x_MASK_CCCALIB 0x20
I suppose unused defines could get cleared. (At least the CC related
ones)...
> +#define BD7182x_MASK_WDT_AUTO 0x40
> +#define BD7182x_MASK_VBAT_ALM_LIMIT_U 0x01
> +#define BD7182x_MASK_CHG_EN 0x01
> +
> +#define BD7182x_DCIN_COLLAPSE_DEFAULT 0x36
> +
> +/* Measured min and max value clear bits */
> +#define BD718XX_MASK_VSYS_MIN_AVG_CLR 0x10
> +
> +#define JITTER_DEFAULT 3000
...Also the loop jitter
> +#define MAX_CURRENT_DEFAULT 890000 /* uA */
> +#define AC_NAME "bd71828_ac"
> +#define BAT_NAME "bd71828_bat"
> +
> +/*
> + * VBAT Low voltage detection Threshold
> + * 0x00D4*16mV = 212*0.016 = 3.392v
> + */
> +#define VBAT_LOW_TH 0x00D4
> +
> +#define THR_RELAX_CURRENT_DEFAULT 5 /* mA */
> +#define THR_RELAX_TIME_DEFAULT (60 * 60) /* sec. */
> +
> +#define DGRD_CYC_CAP_DEFAULT 88 /* 1 micro Ah */
> +
> +#define DGRD_TEMP_H_DEFAULT 450 /* 0.1 degrees C */
> +#define DGRD_TEMP_M_DEFAULT 250 /* 0.1 degrees C */
> +#define DGRD_TEMP_L_DEFAULT 50 /* 0.1 degrees C */
> +#define DGRD_TEMP_VL_DEFAULT 0 /* 0.1 degrees C */
> +
> +#define SOC_EST_MAX_NUM_DEFAULT 5
> +#define PWRCTRL_NORMAL 0x22
> +#define PWRCTRL_RESET 0x23
> +
> +/*
> + * Originally we relied upon a fixed size table of OCV and VDR params.
> + * However the exising linux power-supply batinfo interface for getting the OCV
> + * values from DT does not have fixed amount of OCV values. Thus we use fixed
> + * parameter amount only for values provided as module params - and use this
> + * only as maximum number of parameters when values come from DT.
> + */
> +#define NUM_BAT_PARAMS 23
> +#define MAX_NUM_VDR_VALUES NUM_BAT_PARAMS
> +
> +struct pwr_regs {
> + int used_init_regs;
> + u8 vbat_init;
> + u8 vbat_init2;
> + u8 vbat_init3;
> + u8 vbat_avg;
> + u8 ibat;
> + u8 ibat_avg;
> + u8 meas_clear;
> + u8 vsys_min_avg;
> + u8 btemp_vth;
> + u8 chg_state;
> + u8 coulomb3;
> + u8 coulomb2;
> + u8 coulomb1;
> + u8 coulomb0;
> + u8 coulomb_ctrl;
> + u8 vbat_rex_avg;
> + u8 coulomb_full3;
> + u8 cc_full_clr;
> + u8 coulomb_chg3;
The coulomb counter and vbat_rex related entries could be dropped as
they're now unused. Actually, dropping all unused members would simplify
this quite a bit.
> + u8 bat_temp;
> + u8 dcin_stat;
> + u8 dcin_collapse_limit;
> + u8 chg_set1;
> + u8 chg_en;
> + u8 vbat_alm_limit_u;
> + u8 batcap_mon_limit_u;
> + u8 conf;
> + u8 vdcin;
> +};
> +
...
> +
> +static int bd71828_battery_set_property(struct power_supply *psy,
> + enum power_supply_property psp,
> + const union power_supply_propval *val)
> +{
> + struct bd71828_power *pwr = dev_get_drvdata(psy->dev.parent);
> + int ret = 0;
> +
> + switch (psp) {
> + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
> + if (val->intval == POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO)
> + ret = regmap_update_bits(pwr->regmap, pwr->regs->chg_en,
> + BD7182x_MASK_CHG_EN,
> + BD7182x_MASK_CHG_EN);
> + else
> + ret = regmap_update_bits(pwr->regmap, pwr->regs->chg_en,
> + BD7182x_MASK_CHG_EN,
> + 0);
Nice! I didn't know about the POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO.
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return ret;
> +}
> +
...
> +
> +static int bd71828_power_probe(struct platform_device *pdev)
> +{
> + struct bd71828_power *pwr;
> + struct power_supply_config ac_cfg = {};
> + struct power_supply_config bat_cfg = {};
> + int ret;
> + struct regmap *regmap;
> +
> + regmap = dev_get_regmap(pdev->dev.parent, NULL);
> + if (!regmap) {
> + dev_err(&pdev->dev, "No parent regmap\n");
> + return -EINVAL;
> + }
> +
> + pwr = devm_kzalloc(&pdev->dev, sizeof(*pwr), GFP_KERNEL);
> + if (!pwr)
> + return -ENOMEM;
> +
> + pwr->regmap = regmap;
> + pwr->dev = &pdev->dev;
> + pwr->chip_type = platform_get_device_id(pdev)->driver_data;
> +
> + switch (pwr->chip_type) {
> + case ROHM_CHIP_TYPE_BD71828:
> + pwr->bat_inserted = bd71828_bat_inserted;
> + pwr->get_temp = bd71828_get_temp;
> + pwr->regs = &pwr_regs_bd71828;
> + dev_dbg(pwr->dev, "Found ROHM BD71828\n");
> + break;
> + case ROHM_CHIP_TYPE_BD71815:
> + pwr->bat_inserted = bd71815_bat_inserted;
> + pwr->get_temp = bd71815_get_temp;
> + pwr->regs = &pwr_regs_bd71815;
> + dev_dbg(pwr->dev, "Found ROHM BD71815\n");
> + break;
> + default:
> + dev_err(pwr->dev, "Unknown PMIC\n");
> + return -EINVAL;
> + }
> +
> + ret = bd7182x_get_rsens(pwr);
> + if (ret)
> + return dev_err_probe(&pdev->dev, ret, "sense resistor missing\n");
> +
> + dev_set_drvdata(&pdev->dev, pwr);
> + bd71828_init_hardware(pwr);
> +
> + bat_cfg.drv_data = pwr;
> + bat_cfg.fwnode = dev_fwnode(&pdev->dev);
> +
> + ac_cfg.supplied_to = bd71828_ac_supplied_to;
> + ac_cfg.num_supplicants = ARRAY_SIZE(bd71828_ac_supplied_to);
> + ac_cfg.drv_data = pwr;
> +
> + pwr->ac = devm_power_supply_register(&pdev->dev, &bd71828_ac_desc,
> + &ac_cfg);
> + if (IS_ERR(pwr->ac)) {
> + return dev_err_probe(&pdev->dev, PTR_ERR(pwr->ac),
> + "failed to register ac\n");
> + }
> +
> + pwr->bat = devm_power_supply_register(&pdev->dev, &bd71828_bat_desc,
> + &bat_cfg);
> + if (IS_ERR(pwr->bat)) {
> + return dev_err_probe(&pdev->dev, PTR_ERR(pwr->bat),
> + "failed to register bat\n");
> + }
> +
> + ret = bd7182x_get_irqs(pdev, pwr);
> + if (ret) {
> + return dev_err_probe(&pdev->dev, ret, "failed to request IRQs");
> + };
Can drop the {}
> +
> + /* Configure wakeup capable */
> + device_set_wakeup_capable(pwr->dev, 1);
> + device_set_wakeup_enable(pwr->dev, 1);
> +
> + return 0;
> +}
> +
> +static const struct platform_device_id bd71828_charger_id[] = {
> + { "bd71815-power", ROHM_CHIP_TYPE_BD71815 },
> + { "bd71828-power", ROHM_CHIP_TYPE_BD71828 },
> + { },
> +};
> +MODULE_DEVICE_TABLE(platform, bd71828_charger_id);
> +
> +static struct platform_driver bd71828_power_driver = {
> + .driver = {
> + .name = "bd718xx-power",
> + },
> + .probe = bd71828_power_probe,
> + .id_table = bd71828_charger_id,
> +};
> +
> +module_platform_driver(bd71828_power_driver);
> +MODULE_ALIAS("platform:bd718xx-power");
> +
> +MODULE_AUTHOR("Cong Pham <cpham2403@gmail.com>");
> +MODULE_DESCRIPTION("ROHM BD718(15/17/28/78) PMIC Battery Charger driver");
> +MODULE_LICENSE("GPL");
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-18 10:33 ` Matti Vaittinen
@ 2025-08-18 15:07 ` Andreas Kemnade
0 siblings, 0 replies; 19+ messages in thread
From: Andreas Kemnade @ 2025-08-18 15:07 UTC (permalink / raw)
To: Matti Vaittinen; +Cc: Lee Jones, Sebastian Reichel, linux-kernel, linux-pm
Am Mon, 18 Aug 2025 13:33:05 +0300
schrieb Matti Vaittinen <mazziesaccount@gmail.com>:
[...]
> > +#define BD7182x_MASK_CCNTRST 0x80
> > +#define BD7182x_MASK_CCNTENB 0x40
> > +#define BD7182x_MASK_CCCALIB 0x20
>
> I suppose unused defines could get cleared. (At least the CC related
> ones)...
>
Hmm, I don't think having unused register defines is a problem at least
that is not an uncommon thing.
> > +#define BD7182x_MASK_WDT_AUTO 0x40
> > +#define BD7182x_MASK_VBAT_ALM_LIMIT_U 0x01
> > +#define BD7182x_MASK_CHG_EN 0x01
> > +
> > +#define BD7182x_DCIN_COLLAPSE_DEFAULT 0x36
> > +
> > +/* Measured min and max value clear bits */
> > +#define BD718XX_MASK_VSYS_MIN_AVG_CLR 0x10
> > +
> > +#define JITTER_DEFAULT 3000
>
> ...Also the loop jitter
>
yes, there I agree.
> > +#define MAX_CURRENT_DEFAULT 890000 /* uA */
> > +#define AC_NAME "bd71828_ac"
> > +#define BAT_NAME "bd71828_bat"
> > +
> > +/*
> > + * VBAT Low voltage detection Threshold
> > + * 0x00D4*16mV = 212*0.016 = 3.392v
> > + */
> > +#define VBAT_LOW_TH 0x00D4
> > +
> > +#define THR_RELAX_CURRENT_DEFAULT 5 /* mA */
> > +#define THR_RELAX_TIME_DEFAULT (60 * 60) /* sec. */
> > +
> > +#define DGRD_CYC_CAP_DEFAULT 88 /* 1 micro Ah */
> > +
> > +#define DGRD_TEMP_H_DEFAULT 450 /* 0.1 degrees C */
> > +#define DGRD_TEMP_M_DEFAULT 250 /* 0.1 degrees C */
> > +#define DGRD_TEMP_L_DEFAULT 50 /* 0.1 degrees C */
> > +#define DGRD_TEMP_VL_DEFAULT 0 /* 0.1 degrees C */
> > +
> > +#define SOC_EST_MAX_NUM_DEFAULT 5
> > +#define PWRCTRL_NORMAL 0x22
> > +#define PWRCTRL_RESET 0x23
> > +
> > +/*
> > + * Originally we relied upon a fixed size table of OCV and VDR params.
> > + * However the exising linux power-supply batinfo interface for getting the OCV
> > + * values from DT does not have fixed amount of OCV values. Thus we use fixed
> > + * parameter amount only for values provided as module params - and use this
> > + * only as maximum number of parameters when values come from DT.
> > + */
> > +#define NUM_BAT_PARAMS 23
> > +#define MAX_NUM_VDR_VALUES NUM_BAT_PARAMS
> > +
> > +struct pwr_regs {
> > + int used_init_regs;
> > + u8 vbat_init;
> > + u8 vbat_init2;
> > + u8 vbat_init3;
> > + u8 vbat_avg;
> > + u8 ibat;
> > + u8 ibat_avg;
> > + u8 meas_clear;
> > + u8 vsys_min_avg;
> > + u8 btemp_vth;
> > + u8 chg_state;
> > + u8 coulomb3;
> > + u8 coulomb2;
> > + u8 coulomb1;
> > + u8 coulomb0;
> > + u8 coulomb_ctrl;
> > + u8 vbat_rex_avg;
> > + u8 coulomb_full3;
> > + u8 cc_full_clr;
> > + u8 coulomb_chg3;
>
> The coulomb counter and vbat_rex related entries could be dropped as
> they're now unused. Actually, dropping all unused members would simplify
> this quite a bit.
>
hmm, removing it just to add it back tomorrow again... that are not so
much bytes. I would not remove them.
Regards,
Andreas
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-16 19:19 ` [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver Andreas Kemnade
` (2 preceding siblings ...)
2025-08-18 10:33 ` Matti Vaittinen
@ 2025-08-19 6:14 ` Dan Carpenter
3 siblings, 0 replies; 19+ messages in thread
From: Dan Carpenter @ 2025-08-19 6:14 UTC (permalink / raw)
To: oe-kbuild, Andreas Kemnade, Matti Vaittinen, Matti Vaittinen,
Lee Jones, Sebastian Reichel
Cc: lkp, oe-kbuild-all, linux-kernel, linux-pm, Andreas Kemnade
Hi Andreas,
kernel test robot noticed the following build warnings:
url: https://github.com/intel-lab-lkp/linux/commits/Andreas-Kemnade/mfd-bd71828-bd71815-prepare-for-power-supply-support/20250817-032146
base: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
patch link: https://lore.kernel.org/r/20250816-bd71828-charger-v1-2-71b11bde5c73%40kemnade.info
patch subject: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
config: loongarch-randconfig-r073-20250818 (https://download.01.org/0day-ci/archive/20250819/202508191303.UzPStkjj-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 15.1.0
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202508191303.UzPStkjj-lkp@intel.com/
smatch warnings:
drivers/power/supply/bd71828-power.c:298 bd71828_get_temp() error: uninitialized symbol 't'.
drivers/power/supply/bd71828-power.c:559 bd71828_battery_get_property() error: uninitialized symbol 'tmp'.
vim +/t +298 drivers/power/supply/bd71828-power.c
c57d31029550a0 Andreas Kemnade 2025-08-16 286 static int bd71828_get_temp(struct bd71828_power *pwr, int *temp)
c57d31029550a0 Andreas Kemnade 2025-08-16 287 {
c57d31029550a0 Andreas Kemnade 2025-08-16 288 uint16_t t;
c57d31029550a0 Andreas Kemnade 2025-08-16 289 int ret;
c57d31029550a0 Andreas Kemnade 2025-08-16 290 int tmp = 200 * 10000;
c57d31029550a0 Andreas Kemnade 2025-08-16 291
c57d31029550a0 Andreas Kemnade 2025-08-16 292 ret = bd7182x_read16_himask(pwr, pwr->regs->btemp_vth,
c57d31029550a0 Andreas Kemnade 2025-08-16 293 BD71828_MASK_VM_BTMP_U, &t);
c57d31029550a0 Andreas Kemnade 2025-08-16 294 if (ret || t > 3200)
c57d31029550a0 Andreas Kemnade 2025-08-16 295 dev_err(pwr->dev,
c57d31029550a0 Andreas Kemnade 2025-08-16 296 "Failed to read system min average voltage\n");
We should return the error here.
c57d31029550a0 Andreas Kemnade 2025-08-16 297
c57d31029550a0 Andreas Kemnade 2025-08-16 @298 tmp -= 625ULL * (unsigned int)t;
If bd7182x_read16_himask() fails then t is uninitialized or invalid.
c57d31029550a0 Andreas Kemnade 2025-08-16 299 *temp = tmp / 1000;
c57d31029550a0 Andreas Kemnade 2025-08-16 300
c57d31029550a0 Andreas Kemnade 2025-08-16 301 return ret;
c57d31029550a0 Andreas Kemnade 2025-08-16 302 }
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-18 9:32 ` Matti Vaittinen
@ 2025-08-20 16:05 ` Andreas Kemnade
2025-08-21 5:31 ` Matti Vaittinen
0 siblings, 1 reply; 19+ messages in thread
From: Andreas Kemnade @ 2025-08-20 16:05 UTC (permalink / raw)
To: Matti Vaittinen
Cc: Krzysztof Kozlowski, Lee Jones, Sebastian Reichel, linux-kernel,
linux-pm
Am Mon, 18 Aug 2025 12:32:43 +0300
schrieb Matti Vaittinen <mazziesaccount@gmail.com>:
> > Kobo kernels have these tables as part of the driver, the right one is
> > selected via an index in the NTX_HWCONFIG blob provided by the
> > bootloader to the kernel. So that is not necessarily a problem. It
> > could be translated into dt.
> >
> > static int ocv_table_28_PR284983N[23] = {
> > //4200000, 4162288, 4110762, 4066502, 4025265, 3988454, 3955695, 3926323, 3900244, 3876035, 3834038, 3809386, 3794093, 3782718, 3774483, 3768044, 3748158, 3728750, 3704388, 3675577, 3650676, 3463852, 2768530
> > 4200000, 4166349, 4114949, 4072016, 4031575, 3995353, 3963956, 3935650, 3910161, 3883395, 3845310, 3817535, 3801354, 3789708, 3781393, 3774994, 3765230, 3749035, 3726707, 3699147, 3671953, 3607301, 3148394
> > };
> >
> > static int vdr_table_h_28_PR284983N[23] = {
> > //100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108, 108, 109, 110, 112, 124, 157, 786
> > 100, 100, 101, 102, 102, 105, 106, 107, 112, 108, 108, 105, 105, 108, 110, 110, 110, 111, 112, 114, 120, 131, 620
> > };
> >
> > static int vdr_table_m_28_PR284983N[23] = {
> > //100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 102, 100, 100, 102, 103, 103, 105, 108, 112, 124, 157, 586
> > 100, 100, 103, 106, 110, 114, 115, 119, 122, 122, 115, 113, 112, 114, 117, 124, 126, 123, 122, 126, 140, 156, 558
> > };
> >
> > static int vdr_table_l_28_PR284983N[23] = {
> > //100, 100, 103, 105, 110, 110, 113, 112, 112, 112, 105, 110, 110, 111, 122, 131, 138, 143, 150, 166, 242, 354, 357
> > 100, 100, 105, 110, 114, 117, 121, 125, 126, 122, 116, 114, 115, 118, 124, 132, 140, 148, 156, 170, 210, 355, 579
> > };
> >
> > static int vdr_table_vl_28_PR284983N[23] = {
> > //100, 100, 103, 106, 108, 111, 114, 117, 118, 115, 108, 106, 108, 113, 115, 114, 118, 125, 144, 159, 204, 361, 874
> > 100, 100, 109, 115, 118, 123, 127, 130, 140, 139, 134, 130, 128, 138, 140, 150, 154, 164, 178, 204, 271, 362, 352
> > };
>
> Oh, good. If we can get the right battery parameters from the vendor
> driver, then the main problem gets solved. Although, multiple sets of
> different VDR tables probably means, that there are variants with
> different types of battery out there. I assume the bootloader can
> somehow detect the battery type to provide the correct blob?
Historically the Kobo devices ship said HWCONFIG blob apparently to use
the same kernel on multiple devices, then devicetree was invented and
used what was available. There is then a
switch(gptHWCFG->m_val.bBattery) {
...
ocv_table_default =
ocv_table_28_PR284983N;
So that all only means there
are several different batteries amoung the devices supported by that
kernel. From my guts feeling I wonder if the is_relaxed stuff is
properly working and I wonder whether a Kalman filter would give better
results, but that is all something for the future.
Regards,
Andreas
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-20 16:05 ` Andreas Kemnade
@ 2025-08-21 5:31 ` Matti Vaittinen
2025-08-21 8:10 ` Andreas Kemnade
0 siblings, 1 reply; 19+ messages in thread
From: Matti Vaittinen @ 2025-08-21 5:31 UTC (permalink / raw)
To: Andreas Kemnade
Cc: Krzysztof Kozlowski, Lee Jones, Sebastian Reichel, linux-kernel,
linux-pm
On 20/08/2025 19:05, Andreas Kemnade wrote:
> Am Mon, 18 Aug 2025 12:32:43 +0300
> schrieb Matti Vaittinen <mazziesaccount@gmail.com>:
>
>>> Kobo kernels have these tables as part of the driver, the right one is
>>> selected via an index in the NTX_HWCONFIG blob provided by the
>>> bootloader to the kernel. So that is not necessarily a problem. It
>>> could be translated into dt.
>>>
>>> static int ocv_table_28_PR284983N[23] = {
>>> //4200000, 4162288, 4110762, 4066502, 4025265, 3988454, 3955695, 3926323, 3900244, 3876035, 3834038, 3809386, 3794093, 3782718, 3774483, 3768044, 3748158, 3728750, 3704388, 3675577, 3650676, 3463852, 2768530
>>> 4200000, 4166349, 4114949, 4072016, 4031575, 3995353, 3963956, 3935650, 3910161, 3883395, 3845310, 3817535, 3801354, 3789708, 3781393, 3774994, 3765230, 3749035, 3726707, 3699147, 3671953, 3607301, 3148394
>>> };
>>>
>>> static int vdr_table_h_28_PR284983N[23] = {
>>> //100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108, 108, 109, 110, 112, 124, 157, 786
>>> 100, 100, 101, 102, 102, 105, 106, 107, 112, 108, 108, 105, 105, 108, 110, 110, 110, 111, 112, 114, 120, 131, 620
>>> };
>>>
>>> static int vdr_table_m_28_PR284983N[23] = {
>>> //100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 102, 100, 100, 102, 103, 103, 105, 108, 112, 124, 157, 586
>>> 100, 100, 103, 106, 110, 114, 115, 119, 122, 122, 115, 113, 112, 114, 117, 124, 126, 123, 122, 126, 140, 156, 558
>>> };
>>>
>>> static int vdr_table_l_28_PR284983N[23] = {
>>> //100, 100, 103, 105, 110, 110, 113, 112, 112, 112, 105, 110, 110, 111, 122, 131, 138, 143, 150, 166, 242, 354, 357
>>> 100, 100, 105, 110, 114, 117, 121, 125, 126, 122, 116, 114, 115, 118, 124, 132, 140, 148, 156, 170, 210, 355, 579
>>> };
>>>
>>> static int vdr_table_vl_28_PR284983N[23] = {
>>> //100, 100, 103, 106, 108, 111, 114, 117, 118, 115, 108, 106, 108, 113, 115, 114, 118, 125, 144, 159, 204, 361, 874
>>> 100, 100, 109, 115, 118, 123, 127, 130, 140, 139, 134, 130, 128, 138, 140, 150, 154, 164, 178, 204, 271, 362, 352
>>> };
>>
>> Oh, good. If we can get the right battery parameters from the vendor
>> driver, then the main problem gets solved. Although, multiple sets of
>> different VDR tables probably means, that there are variants with
>> different types of battery out there. I assume the bootloader can
>> somehow detect the battery type to provide the correct blob?
>
> Historically the Kobo devices ship said HWCONFIG blob apparently to use
> the same kernel on multiple devices, then devicetree was invented and
> used what was available. There is then a
> switch(gptHWCFG->m_val.bBattery) {
> ...
> ocv_table_default =
> ocv_table_28_PR284983N;
>
>
>
> So that all only means there
> are several different batteries amoung the devices supported by that
> kernel.
Ah. So you believe the other batteries are used on other devices which
run the same kernel. Makes sense.
> From my guts feeling I wonder if the is_relaxed stuff is
> properly working and I wonder whether a Kalman filter would give better
> results, but that is all something for the future.
I believe your experience is stronger than mine (also) here :) I don't
really know the theory behind the 'relaxed battery' (or much of other
battery chemistry stuff). I was merely trusting the inventions of the HQ
engineers, who told me that the OCV tables can be used to adjust the
coulomb counter when the battery is 'relaxed'. 'Relaxed' here meaning
that it has not been charged (or a lot of current has not been drawn
from it) recently. AFAIR, most of the PMIC models had some hardware
support for detecting if the battery is in 'relaxed' state.
I admit it sounds like somewhat uncertain approach. I'd love to hear how
you think the filter would help. I suppose you think of applying some
filtering to the CC correction? Eg, 'smoothen' the CC resetting based on
relaxed OCV, by applying some filtering to the correction values? Sounds
cool! But... It does also sound the analysis about the impact of the
filtering will be hard.
The reason why I dropped the simple-gauge RFC is, that I don't even have
a BD71828 which is connected to a battery (and even with that the
testing would be hard and slow). I thought of trying to do some
simulation, but even that felt quite futile without some proper
battery-data. So, my work was largely just shooting blindly and
listening if some customer started screaming so loud it could be heard
in Finland ^_^;
I think the "ideology" of the fuel-gauging in the HQ was to accept some
of the errors and trust the VDR table based zero-correction to fix
things when battery was about to get empty. The thinking was that more
accurate battery status gets important only when the battery is getting
exhausted - and that's when the zero-correction kicks in.
Yours,
-- Matti
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver
2025-08-21 5:31 ` Matti Vaittinen
@ 2025-08-21 8:10 ` Andreas Kemnade
0 siblings, 0 replies; 19+ messages in thread
From: Andreas Kemnade @ 2025-08-21 8:10 UTC (permalink / raw)
To: Matti Vaittinen
Cc: Krzysztof Kozlowski, Lee Jones, Sebastian Reichel, linux-kernel,
linux-pm
Am Thu, 21 Aug 2025 08:31:06 +0300
schrieb Matti Vaittinen <mazziesaccount@gmail.com>:
> On 20/08/2025 19:05, Andreas Kemnade wrote:
> > Am Mon, 18 Aug 2025 12:32:43 +0300
> > schrieb Matti Vaittinen <mazziesaccount@gmail.com>:
> >
> >>> Kobo kernels have these tables as part of the driver, the right one is
> >>> selected via an index in the NTX_HWCONFIG blob provided by the
> >>> bootloader to the kernel. So that is not necessarily a problem. It
> >>> could be translated into dt.
> >>>
> >>> static int ocv_table_28_PR284983N[23] = {
> >>> //4200000, 4162288, 4110762, 4066502, 4025265, 3988454, 3955695, 3926323, 3900244, 3876035, 3834038, 3809386, 3794093, 3782718, 3774483, 3768044, 3748158, 3728750, 3704388, 3675577, 3650676, 3463852, 2768530
> >>> 4200000, 4166349, 4114949, 4072016, 4031575, 3995353, 3963956, 3935650, 3910161, 3883395, 3845310, 3817535, 3801354, 3789708, 3781393, 3774994, 3765230, 3749035, 3726707, 3699147, 3671953, 3607301, 3148394
> >>> };
> >>>
> >>> static int vdr_table_h_28_PR284983N[23] = {
> >>> //100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108, 108, 109, 110, 112, 124, 157, 786
> >>> 100, 100, 101, 102, 102, 105, 106, 107, 112, 108, 108, 105, 105, 108, 110, 110, 110, 111, 112, 114, 120, 131, 620
> >>> };
> >>>
> >>> static int vdr_table_m_28_PR284983N[23] = {
> >>> //100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 102, 100, 100, 102, 103, 103, 105, 108, 112, 124, 157, 586
> >>> 100, 100, 103, 106, 110, 114, 115, 119, 122, 122, 115, 113, 112, 114, 117, 124, 126, 123, 122, 126, 140, 156, 558
> >>> };
> >>>
> >>> static int vdr_table_l_28_PR284983N[23] = {
> >>> //100, 100, 103, 105, 110, 110, 113, 112, 112, 112, 105, 110, 110, 111, 122, 131, 138, 143, 150, 166, 242, 354, 357
> >>> 100, 100, 105, 110, 114, 117, 121, 125, 126, 122, 116, 114, 115, 118, 124, 132, 140, 148, 156, 170, 210, 355, 579
> >>> };
> >>>
> >>> static int vdr_table_vl_28_PR284983N[23] = {
> >>> //100, 100, 103, 106, 108, 111, 114, 117, 118, 115, 108, 106, 108, 113, 115, 114, 118, 125, 144, 159, 204, 361, 874
> >>> 100, 100, 109, 115, 118, 123, 127, 130, 140, 139, 134, 130, 128, 138, 140, 150, 154, 164, 178, 204, 271, 362, 352
> >>> };
> >>
> >> Oh, good. If we can get the right battery parameters from the vendor
> >> driver, then the main problem gets solved. Although, multiple sets of
> >> different VDR tables probably means, that there are variants with
> >> different types of battery out there. I assume the bootloader can
> >> somehow detect the battery type to provide the correct blob?
> >
> > Historically the Kobo devices ship said HWCONFIG blob apparently to use
> > the same kernel on multiple devices, then devicetree was invented and
> > used what was available. There is then a
> > switch(gptHWCFG->m_val.bBattery) {
> > ...
> > ocv_table_default =
> > ocv_table_28_PR284983N;
> >
> >
> >
> > So that all only means there
> > are several different batteries amoung the devices supported by that
> > kernel.
>
> Ah. So you believe the other batteries are used on other devices which
> run the same kernel. Makes sense.
>
> > From my guts feeling I wonder if the is_relaxed stuff is
> > properly working and I wonder whether a Kalman filter would give better
> > results, but that is all something for the future.
>
> I believe your experience is stronger than mine (also) here :) I don't
> really know the theory behind the 'relaxed battery' (or much of other
> battery chemistry stuff). I was merely trusting the inventions of the HQ
> engineers, who told me that the OCV tables can be used to adjust the
> coulomb counter when the battery is 'relaxed'. 'Relaxed' here meaning
> that it has not been charged (or a lot of current has not been drawn
> from it) recently. AFAIR, most of the PMIC models had some hardware
> support for detecting if the battery is in 'relaxed' state.
>
I am also no battery chemistry expert. But I have looked a lot at
battery voltage behavior for various reasons e.g. for simple things
like: does my charger behave? I do not believe in
in the concept of a boolean is_relaxed. You can always know something
about battery state by doing something like a table_lookup(vbat -
some_factor * ibat)
Depending on situation you have different accuracy. Your battery will
probably not be empty if e.g. your voltage is at 3.9V and you are not
doing excessive charging. I have seen many surprises. My pinephone
sometimes suddenly went off with battery state like 40%. I personally
feel more confident, if I can additionally see the battery voltage.
I have not debugged such issues much yet.
> I admit it sounds like somewhat uncertain approach. I'd love to hear how
> you think the filter would help. I suppose you think of applying some
> filtering to the CC correction? Eg, 'smoothen' the CC resetting based on
> relaxed OCV, by applying some filtering to the correction values? Sounds
> cool! But... It does also sound the analysis about the impact of the
> filtering will be hard.
The problems to solve look a bit like problems in inertial navigation
and there Kalman filters are used. There you have e.g. gyroscopes to
determine the rate of turn, producing drift like a coloumb counter.
Accelerometers can show your orientation if things are "relaxed" so not
much acceleration besides gravity. Magnetometers can be "unrelaxed" by
some magnetic disturbance.
The basic point is you can put the accuracy into the model. So you can
use the information like battery capacity can be estimated by
looking voltage/current by +/- 15%, so something produced by looking
at the gauge cannot be out of that range. On the other hand capacity can
not change faster than fuel gauge + estimated drift can produce.
You can spend a life time on optimizing such filters. The question is
how easily you can improve something by using them. The analysis of the
impact can be doing a bit more subjective by looking at how sane the
capacity display behaves, and whether there are less surprises.
More objectively, you can of course relax the battery as much as
possible and check if there are no illogical capacity changes or do
well defined charging/discharging and look what happens to see whether
capacity was correct.
Regards,
Andreas
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2025-08-21 8:10 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-16 19:19 [PATCH 0/2] power: supply: add charger for BD71828 Andreas Kemnade,,,
2025-08-16 19:19 ` [PATCH 1/2] mfd: bd71828, bd71815 prepare for power-supply support Andreas Kemnade,,,
2025-08-18 5:49 ` Matti Vaittinen
2025-08-18 6:44 ` Andreas Kemnade
2025-08-16 19:19 ` [PATCH 2/2] power: supply: Add bd718(15/28/78) charger driver Andreas Kemnade
2025-08-17 5:58 ` Krzysztof Kozlowski
2025-08-17 8:11 ` Andreas Kemnade
2025-08-17 8:13 ` Krzysztof Kozlowski
2025-08-18 6:34 ` Matti Vaittinen
2025-08-18 8:36 ` Andreas Kemnade
2025-08-18 9:32 ` Matti Vaittinen
2025-08-20 16:05 ` Andreas Kemnade
2025-08-21 5:31 ` Matti Vaittinen
2025-08-21 8:10 ` Andreas Kemnade
2025-08-18 10:09 ` Matti Vaittinen
2025-08-17 21:33 ` kernel test robot
2025-08-18 10:33 ` Matti Vaittinen
2025-08-18 15:07 ` Andreas Kemnade
2025-08-19 6:14 ` Dan Carpenter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).