Re: [PATCH 8/8] power: supply: Add driver for Qualcomm SMBCHG

From: Yassine Oudjana
Date: Mon Aug 08 2022 - 06:05:45 EST



On Mon, Aug 8 2022 at 11:55:02 +03:00:00, Krzysztof Kozlowski <krzysztof.kozlowski@xxxxxxxxxx> wrote:
On 08/08/2022 10:34, Yassine Oudjana wrote:
From: Yassine Oudjana <y.oudjana@xxxxxxxxxxxxxx>

Add a driver for the switch-mode battery charger found on
PMICs such as PMI8994. This block is referred to in the vendor
kernel[1] as smbcharger or SMBCHG. It has USB and DC inputs,
and can generate VBUS for USB OTG with a boost regulator.
It supports Qualcomm Quick Charge 2.0, and can operate along
with a parallel charger (SMB1357, or SMB1351 for added Quick
Charge 3.0 support) for improved efficiency at higher currents.

At the moment, this driver supports charging off of the USB input
at 5V with input current limit up to 3A. It also includes support
for operating the OTG boost regulator as well as extcon
functionality, reporting states of USB and USB_HOST with VBUS and
charge port types.

Co-developed-by: Alejandro Tafalla <atafalla@xxxxxxxxx>
Signed-off-by: Alejandro Tafalla <atafalla@xxxxxxxxx>
Signed-off-by: Yassine Oudjana <y.oudjana@xxxxxxxxxxxxxx>

[1] https://github.com/android-linux-stable/msm-3.18/blob/kernel.lnx.3.18.r34-rel/drivers/power/qpnp-smbcharger.c
---
MAINTAINERS | 2 +
drivers/power/supply/Kconfig | 11 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/qcom-smbchg.c | 1664 ++++++++++++++++++++++++++++
drivers/power/supply/qcom-smbchg.h | 428 +++++++
5 files changed, 2106 insertions(+)
create mode 100644 drivers/power/supply/qcom-smbchg.c
create mode 100644 drivers/power/supply/qcom-smbchg.h

diff --git a/MAINTAINERS b/MAINTAINERS
index f6cf3a27d132..9b8693050890 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16964,6 +16964,8 @@ L: linux-pm@xxxxxxxxxxxxxxx
L: linux-arm-msm@xxxxxxxxxxxxxxx
S: Maintained
F: Documentation/devicetree/bindings/power/supply/qcom,smbchg.yaml
+F: drivers/power/supply/qcom-smbchg.c
+F: drivers/power/supply/qcom-smbchg.h

QUALCOMM TSENS THERMAL DRIVER
M: Amit Kucheria <amitk@xxxxxxxxxx>
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 1aa8323ad9f6..246bfc118d9f 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -633,6 +633,17 @@ config CHARGER_QCOM_SMBB
documentation for more detail. The base name for this driver is
'pm8941_charger'.

+config CHARGER_QCOM_SMBCHG
+ tristate "Qualcomm Switch-Mode Battery Charger"

As I mentioned in cover letter, this should be either squashed into
Caleb's work, merged into some common part or kept separate but with
clear explaining why it cannot be merged.

Some incomplete review follows:

+ depends on MFD_SPMI_PMIC || COMPILE_TEST
+ depends on OF
+ depends on EXTCON
+ depends on REGULATOR
+ select QCOM_PMIC_SEC_WRITE
+ help
+ Say Y to include support for the Switch-Mode Battery Charger block
+ found in Qualcomm PMICs such as PMI8994.
+
config CHARGER_BQ2415X
tristate "TI BQ2415x battery charger driver"
depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 7f02f36aea55..7c2c037cd8b1 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -83,6 +83,7 @@ obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o
obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o
obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o
+obj-$(CONFIG_CHARGER_QCOM_SMBCHG) += qcom-smbchg.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o
diff --git a/drivers/power/supply/qcom-smbchg.c b/drivers/power/supply/qcom-smbchg.c
new file mode 100644
index 000000000000..23a9667953c9
--- /dev/null
+++ b/drivers/power/supply/qcom-smbchg.c
@@ -0,0 +1,1664 @@
+// SPDX-License-Identifier: GPL-2.0-only

Several things look like based from original sources, so please retain
original copyright.

