1
2
3
4
5
6
7#define LOG_CATEGORY UCLASS_CLK
8
9#include <common.h>
10#include <clk.h>
11#include <clk-uclass.h>
12#include <log.h>
13#include <malloc.h>
14#include <asm/io.h>
15#include <dm/device.h>
16#include <dm/devres.h>
17#include <linux/clk-provider.h>
18#include <linux/err.h>
19
20#include "clk.h"
21
22#define UBOOT_DM_CLK_COMPOSITE "clk_composite"
23
24static u8 clk_composite_get_parent(struct clk *clk)
25{
26 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
27 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
28 struct clk *mux = composite->mux;
29
30 if (mux)
31 return clk_mux_get_parent(mux);
32 else
33 return 0;
34}
35
36static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
37{
38 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
39 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
40 const struct clk_ops *mux_ops = composite->mux_ops;
41 struct clk *mux = composite->mux;
42
43 if (!mux || !mux_ops)
44 return -ENOSYS;
45
46 return mux_ops->set_parent(mux, parent);
47}
48
49static unsigned long clk_composite_recalc_rate(struct clk *clk)
50{
51 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
52 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
53 const struct clk_ops *rate_ops = composite->rate_ops;
54 struct clk *rate = composite->rate;
55
56 if (rate && rate_ops)
57 return rate_ops->get_rate(rate);
58 else
59 return clk_get_parent_rate(clk);
60}
61
62static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate)
63{
64 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
65 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
66 const struct clk_ops *rate_ops = composite->rate_ops;
67 struct clk *clk_rate = composite->rate;
68
69 if (rate && rate_ops)
70 return rate_ops->set_rate(clk_rate, rate);
71 else
72 return clk_get_rate(clk);
73}
74
75static int clk_composite_enable(struct clk *clk)
76{
77 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
78 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
79 const struct clk_ops *gate_ops = composite->gate_ops;
80 struct clk *gate = composite->gate;
81
82 if (gate && gate_ops)
83 return gate_ops->enable(gate);
84 else
85 return 0;
86}
87
88static int clk_composite_disable(struct clk *clk)
89{
90 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
91 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
92 const struct clk_ops *gate_ops = composite->gate_ops;
93 struct clk *gate = composite->gate;
94
95 if (gate && gate_ops)
96 return gate_ops->disable(gate);
97 else
98 return 0;
99}
100
101struct clk *clk_register_composite(struct device *dev, const char *name,
102 const char * const *parent_names,
103 int num_parents, struct clk *mux,
104 const struct clk_ops *mux_ops,
105 struct clk *rate,
106 const struct clk_ops *rate_ops,
107 struct clk *gate,
108 const struct clk_ops *gate_ops,
109 unsigned long flags)
110{
111 struct clk *clk;
112 struct clk_composite *composite;
113 int ret;
114
115 if (!num_parents || (num_parents != 1 && !mux))
116 return ERR_PTR(-EINVAL);
117
118 composite = kzalloc(sizeof(*composite), GFP_KERNEL);
119 if (!composite)
120 return ERR_PTR(-ENOMEM);
121
122 if (mux && mux_ops) {
123 composite->mux = mux;
124 composite->mux_ops = mux_ops;
125 mux->data = (ulong)composite;
126 }
127
128 if (rate && rate_ops) {
129 if (!rate_ops->get_rate) {
130 clk = ERR_PTR(-EINVAL);
131 goto err;
132 }
133
134 composite->rate = rate;
135 composite->rate_ops = rate_ops;
136 rate->data = (ulong)composite;
137 }
138
139 if (gate && gate_ops) {
140 if (!gate_ops->enable || !gate_ops->disable) {
141 clk = ERR_PTR(-EINVAL);
142 goto err;
143 }
144
145 composite->gate = gate;
146 composite->gate_ops = gate_ops;
147 gate->data = (ulong)composite;
148 }
149
150 clk = &composite->clk;
151 clk->flags = flags;
152 ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
153 parent_names[clk_composite_get_parent(clk)]);
154 if (ret) {
155 clk = ERR_PTR(ret);
156 goto err;
157 }
158
159 if (composite->mux)
160 composite->mux->dev = clk->dev;
161 if (composite->rate)
162 composite->rate->dev = clk->dev;
163 if (composite->gate)
164 composite->gate->dev = clk->dev;
165
166 return clk;
167
168err:
169 kfree(composite);
170 return clk;
171}
172
173static const struct clk_ops clk_composite_ops = {
174 .set_parent = clk_composite_set_parent,
175 .get_rate = clk_composite_recalc_rate,
176 .set_rate = clk_composite_set_rate,
177 .enable = clk_composite_enable,
178 .disable = clk_composite_disable,
179};
180
181U_BOOT_DRIVER(clk_composite) = {
182 .name = UBOOT_DM_CLK_COMPOSITE,
183 .id = UCLASS_CLK,
184 .ops = &clk_composite_ops,
185 .flags = DM_FLAG_PRE_RELOC,
186};
187