xref: /linux/drivers/regulator/sgm3804-regulator.c (revision b3438e5ca785565a65ef231bc03cd5a05c3be5c7)
10c47e1a8SKancyJoe // SPDX-License-Identifier: GPL-2.0-only
20c47e1a8SKancyJoe //
30c47e1a8SKancyJoe // SGMicro SGM3804 regulator Driver
40c47e1a8SKancyJoe //
50c47e1a8SKancyJoe // Copyright (C) 2025 Kancy Joe <kancy2333@outlook.com>
60c47e1a8SKancyJoe // Copyright (C) 2026 Linaro Limited
70c47e1a8SKancyJoe // Author: Neil Armstrong <neil.armstrong@linaro.org>
80c47e1a8SKancyJoe 
90c47e1a8SKancyJoe #include <linux/err.h>
100c47e1a8SKancyJoe #include <linux/i2c.h>
110c47e1a8SKancyJoe #include <linux/module.h>
120c47e1a8SKancyJoe #include <linux/regmap.h>
130c47e1a8SKancyJoe #include <linux/regulator/driver.h>
140c47e1a8SKancyJoe #include <linux/regulator/of_regulator.h>
150c47e1a8SKancyJoe #include <linux/gpio/consumer.h>
160c47e1a8SKancyJoe 
170c47e1a8SKancyJoe #define SGM3804_POS_RAIL_VOLTAGE_REG	0x0
180c47e1a8SKancyJoe #define SGM3804_NEG_RAIL_VOLTAGE_REG	0x1
190c47e1a8SKancyJoe #define SGM3804_RAIL_DISCHARGE_REG	0x3
200c47e1a8SKancyJoe 
210c47e1a8SKancyJoe #define RAIL_VOLTAGE_MASK	GENMASK(5, 0)
220c47e1a8SKancyJoe 
230c47e1a8SKancyJoe #define POS_RAIL_DISCHARGE_EN	BIT(1)
240c47e1a8SKancyJoe #define NEG_RAIL_DISCHARGE_EN	BIT(0)
250c47e1a8SKancyJoe 
260c47e1a8SKancyJoe #define RAIL_VOLTAGE_INVALID		RAIL_VOLTAGE_MASK
270c47e1a8SKancyJoe #define RAIL_DISCHARGE_REG_DEFAULT	(POS_RAIL_DISCHARGE_EN | NEG_RAIL_DISCHARGE_EN)
280c47e1a8SKancyJoe 
290c47e1a8SKancyJoe #define SGM3804_VOLTAGES_MAX_SELECTOR	0x2f
300c47e1a8SKancyJoe 
310c47e1a8SKancyJoe enum {
320c47e1a8SKancyJoe 	SGM3804_POS_RAIL = 0,
330c47e1a8SKancyJoe 	SGM3804_NEG_RAIL,
340c47e1a8SKancyJoe 	SGM3804_RAIL_COUNT,
350c47e1a8SKancyJoe };
360c47e1a8SKancyJoe 
370c47e1a8SKancyJoe /*
380c47e1a8SKancyJoe  * The registers are only writable when the gpio is enabled, so
390c47e1a8SKancyJoe  * we need to use the cache for read operations and set the regmap
400c47e1a8SKancyJoe  * as cache_only when both GPIOs are down.
410c47e1a8SKancyJoe  */
420c47e1a8SKancyJoe struct sgm3804_data {
430c47e1a8SKancyJoe 	struct regmap *regmap;
440c47e1a8SKancyJoe 	/* Protects the regcache state update */
450c47e1a8SKancyJoe 	struct mutex lock;
460c47e1a8SKancyJoe 	struct gpio_desc *gpios[SGM3804_RAIL_COUNT];
470c47e1a8SKancyJoe };
480c47e1a8SKancyJoe 
490c47e1a8SKancyJoe static const struct linear_range sgm3804_voltages[] = {
500c47e1a8SKancyJoe 	REGULATOR_LINEAR_RANGE(2400000, 0x20, 0x2f, 100000),
510c47e1a8SKancyJoe 	REGULATOR_LINEAR_RANGE(4000000, 0x00, 0x17, 100000),
520c47e1a8SKancyJoe };
530c47e1a8SKancyJoe 
540c47e1a8SKancyJoe /*
550c47e1a8SKancyJoe  * The cache is populated with those hardware default values
560c47e1a8SKancyJoe  * so the regmap_update_bits operation will use the cached
570c47e1a8SKancyJoe  * value to build a new register value and write it when GPIOs
580c47e1a8SKancyJoe  * are enabled.
590c47e1a8SKancyJoe  */
600c47e1a8SKancyJoe static const struct reg_default sgm3804_reg_defaults[] = {
610c47e1a8SKancyJoe 	{ SGM3804_POS_RAIL_VOLTAGE_REG, RAIL_VOLTAGE_INVALID },
620c47e1a8SKancyJoe 	{ SGM3804_NEG_RAIL_VOLTAGE_REG, RAIL_VOLTAGE_INVALID },
630c47e1a8SKancyJoe 	{ SGM3804_RAIL_DISCHARGE_REG, RAIL_DISCHARGE_REG_DEFAULT },
640c47e1a8SKancyJoe };
650c47e1a8SKancyJoe 
660c47e1a8SKancyJoe /* Registers are only writable */
670c47e1a8SKancyJoe static bool sgm3804_writeable_reg(struct device *dev, unsigned int reg)
680c47e1a8SKancyJoe {
690c47e1a8SKancyJoe 	switch (reg) {
700c47e1a8SKancyJoe 	case SGM3804_POS_RAIL_VOLTAGE_REG:
710c47e1a8SKancyJoe 	case SGM3804_NEG_RAIL_VOLTAGE_REG:
720c47e1a8SKancyJoe 	case SGM3804_RAIL_DISCHARGE_REG:
730c47e1a8SKancyJoe 		return true;
740c47e1a8SKancyJoe 	default:
750c47e1a8SKancyJoe 		return false;
760c47e1a8SKancyJoe 	}
770c47e1a8SKancyJoe }
780c47e1a8SKancyJoe 
790c47e1a8SKancyJoe /*
800c47e1a8SKancyJoe  * Since all registers are only writeable, regmap will only read from the cache data.
810c47e1a8SKancyJoe  */
820c47e1a8SKancyJoe static bool sgm3804_readable_reg(struct device *dev, unsigned int reg)
830c47e1a8SKancyJoe {
840c47e1a8SKancyJoe 	return false;
850c47e1a8SKancyJoe }
860c47e1a8SKancyJoe 
870c47e1a8SKancyJoe static const struct regmap_config sgm3804_regmap_config = {
880c47e1a8SKancyJoe 	.reg_bits = 8,
890c47e1a8SKancyJoe 	.val_bits = 8,
900c47e1a8SKancyJoe 	.max_register = 0x03,
910c47e1a8SKancyJoe 	.writeable_reg = sgm3804_writeable_reg,
920c47e1a8SKancyJoe 	.readable_reg = sgm3804_readable_reg,
930c47e1a8SKancyJoe 	.cache_type = REGCACHE_MAPLE,
940c47e1a8SKancyJoe 	.reg_defaults = sgm3804_reg_defaults,
950c47e1a8SKancyJoe 	.num_reg_defaults = ARRAY_SIZE(sgm3804_reg_defaults),
960c47e1a8SKancyJoe };
970c47e1a8SKancyJoe 
980c47e1a8SKancyJoe static int sgm3804_sync_regcache_state(struct sgm3804_data *ctx)
990c47e1a8SKancyJoe {
1000c47e1a8SKancyJoe 	guard(mutex)(&ctx->lock);
1010c47e1a8SKancyJoe 
1020c47e1a8SKancyJoe 	/* If both GPIOs are down, IC is powered down and I2C writes will fail */
1030c47e1a8SKancyJoe 	if (!gpiod_get_value_cansleep(ctx->gpios[SGM3804_POS_RAIL]) &&
1040c47e1a8SKancyJoe 	    !gpiod_get_value_cansleep(ctx->gpios[SGM3804_NEG_RAIL])) {
1050c47e1a8SKancyJoe 		regcache_cache_only(ctx->regmap, true);
1060c47e1a8SKancyJoe 		regcache_mark_dirty(ctx->regmap);
1070c47e1a8SKancyJoe 	} else {
1080c47e1a8SKancyJoe 		int ret;
1090c47e1a8SKancyJoe 
1100c47e1a8SKancyJoe 		/* At least a GPIO is up, we can write registers */
1110c47e1a8SKancyJoe 		regcache_cache_only(ctx->regmap, false);
1120c47e1a8SKancyJoe 		ret = regcache_sync(ctx->regmap);
1130c47e1a8SKancyJoe 		if (ret) {
1140c47e1a8SKancyJoe 			regcache_cache_only(ctx->regmap, true);
1150c47e1a8SKancyJoe 			return ret;
1160c47e1a8SKancyJoe 		}
1170c47e1a8SKancyJoe 	}
1180c47e1a8SKancyJoe 
1190c47e1a8SKancyJoe 	return 0;
1200c47e1a8SKancyJoe }
1210c47e1a8SKancyJoe 
1220c47e1a8SKancyJoe static int sgm3804_get_voltage_sel(struct regulator_dev *rdev)
1230c47e1a8SKancyJoe {
1240c47e1a8SKancyJoe 	int ret;
1250c47e1a8SKancyJoe 
1260c47e1a8SKancyJoe 	ret = regulator_get_voltage_sel_regmap(rdev);
1270c47e1a8SKancyJoe 	if (ret < 0)
1280c47e1a8SKancyJoe 		return ret;
1290c47e1a8SKancyJoe 
1300c47e1a8SKancyJoe 	/* Force setting a voltage on probe */
1310c47e1a8SKancyJoe 	if (ret == RAIL_VOLTAGE_INVALID)
1320c47e1a8SKancyJoe 		return -ENOTRECOVERABLE;
1330c47e1a8SKancyJoe 
1340c47e1a8SKancyJoe 	return ret;
1350c47e1a8SKancyJoe }
1360c47e1a8SKancyJoe 
1370c47e1a8SKancyJoe static int sgm3804_enable(struct regulator_dev *rdev)
1380c47e1a8SKancyJoe {
1390c47e1a8SKancyJoe 	struct sgm3804_data *ctx = rdev->reg_data;
1400c47e1a8SKancyJoe 	int ret;
1410c47e1a8SKancyJoe 
1420c47e1a8SKancyJoe 	ret = gpiod_set_value_cansleep(ctx->gpios[rdev_get_id(rdev)], 1);
1430c47e1a8SKancyJoe 	if (ret)
1440c47e1a8SKancyJoe 		return ret;
1450c47e1a8SKancyJoe 
1460c47e1a8SKancyJoe 	ret = sgm3804_sync_regcache_state(ctx);
1470c47e1a8SKancyJoe 	if (ret)
1480c47e1a8SKancyJoe 		goto err;
1490c47e1a8SKancyJoe 
1500c47e1a8SKancyJoe 	return 0;
1510c47e1a8SKancyJoe 
1520c47e1a8SKancyJoe err:
1530c47e1a8SKancyJoe 	gpiod_set_value_cansleep(ctx->gpios[rdev_get_id(rdev)], 0);
1540c47e1a8SKancyJoe 	return ret;
1550c47e1a8SKancyJoe }
1560c47e1a8SKancyJoe 
1570c47e1a8SKancyJoe static int sgm3804_disable(struct regulator_dev *rdev)
1580c47e1a8SKancyJoe {
1590c47e1a8SKancyJoe 	struct sgm3804_data *ctx = rdev->reg_data;
1600c47e1a8SKancyJoe 	int ret;
1610c47e1a8SKancyJoe 
1620c47e1a8SKancyJoe 	ret = gpiod_set_value_cansleep(ctx->gpios[rdev_get_id(rdev)], 0);
1630c47e1a8SKancyJoe 	if (ret)
1640c47e1a8SKancyJoe 		return ret;
1650c47e1a8SKancyJoe 
1660c47e1a8SKancyJoe 	return sgm3804_sync_regcache_state(ctx);
1670c47e1a8SKancyJoe }
1680c47e1a8SKancyJoe 
1690c47e1a8SKancyJoe static int sgm3804_is_enabled(struct regulator_dev *rdev)
1700c47e1a8SKancyJoe {
1710c47e1a8SKancyJoe 	struct sgm3804_data *ctx = rdev->reg_data;
1720c47e1a8SKancyJoe 
1730c47e1a8SKancyJoe 	return gpiod_get_value_cansleep(ctx->gpios[rdev_get_id(rdev)]);
1740c47e1a8SKancyJoe }
1750c47e1a8SKancyJoe 
1760c47e1a8SKancyJoe static const struct regulator_ops sgm3804_ops = {
1770c47e1a8SKancyJoe 	.list_voltage = regulator_list_voltage_linear_range,
1780c47e1a8SKancyJoe 	.map_voltage = regulator_map_voltage_linear_range,
1790c47e1a8SKancyJoe 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1800c47e1a8SKancyJoe 	.get_voltage_sel = sgm3804_get_voltage_sel,
1810c47e1a8SKancyJoe 	.set_active_discharge = regulator_set_active_discharge_regmap,
1820c47e1a8SKancyJoe 	.enable = sgm3804_enable,
1830c47e1a8SKancyJoe 	.disable = sgm3804_disable,
1840c47e1a8SKancyJoe 	.is_enabled = sgm3804_is_enabled,
1850c47e1a8SKancyJoe };
1860c47e1a8SKancyJoe 
1870c47e1a8SKancyJoe static const struct regulator_desc sgm3804_regulator_desc[] = {
1880c47e1a8SKancyJoe 	/* Positive Output */
1890c47e1a8SKancyJoe 	{
1900c47e1a8SKancyJoe 		.name = "pos",
1910c47e1a8SKancyJoe 		.of_match = "pos",
1920c47e1a8SKancyJoe 		.supply_name = "vin",
1930c47e1a8SKancyJoe 		.id = SGM3804_POS_RAIL,
1940c47e1a8SKancyJoe 		.ops = &sgm3804_ops,
1950c47e1a8SKancyJoe 		.type = REGULATOR_VOLTAGE,
1960c47e1a8SKancyJoe 		.linear_ranges = sgm3804_voltages,
1970c47e1a8SKancyJoe 		.n_linear_ranges = ARRAY_SIZE(sgm3804_voltages),
1980c47e1a8SKancyJoe 		.n_voltages = SGM3804_VOLTAGES_MAX_SELECTOR + 1,
1990c47e1a8SKancyJoe 		.vsel_reg = SGM3804_POS_RAIL_VOLTAGE_REG,
2000c47e1a8SKancyJoe 		.vsel_mask = RAIL_VOLTAGE_MASK,
2010c47e1a8SKancyJoe 		.active_discharge_on = POS_RAIL_DISCHARGE_EN,
2020c47e1a8SKancyJoe 		.active_discharge_mask = POS_RAIL_DISCHARGE_EN,
2030c47e1a8SKancyJoe 		.active_discharge_reg = SGM3804_RAIL_DISCHARGE_REG,
2040c47e1a8SKancyJoe 		.enable_time = 40000,
2050c47e1a8SKancyJoe 		.owner = THIS_MODULE,
2060c47e1a8SKancyJoe 	},
2070c47e1a8SKancyJoe 	/* Negative Output */
2080c47e1a8SKancyJoe 	{
2090c47e1a8SKancyJoe 		.name = "neg",
2100c47e1a8SKancyJoe 		.of_match = "neg",
2110c47e1a8SKancyJoe 		.supply_name = "vin",
2120c47e1a8SKancyJoe 		.id = SGM3804_NEG_RAIL,
2130c47e1a8SKancyJoe 		.ops = &sgm3804_ops,
2140c47e1a8SKancyJoe 		.type = REGULATOR_VOLTAGE,
2150c47e1a8SKancyJoe 		.linear_ranges = sgm3804_voltages,
2160c47e1a8SKancyJoe 		.n_linear_ranges = ARRAY_SIZE(sgm3804_voltages),
2170c47e1a8SKancyJoe 		.n_voltages = SGM3804_VOLTAGES_MAX_SELECTOR + 1,
2180c47e1a8SKancyJoe 		.vsel_reg = SGM3804_NEG_RAIL_VOLTAGE_REG,
2190c47e1a8SKancyJoe 		.vsel_mask = RAIL_VOLTAGE_MASK,
2200c47e1a8SKancyJoe 		.active_discharge_on = NEG_RAIL_DISCHARGE_EN,
2210c47e1a8SKancyJoe 		.active_discharge_mask = NEG_RAIL_DISCHARGE_EN,
2220c47e1a8SKancyJoe 		.active_discharge_reg = SGM3804_RAIL_DISCHARGE_REG,
2230c47e1a8SKancyJoe 		.enable_time = 40000,
2240c47e1a8SKancyJoe 		.owner = THIS_MODULE,
2250c47e1a8SKancyJoe 	},
2260c47e1a8SKancyJoe };
2270c47e1a8SKancyJoe 
2280c47e1a8SKancyJoe static int sgm3804_probe(struct i2c_client *i2c)
2290c47e1a8SKancyJoe {
2300c47e1a8SKancyJoe 	struct device *dev = &i2c->dev;
2310c47e1a8SKancyJoe 	struct sgm3804_data *ctx;
2320c47e1a8SKancyJoe 	int ret, i;
2330c47e1a8SKancyJoe 
2340c47e1a8SKancyJoe 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
2350c47e1a8SKancyJoe 	if (!ctx)
2360c47e1a8SKancyJoe 		return -ENOMEM;
2370c47e1a8SKancyJoe 
2380c47e1a8SKancyJoe 	mutex_init(&ctx->lock);
2390c47e1a8SKancyJoe 
2400c47e1a8SKancyJoe 	ctx->regmap = devm_regmap_init_i2c(i2c, &sgm3804_regmap_config);
2410c47e1a8SKancyJoe 	if (IS_ERR(ctx->regmap))
2420c47e1a8SKancyJoe 		return dev_err_probe(dev, PTR_ERR(ctx->regmap),
2430c47e1a8SKancyJoe 				     "failed to init regmap\n");
2440c47e1a8SKancyJoe 
2450c47e1a8SKancyJoe 	/* Get enable GPIOs */
2460c47e1a8SKancyJoe 	for (i = 0; i < ARRAY_SIZE(sgm3804_regulator_desc); i++) {
2470c47e1a8SKancyJoe 		const struct regulator_desc *reg = &sgm3804_regulator_desc[i];
2480c47e1a8SKancyJoe 		struct fwnode_handle *child;
2490c47e1a8SKancyJoe 
2500c47e1a8SKancyJoe 		child = device_get_named_child_node(dev, reg->of_match);
2510c47e1a8SKancyJoe 		if (!child) {
2520c47e1a8SKancyJoe 			dev_err(dev, "missing child '%s'\n", reg->of_match);
2530c47e1a8SKancyJoe 			return -EINVAL;
2540c47e1a8SKancyJoe 		}
2550c47e1a8SKancyJoe 
2560c47e1a8SKancyJoe 		ctx->gpios[i] = devm_fwnode_gpiod_get(dev, child, "enable",
2570c47e1a8SKancyJoe 						      GPIOD_ASIS, reg->name);
2580c47e1a8SKancyJoe 		fwnode_handle_put(child);
2590c47e1a8SKancyJoe 		if (IS_ERR(ctx->gpios[i]))
2600c47e1a8SKancyJoe 			return dev_err_probe(dev, PTR_ERR(ctx->gpios[i]),
2610c47e1a8SKancyJoe 					     "failed to get '%s' enable GPIO\n",
2620c47e1a8SKancyJoe 					     reg->name);
2630c47e1a8SKancyJoe 	}
2640c47e1a8SKancyJoe 
2650c47e1a8SKancyJoe 	ret = sgm3804_sync_regcache_state(ctx);
2660c47e1a8SKancyJoe 	if (ret)
2670c47e1a8SKancyJoe 		return ret;
2680c47e1a8SKancyJoe 
2690c47e1a8SKancyJoe 	for (i = 0; i < ARRAY_SIZE(sgm3804_regulator_desc); i++) {
2700c47e1a8SKancyJoe 		struct regulator_config config = { };
2710c47e1a8SKancyJoe 		struct regulator_dev *rdev;
2720c47e1a8SKancyJoe 
2730c47e1a8SKancyJoe 		config.dev = dev;
2740c47e1a8SKancyJoe 		config.regmap = ctx->regmap;
2750c47e1a8SKancyJoe 		config.of_node = dev_of_node(dev);
2760c47e1a8SKancyJoe 		config.driver_data = ctx;
2770c47e1a8SKancyJoe 		rdev = devm_regulator_register(dev, &sgm3804_regulator_desc[i],
2780c47e1a8SKancyJoe 					       &config);
2790c47e1a8SKancyJoe 		if (IS_ERR(rdev))
2800c47e1a8SKancyJoe 			return dev_err_probe(dev, PTR_ERR(rdev),
2810c47e1a8SKancyJoe 					     "failed to register regulator %d\n", i);
2820c47e1a8SKancyJoe 	}
2830c47e1a8SKancyJoe 
2840c47e1a8SKancyJoe 	return 0;
2850c47e1a8SKancyJoe }
2860c47e1a8SKancyJoe 
2870c47e1a8SKancyJoe static const struct i2c_device_id sgm3804_id[] = {
288*8e74b2dbSUwe Kleine-König (The Capable Hub) 	{ .name = "sgm3804" },
2890c47e1a8SKancyJoe 	{ }
2900c47e1a8SKancyJoe };
2910c47e1a8SKancyJoe MODULE_DEVICE_TABLE(i2c, sgm3804_id);
2920c47e1a8SKancyJoe 
2930c47e1a8SKancyJoe static const struct of_device_id sgm3804_of_match[] = {
2940c47e1a8SKancyJoe 	{ .compatible = "sgmicro,sgm3804" },
2950c47e1a8SKancyJoe 	{ }
2960c47e1a8SKancyJoe };
2970c47e1a8SKancyJoe MODULE_DEVICE_TABLE(of, sgm3804_of_match);
2980c47e1a8SKancyJoe 
2990c47e1a8SKancyJoe static struct i2c_driver sgm3804_regulator_driver = {
3000c47e1a8SKancyJoe 	.driver = {
3010c47e1a8SKancyJoe 		.name = "sgm3804",
3020c47e1a8SKancyJoe 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
3030c47e1a8SKancyJoe 		.of_match_table = sgm3804_of_match,
3040c47e1a8SKancyJoe 	},
3050c47e1a8SKancyJoe 	.probe = sgm3804_probe,
3060c47e1a8SKancyJoe 	.id_table = sgm3804_id,
3070c47e1a8SKancyJoe };
3080c47e1a8SKancyJoe 
3090c47e1a8SKancyJoe module_i2c_driver(sgm3804_regulator_driver);
3100c47e1a8SKancyJoe 
3110c47e1a8SKancyJoe MODULE_DESCRIPTION("SGMicro SGM3804 regulator Driver");
3120c47e1a8SKancyJoe MODULE_AUTHOR("Kancy Joe <kancy2333@outlook.com>");
3130c47e1a8SKancyJoe MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
3140c47e1a8SKancyJoe MODULE_LICENSE("GPL");
315