1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2015 Samsung Electronics
4 *
5 * Przemyslaw Marczak <p.marczak@samsung.com>
6 */
7
8 #include <common.h>
9 #include <clk.h>
10 #include <errno.h>
11 #include <dm.h>
12 #include <linux/delay.h>
13 #include <log.h>
14 #include <power/pmic.h>
15 #include <power/regulator.h>
16
17 #include "regulator_common.h"
18
19 struct fixed_clock_regulator_plat {
20 struct clk *enable_clock;
21 unsigned int clk_enable_counter;
22 };
23
fixed_regulator_of_to_plat(struct udevice * dev)24 static int fixed_regulator_of_to_plat(struct udevice *dev)
25 {
26 struct dm_regulator_uclass_plat *uc_pdata;
27 struct regulator_common_plat *dev_pdata;
28
29 dev_pdata = dev_get_plat(dev);
30 uc_pdata = dev_get_uclass_plat(dev);
31 if (!uc_pdata)
32 return -ENXIO;
33
34 uc_pdata->type = REGULATOR_TYPE_FIXED;
35
36 return regulator_common_of_to_plat(dev, dev_pdata, "gpio");
37 }
38
fixed_regulator_get_value(struct udevice * dev)39 static int fixed_regulator_get_value(struct udevice *dev)
40 {
41 struct dm_regulator_uclass_plat *uc_pdata;
42
43 uc_pdata = dev_get_uclass_plat(dev);
44 if (!uc_pdata)
45 return -ENXIO;
46
47 if (uc_pdata->min_uV != uc_pdata->max_uV) {
48 debug("Invalid constraints for: %s\n", uc_pdata->name);
49 return -EINVAL;
50 }
51
52 return uc_pdata->min_uV;
53 }
54
fixed_regulator_get_current(struct udevice * dev)55 static int fixed_regulator_get_current(struct udevice *dev)
56 {
57 struct dm_regulator_uclass_plat *uc_pdata;
58
59 uc_pdata = dev_get_uclass_plat(dev);
60 if (!uc_pdata)
61 return -ENXIO;
62
63 if (uc_pdata->min_uA != uc_pdata->max_uA) {
64 debug("Invalid constraints for: %s\n", uc_pdata->name);
65 return -EINVAL;
66 }
67
68 return uc_pdata->min_uA;
69 }
70
fixed_regulator_get_enable(struct udevice * dev)71 static int fixed_regulator_get_enable(struct udevice *dev)
72 {
73 return regulator_common_get_enable(dev, dev_get_plat(dev));
74 }
75
fixed_regulator_set_enable(struct udevice * dev,bool enable)76 static int fixed_regulator_set_enable(struct udevice *dev, bool enable)
77 {
78 return regulator_common_set_enable(dev, dev_get_plat(dev), enable);
79 }
80
fixed_clock_regulator_get_enable(struct udevice * dev)81 static int fixed_clock_regulator_get_enable(struct udevice *dev)
82 {
83 struct fixed_clock_regulator_plat *priv = dev_get_priv(dev);
84
85 return priv->clk_enable_counter > 0;
86 }
87
fixed_clock_regulator_set_enable(struct udevice * dev,bool enable)88 static int fixed_clock_regulator_set_enable(struct udevice *dev, bool enable)
89 {
90 struct fixed_clock_regulator_plat *priv = dev_get_priv(dev);
91 struct regulator_common_plat *dev_pdata = dev_get_plat(dev);
92 int ret = 0;
93
94 if (enable) {
95 ret = clk_enable(priv->enable_clock);
96 priv->clk_enable_counter++;
97 } else {
98 ret = clk_disable(priv->enable_clock);
99 priv->clk_enable_counter--;
100 }
101 if (ret)
102 return ret;
103
104 if (enable && dev_pdata->startup_delay_us)
105 udelay(dev_pdata->startup_delay_us);
106
107 if (!enable && dev_pdata->off_on_delay_us)
108 udelay(dev_pdata->off_on_delay_us);
109
110 return ret;
111 }
112
113 static const struct dm_regulator_ops fixed_regulator_ops = {
114 .get_value = fixed_regulator_get_value,
115 .get_current = fixed_regulator_get_current,
116 .get_enable = fixed_regulator_get_enable,
117 .set_enable = fixed_regulator_set_enable,
118 };
119
120 static const struct dm_regulator_ops fixed_clock_regulator_ops = {
121 .get_enable = fixed_clock_regulator_get_enable,
122 .set_enable = fixed_clock_regulator_set_enable,
123 };
124
125 static const struct udevice_id fixed_regulator_ids[] = {
126 { .compatible = "regulator-fixed" },
127 { },
128 };
129
130 static const struct udevice_id fixed_clock_regulator_ids[] = {
131 { .compatible = "regulator-fixed-clock" },
132 { },
133 };
134
135 U_BOOT_DRIVER(regulator_fixed) = {
136 .name = "regulator_fixed",
137 .id = UCLASS_REGULATOR,
138 .ops = &fixed_regulator_ops,
139 .of_match = fixed_regulator_ids,
140 .of_to_plat = fixed_regulator_of_to_plat,
141 .plat_auto = sizeof(struct regulator_common_plat),
142 };
143
144 U_BOOT_DRIVER(regulator_fixed_clock) = {
145 .name = "regulator_fixed_clk",
146 .id = UCLASS_REGULATOR,
147 .ops = &fixed_clock_regulator_ops,
148 .of_match = fixed_clock_regulator_ids,
149 .of_to_plat = fixed_regulator_of_to_plat,
150 .plat_auto = sizeof(struct fixed_clock_regulator_plat),
151 };
152