2 * ROHM BD9571MWV-M regulator driver
4 * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether expressed or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License version 2 for more details.
15 * Based on the TPS65086 driver
17 * NOTE: VD09 is missing
20 #include <linux/module.h>
22 #include <linux/platform_device.h>
23 #include <linux/regulator/driver.h>
25 #include <linux/mfd/bd9571mwv.h>
27 struct bd9571mwv_reg
{
30 /* DDR Backup Power */
31 u8 bkup_mode_cnt_keepon
; /* from "rohm,ddr-backup-power" */
32 u8 bkup_mode_cnt_saved
;
33 bool bkup_mode_enabled
;
35 /* Power switch type */
40 enum bd9571mwv_regulators
{ VD09
, VD18
, VD25
, VD33
, DVFS
};
42 #define BD9571MWV_REG(_name, _of, _id, _ops, _vr, _vm, _nv, _min, _step, _lmin)\
45 .of_match = of_match_ptr(_of), \
46 .regulators_node = "regulators", \
50 .type = REGULATOR_VOLTAGE, \
51 .owner = THIS_MODULE, \
56 .linear_min_sel = _lmin, \
59 static int bd9571mwv_avs_get_moni_state(struct regulator_dev
*rdev
)
64 ret
= regmap_read(rdev
->regmap
, BD9571MWV_AVS_SET_MONI
, &val
);
68 return val
& BD9571MWV_AVS_SET_MONI_MASK
;
71 static int bd9571mwv_avs_set_voltage_sel_regmap(struct regulator_dev
*rdev
,
76 ret
= bd9571mwv_avs_get_moni_state(rdev
);
80 return regmap_write_bits(rdev
->regmap
, BD9571MWV_AVS_VD09_VID(ret
),
81 rdev
->desc
->vsel_mask
, sel
);
84 static int bd9571mwv_avs_get_voltage_sel_regmap(struct regulator_dev
*rdev
)
89 ret
= bd9571mwv_avs_get_moni_state(rdev
);
93 ret
= regmap_read(rdev
->regmap
, BD9571MWV_AVS_VD09_VID(ret
), &val
);
97 val
&= rdev
->desc
->vsel_mask
;
98 val
>>= ffs(rdev
->desc
->vsel_mask
) - 1;
103 static int bd9571mwv_reg_set_voltage_sel_regmap(struct regulator_dev
*rdev
,
106 return regmap_write_bits(rdev
->regmap
, BD9571MWV_DVFS_SETVID
,
107 rdev
->desc
->vsel_mask
, sel
);
110 /* Operations permitted on AVS voltage regulator */
111 static struct regulator_ops avs_ops
= {
112 .set_voltage_sel
= bd9571mwv_avs_set_voltage_sel_regmap
,
113 .map_voltage
= regulator_map_voltage_linear
,
114 .get_voltage_sel
= bd9571mwv_avs_get_voltage_sel_regmap
,
115 .list_voltage
= regulator_list_voltage_linear
,
118 /* Operations permitted on voltage regulators */
119 static struct regulator_ops reg_ops
= {
120 .set_voltage_sel
= bd9571mwv_reg_set_voltage_sel_regmap
,
121 .map_voltage
= regulator_map_voltage_linear
,
122 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
123 .list_voltage
= regulator_list_voltage_linear
,
126 /* Operations permitted on voltage monitors */
127 static struct regulator_ops vid_ops
= {
128 .map_voltage
= regulator_map_voltage_linear
,
129 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
130 .list_voltage
= regulator_list_voltage_linear
,
133 static struct regulator_desc regulators
[] = {
134 BD9571MWV_REG("VD09", "vd09", VD09
, avs_ops
, 0, 0x7f,
135 0x80, 600000, 10000, 0x3c),
136 BD9571MWV_REG("VD18", "vd18", VD18
, vid_ops
, BD9571MWV_VD18_VID
, 0xf,
137 16, 1625000, 25000, 0),
138 BD9571MWV_REG("VD25", "vd25", VD25
, vid_ops
, BD9571MWV_VD25_VID
, 0xf,
139 16, 2150000, 50000, 0),
140 BD9571MWV_REG("VD33", "vd33", VD33
, vid_ops
, BD9571MWV_VD33_VID
, 0xf,
141 11, 2800000, 100000, 0),
142 BD9571MWV_REG("DVFS", "dvfs", DVFS
, reg_ops
,
143 BD9571MWV_DVFS_MONIVDAC
, 0x7f,
144 0x80, 600000, 10000, 0x3c),
147 #ifdef CONFIG_PM_SLEEP
148 static int bd9571mwv_bkup_mode_read(struct bd9571mwv
*bd
, unsigned int *mode
)
152 ret
= regmap_read(bd
->regmap
, BD9571MWV_BKUP_MODE_CNT
, mode
);
154 dev_err(bd
->dev
, "failed to read backup mode (%d)\n", ret
);
161 static int bd9571mwv_bkup_mode_write(struct bd9571mwv
*bd
, unsigned int mode
)
165 ret
= regmap_write(bd
->regmap
, BD9571MWV_BKUP_MODE_CNT
, mode
);
167 dev_err(bd
->dev
, "failed to configure backup mode 0x%x (%d)\n",
175 static ssize_t
backup_mode_show(struct device
*dev
,
176 struct device_attribute
*attr
, char *buf
)
178 struct bd9571mwv_reg
*bdreg
= dev_get_drvdata(dev
);
180 return sprintf(buf
, "%s\n", bdreg
->bkup_mode_enabled
? "on" : "off");
183 static ssize_t
backup_mode_store(struct device
*dev
,
184 struct device_attribute
*attr
,
185 const char *buf
, size_t count
)
187 struct bd9571mwv_reg
*bdreg
= dev_get_drvdata(dev
);
194 ret
= kstrtobool(buf
, &bdreg
->bkup_mode_enabled
);
198 if (!bdreg
->rstbmode_level
)
202 * Configure DDR Backup Mode, to change the role of the accessory power
203 * switch from a power switch to a wake-up switch, or vice versa
205 ret
= bd9571mwv_bkup_mode_read(bdreg
->bd
, &mode
);
209 mode
&= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK
;
210 if (bdreg
->bkup_mode_enabled
)
211 mode
|= bdreg
->bkup_mode_cnt_keepon
;
213 ret
= bd9571mwv_bkup_mode_write(bdreg
->bd
, mode
);
220 static DEVICE_ATTR_RW(backup_mode
);
222 static int bd9571mwv_suspend(struct device
*dev
)
224 struct bd9571mwv_reg
*bdreg
= dev_get_drvdata(dev
);
228 if (!bdreg
->bkup_mode_enabled
)
231 /* Save DDR Backup Mode */
232 ret
= bd9571mwv_bkup_mode_read(bdreg
->bd
, &mode
);
236 bdreg
->bkup_mode_cnt_saved
= mode
;
238 if (!bdreg
->rstbmode_pulse
)
241 /* Enable DDR Backup Mode */
242 mode
&= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK
;
243 mode
|= bdreg
->bkup_mode_cnt_keepon
;
245 if (mode
!= bdreg
->bkup_mode_cnt_saved
)
246 return bd9571mwv_bkup_mode_write(bdreg
->bd
, mode
);
251 static int bd9571mwv_resume(struct device
*dev
)
253 struct bd9571mwv_reg
*bdreg
= dev_get_drvdata(dev
);
255 if (!bdreg
->bkup_mode_enabled
)
258 /* Restore DDR Backup Mode */
259 return bd9571mwv_bkup_mode_write(bdreg
->bd
, bdreg
->bkup_mode_cnt_saved
);
262 static const struct dev_pm_ops bd9571mwv_pm
= {
263 SET_SYSTEM_SLEEP_PM_OPS(bd9571mwv_suspend
, bd9571mwv_resume
)
266 static int bd9571mwv_regulator_remove(struct platform_device
*pdev
)
268 device_remove_file(&pdev
->dev
, &dev_attr_backup_mode
);
271 #define DEV_PM_OPS &bd9571mwv_pm
273 #define DEV_PM_OPS NULL
274 #define bd9571mwv_regulator_remove NULL
275 #endif /* CONFIG_PM_SLEEP */
277 static int bd9571mwv_regulator_probe(struct platform_device
*pdev
)
279 struct bd9571mwv
*bd
= dev_get_drvdata(pdev
->dev
.parent
);
280 struct regulator_config config
= { };
281 struct bd9571mwv_reg
*bdreg
;
282 struct regulator_dev
*rdev
;
286 bdreg
= devm_kzalloc(&pdev
->dev
, sizeof(*bdreg
), GFP_KERNEL
);
292 platform_set_drvdata(pdev
, bdreg
);
294 config
.dev
= &pdev
->dev
;
295 config
.dev
->of_node
= bd
->dev
->of_node
;
296 config
.driver_data
= bd
;
297 config
.regmap
= bd
->regmap
;
299 for (i
= 0; i
< ARRAY_SIZE(regulators
); i
++) {
300 rdev
= devm_regulator_register(&pdev
->dev
, ®ulators
[i
],
303 dev_err(bd
->dev
, "failed to register %s regulator\n",
305 return PTR_ERR(rdev
);
310 of_property_read_u32(bd
->dev
->of_node
, "rohm,ddr-backup-power", &val
);
311 if (val
& ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK
) {
312 dev_err(bd
->dev
, "invalid %s mode %u\n",
313 "rohm,ddr-backup-power", val
);
316 bdreg
->bkup_mode_cnt_keepon
= val
;
318 bdreg
->rstbmode_level
= of_property_read_bool(bd
->dev
->of_node
,
319 "rohm,rstbmode-level");
320 bdreg
->rstbmode_pulse
= of_property_read_bool(bd
->dev
->of_node
,
321 "rohm,rstbmode-pulse");
322 if (bdreg
->rstbmode_level
&& bdreg
->rstbmode_pulse
) {
323 dev_err(bd
->dev
, "only one rohm,rstbmode-* may be specified");
327 #ifdef CONFIG_PM_SLEEP
328 if (bdreg
->bkup_mode_cnt_keepon
) {
332 * Backup mode is enabled by default in pulse mode, but needs
333 * explicit user setup in level mode.
335 bdreg
->bkup_mode_enabled
= bdreg
->rstbmode_pulse
;
337 ret
= device_create_file(&pdev
->dev
, &dev_attr_backup_mode
);
341 #endif /* CONFIG_PM_SLEEP */
346 static const struct platform_device_id bd9571mwv_regulator_id_table
[] = {
347 { "bd9571mwv-regulator", },
350 MODULE_DEVICE_TABLE(platform
, bd9571mwv_regulator_id_table
);
352 static struct platform_driver bd9571mwv_regulator_driver
= {
354 .name
= "bd9571mwv-regulator",
357 .probe
= bd9571mwv_regulator_probe
,
358 .remove
= bd9571mwv_regulator_remove
,
359 .id_table
= bd9571mwv_regulator_id_table
,
361 module_platform_driver(bd9571mwv_regulator_driver
);
363 MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
364 MODULE_DESCRIPTION("BD9571MWV Regulator driver");
365 MODULE_LICENSE("GPL v2");