[PATCH] regulator: Add Fairchild FAN53555 driver

Alexander Shiyan eagle.alexander923 at gmail.com
Thu Jun 20 22:18:06 PDT 2024


This driver supports Fairchild FAN53555 Digitally Programmable TinyBuck Regulator.

Supported ICs:
fan53526, fan53555, rk8600, rk8602, syr827, syr828, tcs4525, tcs4526.

The driver is written based on the fan53555.c linux kernel driver.
Widely used in new developments based on Rockchip SOCs RK35xx.

Signed-off-by: Alexander Shiyan <eagle.alexander923 at gmail.com>
---
 drivers/regulator/Kconfig    |  11 +
 drivers/regulator/Makefile   |   1 +
 drivers/regulator/fan53555.c | 481 +++++++++++++++++++++++++++++++++++
 3 files changed, 493 insertions(+)
 create mode 100644 drivers/regulator/fan53555.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 17e217f0bb..54f27e1824 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -17,6 +17,17 @@ config REGULATOR_BCM283X
 	depends on ARCH_BCM283X
 	default y
 
+config REGULATOR_FAN53555
+	bool "Fairchild FAN53555 Regulator"
+	depends on I2C
+	depends on OFDEVICE
+	help
+	  This driver supports Fairchild FAN53555 Digitally Programmable
+	  TinyBuck Regulator. The FAN53555 is a step-down switching voltage
+	  regulator that delivers a digitally programmable output from an
+	  input voltage supply of 2.5V to 5.5V. The output voltage is
+	  programmed through an I2C interface.
+
 config REGULATOR_PFUZE
 	bool "Freescale PFUZE100/200/3000 regulator driver"
 	depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 95e42719d1..54ab6ef650 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_REGULATOR) += core.o helpers.o
 obj-$(CONFIG_OFDEVICE) += of_regulator.o
+obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
 obj-$(CONFIG_REGULATOR_FIXED) += fixed.o
 obj-$(CONFIG_REGULATOR_BCM283X) += bcm2835.o
 obj-$(CONFIG_REGULATOR_PFUZE) += pfuze.o
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
new file mode 100644
index 0000000000..9573dae803
--- /dev/null
+++ b/drivers/regulator/fan53555.c
@@ -0,0 +1,481 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// FAN53555 Fairchild Digitally Programmable TinyBuck Regulator Driver.
+//
+// Based on fan53555.c linux kernel driver:
+// Copyright (c) 2012 Marvell Technology Ltd.
+// Yunfan Zhang <yfzhang at marvell.com>
+
+#include <common.h>
+#include <driver.h>
+#include <of_device.h>
+#include <regulator.h>
+#include <i2c/i2c.h>
+#include <linux/regmap.h>
+
+#define FAN53555_VSEL0		(0x00)
+#define FAN53555_VSEL1		(0x01)
+# define VSEL_MODE		BIT(6)
+# define VSEL_BUCK_EN		BIT(7)
+#define FAN53555_CONTROL	(0x02)
+# define CTL_MODE_VSEL0_MODE	BIT(0)
+# define CTL_MODE_VSEL1_MODE	BIT(1)
+#define FAN53555_ID1		(0x03)
+# define DIE_ID			(0x0f)
+#define FAN53555_ID2		(0x04)
+# define DIE_REV		(0x0f)
+
+#define RK8602_VSEL0		(0x06)
+#define RK8602_VSEL1		(0x07)
+
+#define TCS4525_VSEL1		(0x10)
+#define TCS4525_VSEL0		(0x11)
+#define TCS4525_COMMAND		(0x14)
+# define TCS_VSEL1_MODE		BIT(6)
+# define TCS_VSEL0_MODE		BIT(7)
+
+#define FAN53555_NVOLTAGES	64
+#define FAN53526_NVOLTAGES	128
+#define RK8602_NVOLTAGES	160
+
+enum {
+	FAN53555_VSEL_ID_0 = 0,
+	FAN53555_VSEL_ID_1,
+};
+
+enum fan53555_vendor {
+	FAN53526_VENDOR_FAIRCHILD = 0,
+	FAN53555_VENDOR_FAIRCHILD,
+	FAN53555_VENDOR_ROCKCHIP,	/* RK8600, RK8601 */
+	RK8602_VENDOR_ROCKCHIP,		/* RK8602, RK8603 */
+	FAN53555_VENDOR_SILERGY,
+	FAN53526_VENDOR_TCS,
+};
+
+enum {
+	FAN53526_CHIP_ID_01 = 1,
+};
+
+enum {
+	FAN53526_CHIP_REV_08 = 8,
+};
+
+enum {
+	FAN53555_CHIP_ID_00 = 0,
+	FAN53555_CHIP_ID_01,
+	FAN53555_CHIP_ID_02,
+	FAN53555_CHIP_ID_03,
+	FAN53555_CHIP_ID_04,
+	FAN53555_CHIP_ID_05,
+	FAN53555_CHIP_ID_08 = 8,
+};
+
+enum {
+	RK8600_CHIP_ID_08 = 8,		/* RK8600, RK8601 */
+};
+
+enum {
+	RK8602_CHIP_ID_10 = 10,		/* RK8602, RK8603 */
+};
+
+enum {
+	TCS4525_CHIP_ID_12 = 12,
+};
+
+enum {
+	TCS4526_CHIP_ID_00 = 0,
+};
+
+enum {
+	FAN53555_CHIP_REV_00 = 0x3,
+	FAN53555_CHIP_REV_13 = 0xf,
+};
+
+enum {
+	SILERGY_SYR82X = 8,
+	SILERGY_SYR83X = 9,
+};
+
+struct fan53555_device_info {
+	enum fan53555_vendor vendor;
+	struct device *dev;
+	struct regulator_dev rdev;
+	struct regulator_desc rdesc;
+	int chip_id;
+	int chip_rev;
+	unsigned int sleep_vsel_id;
+};
+
+static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di)
+{
+	switch (di->chip_id) {
+	case FAN53526_CHIP_ID_01:
+		switch (di->chip_rev) {
+		case FAN53526_CHIP_REV_08:
+			di->rdesc.min_uV = 600000;
+			di->rdesc.uV_step = 6250;
+			di->rdesc.n_voltages = FAN53526_NVOLTAGES;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
+{
+	switch (di->chip_id) {
+	case FAN53555_CHIP_ID_00:
+		switch (di->chip_rev) {
+		case FAN53555_CHIP_REV_00:
+			di->rdesc.min_uV = 600000;
+			di->rdesc.uV_step = 10000;
+			break;
+		case FAN53555_CHIP_REV_13:
+			di->rdesc.min_uV = 800000;
+			di->rdesc.uV_step = 10000;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case FAN53555_CHIP_ID_01:
+	case FAN53555_CHIP_ID_03:
+	case FAN53555_CHIP_ID_05:
+	case FAN53555_CHIP_ID_08:
+		di->rdesc.min_uV = 600000;
+		di->rdesc.uV_step = 10000;
+		break;
+	case FAN53555_CHIP_ID_04:
+		di->rdesc.min_uV = 603000;
+		di->rdesc.uV_step = 12826;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	di->rdesc.n_voltages = FAN53555_NVOLTAGES;
+
+	return 0;
+}
+
+static int fan53555_voltages_setup_rockchip(struct fan53555_device_info *di)
+{
+	switch (di->chip_id) {
+	case RK8600_CHIP_ID_08:
+		di->rdesc.min_uV = 712500;
+		di->rdesc.uV_step = 12500;
+		di->rdesc.n_voltages = FAN53555_NVOLTAGES;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rk8602_voltages_setup_rockchip(struct fan53555_device_info *di)
+{
+	switch (di->chip_id) {
+	case RK8602_CHIP_ID_10:
+		di->rdesc.min_uV = 500000;
+		di->rdesc.uV_step = 6250;
+		di->rdesc.n_voltages = RK8602_NVOLTAGES;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
+{
+	switch (di->chip_id) {
+	case SILERGY_SYR82X:
+	case SILERGY_SYR83X:
+		di->rdesc.min_uV = 712500;
+		di->rdesc.uV_step = 12500;
+		di->rdesc.n_voltages = FAN53555_NVOLTAGES;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fan53526_voltages_setup_tcs(struct fan53555_device_info *di)
+{
+	switch (di->chip_id) {
+	case TCS4525_CHIP_ID_12:
+	case TCS4526_CHIP_ID_00:
+		di->rdesc.min_uV = 600000;
+		di->rdesc.uV_step = 6250;
+		di->rdesc.n_voltages = FAN53526_NVOLTAGES;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct regulator_ops fan53555_regulator_ops = {
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.map_voltage = regulator_map_voltage_linear,
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+};
+
+static int fan53555_device_setup(struct fan53555_device_info *di)
+{
+	unsigned int mode_reg, mode_mask;
+	int ret = 0;
+
+	/* Setup voltage control register */
+	switch (di->vendor) {
+	case FAN53526_VENDOR_FAIRCHILD:
+	case FAN53555_VENDOR_FAIRCHILD:
+	case FAN53555_VENDOR_ROCKCHIP:
+	case FAN53555_VENDOR_SILERGY:
+		switch (di->sleep_vsel_id) {
+		case FAN53555_VSEL_ID_0:
+			di->rdesc.vsel_reg = FAN53555_VSEL1;
+			break;
+		case FAN53555_VSEL_ID_1:
+			di->rdesc.vsel_reg = FAN53555_VSEL0;
+			break;
+		}
+		di->rdesc.enable_reg = di->rdesc.vsel_reg;
+		break;
+	case RK8602_VENDOR_ROCKCHIP:
+		switch (di->sleep_vsel_id) {
+		case FAN53555_VSEL_ID_0:
+			di->rdesc.vsel_reg = RK8602_VSEL1;
+			di->rdesc.enable_reg = FAN53555_VSEL1;
+			break;
+		case FAN53555_VSEL_ID_1:
+			di->rdesc.vsel_reg = RK8602_VSEL0;
+			di->rdesc.enable_reg = FAN53555_VSEL0;
+			break;
+		}
+		break;
+	case FAN53526_VENDOR_TCS:
+		switch (di->sleep_vsel_id) {
+		case FAN53555_VSEL_ID_0:
+			di->rdesc.vsel_reg = TCS4525_VSEL1;
+			break;
+		case FAN53555_VSEL_ID_1:
+			di->rdesc.vsel_reg = TCS4525_VSEL0;
+			break;
+		}
+		di->rdesc.enable_reg = di->rdesc.vsel_reg;
+		break;
+	default:
+		dev_err(di->dev, "Vendor %d not supported!\n", di->vendor);
+		return -EINVAL;
+	}
+
+	/* Setup mode control register */
+	switch (di->vendor) {
+	case FAN53526_VENDOR_FAIRCHILD:
+		mode_reg = FAN53555_CONTROL;
+
+		switch (di->sleep_vsel_id) {
+		case FAN53555_VSEL_ID_0:
+			mode_mask = CTL_MODE_VSEL1_MODE;
+			break;
+		case FAN53555_VSEL_ID_1:
+			mode_mask = CTL_MODE_VSEL0_MODE;
+			break;
+		}
+		break;
+	case FAN53555_VENDOR_FAIRCHILD:
+	case FAN53555_VENDOR_ROCKCHIP:
+	case FAN53555_VENDOR_SILERGY:
+		mode_reg = di->rdesc.vsel_reg;
+		mode_mask = VSEL_MODE;
+		break;
+	case RK8602_VENDOR_ROCKCHIP:
+		mode_mask = VSEL_MODE;
+
+		switch (di->sleep_vsel_id) {
+		case FAN53555_VSEL_ID_0:
+			mode_reg = FAN53555_VSEL1;
+			break;
+		case FAN53555_VSEL_ID_1:
+			mode_reg = FAN53555_VSEL0;
+			break;
+		}
+		break;
+	case FAN53526_VENDOR_TCS:
+		mode_reg = TCS4525_COMMAND;
+
+		switch (di->sleep_vsel_id) {
+		case FAN53555_VSEL_ID_0:
+			mode_mask = TCS_VSEL1_MODE;
+			break;
+		case FAN53555_VSEL_ID_1:
+			mode_mask = TCS_VSEL0_MODE;
+			break;
+		}
+		break;
+	}
+
+	/* Setup voltage range */
+	switch (di->vendor) {
+	case FAN53526_VENDOR_FAIRCHILD:
+		ret = fan53526_voltages_setup_fairchild(di);
+		break;
+	case FAN53555_VENDOR_FAIRCHILD:
+		ret = fan53555_voltages_setup_fairchild(di);
+		break;
+	case FAN53555_VENDOR_ROCKCHIP:
+		ret = fan53555_voltages_setup_rockchip(di);
+		break;
+	case RK8602_VENDOR_ROCKCHIP:
+		ret = rk8602_voltages_setup_rockchip(di);
+		break;
+	case FAN53555_VENDOR_SILERGY:
+		ret = fan53555_voltages_setup_silergy(di);
+		break;
+	case FAN53526_VENDOR_TCS:
+		ret = fan53526_voltages_setup_tcs(di);
+		break;
+	}
+	if (!ret) {
+		di->rdesc.supply_name = "vin";
+		di->rdesc.ops = &fan53555_regulator_ops;
+		di->rdesc.vsel_mask = BIT(fls(di->rdesc.n_voltages - 1)) - 1;
+		di->rdesc.enable_mask = VSEL_BUCK_EN;
+
+		/* REGULATOR_MODE_NORMAL */
+		regmap_update_bits(di->rdev.regmap, mode_reg, mode_mask, 0);
+	} else
+		dev_err(di->dev, "Chip ID %d with rev %d not supported!\n",
+			di->chip_id, di->chip_rev);
+
+	return ret;
+}
+
+static const struct regmap_config fan53555_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int fan53555_regulator_probe(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct device_node *np = client->dev.of_node;
+	struct fan53555_device_info *di;
+	unsigned int val;
+	int ret;
+
+	di = xzalloc(sizeof(*di));
+
+	di->vendor = (enum fan53555_vendor)device_get_match_data(dev);
+
+	di->rdev.desc = &di->rdesc;
+	di->rdev.dev = dev;
+
+	di->rdev.regmap = regmap_init_i2c(client, &fan53555_regmap_config);
+	if (IS_ERR(di->rdev.regmap)) {
+		ret = PTR_ERR(di->rdev.regmap);
+		goto err;
+	}
+
+	di->dev = &client->dev;
+
+	/* Get chip ID */
+	ret = regmap_read(di->rdev.regmap, FAN53555_ID1, &val);
+	if (ret < 0) {
+		dev_err(di->dev, "Failed to get chip ID!\n");
+		goto err;
+	}
+
+	di->chip_id = val & DIE_ID;
+
+	/* Get chip revision */
+	ret = regmap_read(di->rdev.regmap, FAN53555_ID2, &val);
+	if (ret < 0) {
+		dev_err(di->dev, "Failed to get chip Rev!\n");
+		goto err;
+	}
+
+	di->chip_rev = val & DIE_REV;
+
+	ret = of_property_read_u32(np, "fcs,suspend-voltage-selector", &val);
+	if (!ret) {
+		if (val >> 1) {
+			dev_err(di->dev, "Invalid VSEL ID=%u!\n", val);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		di->sleep_vsel_id = val;
+	}
+
+	ret = fan53555_device_setup(di);
+	if (ret < 0)
+		goto err;
+
+	ret = of_regulator_register(&di->rdev, np);
+	if (!ret) {
+		dev_info(di->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n",
+			 di->chip_id, di->chip_rev);
+		return 0;
+	}
+
+	dev_err(di->dev, "Failed to register regulator!\n");
+
+err:
+	free(di);
+
+	return ret;
+}
+
+static const struct of_device_id __maybe_unused fan53555_dt_ids[] = {
+	{
+		.compatible = "fcs,fan53526",
+		.data = (void *)FAN53526_VENDOR_FAIRCHILD,
+	}, {
+		.compatible = "fcs,fan53555",
+		.data = (void *)FAN53555_VENDOR_FAIRCHILD
+	}, {
+		.compatible = "rockchip,rk8600",
+		.data = (void *)FAN53555_VENDOR_ROCKCHIP
+	}, {
+		.compatible = "rockchip,rk8602",
+		.data = (void *)RK8602_VENDOR_ROCKCHIP
+	}, {
+		.compatible = "silergy,syr827",
+		.data = (void *)FAN53555_VENDOR_SILERGY,
+	}, {
+		.compatible = "silergy,syr828",
+		.data = (void *)FAN53555_VENDOR_SILERGY,
+	}, {
+		.compatible = "tcs,tcs4525",
+		.data = (void *)FAN53526_VENDOR_TCS
+	}, {
+		.compatible = "tcs,tcs4526",
+		.data = (void *)FAN53526_VENDOR_TCS
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, fan53555_dt_ids);
+
+static struct driver fan53555_regulator_driver = {
+	.name		= "fan53555-regulator",
+	.probe		= fan53555_regulator_probe,
+	.of_compatible	= fan53555_dt_ids,
+};
+device_i2c_driver(fan53555_regulator_driver);
-- 
2.39.1




More information about the barebox mailing list