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