From: Alexander Shiyan <eagle.alexander923@gmail.com>
To: barebox@lists.infradead.org
Cc: Alexander Shiyan <eagle.alexander923@gmail.com>
Subject: [PATCH] regulator: Add Fairchild FAN53555 driver
Date: Fri, 21 Jun 2024 08:18:06 +0300 [thread overview]
Message-ID: <20240621051806.5660-1-eagle.alexander923@gmail.com> (raw)
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@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@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
next reply other threads:[~2024-06-21 5:19 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-21 5:18 Alexander Shiyan [this message]
2024-07-01 13:03 ` Sascha Hauer
2024-07-01 13:08 ` Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240621051806.5660-1-eagle.alexander923@gmail.com \
--to=eagle.alexander923@gmail.com \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox