xref: /linux/drivers/regulator/s2dos05-regulator.c (revision bb2441402392ef1f49563be68e8f0dcb127ac965)
1*bb244140SDzmitry Sankouski // SPDX-License-Identifier: GPL-2.0+
2*bb244140SDzmitry Sankouski //
3*bb244140SDzmitry Sankouski // s2dos05.c - Regulator driver for the Samsung s2dos05
4*bb244140SDzmitry Sankouski //
5*bb244140SDzmitry Sankouski // Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com>
6*bb244140SDzmitry Sankouski 
7*bb244140SDzmitry Sankouski #include <linux/bug.h>
8*bb244140SDzmitry Sankouski #include <linux/delay.h>
9*bb244140SDzmitry Sankouski #include <linux/err.h>
10*bb244140SDzmitry Sankouski #include <linux/slab.h>
11*bb244140SDzmitry Sankouski #include <linux/module.h>
12*bb244140SDzmitry Sankouski #include <linux/regmap.h>
13*bb244140SDzmitry Sankouski #include <linux/interrupt.h>
14*bb244140SDzmitry Sankouski #include <linux/platform_device.h>
15*bb244140SDzmitry Sankouski #include <linux/regulator/driver.h>
16*bb244140SDzmitry Sankouski #include <linux/regulator/machine.h>
17*bb244140SDzmitry Sankouski #include <linux/regulator/of_regulator.h>
18*bb244140SDzmitry Sankouski #include <linux/mfd/samsung/core.h>
19*bb244140SDzmitry Sankouski #include <linux/regulator/s2dos05.h>
20*bb244140SDzmitry Sankouski #include <linux/i2c.h>
21*bb244140SDzmitry Sankouski 
22*bb244140SDzmitry Sankouski struct s2dos05_data {
23*bb244140SDzmitry Sankouski 	struct regmap *regmap;
24*bb244140SDzmitry Sankouski 	struct device *dev;
25*bb244140SDzmitry Sankouski };
26*bb244140SDzmitry Sankouski 
27*bb244140SDzmitry Sankouski #define _BUCK(macro)	S2DOS05_BUCK##macro
28*bb244140SDzmitry Sankouski #define _buck_ops(num)	s2dos05_ops##num
29*bb244140SDzmitry Sankouski #define _LDO(macro)	S2DOS05_LDO##macro
30*bb244140SDzmitry Sankouski #define _REG(ctrl)	S2DOS05_REG##ctrl
31*bb244140SDzmitry Sankouski #define _ldo_ops(num)	s2dos05_ops##num
32*bb244140SDzmitry Sankouski #define _MASK(macro)	S2DOS05_ENABLE_MASK##macro
33*bb244140SDzmitry Sankouski #define _TIME(macro)	S2DOS05_ENABLE_TIME##macro
34*bb244140SDzmitry Sankouski 
35*bb244140SDzmitry Sankouski #define BUCK_DESC(_name, _id, _ops, m, s, v, e, em, t, a) {	\
36*bb244140SDzmitry Sankouski 	.name		= _name,				\
37*bb244140SDzmitry Sankouski 	.id		= _id,					\
38*bb244140SDzmitry Sankouski 	.ops		= _ops,					\
39*bb244140SDzmitry Sankouski 	.of_match = of_match_ptr(_name),			\
40*bb244140SDzmitry Sankouski 	.of_match_full_name = true,				\
41*bb244140SDzmitry Sankouski 	.regulators_node = of_match_ptr("regulators"),		\
42*bb244140SDzmitry Sankouski 	.type		= REGULATOR_VOLTAGE,			\
43*bb244140SDzmitry Sankouski 	.owner		= THIS_MODULE,				\
44*bb244140SDzmitry Sankouski 	.min_uV		= m,					\
45*bb244140SDzmitry Sankouski 	.uV_step	= s,					\
46*bb244140SDzmitry Sankouski 	.n_voltages	= S2DOS05_BUCK_N_VOLTAGES,		\
47*bb244140SDzmitry Sankouski 	.vsel_reg	= v,					\
48*bb244140SDzmitry Sankouski 	.vsel_mask	= S2DOS05_BUCK_VSEL_MASK,		\
49*bb244140SDzmitry Sankouski 	.enable_reg	= e,					\
50*bb244140SDzmitry Sankouski 	.enable_mask	= em,					\
51*bb244140SDzmitry Sankouski 	.enable_time	= t,					\
52*bb244140SDzmitry Sankouski 	.active_discharge_off = 0,				\
53*bb244140SDzmitry Sankouski 	.active_discharge_on = S2DOS05_BUCK_FD_MASK,		\
54*bb244140SDzmitry Sankouski 	.active_discharge_reg	= a,				\
55*bb244140SDzmitry Sankouski 	.active_discharge_mask	= S2DOS05_BUCK_FD_MASK		\
56*bb244140SDzmitry Sankouski }
57*bb244140SDzmitry Sankouski 
58*bb244140SDzmitry Sankouski #define LDO_DESC(_name, _id, _ops, m, s, v, e, em, t, a) {	\
59*bb244140SDzmitry Sankouski 	.name		= _name,				\
60*bb244140SDzmitry Sankouski 	.id		= _id,					\
61*bb244140SDzmitry Sankouski 	.ops		= _ops,					\
62*bb244140SDzmitry Sankouski 	.of_match = of_match_ptr(_name),			\
63*bb244140SDzmitry Sankouski 	.of_match_full_name = true,				\
64*bb244140SDzmitry Sankouski 	.regulators_node = of_match_ptr("regulators"),		\
65*bb244140SDzmitry Sankouski 	.type		= REGULATOR_VOLTAGE,			\
66*bb244140SDzmitry Sankouski 	.owner		= THIS_MODULE,				\
67*bb244140SDzmitry Sankouski 	.min_uV		= m,					\
68*bb244140SDzmitry Sankouski 	.uV_step	= s,					\
69*bb244140SDzmitry Sankouski 	.n_voltages	= S2DOS05_LDO_N_VOLTAGES,		\
70*bb244140SDzmitry Sankouski 	.vsel_reg	= v,					\
71*bb244140SDzmitry Sankouski 	.vsel_mask	= S2DOS05_LDO_VSEL_MASK,		\
72*bb244140SDzmitry Sankouski 	.enable_reg	= e,					\
73*bb244140SDzmitry Sankouski 	.enable_mask	= em,					\
74*bb244140SDzmitry Sankouski 	.enable_time	= t,					\
75*bb244140SDzmitry Sankouski 	.active_discharge_off = 0,				\
76*bb244140SDzmitry Sankouski 	.active_discharge_on = S2DOS05_LDO_FD_MASK,		\
77*bb244140SDzmitry Sankouski 	.active_discharge_reg	= a,				\
78*bb244140SDzmitry Sankouski 	.active_discharge_mask	= S2DOS05_LDO_FD_MASK		\
79*bb244140SDzmitry Sankouski }
80*bb244140SDzmitry Sankouski 
81*bb244140SDzmitry Sankouski static const struct regulator_ops s2dos05_ops = {
82*bb244140SDzmitry Sankouski 	.list_voltage		= regulator_list_voltage_linear,
83*bb244140SDzmitry Sankouski 	.map_voltage		= regulator_map_voltage_linear,
84*bb244140SDzmitry Sankouski 	.is_enabled		= regulator_is_enabled_regmap,
85*bb244140SDzmitry Sankouski 	.enable			= regulator_enable_regmap,
86*bb244140SDzmitry Sankouski 	.disable		= regulator_disable_regmap,
87*bb244140SDzmitry Sankouski 	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
88*bb244140SDzmitry Sankouski 	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
89*bb244140SDzmitry Sankouski 	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
90*bb244140SDzmitry Sankouski 	.set_active_discharge	= regulator_set_active_discharge_regmap,
91*bb244140SDzmitry Sankouski };
92*bb244140SDzmitry Sankouski 
93*bb244140SDzmitry Sankouski static const struct regulator_desc regulators[S2DOS05_REGULATOR_MAX] = {
94*bb244140SDzmitry Sankouski 		// name, id, ops, min_uv, uV_step, vsel_reg, enable_reg
95*bb244140SDzmitry Sankouski 		LDO_DESC("ldo1", _LDO(1), &_ldo_ops(), _LDO(_MIN1),
96*bb244140SDzmitry Sankouski 			_LDO(_STEP1), _REG(_LDO1_CFG),
97*bb244140SDzmitry Sankouski 			_REG(_EN), _MASK(_L1), _TIME(_LDO), _REG(_LDO1_CFG)),
98*bb244140SDzmitry Sankouski 		LDO_DESC("ldo2", _LDO(2), &_ldo_ops(), _LDO(_MIN1),
99*bb244140SDzmitry Sankouski 			_LDO(_STEP1), _REG(_LDO2_CFG),
100*bb244140SDzmitry Sankouski 			_REG(_EN), _MASK(_L2), _TIME(_LDO), _REG(_LDO2_CFG)),
101*bb244140SDzmitry Sankouski 		LDO_DESC("ldo3", _LDO(3), &_ldo_ops(), _LDO(_MIN2),
102*bb244140SDzmitry Sankouski 			_LDO(_STEP1), _REG(_LDO3_CFG),
103*bb244140SDzmitry Sankouski 			_REG(_EN), _MASK(_L3), _TIME(_LDO), _REG(_LDO3_CFG)),
104*bb244140SDzmitry Sankouski 		LDO_DESC("ldo4", _LDO(4), &_ldo_ops(), _LDO(_MIN2),
105*bb244140SDzmitry Sankouski 			_LDO(_STEP1), _REG(_LDO4_CFG),
106*bb244140SDzmitry Sankouski 			_REG(_EN), _MASK(_L4), _TIME(_LDO), _REG(_LDO4_CFG)),
107*bb244140SDzmitry Sankouski 		BUCK_DESC("buck", _BUCK(1), &_buck_ops(), _BUCK(_MIN1),
108*bb244140SDzmitry Sankouski 			_BUCK(_STEP1), _REG(_BUCK_VOUT),
109*bb244140SDzmitry Sankouski 			_REG(_EN), _MASK(_B1), _TIME(_BUCK), _REG(_BUCK_CFG)),
110*bb244140SDzmitry Sankouski };
111*bb244140SDzmitry Sankouski 
112*bb244140SDzmitry Sankouski static int s2dos05_pmic_probe(struct platform_device *pdev)
113*bb244140SDzmitry Sankouski {
114*bb244140SDzmitry Sankouski 	struct device *dev = &pdev->dev;
115*bb244140SDzmitry Sankouski 	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
116*bb244140SDzmitry Sankouski 	struct s2dos05_data *s2dos05;
117*bb244140SDzmitry Sankouski 	struct regulator_config config = { };
118*bb244140SDzmitry Sankouski 	unsigned int rdev_num = ARRAY_SIZE(regulators);
119*bb244140SDzmitry Sankouski 
120*bb244140SDzmitry Sankouski 	s2dos05 = devm_kzalloc(dev, sizeof(*s2dos05), GFP_KERNEL);
121*bb244140SDzmitry Sankouski 	if (!s2dos05)
122*bb244140SDzmitry Sankouski 		return -ENOMEM;
123*bb244140SDzmitry Sankouski 
124*bb244140SDzmitry Sankouski 	platform_set_drvdata(pdev, s2dos05);
125*bb244140SDzmitry Sankouski 
126*bb244140SDzmitry Sankouski 	s2dos05->regmap = iodev->regmap_pmic;
127*bb244140SDzmitry Sankouski 	s2dos05->dev = dev;
128*bb244140SDzmitry Sankouski 	if (!dev->of_node)
129*bb244140SDzmitry Sankouski 		dev->of_node = dev->parent->of_node;
130*bb244140SDzmitry Sankouski 
131*bb244140SDzmitry Sankouski 	config.dev = dev;
132*bb244140SDzmitry Sankouski 	config.driver_data = s2dos05;
133*bb244140SDzmitry Sankouski 
134*bb244140SDzmitry Sankouski 	for (int i = 0; i < rdev_num; i++) {
135*bb244140SDzmitry Sankouski 		struct regulator_dev *regulator;
136*bb244140SDzmitry Sankouski 
137*bb244140SDzmitry Sankouski 		regulator = devm_regulator_register(&pdev->dev,
138*bb244140SDzmitry Sankouski 						&regulators[i], &config);
139*bb244140SDzmitry Sankouski 		if (IS_ERR(regulator)) {
140*bb244140SDzmitry Sankouski 			return dev_err_probe(&pdev->dev, PTR_ERR(regulator),
141*bb244140SDzmitry Sankouski 					"regulator init failed for %d\n", i);
142*bb244140SDzmitry Sankouski 		}
143*bb244140SDzmitry Sankouski 	}
144*bb244140SDzmitry Sankouski 
145*bb244140SDzmitry Sankouski 	return 0;
146*bb244140SDzmitry Sankouski }
147*bb244140SDzmitry Sankouski 
148*bb244140SDzmitry Sankouski static const struct platform_device_id s2dos05_pmic_id[] = {
149*bb244140SDzmitry Sankouski 	{ "s2dos05-regulator" },
150*bb244140SDzmitry Sankouski 	{ },
151*bb244140SDzmitry Sankouski };
152*bb244140SDzmitry Sankouski MODULE_DEVICE_TABLE(platform, s2dos05_pmic_id);
153*bb244140SDzmitry Sankouski 
154*bb244140SDzmitry Sankouski static struct platform_driver s2dos05_platform_driver = {
155*bb244140SDzmitry Sankouski 	.driver = {
156*bb244140SDzmitry Sankouski 		.name = "s2dos05",
157*bb244140SDzmitry Sankouski 	},
158*bb244140SDzmitry Sankouski 	.probe = s2dos05_pmic_probe,
159*bb244140SDzmitry Sankouski 	.id_table = s2dos05_pmic_id,
160*bb244140SDzmitry Sankouski };
161*bb244140SDzmitry Sankouski module_platform_driver(s2dos05_platform_driver);
162*bb244140SDzmitry Sankouski 
163*bb244140SDzmitry Sankouski MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>");
164*bb244140SDzmitry Sankouski MODULE_DESCRIPTION("Samsung S2DOS05 Regulator Driver");
165*bb244140SDzmitry Sankouski MODULE_LICENSE("GPL");
166