1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ROHM BD9571MWV-M and BD9574MWF-M regulator driver
4 *
5 * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
6 *
7 * Based on the TPS65086 driver
8 *
9 * NOTE: VD09 is missing
10 */
11
12#include <linux/mfd/rohm-generic.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/platform_device.h>
16#include <linux/regulator/driver.h>
17
18#include <linux/mfd/bd9571mwv.h>
19
20struct bd9571mwv_reg {
21	struct regmap *regmap;
22
23	/* DDR Backup Power */
24	u8 bkup_mode_cnt_keepon;	/* from "rohm,ddr-backup-power" */
25	u8 bkup_mode_cnt_saved;
26	bool bkup_mode_enabled;
27
28	/* Power switch type */
29	bool rstbmode_level;
30	bool rstbmode_pulse;
31};
32
33enum bd9571mwv_regulators { VD09, VD18, VD25, VD33, DVFS };
34
35#define BD9571MWV_REG(_name, _of, _id, _ops, _vr, _vm, _nv, _min, _step, _lmin)\
36	{							\
37		.name			= _name,		\
38		.of_match		= of_match_ptr(_of),	\
39		.regulators_node	= "regulators",		\
40		.id			= _id,			\
41		.ops			= &_ops,		\
42		.n_voltages		= _nv,			\
43		.type			= REGULATOR_VOLTAGE,	\
44		.owner			= THIS_MODULE,		\
45		.vsel_reg		= _vr,			\
46		.vsel_mask		= _vm,			\
47		.min_uV			= _min,			\
48		.uV_step		= _step,		\
49		.linear_min_sel		= _lmin,		\
50	}
51
52static int bd9571mwv_avs_get_moni_state(struct regulator_dev *rdev)
53{
54	unsigned int val;
55	int ret;
56
57	ret = regmap_read(rdev->regmap, BD9571MWV_AVS_SET_MONI, &val);
58	if (ret != 0)
59		return ret;
60
61	return val & BD9571MWV_AVS_SET_MONI_MASK;
62}
63
64static int bd9571mwv_avs_set_voltage_sel_regmap(struct regulator_dev *rdev,
65						unsigned int sel)
66{
67	int ret;
68
69	ret = bd9571mwv_avs_get_moni_state(rdev);
70	if (ret < 0)
71		return ret;
72
73	return regmap_write_bits(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret),
74				 rdev->desc->vsel_mask, sel);
75}
76
77static int bd9571mwv_avs_get_voltage_sel_regmap(struct regulator_dev *rdev)
78{
79	unsigned int val;
80	int ret;
81
82	ret = bd9571mwv_avs_get_moni_state(rdev);
83	if (ret < 0)
84		return ret;
85
86	ret = regmap_read(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret), &val);
87	if (ret != 0)
88		return ret;
89
90	val &= rdev->desc->vsel_mask;
91	val >>= ffs(rdev->desc->vsel_mask) - 1;
92
93	return val;
94}
95
96static int bd9571mwv_reg_set_voltage_sel_regmap(struct regulator_dev *rdev,
97						unsigned int sel)
98{
99	return regmap_write_bits(rdev->regmap, BD9571MWV_DVFS_SETVID,
100				 rdev->desc->vsel_mask, sel);
101}
102
103/* Operations permitted on AVS voltage regulator */
104static const struct regulator_ops avs_ops = {
105	.set_voltage_sel	= bd9571mwv_avs_set_voltage_sel_regmap,
106	.map_voltage		= regulator_map_voltage_linear,
107	.get_voltage_sel	= bd9571mwv_avs_get_voltage_sel_regmap,
108	.list_voltage		= regulator_list_voltage_linear,
109};
110
111/* Operations permitted on voltage regulators */
112static const struct regulator_ops reg_ops = {
113	.set_voltage_sel	= bd9571mwv_reg_set_voltage_sel_regmap,
114	.map_voltage		= regulator_map_voltage_linear,
115	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
116	.list_voltage		= regulator_list_voltage_linear,
117};
118
119/* Operations permitted on voltage monitors */
120static const struct regulator_ops vid_ops = {
121	.map_voltage		= regulator_map_voltage_linear,
122	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
123	.list_voltage		= regulator_list_voltage_linear,
124};
125
126static const struct regulator_desc regulators[] = {
127	BD9571MWV_REG("VD09", "vd09", VD09, avs_ops, 0, 0x7f,
128		      0x6f, 600000, 10000, 0x3c),
129	BD9571MWV_REG("VD18", "vd18", VD18, vid_ops, BD9571MWV_VD18_VID, 0xf,
130		      16, 1625000, 25000, 0),
131	BD9571MWV_REG("VD25", "vd25", VD25, vid_ops, BD9571MWV_VD25_VID, 0xf,
132		      16, 2150000, 50000, 0),
133	BD9571MWV_REG("VD33", "vd33", VD33, vid_ops, BD9571MWV_VD33_VID, 0xf,
134		      11, 2800000, 100000, 0),
135	BD9571MWV_REG("DVFS", "dvfs", DVFS, reg_ops,
136		      BD9571MWV_DVFS_MONIVDAC, 0x7f,
137		      0x6f, 600000, 10000, 0x3c),
138};
139
140#ifdef CONFIG_PM_SLEEP
141static int bd9571mwv_bkup_mode_read(struct bd9571mwv_reg *bdreg,
142				    unsigned int *mode)
143{
144	int ret;
145
146	ret = regmap_read(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
147	if (ret) {
148		dev_err(regmap_get_device(bdreg->regmap),
149			"failed to read backup mode (%d)\n", ret);
150		return ret;
151	}
152
153	return 0;
154}
155
156static int bd9571mwv_bkup_mode_write(struct bd9571mwv_reg *bdreg,
157				     unsigned int mode)
158{
159	int ret;
160
161	ret = regmap_write(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
162	if (ret) {
163		dev_err(regmap_get_device(bdreg->regmap),
164			"failed to configure backup mode 0x%x (%d)\n",
165			mode, ret);
166		return ret;
167	}
168
169	return 0;
170}
171
172static ssize_t backup_mode_show(struct device *dev,
173				struct device_attribute *attr, char *buf)
174{
175	struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
176
177	return sysfs_emit(buf, "%s\n", bdreg->bkup_mode_enabled ? "on" : "off");
178}
179
180static ssize_t backup_mode_store(struct device *dev,
181				 struct device_attribute *attr,
182				 const char *buf, size_t count)
183{
184	struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
185	unsigned int mode;
186	int ret;
187
188	if (!count)
189		return 0;
190
191	ret = kstrtobool(buf, &bdreg->bkup_mode_enabled);
192	if (ret)
193		return ret;
194
195	if (!bdreg->rstbmode_level)
196		return count;
197
198	/*
199	 * Configure DDR Backup Mode, to change the role of the accessory power
200	 * switch from a power switch to a wake-up switch, or vice versa
201	 */
202	ret = bd9571mwv_bkup_mode_read(bdreg, &mode);
203	if (ret)
204		return ret;
205
206	mode &= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK;
207	if (bdreg->bkup_mode_enabled)
208		mode |= bdreg->bkup_mode_cnt_keepon;
209
210	ret = bd9571mwv_bkup_mode_write(bdreg, mode);
211	if (ret)
212		return ret;
213
214	return count;
215}
216
217static DEVICE_ATTR_RW(backup_mode);
218
219static int bd9571mwv_suspend(struct device *dev)
220{
221	struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
222	unsigned int mode;
223	int ret;
224
225	if (!bdreg->bkup_mode_enabled)
226		return 0;
227
228	/* Save DDR Backup Mode */
229	ret = bd9571mwv_bkup_mode_read(bdreg, &mode);
230	if (ret)
231		return ret;
232
233	bdreg->bkup_mode_cnt_saved = mode;
234
235	if (!bdreg->rstbmode_pulse)
236		return 0;
237
238	/* Enable DDR Backup Mode */
239	mode &= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK;
240	mode |= bdreg->bkup_mode_cnt_keepon;
241
242	if (mode != bdreg->bkup_mode_cnt_saved)
243		return bd9571mwv_bkup_mode_write(bdreg, mode);
244
245	return 0;
246}
247
248static int bd9571mwv_resume(struct device *dev)
249{
250	struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
251
252	if (!bdreg->bkup_mode_enabled)
253		return 0;
254
255	/* Restore DDR Backup Mode */
256	return bd9571mwv_bkup_mode_write(bdreg, bdreg->bkup_mode_cnt_saved);
257}
258
259static const struct dev_pm_ops bd9571mwv_pm  = {
260	SET_SYSTEM_SLEEP_PM_OPS(bd9571mwv_suspend, bd9571mwv_resume)
261};
262
263static void bd9571mwv_regulator_remove(struct platform_device *pdev)
264{
265	device_remove_file(&pdev->dev, &dev_attr_backup_mode);
266}
267#define DEV_PM_OPS	&bd9571mwv_pm
268#else
269#define DEV_PM_OPS	NULL
270#define bd9571mwv_regulator_remove	NULL
271#endif /* CONFIG_PM_SLEEP */
272
273static int bd9571mwv_regulator_probe(struct platform_device *pdev)
274{
275	struct regulator_config config = { };
276	struct bd9571mwv_reg *bdreg;
277	struct regulator_dev *rdev;
278	unsigned int val;
279	int i;
280	enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
281
282	bdreg = devm_kzalloc(&pdev->dev, sizeof(*bdreg), GFP_KERNEL);
283	if (!bdreg)
284		return -ENOMEM;
285
286	bdreg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
287
288	platform_set_drvdata(pdev, bdreg);
289
290	config.dev = &pdev->dev;
291	config.dev->of_node = pdev->dev.parent->of_node;
292	config.driver_data = bdreg;
293	config.regmap = bdreg->regmap;
294
295	for (i = 0; i < ARRAY_SIZE(regulators); i++) {
296		/* BD9574MWF supports DVFS only */
297		if (chip == ROHM_CHIP_TYPE_BD9574 && regulators[i].id != DVFS)
298			continue;
299		rdev = devm_regulator_register(&pdev->dev, &regulators[i],
300					       &config);
301		if (IS_ERR(rdev)) {
302			dev_err(&pdev->dev, "failed to register %s regulator\n",
303				regulators[i].name);
304			return PTR_ERR(rdev);
305		}
306	}
307
308	val = 0;
309	of_property_read_u32(config.dev->of_node, "rohm,ddr-backup-power", &val);
310	if (val & ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK) {
311		dev_err(&pdev->dev, "invalid %s mode %u\n",
312			"rohm,ddr-backup-power", val);
313		return -EINVAL;
314	}
315	bdreg->bkup_mode_cnt_keepon = val;
316
317	bdreg->rstbmode_level = of_property_read_bool(config.dev->of_node,
318						      "rohm,rstbmode-level");
319	bdreg->rstbmode_pulse = of_property_read_bool(config.dev->of_node,
320						      "rohm,rstbmode-pulse");
321	if (bdreg->rstbmode_level && bdreg->rstbmode_pulse) {
322		dev_err(&pdev->dev, "only one rohm,rstbmode-* may be specified");
323		return -EINVAL;
324	}
325
326#ifdef CONFIG_PM_SLEEP
327	if (bdreg->bkup_mode_cnt_keepon) {
328		int ret;
329
330		/*
331		 * Backup mode is enabled by default in pulse mode, but needs
332		 * explicit user setup in level mode.
333		 */
334		bdreg->bkup_mode_enabled = bdreg->rstbmode_pulse;
335
336		ret = device_create_file(&pdev->dev, &dev_attr_backup_mode);
337		if (ret)
338			return ret;
339	}
340#endif /* CONFIG_PM_SLEEP */
341
342	return 0;
343}
344
345static const struct platform_device_id bd9571mwv_regulator_id_table[] = {
346	{ "bd9571mwv-regulator", ROHM_CHIP_TYPE_BD9571 },
347	{ "bd9574mwf-regulator", ROHM_CHIP_TYPE_BD9574 },
348	{ /* sentinel */ }
349};
350MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table);
351
352static struct platform_driver bd9571mwv_regulator_driver = {
353	.driver = {
354		.name = "bd9571mwv-regulator",
355		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
356		.pm = DEV_PM_OPS,
357	},
358	.probe = bd9571mwv_regulator_probe,
359	.remove_new = bd9571mwv_regulator_remove,
360	.id_table = bd9571mwv_regulator_id_table,
361};
362module_platform_driver(bd9571mwv_regulator_driver);
363
364MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
365MODULE_DESCRIPTION("BD9571MWV Regulator driver");
366MODULE_LICENSE("GPL v2");
367