1// SPDX-License-Identifier: GPL-2.0+
2
3#include <linux/bits.h>
4#include <linux/gpio/consumer.h>
5#include <linux/interrupt.h>
6#include <linux/kernel.h>
7#include <linux/mod_devicetable.h>
8#include <linux/module.h>
9#include <linux/of.h>
10#include <linux/platform_device.h>
11#include <linux/regmap.h>
12#include <linux/regulator/driver.h>
13#include <linux/regulator/machine.h>
14
15enum {
16	MT6370_IDX_DSVBOOST = 0,
17	MT6370_IDX_DSVPOS,
18	MT6370_IDX_DSVNEG,
19	MT6370_IDX_VIBLDO,
20	MT6370_MAX_IDX
21};
22
23#define MT6370_REG_LDO_CFG	0x180
24#define MT6370_REG_LDO_VOUT	0x181
25#define MT6370_REG_DB_CTRL1	0x1B0
26#define MT6370_REG_DB_CTRL2	0x1B1
27#define MT6370_REG_DB_VBST	0x1B2
28#define MT6370_REG_DB_VPOS	0x1B3
29#define MT6370_REG_DB_VNEG	0x1B4
30#define MT6370_REG_LDO_STAT	0x1DC
31#define MT6370_REG_DB_STAT	0x1DF
32
33#define MT6370_LDOOMS_MASK	BIT(7)
34#define MT6370_LDOEN_MASK	BIT(7)
35#define MT6370_LDOVOUT_MASK	GENMASK(3, 0)
36#define MT6370_DBPERD_MASK	(BIT(7) | BIT(4))
37#define MT6370_DBEXTEN_MASK	BIT(0)
38#define MT6370_DBVPOSEN_MASK	BIT(6)
39#define MT6370_DBVPOSDISG_MASK	BIT(5)
40#define MT6370_DBVNEGEN_MASK	BIT(3)
41#define MT6370_DBVNEGDISG_MASK	BIT(2)
42#define MT6370_DBALLON_MASK	(MT6370_DBVPOSEN_MASK | MT6370_DBVNEGEN_MASK)
43#define MT6370_DBSLEW_MASK	GENMASK(7, 6)
44#define MT6370_DBVOUT_MASK	GENMASK(5, 0)
45#define MT6370_LDOOC_EVT_MASK	BIT(7)
46#define MT6370_POSSCP_EVT_MASK	BIT(7)
47#define MT6370_NEGSCP_EVT_MASK	BIT(6)
48#define MT6370_BSTOCP_EVT_MASK	BIT(5)
49#define MT6370_POSOCP_EVT_MASK	BIT(4)
50#define MT6370_NEGOCP_EVT_MASK	BIT(3)
51
52#define MT6370_LDO_MINUV	1600000
53#define MT6370_LDO_STPUV	200000
54#define MT6370_LDO_N_VOLT	13
55#define MT6370_DBVBOOST_MINUV	4000000
56#define MT6370_DBVBOOST_STPUV	50000
57#define MT6370_DBVBOOST_N_VOLT	45
58#define MT6370_DBVOUT_MINUV	4000000
59#define MT6370_DBVOUT_STPUV	50000
60#define MT6370_DBVOUT_N_VOLT	41
61
62struct mt6370_priv {
63	struct device *dev;
64	struct regmap *regmap;
65	struct regulator_dev *rdev[MT6370_MAX_IDX];
66	bool use_external_ctrl;
67};
68
69static const unsigned int mt6370_vpos_ramp_tbl[] = { 8540, 5840, 4830, 3000 };
70static const unsigned int mt6370_vneg_ramp_tbl[] = { 10090, 6310, 5050, 3150 };
71
72static int mt6370_get_error_flags(struct regulator_dev *rdev,
73				  unsigned int *flags)
74{
75	struct regmap *regmap = rdev_get_regmap(rdev);
76	unsigned int stat_reg, stat, rpt_flags = 0;
77	int rid = rdev_get_id(rdev), ret;
78
79	if (rid == MT6370_IDX_VIBLDO)
80		stat_reg = MT6370_REG_LDO_STAT;
81	else
82		stat_reg = MT6370_REG_DB_STAT;
83
84	ret = regmap_read(regmap, stat_reg, &stat);
85	if (ret)
86		return ret;
87
88	switch (rid) {
89	case MT6370_IDX_DSVBOOST:
90		if (stat & MT6370_BSTOCP_EVT_MASK)
91			rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
92		break;
93	case MT6370_IDX_DSVPOS:
94		if (stat & MT6370_POSSCP_EVT_MASK)
95			rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;
96
97		if (stat & MT6370_POSOCP_EVT_MASK)
98			rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
99		break;
100	case MT6370_IDX_DSVNEG:
101		if (stat & MT6370_NEGSCP_EVT_MASK)
102			rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;
103
104		if (stat & MT6370_NEGOCP_EVT_MASK)
105			rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
106		break;
107	default:
108		if (stat & MT6370_LDOOC_EVT_MASK)
109			rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
110		break;
111	}
112
113	*flags = rpt_flags;
114	return 0;
115}
116
117static const struct regulator_ops mt6370_dbvboost_ops = {
118	.get_voltage_sel = regulator_get_voltage_sel_regmap,
119	.set_voltage_sel = regulator_set_voltage_sel_regmap,
120	.list_voltage = regulator_list_voltage_linear,
121	.get_bypass = regulator_get_bypass_regmap,
122	.set_bypass = regulator_set_bypass_regmap,
123	.get_error_flags = mt6370_get_error_flags,
124};
125
126static const struct regulator_ops mt6370_dbvout_ops = {
127	.get_voltage_sel = regulator_get_voltage_sel_regmap,
128	.set_voltage_sel = regulator_set_voltage_sel_regmap,
129	.list_voltage = regulator_list_voltage_linear,
130	.is_enabled = regulator_is_enabled_regmap,
131	.enable = regulator_enable_regmap,
132	.disable = regulator_disable_regmap,
133	.set_active_discharge = regulator_set_active_discharge_regmap,
134	.set_ramp_delay = regulator_set_ramp_delay_regmap,
135	.get_error_flags = mt6370_get_error_flags,
136};
137
138static const struct regulator_ops mt6370_ldo_ops = {
139	.get_voltage_sel = regulator_get_voltage_sel_regmap,
140	.set_voltage_sel = regulator_set_voltage_sel_regmap,
141	.list_voltage = regulator_list_voltage_linear,
142	.is_enabled = regulator_is_enabled_regmap,
143	.enable = regulator_enable_regmap,
144	.disable = regulator_disable_regmap,
145	.set_active_discharge = regulator_set_active_discharge_regmap,
146	.get_error_flags = mt6370_get_error_flags,
147};
148
149static int mt6370_of_parse_cb(struct device_node *np,
150			      const struct regulator_desc *desc,
151			      struct regulator_config *config)
152{
153	struct mt6370_priv *priv = config->driver_data;
154	struct gpio_desc *enable_gpio;
155	int ret;
156
157	enable_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np), "enable", 0,
158					     GPIOD_OUT_HIGH |
159					     GPIOD_FLAGS_BIT_NONEXCLUSIVE,
160					     desc->name);
161	if (IS_ERR(enable_gpio)) {
162		config->ena_gpiod = NULL;
163		return 0;
164	}
165
166	/*
167	 * RG control by default
168	 * Only if all are using external pin, change all by external control
169	 */
170	if (priv->use_external_ctrl) {
171		ret = regmap_update_bits(priv->regmap, MT6370_REG_DB_CTRL1,
172					 MT6370_DBEXTEN_MASK,
173					 MT6370_DBEXTEN_MASK);
174		if (ret)
175			return ret;
176	}
177
178	config->ena_gpiod = enable_gpio;
179	priv->use_external_ctrl = true;
180	return 0;
181}
182
183static const struct regulator_desc mt6370_regulator_descs[] = {
184	{
185		.name = "mt6370-dsv-vbst",
186		.of_match = of_match_ptr("dsvbst"),
187		.regulators_node = of_match_ptr("regulators"),
188		.id = MT6370_IDX_DSVBOOST,
189		.type = REGULATOR_VOLTAGE,
190		.owner = THIS_MODULE,
191		.ops = &mt6370_dbvboost_ops,
192		.min_uV = MT6370_DBVBOOST_MINUV,
193		.uV_step = MT6370_DBVBOOST_STPUV,
194		.n_voltages = MT6370_DBVBOOST_N_VOLT,
195		.vsel_reg = MT6370_REG_DB_VBST,
196		.vsel_mask = MT6370_DBVOUT_MASK,
197		.bypass_reg = MT6370_REG_DB_CTRL1,
198		.bypass_mask = MT6370_DBPERD_MASK,
199		.bypass_val_on = MT6370_DBPERD_MASK,
200	},
201	{
202		.name = "mt6370-dsv-vpos",
203		.of_match = of_match_ptr("dsvpos"),
204		.regulators_node = of_match_ptr("regulators"),
205		.id = MT6370_IDX_DSVPOS,
206		.type = REGULATOR_VOLTAGE,
207		.owner = THIS_MODULE,
208		.of_parse_cb = mt6370_of_parse_cb,
209		.ops = &mt6370_dbvout_ops,
210		.min_uV = MT6370_DBVOUT_MINUV,
211		.uV_step = MT6370_DBVOUT_STPUV,
212		.n_voltages = MT6370_DBVOUT_N_VOLT,
213		.vsel_reg = MT6370_REG_DB_VPOS,
214		.vsel_mask = MT6370_DBVOUT_MASK,
215		.enable_reg = MT6370_REG_DB_CTRL2,
216		.enable_mask = MT6370_DBVPOSEN_MASK,
217		.ramp_reg = MT6370_REG_DB_VPOS,
218		.ramp_mask = MT6370_DBSLEW_MASK,
219		.ramp_delay_table = mt6370_vpos_ramp_tbl,
220		.n_ramp_values = ARRAY_SIZE(mt6370_vpos_ramp_tbl),
221		.active_discharge_reg = MT6370_REG_DB_CTRL2,
222		.active_discharge_mask = MT6370_DBVPOSDISG_MASK,
223		.active_discharge_on = MT6370_DBVPOSDISG_MASK,
224	},
225	{
226		.name = "mt6370-dsv-vneg",
227		.of_match = of_match_ptr("dsvneg"),
228		.regulators_node = of_match_ptr("regulators"),
229		.id = MT6370_IDX_DSVNEG,
230		.type = REGULATOR_VOLTAGE,
231		.owner = THIS_MODULE,
232		.of_parse_cb = mt6370_of_parse_cb,
233		.ops = &mt6370_dbvout_ops,
234		.min_uV = MT6370_DBVOUT_MINUV,
235		.uV_step = MT6370_DBVOUT_STPUV,
236		.n_voltages = MT6370_DBVOUT_N_VOLT,
237		.vsel_reg = MT6370_REG_DB_VNEG,
238		.vsel_mask = MT6370_DBVOUT_MASK,
239		.enable_reg = MT6370_REG_DB_CTRL2,
240		.enable_mask = MT6370_DBVNEGEN_MASK,
241		.ramp_reg = MT6370_REG_DB_VNEG,
242		.ramp_mask = MT6370_DBSLEW_MASK,
243		.ramp_delay_table = mt6370_vneg_ramp_tbl,
244		.n_ramp_values = ARRAY_SIZE(mt6370_vneg_ramp_tbl),
245		.active_discharge_reg = MT6370_REG_DB_CTRL2,
246		.active_discharge_mask = MT6370_DBVNEGDISG_MASK,
247		.active_discharge_on = MT6370_DBVNEGDISG_MASK,
248	},
249	{
250		.name = "mt6370-vib-ldo",
251		.of_match = of_match_ptr("vibldo"),
252		.regulators_node = of_match_ptr("regulators"),
253		.id = MT6370_IDX_VIBLDO,
254		.type = REGULATOR_VOLTAGE,
255		.owner = THIS_MODULE,
256		.ops = &mt6370_ldo_ops,
257		.min_uV = MT6370_LDO_MINUV,
258		.uV_step = MT6370_LDO_STPUV,
259		.n_voltages = MT6370_LDO_N_VOLT,
260		.vsel_reg = MT6370_REG_LDO_VOUT,
261		.vsel_mask = MT6370_LDOVOUT_MASK,
262		.enable_reg = MT6370_REG_LDO_VOUT,
263		.enable_mask = MT6370_LDOEN_MASK,
264		.active_discharge_reg = MT6370_REG_LDO_CFG,
265		.active_discharge_mask = MT6370_LDOOMS_MASK,
266		.active_discharge_on = MT6370_LDOOMS_MASK,
267	}
268};
269
270static irqreturn_t mt6370_scp_handler(int irq, void *data)
271{
272	struct regulator_dev *rdev = data;
273
274	regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE,
275				      NULL);
276	return IRQ_HANDLED;
277}
278
279static irqreturn_t mt6370_ocp_handler(int irq, void *data)
280{
281	struct regulator_dev *rdev = data;
282
283	regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL);
284	return IRQ_HANDLED;
285}
286
287static int mt6370_regulator_irq_register(struct mt6370_priv *priv)
288{
289	struct platform_device *pdev = to_platform_device(priv->dev);
290	static const struct {
291		const char *name;
292		int rid;
293		irq_handler_t handler;
294	} mt6370_irqs[] = {
295		{ "db_vpos_scp", MT6370_IDX_DSVPOS, mt6370_scp_handler },
296		{ "db_vneg_scp", MT6370_IDX_DSVNEG, mt6370_scp_handler },
297		{ "db_vbst_ocp", MT6370_IDX_DSVBOOST, mt6370_ocp_handler },
298		{ "db_vpos_ocp", MT6370_IDX_DSVPOS,  mt6370_ocp_handler },
299		{ "db_vneg_ocp", MT6370_IDX_DSVNEG, mt6370_ocp_handler },
300		{ "ldo_oc", MT6370_IDX_VIBLDO, mt6370_ocp_handler }
301	};
302	struct regulator_dev *rdev;
303	int i, irq, ret;
304
305	for (i = 0; i < ARRAY_SIZE(mt6370_irqs); i++) {
306		irq = platform_get_irq_byname(pdev, mt6370_irqs[i].name);
307
308		rdev = priv->rdev[mt6370_irqs[i].rid];
309
310		ret = devm_request_threaded_irq(priv->dev, irq, NULL,
311						mt6370_irqs[i].handler, 0,
312						mt6370_irqs[i].name, rdev);
313		if (ret) {
314			dev_err(priv->dev,
315				"Failed to register (%d) interrupt\n", i);
316			return ret;
317		}
318	}
319
320	return 0;
321}
322
323static int mt6370_regualtor_register(struct mt6370_priv *priv)
324{
325	struct regulator_dev *rdev;
326	struct regulator_config cfg = {};
327	struct device *parent = priv->dev->parent;
328	int i;
329
330	cfg.dev = parent;
331	cfg.driver_data = priv;
332
333	for (i = 0; i < MT6370_MAX_IDX; i++) {
334		rdev = devm_regulator_register(priv->dev,
335					       mt6370_regulator_descs + i,
336					       &cfg);
337		if (IS_ERR(rdev)) {
338			dev_err(priv->dev,
339				"Failed to register (%d) regulator\n", i);
340			return PTR_ERR(rdev);
341		}
342
343		priv->rdev[i] = rdev;
344	}
345
346	return 0;
347}
348
349static int mt6370_regulator_probe(struct platform_device *pdev)
350{
351	struct mt6370_priv *priv;
352	int ret;
353
354	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
355	if (!priv)
356		return -ENOMEM;
357
358	priv->dev = &pdev->dev;
359
360	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
361	if (!priv->regmap) {
362		dev_err(&pdev->dev, "Failed to init regmap\n");
363		return -ENODEV;
364	}
365
366	ret = mt6370_regualtor_register(priv);
367	if (ret)
368		return ret;
369
370	return mt6370_regulator_irq_register(priv);
371}
372
373static const struct platform_device_id mt6370_devid_table[] = {
374	{ "mt6370-regulator", 0},
375	{}
376};
377MODULE_DEVICE_TABLE(platform, mt6370_devid_table);
378
379static struct platform_driver mt6370_regulator_driver = {
380	.driver = {
381		.name = "mt6370-regulator",
382		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
383	},
384	.id_table = mt6370_devid_table,
385	.probe = mt6370_regulator_probe,
386};
387module_platform_driver(mt6370_regulator_driver);
388
389MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
390MODULE_DESCRIPTION("Mediatek MT6370 Regulator Driver");
391MODULE_LICENSE("GPL v2");
392