Prepare v2023.10
[platform/kernel/u-boot.git] / drivers / clk / clk-composite.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2013 NVIDIA CORPORATION.  All rights reserved.
4  * Copyright 2019 NXP
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
24 static 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
36 static 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
49 static 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
62 static 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
75 static 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
88 static 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
101 struct 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
168 err:
169         kfree(composite);
170         return clk;
171 }
172
173 static 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
181 U_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 };