[PATCH 6/7] regulator: sy7636a: bind to the I2C device directly

From: Pablo Mazzini

Date: Sun Oct 25 2026 - 20:44:15 EST


With the temperature reported here, the regulator is all that is left
behind simple-mfd-i2c. Bind to the chip directly, as the TPS65185 and
FP9931 drivers do, and drop the MFD glue and header. It now probes before
the GPIOs may be ready, so report the power good GPIO with
dev_err_probe().

Signed-off-by: Pablo Mazzini <pmazzini@xxxxxxxxx>
---
drivers/mfd/Kconfig | 10 ----
drivers/mfd/simple-mfd-i2c.c | 10 ----
drivers/regulator/Kconfig | 3 +-
drivers/regulator/sy7636a-regulator.c | 86 +++++++++++++++------------
include/linux/mfd/sy7636a.h | 34 -----------
5 files changed, 50 insertions(+), 93 deletions(-)
delete mode 100644 include/linux/mfd/sy7636a.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0a2778052519..9130dac7a7ff 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1305,16 +1305,6 @@ config MFD_SPMI_PMIC
Say M here if you want to include support for the SPMI PMIC
series as a module. The module will be called "qcom-spmi-pmic".

-config MFD_SY7636A
- tristate "Silergy SY7636A voltage regulator"
- depends on I2C
- select MFD_SIMPLE_MFD_I2C
- help
- Enable support for Silergy SY7636A voltage regulator.
-
- To enable support for building sub-devices as modules,
- choose M here.
-
config MFD_RDC321X
tristate "RDC R-321x southbridge"
select MFD_CORE
diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c
index 168b4cf49b8c..0c9162034899 100644
--- a/drivers/mfd/simple-mfd-i2c.c
+++ b/drivers/mfd/simple-mfd-i2c.c
@@ -67,15 +67,6 @@ static int simple_mfd_i2c_probe(struct i2c_client *i2c)
return ret;
}