Do I replace the existing copyright here with the original one, just add it, or mention that this driver is based on downstream sources (maybe putting a link as well) then add it?


+/*
+ * Power supply driver for Qualcomm PMIC switch-mode battery charger
+ *
+ * Copyright (c) 2021 Yassine Oudjana <y.oudjana@xxxxxxxxxxxxxx>
+ * Copyright (c) 2021 Alejandro Tafalla <atafalla@xxxxxxxxx>
+ */
+
+#include <asm/unaligned.h>
+#include <linux/errno.h>
+#include <linux/extcon-provider.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/reboot.h>
+#include <linux/regulator/driver.h>
+#include <linux/util_macros.h>
+#include <soc/qcom/pmic-sec-write.h>
+
+#include "qcom-smbchg.h"
+


(...)

+/**
+ * @brief smbchg_otg_enable() - Enable OTG regulator
+ *
+ * @param rdev Pointer to regulator_dev
+ * @return 0 on success, -errno on failure
+ */
+static int smbchg_otg_enable(struct regulator_dev *rdev)
+{
+ struct smbchg_chip *chip = rdev_get_drvdata(rdev);
+ int ret;
+
+ dev_dbg(chip->dev, "Enabling OTG VBUS regulator");
+
+ ret = regmap_update_bits(chip->regmap,
+ chip->base + SMBCHG_BAT_IF_CMD_CHG, OTG_EN_BIT,
+ OTG_EN_BIT);
+ if (ret)
+ dev_err(chip->dev, "Failed to enable OTG regulator: %pe\n",
+ ERR_PTR(ret));
+
+ return ret;
+}
+
+/**
+ * @brief smbchg_otg_disable() - Disable OTG regulator
+ *
+ * @param rdev Pointer to regulator_dev
+ * @return 0 on success, -errno on failure
+ */
+static int smbchg_otg_disable(struct regulator_dev *rdev)
+{
+ struct smbchg_chip *chip = rdev_get_drvdata(rdev);
+ int ret;
+
+ dev_dbg(chip->dev, "Disabling OTG VBUS regulator");

Here and in other places - no dbg messages replacing tracing. We have
tracing for that.

Will look into it.


+
+ ret = regmap_update_bits(chip->regmap,
+ chip->base + SMBCHG_BAT_IF_CMD_CHG, OTG_EN_BIT,
+ 0);
+ if (ret) {
+ dev_err(chip->dev, "Failed to disable OTG regulator: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ return 0;
+}
+

(...)

+static irqreturn_t smbchg_handle_charger_error(int irq, void *data)
+{
+ struct smbchg_chip *chip = data;
+
+ dev_err(chip->dev, "Charger error");
+
+ power_supply_changed(chip->usb_psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t smbchg_handle_p2f(int irq, void *data)
+{
+ struct smbchg_chip *chip = data;
+
+ dev_dbg(chip->dev, "Fast charging threshold reached");
+
+ power_supply_changed(chip->usb_psy);
+
+ return IRQ_HANDLED;

Several interrupts which are exactly the same... no, use one interrupt
handler for all such cases. Anyway I have some doubts about these 20 or
more separate interrupt lines...

This was to allow for printing different debug messages. I believe there are interrupt status registers that can be used instead, so I might try to use them to find out the specific event in a single handler while adding tracing.


+}
+
+static irqreturn_t smbchg_handle_rechg(int irq, void *data)
+{
+ struct smbchg_chip *chip = data;
+
+ dev_dbg(chip->dev, "Recharge threshold reached");
+
+ /* Auto-recharge is enabled, nothing to do here */
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t smbchg_handle_taper(int irq, void *data)
+{
+ struct smbchg_chip *chip = data;
+
+ dev_dbg(chip->dev, "Taper charging threshold reached");
+
+ power_supply_changed(chip->usb_psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t smbchg_handle_tcc(int irq, void *data)
+{
+ struct smbchg_chip *chip = data;
+
+ dev_dbg(chip->dev, "Termination current reached");
+
+ power_supply_changed(chip->usb_psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t smbchg_handle_batt_temp(int irq, void *data)
+{
+ struct smbchg_chip *chip = data;
+
+ power_supply_changed(chip->usb_psy);
+
+ return IRQ_HANDLED;
+}

(...)

+
+const struct smbchg_irq smbchg_irqs[] = {

You mix everywhere functions with static variables. All variables -
except platform_driver related go to the beginning of the file.

They were grouped based on their topic (interrupt handling, power supply properties, ...). Will rearrange them.


+ { "chg-error", smbchg_handle_charger_error },
+ { "chg-inhibit", NULL },
+ { "chg-prechg-sft", NULL },
+ { "chg-complete-chg-sft", NULL },
+ { "chg-p2f-thr", smbchg_handle_p2f },
+ { "chg-rechg-thr", smbchg_handle_rechg },
+ { "chg-taper-thr", smbchg_handle_taper },
+ { "chg-tcc-thr", smbchg_handle_tcc },
+ { "batt-hot", smbchg_handle_batt_temp },
+ { "batt-warm", smbchg_handle_batt_temp },
+ { "batt-cold", smbchg_handle_batt_temp },
+ { "batt-cool", smbchg_handle_batt_temp },
+ { "batt-ov", NULL },
+ { "batt-low", NULL },
+ { "batt-missing", smbchg_handle_batt_presence },
+ { "batt-term-missing", NULL },
+ { "usbin-uv", NULL },
+ { "usbin-ov", NULL },
+ { "usbin-src-det", smbchg_handle_usb_source_detect },
+ { "usbid-change", smbchg_handle_usbid_change },
+ { "otg-fail", smbchg_handle_otg_fail },
+ { "otg-oc", smbchg_handle_otg_oc },
+ { "aicl-done", smbchg_handle_aicl_done },
+ { "dcin-uv", NULL },
+ { "dcin-ov", NULL },
+ { "power-ok", NULL },
+ { "temp-shutdown", smbchg_handle_temp_shutdown },
+ { "wdog-timeout", NULL },
+ { "flash-fail", NULL },
+ { "otst2", NULL },
+ { "otst3", NULL },
+};
+
+/**

(...)

+
+static int smbchg_probe(struct platform_device *pdev)
+{
+ struct smbchg_chip *chip;
+ struct regulator_config config = {};
+ struct power_supply_config supply_config = {};
+ int i, irq, ret;
+
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = &pdev->dev;
+
+ chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
+ if (!chip->regmap) {
+ dev_err(chip->dev, "Failed to get regmap\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(chip->dev->of_node, "reg", &chip->base);

First: device_xxx

Okay.

Second: what if address is bigger than u32? Shouldn't this be
of_read_number or something similar in device_xxx API?

The address wouldn't exceed sizeof(u16). Actually now I think I should've used property_read_u16 instead. I couldn't find a device_* equivalent of of_read_number (or at least not a direct one), are you sure it exists?


+ if (ret) {
+ dev_err(chip->dev, "Failed to get base address: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ spin_lock_init(&chip->sec_access_lock);
+ INIT_WORK(&chip->otg_reset_work, smbchg_otg_reset_worker);
+
+ /* Initialize OTG regulator */
+ chip->otg_rdesc.id = -1;
+ chip->otg_rdesc.name = "otg-vbus";
+ chip->otg_rdesc.ops = &smbchg_otg_ops;
+ chip->otg_rdesc.owner = THIS_MODULE;
+ chip->otg_rdesc.type = REGULATOR_VOLTAGE;
+ chip->otg_rdesc.of_match = "otg-vbus";
+
+ config.dev = chip->dev;
+ config.driver_data = chip;
+
+ chip->otg_reg =
+ devm_regulator_register(chip->dev, &chip->otg_rdesc, &config);

This wrapping is difficult to read.

This was done by clang-format. I don't mind changing it manually, but shouldn't it be conforming to the linux code style if it was done automatically following the .clang-format config file in the root of the kernel tree?


+ if (IS_ERR(chip->otg_reg)) {
+ dev_err(chip->dev,
+ "Failed to register OTG VBUS regulator: %pe\n",
+ chip->otg_reg);
+ return PTR_ERR(chip->otg_reg);
+ }
+
+ chip->data = of_device_get_match_data(chip->dev);
+
+ supply_config.drv_data = chip;
+ supply_config.of_node = pdev->dev.of_node;
+ chip->usb_psy = devm_power_supply_register(

This wrapping is difficult to read.

Ditto.


+ chip->dev, &smbchg_usb_psy_desc, &supply_config);
+ if (IS_ERR(chip->usb_psy)) {
+ dev_err(chip->dev, "Failed to register USB power supply: %pe\n",
+ chip->usb_psy);
+ return PTR_ERR(chip->usb_psy);
+ }
+
+ ret = power_supply_get_battery_info(chip->usb_psy, &chip->batt_info);
+ if (ret) {
+ dev_err(chip->dev, "Failed to get battery info: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ if (chip->batt_info->voltage_max_design_uv == -EINVAL) {
+ dev_err(chip->dev,
+ "Battery info missing maximum design voltage\n");
+ return -EINVAL;
+ }
+
+ if (chip->batt_info->constant_charge_current_max_ua == -EINVAL) {
+ dev_err(chip->dev,
+ "Battery info missing maximum constant charge current\n");
+ return -EINVAL;
+ }
+
+ /* Initialize extcon */
+ chip->edev = devm_extcon_dev_allocate(chip->dev, smbchg_extcon_cable);
+ if (IS_ERR(chip->edev)) {
+ dev_err(chip->dev, "Failed to allocate extcon device: %pe\n",
+ chip->edev);
+ return PTR_ERR(chip->edev);
+ }
+
+ ret = devm_extcon_dev_register(chip->dev, chip->edev);
+ if (ret) {
+ dev_err(chip->dev, "Failed to register extcon device: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ extcon_set_property_capability(chip->edev, EXTCON_USB,
+ EXTCON_PROP_USB_VBUS);
+ extcon_set_property_capability(chip->edev, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_VBUS);
+
+ /* Initialize charger */
+ ret = smbchg_init(chip);
+ if (ret)
+ return ret;
+
+ /* Request IRQs */
+ for (i = 0; i < ARRAY_SIZE(smbchg_irqs); ++i) {
+ /* IRQ unused */
+ if (!smbchg_irqs[i].handler)
+ continue;
+
+ irq = of_irq_get_byname(pdev->dev.of_node, smbchg_irqs[i].name);
+ if (irq < 0) {
+ dev_err(chip->dev, "Failed to get %s IRQ: %pe\n",
+ smbchg_irqs[i].name, ERR_PTR(irq));
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(chip->dev, irq, NULL,
+ smbchg_irqs[i].handler,
+ IRQF_ONESHOT,
+ smbchg_irqs[i].name, chip);
+ if (ret) {
+ dev_err(chip->dev, "failed to request %s IRQ: %pe\n",
+ smbchg_irqs[i].name, ERR_PTR(irq));
+ return ret;
+ }
+ }
+
+ platform_set_drvdata(pdev, chip);
+
+ return 0;
+}
+
+static int smbchg_remove(struct platform_device *pdev)
+{
+ struct smbchg_chip *chip = platform_get_drvdata(pdev);
+
+ smbchg_usb_enable(chip, false);
+ smbchg_charging_enable(chip, false);
+
+ return 0;
+}
+
+static const struct of_device_id smbchg_id_table[] = {
+ { .compatible = "qcom,pmi8994-smbchg", .data = &smbchg_pmi8994_data },
+ { .compatible = "qcom,pmi8996-smbchg", .data = &smbchg_pmi8996_data },
+ {}
+};
+MODULE_DEVICE_TABLE(of, smbchg_id_table);
+
+static struct platform_driver smbchg_driver = {
+ .probe = smbchg_probe,
+ .remove = smbchg_remove,
+ .driver = {
+ .name = "qcom-smbchg",
+ .of_match_table = smbchg_id_table,
+ },
+};
+module_platform_driver(smbchg_driver);
+
+MODULE_AUTHOR("Yassine Oudjana <y.oudjana@xxxxxxxxxxxxxx>");
+MODULE_AUTHOR("Alejandro Tafalla <atafalla@xxxxxxxxx>");
+MODULE_DESCRIPTION("Qualcomm PMIC switch-mode battery charger driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/qcom-smbchg.h b/drivers/power/supply/qcom-smbchg.h
new file mode 100644
index 000000000000..06445e10b4db
--- /dev/null
+++ b/drivers/power/supply/qcom-smbchg.h
@@ -0,0 +1,428 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* Registers */
+/* CHGR */
+#define SMBCHG_CHGR_FV_STS 0x00c
+#define SMBCHG_CHGR_STS 0x00e
+#define SMBCHG_CHGR_RT_STS 0x010
+#define SMBCHG_CHGR_FCC_CFG 0x0f2
+#define SMBCHG_CHGR_FCC_CMP_CFG 0x0f3
+#define SMBCHG_CHGR_FV_CFG 0x0f4
+#define SMBCHG_CHGR_FV_CMP 0x0f5
+#define SMBCHG_CHGR_AFVC_CFG 0x0f6
+#define SMBCHG_CHGR_CHG_INHIB_CFG 0x0f7
+#define SMBCHG_CHGR_TCC_CFG 0x0f9
+#define SMBCHG_CHGR_CCMP_CFG 0x0fa
+#define SMBCHG_CHGR_CHGR_CFG1 0x0fb
+#define SMBCHG_CHGR_CHGR_CFG2 0x0fc
+#define SMBCHG_CHGR_SFT_CFG 0x0fd
+#define SMBCHG_CHGR_CFG 0x0ff
+
+/* OTG */
+#define SMBCHG_OTG_RT_STS 0x110
+#define SMBCHG_OTG_OTG_CFG 0x1f1
+#define SMBCHG_OTG_TRIM6 0x1f6
+#define SMBCHG_OTG_LOW_PWR_OPTIONS 0x1ff
+
+/* BAT-IF */
+#define SMBCHG_BAT_IF_BAT_PRES_STS 0x208
+#define SMBCHG_BAT_IF_RT_STS 0x210
+#define SMBCHG_BAT_IF_CMD_CHG 0x242
+#define SMBCHG_BAT_IF_CMD_CHG_LED 0x243
+#define SMBCHG_BAT_IF_BM_CFG 0x2f3
+#define SMBCHG_BAT_IF_BAT_IF_TRIM7 0x2f7
+#define SMBCHG_BAT_IF_BB_CLMP_SEL 0x2f8
+#define SMBCHG_BAT_IF_ZIN_ICL_PT 0x2fc
+#define SMBCHG_BAT_IF_ZIN_ICL_LV 0x2fd
+#define SMBCHG_BAT_IF_ZIN_ICL_HV 0x2fe
+
+/* USB-CHGPTH */
+#define SMBCHG_USB_CHGPTH_ICL_STS_1 0x307
+#define SMBCHG_USB_CHGPTH_PWR_PATH 0x308
+#define SMBCHG_USB_CHGPTH_ICL_STS_2 0x309
+#define SMBCHG_USB_CHGPTH_RID_STS 0x30b
+#define SMBCHG_USB_CHGPTH_USBIN_HVDCP_STS 0x30c
+#define SMBCHG_USB_CHGPTH_INPUT_STS 0x30d
+#define SMBCHG_USB_CHGPTH_USBID_MSB 0x30e
+#define SMBCHG_USB_CHGPTH_RT_STS 0x310
+#define SMBCHG_USB_CHGPTH_CMD_IL 0x340
+#define SMBCHG_USB_CHGPTH_CMD_APSD 0x341
+#define SMBCHG_USB_CHGPTH_CMD_HVDCP_1 0x342
+#define SMBCHG_USB_CHGPTH_CMD_HVDCP_2 0x343
+#define SMBCHG_USB_CHGPTH_USBIN_CHGR_CFG 0x3f1
+#define SMBCHG_USB_CHGPTH_IL_CFG 0x3f2
+#define SMBCHG_USB_CHGPTH_AICL_CFG 0x3f3
+#define SMBCHG_USB_CHGPTH_CFG 0x3f4
+#define SMBCHG_USB_CHGPTH_APSD_CFG 0x3f5
+#define SMBCHG_USB_CHGPTH_TR_RID 0x3fa
+#define SMBCHG_USB_CHGPTH_ICL_BUF_CONFIG 0x3fc
+#define SMBCHG_USB_CHGPTH_TR_8OR32B 0x3fe
+
+/* DC-CHGPTH */
+#define SMBCHG_DC_CHGPTH_RT_STS 0x410
+#define SMBCHG_DC_CHGPTH_IL_CFG 0x4f2
+#define SMBCHG_DC_CHGPTH_AICL_CFG 0x4f3
+#define SMBCHG_DC_CHGPTH_AICL_WL_SEL_CFG 0x4f5
+
+/* MISC */
+#define SMBCHG_MISC_REVISION1 0x600
+#define SMBCHG_MISC_IDEV_STS 0x608
+#define SMBCHG_MISC_RT_STS 0x610
+#define SMBCHG_MISC_TEST 0x6e2
+#define SMBCHG_MISC_NTC_VOUT_CFG 0x6f3
+#define SMBCHG_MISC_TRIM_OPT_15_8 0x6f5
+#define SMBCHG_MISC_TRIM_OPT_7_0 0x6f6
+#define SMBCHG_MISC_TRIM_14 0x6fe
+
+/* Bits */
+/* CHGR_STS bits */
+#define CHG_TYPE_MASK GENMASK(2, 1)
+#define CHG_HOLD_OFF_BIT BIT(3)\
+
+/* CHGR_FCC_CFG bits */
+#define FCC_MASK GENMASK(4, 0)
+
+/* CHGR_RT_STS bits */
+#define CHG_INHIBIT_BIT BIT(1)
+#define CHG_COMP_SFT_BIT BIT(3)
+#define BAT_TCC_REACHED_BIT BIT(7)
+
+/* CHGR_FV_CFG bits */
+#define FV_MASK GENMASK(5, 0)
+
+/* CHGR_TCC_CFG bits */
+#define CHG_ITERM_MASK GENMASK(2, 0)
+
+/* CHGR_CHGR_CFG1 bits */
+#define RECHG_THRESHOLD_SRC_BIT BIT(1)
+#define TERM_I_SRC_BIT BIT(2)
+
+/* CHGR_CHGR_CFG2 bits */
+#define CHARGER_INHIBIT_BIT BIT(0)
+#define AUTO_RECHG_BIT BIT(2)
+#define I_TERM_BIT BIT(3)
+#define P2F_CHG_TRAN_BIT BIT(5)
+#define CHG_EN_POLARITY_BIT BIT(6)
+#define CHG_EN_SRC_BIT BIT(7)
+
+/* CHGR_CFG bits */
+#define RCHG_LVL_BIT BIT(0)
+
+/* BAT_IF_CMD_CHG bits */
+#define OTG_EN_BIT BIT(0)
+#define CHG_EN_BIT BIT(1)
+
+/* BAT_IF_RT_STS bits */
+#define HOT_BAT_HARD_BIT BIT(0)
+#define HOT_BAT_SOFT_BIT BIT(1)
+#define COLD_BAT_HARD_BIT BIT(2)
+#define COLD_BAT_SOFT_BIT BIT(3)
+#define BAT_OV_BIT BIT(4)
+#define BAT_LOW_BIT BIT(5)
+#define BAT_MISSING_BIT BIT(6)
+#define BAT_TERM_MISSING_BIT BIT(7)
+
+/* USB_CHGPTH_ICL_STS_1 bits */
+#define ICL_STS_MASK GENMASK(4, 0)
+#define AICL_STS_BIT BIT(5)
+#define AICL_SUSP_BIT BIT(6)
+
+/* USB_CHGPTH_CFG bits */
+#define USB51AC_CTRL BIT(1)
+#define USB51_COMMAND_POL BIT(2)
+#define CFG_USB3P0_SEL_BIT BIT(7)
+
+/* USB_CHGPTH_RT_STS bits */
+#define USBIN_OV_BIT BIT(1)
+#define USBIN_SRC_DET_BIT BIT(2)
+
+/* USB_CHGPTH_RID_STS bits */
+#define RID_MASK GENMASK(3, 0)
+
+/* USB_CHGPTH_CMD_IL bits */
+#define USBIN_MODE_HC_BIT BIT(0)
+#define USB51_MODE_BIT BIT(1)
+#define ICL_OVERRIDE_BIT BIT(2)
+#define USBIN_SUSPEND_BIT BIT(4)
+
+/* USB_CHGPTH_IL_CFG bits */
+#define USBIN_INPUT_MASK GENMASK(4, 0)
+
+/* USB_CHGPTH_AICL_CFG bits */
+#define USB_CHGPTH_AICL_EN BIT(2)
+
+/* USB_CHGPTH_APSD_CFG bits */
+#define USB_CHGPTH_APSD_EN BIT(0)
+
+/* MISC_IDEV_STS bits */
+#define FMB_STS_MASK GENMASK(3, 0)
+
+/* MISC_TRIM_OPT_15_8 bits */
+#define AICL_RERUN_MASK GENMASK(5, 4)
+#define AICL_RERUN_DC_BIT BIT(4)
+#define AICL_RERUN_USB_BIT BIT(5)
+
+/* Values */
+/* CHGR_STS values */
+#define CHG_TYPE_SHIFT 1
+#define BATT_NOT_CHG_VAL 0x0
+#define BATT_PRE_CHG_VAL 0x1
+#define BATT_FAST_CHG_VAL 0x2
+#define BATT_TAPER_CHG_VAL 0x3
+
+/* CHGR_CHGR_CFG1 values */
+#define RCHG_SRC_ANA 0
+#define RCHG_SRC_FG BIT(1)
+#define TERM_SRC_ANA 0
+#define TERM_SRC_FG BIT(2)
+
+/* CHGR_CHGR_CFG2 values */
+#define CHG_INHIBIT_DIS 0
+#define CHG_INHIBIT_EN BIT(0)
+#define AUTO_RCHG_EN 0
+#define AUTO_RCHG_DIS BIT(2)
+#define CURRENT_TERM_EN 0
+#define CURRENT_TERM_DIS BIT(3)
+#define PRE_FAST_AUTO 0
+#define PRE_FAST_CMD BIT(5)
+#define CHG_EN_SRC_CMD 0
+#define CHG_EN_SRC_PIN BIT(7)
+
+/* CHGR_CFG values */
+#define RCHG_THRESH_100MV 0
+#define RCHG_THRESH_200MV BIT(0)
+
+/* USB_CHGPTH_INPUT_STS values */
+#define USBIN_9V BIT(5)
+#define USBIN_UNREG BIT(4)
+#define USBIN_LV BIT(3)
+
+/* USB_CHGPTH_USBID_MSB values */
+#define USBID_GND_THRESHOLD 0x495
+
+/* USB_CHGPTH_CFG values */
+#define USB51_COMMAND_CONTROL 0
+#define USB51_PIN_CONTROL BIT(1)
+#define USB51AC_COMMAND1_500 0
+#define USB51AC_COMMAND1_100 BIT(2)
+#define USB_2P0_SEL 0
+#define USB_3P0_SEL BIT(7)
+
+/* MISC_IDEV_STS values */
+#define USB_TYPE_SDP_BIT BIT(4)
+#define USB_TYPE_OTHER_BIT BIT(5)
+#define USB_TYPE_DCP_BIT BIT(6)
+#define USB_TYPE_CDP_BIT BIT(7)
+
+/* Constant parameters */
+#define NUM_OTG_RESET_RETRIES 5
+#define OTG_RESET_DELAY_MS 20
+
+/*
+ * These values can be indexed using a bitmask:
+ * 0: USB 2.0/3.0
+ * 1: Limited/full current
+ */
+static const int smbchg_lc_ilim_options[] = {
+ [0b00] = 100000,
+ [0b01] = 150000,
+ [0b10] = 500000,
+ [0b11] = 900000
+};
+#define LC_ILIM_USB3_BIT BIT(0)
+#define LC_ILIM_FULL_CURRENT_BIT BIT(1)
+#define smbchg_lc_ilim(usb_3, full_current) smbchg_lc_ilim_options[usb_3 | full_current << 1]
+
+struct smbchg_chip {
+ unsigned int base;
+ struct device *dev;
+ struct regmap *regmap;
+
+ struct power_supply_battery_info *batt_info;
+ struct power_supply *usb_psy;
+
+ struct regulator_desc otg_rdesc;
+ struct regulator_dev *otg_reg;
+ int otg_resets;
+
+ struct extcon_dev *edev;
+
+ spinlock_t sec_access_lock;
+ struct work_struct otg_reset_work;
+
+ const struct smbchg_data *data;
+};
+
+struct smbchg_irq {
+ const char *name;
+ irq_handler_t handler;
+};
+
+struct smbchg_data {
+ const int *iterm_table;
+ unsigned int iterm_table_len;
+ const int *ilim_table;
+ unsigned int ilim_table_len;
+
+ bool reset_otg_on_oc;
+};
+
+static const int smbchg_fv_table[] = {

No static data in headers.

Understood.


Best regards,
Krzysztof