Blame view
drivers/regulator/anatop-regulator.c
10.2 KB
c07bbfe70 regulator: anatop... |
1 2 3 |
// SPDX-License-Identifier: GPL-2.0+ // // Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. |
e3e5aff71 regulator: Add An... |
4 5 6 7 |
#include <linux/slab.h> #include <linux/device.h> #include <linux/module.h> |
baa64151a regulator: anatop... |
8 |
#include <linux/mfd/syscon.h> |
e3e5aff71 regulator: Add An... |
9 10 11 12 13 |
#include <linux/err.h> #include <linux/io.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_address.h> |
baa64151a regulator: anatop... |
14 |
#include <linux/regmap.h> |
e3e5aff71 regulator: Add An... |
15 16 |
#include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> |
0d19208e7 regulator: i.MX a... |
17 |
#include <linux/regulator/machine.h> |
e3e5aff71 regulator: Add An... |
18 |
|
9ee417c07 regulators: anato... |
19 20 |
#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ #define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */ |
605ebd35f regulator: anatop... |
21 |
#define LDO_POWER_GATE 0x00 |
d38018f20 regulator: anatop... |
22 |
#define LDO_FET_FULL_ON 0x1f |
605ebd35f regulator: anatop... |
23 |
|
275c6b1c0 MLK-13793-6 regul... |
24 |
#define LDO_MIN_DROPOUT_UV 125000 |
e3e5aff71 regulator: Add An... |
25 |
struct anatop_regulator { |
9ee417c07 regulators: anato... |
26 27 28 |
u32 delay_reg; int delay_bit_shift; int delay_bit_width; |
e3e5aff71 regulator: Add An... |
29 |
struct regulator_desc rdesc; |
d38018f20 regulator: anatop... |
30 |
bool bypass; |
605ebd35f regulator: anatop... |
31 |
int sel; |
e3e5aff71 regulator: Add An... |
32 |
}; |
275c6b1c0 MLK-13793-6 regul... |
33 34 |
static struct anatop_regulator *vddpu; static struct anatop_regulator *vddsoc; |
9ee417c07 regulators: anato... |
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg, unsigned int old_sel, unsigned int new_sel) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); u32 val; int ret = 0; /* check whether need to care about LDO ramp up speed */ if (anatop_reg->delay_bit_width && new_sel > old_sel) { /* * the delay for LDO ramp up time is * based on the register setting, we need * to calculate how many steps LDO need to * ramp up, and how much delay needed. (us) */ |
f34a26922 regulator: anatop... |
51 |
regmap_read(reg->regmap, anatop_reg->delay_reg, &val); |
9ee417c07 regulators: anato... |
52 53 |
val = (val >> anatop_reg->delay_bit_shift) & ((1 << anatop_reg->delay_bit_width) - 1); |
ff1ce0571 regulator: anatop... |
54 55 |
ret = (new_sel - old_sel) * (LDO_RAMP_UP_UNIT_IN_CYCLES << val) / LDO_RAMP_UP_FREQ_IN_MHZ + 1; |
9ee417c07 regulators: anato... |
56 57 58 59 |
} return ret; } |
605ebd35f regulator: anatop... |
60 61 62 |
static int anatop_regmap_enable(struct regulator_dev *reg) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); |
d38018f20 regulator: anatop... |
63 |
int sel; |
605ebd35f regulator: anatop... |
64 |
|
275c6b1c0 MLK-13793-6 regul... |
65 66 67 68 69 70 71 72 73 74 |
/* * The vddpu has to stay at the same voltage level as vddsoc * whenever it's about to be enabled. */ if (anatop_reg == vddpu && vddsoc) { anatop_reg->sel = vddsoc->sel; anatop_reg->bypass = vddsoc->bypass; if (anatop_reg->bypass) anatop_reg->rdesc.min_dropout_uV = 0; } |
d38018f20 regulator: anatop... |
75 76 |
sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel; return regulator_set_voltage_sel_regmap(reg, sel); |
605ebd35f regulator: anatop... |
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
} static int anatop_regmap_disable(struct regulator_dev *reg) { return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE); } static int anatop_regmap_is_enabled(struct regulator_dev *reg) { return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE; } static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg, unsigned selector) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); int ret; |
d38018f20 regulator: anatop... |
94 |
if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) { |
605ebd35f regulator: anatop... |
95 96 97 98 99 100 101 102 103 104 105 106 107 |
anatop_reg->sel = selector; return 0; } ret = regulator_set_voltage_sel_regmap(reg, selector); if (!ret) anatop_reg->sel = selector; return ret; } static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); |
d38018f20 regulator: anatop... |
108 |
if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) |
605ebd35f regulator: anatop... |
109 110 111 112 |
return anatop_reg->sel; return regulator_get_voltage_sel_regmap(reg); } |
d38018f20 regulator: anatop... |
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
static int anatop_regmap_get_bypass(struct regulator_dev *reg, bool *enable) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); int sel; sel = regulator_get_voltage_sel_regmap(reg); if (sel == LDO_FET_FULL_ON) WARN_ON(!anatop_reg->bypass); else if (sel != LDO_POWER_GATE) WARN_ON(anatop_reg->bypass); *enable = anatop_reg->bypass; return 0; } static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); int sel; if (enable == anatop_reg->bypass) return 0; sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel; anatop_reg->bypass = enable; |
275c6b1c0 MLK-13793-6 regul... |
138 139 140 141 |
if (anatop_reg->bypass) anatop_reg->rdesc.min_dropout_uV = 0; else anatop_reg->rdesc.min_dropout_uV = LDO_MIN_DROPOUT_UV; |
d38018f20 regulator: anatop... |
142 143 144 |
return regulator_set_voltage_sel_regmap(reg, sel); } |
e3e5aff71 regulator: Add An... |
145 |
static struct regulator_ops anatop_rops = { |
114c5748d regulator: anatop... |
146 147 |
.set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, |
d01c3a1e1 regulator: anatop... |
148 149 |
.list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, |
e3e5aff71 regulator: Add An... |
150 |
}; |
cae62a937 regulator: anatop... |
151 |
static const struct regulator_ops anatop_core_rops = { |
605ebd35f regulator: anatop... |
152 153 154 155 156 157 158 159 |
.enable = anatop_regmap_enable, .disable = anatop_regmap_disable, .is_enabled = anatop_regmap_is_enabled, .set_voltage_sel = anatop_regmap_core_set_voltage_sel, .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel, .get_voltage_sel = anatop_regmap_core_get_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, |
d38018f20 regulator: anatop... |
160 161 |
.get_bypass = anatop_regmap_get_bypass, .set_bypass = anatop_regmap_set_bypass, |
605ebd35f regulator: anatop... |
162 |
}; |
a5023574d regulator: remove... |
163 |
static int anatop_regulator_probe(struct platform_device *pdev) |
e3e5aff71 regulator: Add An... |
164 165 166 |
{ struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; |
baa64151a regulator: anatop... |
167 |
struct device_node *anatop_np; |
e3e5aff71 regulator: Add An... |
168 169 170 171 |
struct regulator_desc *rdesc; struct regulator_dev *rdev; struct anatop_regulator *sreg; struct regulator_init_data *initdata; |
d914d81b7 regulator: Conver... |
172 |
struct regulator_config config = { }; |
f34a26922 regulator: anatop... |
173 174 175 176 177 178 179 |
struct regmap *regmap; u32 control_reg; u32 vol_bit_shift; u32 vol_bit_width; u32 min_bit_val; u32 min_voltage; u32 max_voltage; |
e3e5aff71 regulator: Add An... |
180 |
int ret = 0; |
605ebd35f regulator: anatop... |
181 |
u32 val; |
e3e5aff71 regulator: Add An... |
182 |
|
e3e5aff71 regulator: Add An... |
183 184 185 |
sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); if (!sreg) return -ENOMEM; |
5062e0471 regulator: anatop... |
186 |
|
e3e5aff71 regulator: Add An... |
187 |
rdesc = &sreg->rdesc; |
e3e5aff71 regulator: Add An... |
188 189 |
rdesc->type = REGULATOR_VOLTAGE; rdesc->owner = THIS_MODULE; |
baa64151a regulator: anatop... |
190 |
|
aeb1404d6 regulator: anatop... |
191 |
of_property_read_string(np, "regulator-name", &rdesc->name); |
4af5924c0 regulator: anatop... |
192 193 194 195 196 |
if (!rdesc->name) { dev_err(dev, "failed to get a regulator-name "); return -EINVAL; } |
aeb1404d6 regulator: anatop... |
197 |
|
072e78b12 regulator: of: Ad... |
198 |
initdata = of_get_regulator_init_data(dev, np, rdesc); |
7f51cf2ea regulator: anatop... |
199 200 |
if (!initdata) return -ENOMEM; |
0d19208e7 regulator: i.MX a... |
201 |
initdata->supply_regulator = "vin"; |
072e78b12 regulator: of: Ad... |
202 |
|
baa64151a regulator: anatop... |
203 204 205 |
anatop_np = of_get_parent(np); if (!anatop_np) return -ENODEV; |
f34a26922 regulator: anatop... |
206 |
regmap = syscon_node_to_regmap(anatop_np); |
baa64151a regulator: anatop... |
207 |
of_node_put(anatop_np); |
f34a26922 regulator: anatop... |
208 209 |
if (IS_ERR(regmap)) return PTR_ERR(regmap); |
baa64151a regulator: anatop... |
210 |
|
f34a26922 regulator: anatop... |
211 |
ret = of_property_read_u32(np, "anatop-reg-offset", &control_reg); |
e3e5aff71 regulator: Add An... |
212 |
if (ret) { |
2f2cc27f5 regulator: anatop... |
213 214 |
dev_err(dev, "no anatop-reg-offset property set "); |
f2b269b83 regulator: anatop... |
215 |
return ret; |
e3e5aff71 regulator: Add An... |
216 |
} |
f34a26922 regulator: anatop... |
217 |
ret = of_property_read_u32(np, "anatop-vol-bit-width", &vol_bit_width); |
e3e5aff71 regulator: Add An... |
218 219 220 |
if (ret) { dev_err(dev, "no anatop-vol-bit-width property set "); |
f2b269b83 regulator: anatop... |
221 |
return ret; |
e3e5aff71 regulator: Add An... |
222 |
} |
f34a26922 regulator: anatop... |
223 |
ret = of_property_read_u32(np, "anatop-vol-bit-shift", &vol_bit_shift); |
e3e5aff71 regulator: Add An... |
224 225 226 |
if (ret) { dev_err(dev, "no anatop-vol-bit-shift property set "); |
f2b269b83 regulator: anatop... |
227 |
return ret; |
e3e5aff71 regulator: Add An... |
228 |
} |
f34a26922 regulator: anatop... |
229 |
ret = of_property_read_u32(np, "anatop-min-bit-val", &min_bit_val); |
e3e5aff71 regulator: Add An... |
230 231 232 |
if (ret) { dev_err(dev, "no anatop-min-bit-val property set "); |
f2b269b83 regulator: anatop... |
233 |
return ret; |
e3e5aff71 regulator: Add An... |
234 |
} |
f34a26922 regulator: anatop... |
235 |
ret = of_property_read_u32(np, "anatop-min-voltage", &min_voltage); |
e3e5aff71 regulator: Add An... |
236 237 238 |
if (ret) { dev_err(dev, "no anatop-min-voltage property set "); |
f2b269b83 regulator: anatop... |
239 |
return ret; |
e3e5aff71 regulator: Add An... |
240 |
} |
f34a26922 regulator: anatop... |
241 |
ret = of_property_read_u32(np, "anatop-max-voltage", &max_voltage); |
e3e5aff71 regulator: Add An... |
242 243 244 |
if (ret) { dev_err(dev, "no anatop-max-voltage property set "); |
f2b269b83 regulator: anatop... |
245 |
return ret; |
e3e5aff71 regulator: Add An... |
246 |
} |
9ee417c07 regulators: anato... |
247 248 249 250 251 252 253 |
/* read LDO ramp up setting, only for core reg */ of_property_read_u32(np, "anatop-delay-reg-offset", &sreg->delay_reg); of_property_read_u32(np, "anatop-delay-bit-width", &sreg->delay_bit_width); of_property_read_u32(np, "anatop-delay-bit-shift", &sreg->delay_bit_shift); |
f34a26922 regulator: anatop... |
254 255 256 |
rdesc->n_voltages = (max_voltage - min_voltage) / 25000 + 1 + min_bit_val; rdesc->min_uV = min_voltage; |
0713e6abf regulator: anatop... |
257 |
rdesc->uV_step = 25000; |
f34a26922 regulator: anatop... |
258 259 260 |
rdesc->linear_min_sel = min_bit_val; rdesc->vsel_reg = control_reg; rdesc->vsel_mask = ((1 << vol_bit_width) - 1) << vol_bit_shift; |
275c6b1c0 MLK-13793-6 regul... |
261 |
rdesc->min_dropout_uV = LDO_MIN_DROPOUT_UV; |
e3e5aff71 regulator: Add An... |
262 |
|
d914d81b7 regulator: Conver... |
263 264 265 266 |
config.dev = &pdev->dev; config.init_data = initdata; config.driver_data = sreg; config.of_node = pdev->dev.of_node; |
f34a26922 regulator: anatop... |
267 |
config.regmap = regmap; |
d914d81b7 regulator: Conver... |
268 |
|
605ebd35f regulator: anatop... |
269 |
/* Only core regulators have the ramp up delay configuration. */ |
f34a26922 regulator: anatop... |
270 |
if (control_reg && sreg->delay_bit_width) { |
605ebd35f regulator: anatop... |
271 272 273 274 275 276 277 278 |
rdesc->ops = &anatop_core_rops; ret = regmap_read(config.regmap, rdesc->vsel_reg, &val); if (ret) { dev_err(dev, "failed to read initial state "); return ret; } |
f34a26922 regulator: anatop... |
279 |
sreg->sel = (val & rdesc->vsel_mask) >> vol_bit_shift; |
d38018f20 regulator: anatop... |
280 281 282 |
if (sreg->sel == LDO_FET_FULL_ON) { sreg->sel = 0; sreg->bypass = true; |
275c6b1c0 MLK-13793-6 regul... |
283 |
rdesc->min_dropout_uV = 0; |
d38018f20 regulator: anatop... |
284 |
} |
fe08be3ec regulator: anatop... |
285 286 287 288 289 290 |
/* * In case vddpu was disabled by the bootloader, we need to set * a sane default until imx6-cpufreq was probed and changes the * voltage to the correct value. In this case we set 1.25V. */ |
275c6b1c0 MLK-13793-6 regul... |
291 |
if (!sreg->sel && !strcmp(rdesc->name, "vddpu")) { |
fe08be3ec regulator: anatop... |
292 |
sreg->sel = 22; |
275c6b1c0 MLK-13793-6 regul... |
293 294 |
vddpu = sreg; } |
da0607c8d regulator: anatop... |
295 |
|
9bf944548 regulator: anatop... |
296 |
/* set the default voltage of the pcie phy to be 1.100v */ |
4af5924c0 regulator: anatop... |
297 |
if (!sreg->sel && !strcmp(rdesc->name, "vddpcie")) |
9bf944548 regulator: anatop... |
298 |
sreg->sel = 0x10; |
275c6b1c0 MLK-13793-6 regul... |
299 300 |
if (!strcmp(rdesc->name, "vddsoc")) vddsoc = sreg; |
8a092e682 regulator: anatop... |
301 |
if (!sreg->bypass && !sreg->sel) { |
da0607c8d regulator: anatop... |
302 303 304 305 |
dev_err(&pdev->dev, "Failed to read a valid default voltage selector. "); return -EINVAL; } |
605ebd35f regulator: anatop... |
306 |
} else { |
ca7734ad7 regulator: anatop... |
307 |
u32 enable_bit; |
605ebd35f regulator: anatop... |
308 |
rdesc->ops = &anatop_rops; |
ca7734ad7 regulator: anatop... |
309 310 311 312 313 314 |
if (!of_property_read_u32(np, "anatop-enable-bit", &enable_bit)) { anatop_rops.enable = regulator_enable_regmap; anatop_rops.disable = regulator_disable_regmap; anatop_rops.is_enabled = regulator_is_enabled_regmap; |
f34a26922 regulator: anatop... |
315 |
rdesc->enable_reg = control_reg; |
ca7734ad7 regulator: anatop... |
316 317 |
rdesc->enable_mask = BIT(enable_bit); } |
605ebd35f regulator: anatop... |
318 |
} |
e3e5aff71 regulator: Add An... |
319 |
/* register regulator */ |
be1221e89 regulator: anatop... |
320 |
rdev = devm_regulator_register(dev, rdesc, &config); |
e3e5aff71 regulator: Add An... |
321 |
if (IS_ERR(rdev)) { |
788bfc6eb regulator: anatop... |
322 323 324 325 326 327 328 329 330 |
ret = PTR_ERR(rdev); if (ret == -EPROBE_DEFER) dev_dbg(dev, "failed to register %s, deferring... ", rdesc->name); else dev_err(dev, "failed to register %s ", rdesc->name); return ret; |
e3e5aff71 regulator: Add An... |
331 332 333 |
} platform_set_drvdata(pdev, rdev); |
e3e5aff71 regulator: Add An... |
334 335 |
return 0; } |
a799baab1 regulator: anatop... |
336 |
static const struct of_device_id of_anatop_regulator_match_tbl[] = { |
e3e5aff71 regulator: Add An... |
337 338 339 |
{ .compatible = "fsl,anatop-regulator", }, { /* end */ } }; |
d702ffd4d regulator: anatop... |
340 |
MODULE_DEVICE_TABLE(of, of_anatop_regulator_match_tbl); |
e3e5aff71 regulator: Add An... |
341 |
|
c0d78c234 regulator: anatop... |
342 |
static struct platform_driver anatop_regulator_driver = { |
e3e5aff71 regulator: Add An... |
343 344 |
.driver = { .name = "anatop_regulator", |
e3e5aff71 regulator: Add An... |
345 346 347 |
.of_match_table = of_anatop_regulator_match_tbl, }, .probe = anatop_regulator_probe, |
e3e5aff71 regulator: Add An... |
348 349 350 351 |
}; static int __init anatop_regulator_init(void) { |
c0d78c234 regulator: anatop... |
352 |
return platform_driver_register(&anatop_regulator_driver); |
e3e5aff71 regulator: Add An... |
353 354 355 356 357 |
} postcore_initcall(anatop_regulator_init); static void __exit anatop_regulator_exit(void) { |
c0d78c234 regulator: anatop... |
358 |
platform_driver_unregister(&anatop_regulator_driver); |
e3e5aff71 regulator: Add An... |
359 360 |
} module_exit(anatop_regulator_exit); |
34f756851 regulator: anatop... |
361 362 |
MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>"); MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); |
e3e5aff71 regulator: Add An... |
363 364 |
MODULE_DESCRIPTION("ANATOP Regulator driver"); MODULE_LICENSE("GPL v2"); |
89705b9e3 regulator: anatop... |
365 |
MODULE_ALIAS("platform:anatop_regulator"); |