-static const struct mfd_cell sy7636a_cells[] = {
- { .name = "sy7636a-regulator", },
-};
-
-static const struct simple_mfd_data silergy_sy7636a = {
- .mfd_cell = sy7636a_cells,
- .mfd_cell_size = ARRAY_SIZE(sy7636a_cells),
-};
-
static const struct mfd_cell max5970_cells[] = {
{ .name = "max5970-regulator", },
{ .name = "max5970-iio", },
@@ -123,7 +114,6 @@ static const struct of_device_id simple_mfd_i2c_of_match[] = {
{ .compatible = "maxim,max5970", .data = &maxim_max5970 },
{ .compatible = "maxim,max5978", .data = &maxim_max5970 },
{ .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705 },
- { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a },
{ .compatible = "spacemit,p1", .data = &spacemit_p1 },
{}
};
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index f0d8d1319a1b..49b7c6dc541f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1621,7 +1621,8 @@ config REGULATOR_SUN20I

config REGULATOR_SY7636A
tristate "Silergy SY7636A voltage regulator"
- depends on MFD_SY7636A
+ depends on I2C
+ select REGMAP_I2C
help
This driver supports Silergy SY7636A voltage regulator.
If HWMON is enabled, it also provides temperature measurement.
diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c
index 816df7716c0e..e170461a15ad 100644
--- a/drivers/regulator/sy7636a-regulator.c
+++ b/drivers/regulator/sy7636a-regulator.c
@@ -12,14 +12,23 @@
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/mfd/sy7636a.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regmap.h>

+#define SY7636A_REG_OPERATION_MODE_CRL 0x00
+#define SY7636A_OPERATION_MODE_CRL_VCOMCTL BIT(6)
+#define SY7636A_OPERATION_MODE_CRL_ONOFF BIT(7)
+#define SY7636A_REG_VCOM_ADJUST_CTRL_L 0x01
+#define SY7636A_REG_VCOM_ADJUST_CTRL_H 0x02
+#define SY7636A_REG_POWER_ON_DELAY_TIME 0x06
+#define SY7636A_REG_TERMISTOR_READOUT 0x08
+
+#define VCOM_ADJUST_CTRL_MASK 0x1ff
+#define VCOM_ADJUST_CTRL_SCAL 10000
+
#define PGOOD_TIMEOUT_MSECS 200

struct sy7636a_data {
@@ -194,49 +203,52 @@ static const struct hwmon_chip_info sy7636a_hwmon_chip_info = {
.info = sy7636a_hwmon_info,
};

-static int sy7636a_regulator_probe(struct platform_device *pdev)
+static const struct regmap_config sy7636a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int sy7636a_regulator_probe(struct i2c_client *client)
{
- struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ struct device *dev = &client->dev;
struct regulator_config config = { };
struct regulator_dev *rdev;
struct gpio_desc *gdp;
struct sy7636a_data *data;
+ struct regmap *regmap;
int irq, ret;

- if (!regmap)
- return -EPROBE_DEFER;
-
- device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
+ regmap = devm_regmap_init_i2c(client, &sy7636a_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "failed to allocate regmap\n");

- gdp = devm_gpiod_get(&pdev->dev, "epd-pwr-good", GPIOD_IN);
- if (IS_ERR(gdp)) {
- dev_err(&pdev->dev, "Power good GPIO fault %ld\n", PTR_ERR(gdp));
- return PTR_ERR(gdp);
- }
+ gdp = devm_gpiod_get(dev, "epd-pwr-good", GPIOD_IN);
+ if (IS_ERR(gdp))
+ return dev_err_probe(dev, PTR_ERR(gdp), "Power good GPIO fault\n");

- data = devm_kzalloc(&pdev->dev, sizeof(struct sy7636a_data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct sy7636a_data), GFP_KERNEL);
if (!data)
return -ENOMEM;

data->regmap = regmap;
data->pgood_gpio = gdp;

- ret = devm_regulator_get_enable_optional(&pdev->dev, "vin");
+ ret = devm_regulator_get_enable_optional(dev, "vin");
if (ret)
- return dev_err_probe(&pdev->dev, ret,
+ return dev_err_probe(dev, ret,
"failed to get vin regulator\n");

- data->en_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
+ data->en_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_HIGH);
if (IS_ERR(data->en_gpio))
- return dev_err_probe(&pdev->dev,
+ return dev_err_probe(dev,
PTR_ERR(data->en_gpio),
"failed to get en gpio\n");

- data->vcom_en_gpio = devm_gpiod_get_optional(&pdev->dev,
+ data->vcom_en_gpio = devm_gpiod_get_optional(dev,
"vcom-en", GPIOD_OUT_LOW);
if (IS_ERR(data->vcom_en_gpio))
- return dev_err_probe(&pdev->dev,
+ return dev_err_probe(dev,
PTR_ERR(data->vcom_en_gpio),
"failed to get vcom-en gpio\n");

@@ -244,25 +256,24 @@ static int sy7636a_regulator_probe(struct platform_device *pdev)
if (data->en_gpio)
usleep_range(2500, 4000);

- platform_set_drvdata(pdev, data);
+ i2c_set_clientdata(client, data);

ret = regmap_write(regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0);
if (ret) {
- dev_err(pdev->dev.parent, "Failed to initialize regulator: %d\n", ret);
+ dev_err(dev, "Failed to initialize regulator: %d\n", ret);
return ret;
}

irq = gpiod_to_irq(data->pgood_gpio);
if (irq < 0)
- return dev_err_probe(&pdev->dev, irq, "no power good interrupt\n");
+ return dev_err_probe(dev, irq, "no power good interrupt\n");

init_completion(&data->pgood_completion);
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, sy7636a_pgood_handler,
+ ret = devm_request_threaded_irq(dev, irq, NULL, sy7636a_pgood_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"sy7636a-pgood", data);
if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "failed to request power good interrupt\n");
+ return dev_err_probe(dev, ret, "failed to request power good interrupt\n");

/* VCOM switched by the VCOM_EN line; otherwise it follows the power on sequence */
if (data->vcom_en_gpio) {
@@ -272,43 +283,42 @@ static int sy7636a_regulator_probe(struct platform_device *pdev)
return ret;
}

- config.dev = &pdev->dev;
+ config.dev = dev;
config.regmap = regmap;

- rdev = devm_regulator_register(&pdev->dev, &desc, &config);
+ rdev = devm_regulator_register(dev, &desc, &config);
if (IS_ERR(rdev)) {
- dev_err(pdev->dev.parent, "Failed to register %s regulator\n",
- pdev->name);
+ dev_err(dev, "Failed to register %s regulator\n", desc.name);
return PTR_ERR(rdev);
}

if (IS_REACHABLE(CONFIG_HWMON)) {
struct device *hwmon_dev;

- hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "sy7636a", data,
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, "sy7636a", data,
&sy7636a_hwmon_chip_info, NULL);
if (IS_ERR(hwmon_dev))
- dev_notice(&pdev->dev, "failed to register hwmon\n");
+ dev_notice(dev, "failed to register hwmon\n");
}

return 0;
}

-static const struct platform_device_id sy7636a_regulator_id_table[] = {
- { .name = "sy7636a-regulator" },
+static const struct of_device_id sy7636a_of_match[] = {
+ { .compatible = "silergy,sy7636a" },
{ }
};
-MODULE_DEVICE_TABLE(platform, sy7636a_regulator_id_table);
+MODULE_DEVICE_TABLE(of, sy7636a_of_match);

-static struct platform_driver sy7636a_regulator_driver = {
+static struct i2c_driver sy7636a_regulator_driver = {
.driver = {
.name = "sy7636a-regulator",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = sy7636a_of_match,
},
.probe = sy7636a_regulator_probe,
- .id_table = sy7636a_regulator_id_table,
};
-module_platform_driver(sy7636a_regulator_driver);
+module_i2c_driver(sy7636a_regulator_driver);

MODULE_AUTHOR("Lars Ivar Miljeteig <lars.ivar.miljeteig@xxxxxxxxxxxxxx>");
MODULE_DESCRIPTION("SY7636A voltage regulator driver");
diff --git a/include/linux/mfd/sy7636a.h b/include/linux/mfd/sy7636a.h
deleted file mode 100644
index 22f03b2f851e..000000000000
--- a/include/linux/mfd/sy7636a.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Functions to access SY3686A power management chip.
- *
- * Copyright (C) 2021 reMarkable AS - http://www.remarkable.com/
- */
-
-#ifndef __MFD_SY7636A_H
-#define __MFD_SY7636A_H
-
-#define SY7636A_REG_OPERATION_MODE_CRL 0x00
-/* It is set if a gpio is used to control the regulator */
-#define SY7636A_OPERATION_MODE_CRL_VCOMCTL BIT(6)
-#define SY7636A_OPERATION_MODE_CRL_ONOFF BIT(7)
-#define SY7636A_REG_VCOM_ADJUST_CTRL_L 0x01
-#define SY7636A_REG_VCOM_ADJUST_CTRL_H 0x02
-#define SY7636A_REG_VCOM_ADJUST_CTRL_MASK 0x01ff
-#define SY7636A_REG_VLDO_VOLTAGE_ADJULST_CTRL 0x03
-#define SY7636A_REG_POWER_ON_DELAY_TIME 0x06
-#define SY7636A_REG_FAULT_FLAG 0x07
-#define SY7636A_FAULT_FLAG_PG BIT(0)
-#define SY7636A_REG_TERMISTOR_READOUT 0x08
-
-#define SY7636A_REG_MAX 0x08
-
-#define VCOM_ADJUST_CTRL_MASK 0x1ff
-// Used to shift the high byte
-#define VCOM_ADJUST_CTRL_SHIFT 8
-// Used to scale from VCOM_ADJUST_CTRL to mv
-#define VCOM_ADJUST_CTRL_SCAL 10000
-
-#define FAULT_FLAG_SHIFT 1
-
-#endif /* __LINUX_MFD_SY7636A_H */
--
2.52.0