blob: 6eb2b8133a3b958d017e5a5ddf5e3ea2807b389f [file] [log] [blame]
Peng Fan2d9bd932019-07-31 07:01:54 +00001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved.
4 * Copyright 2019 NXP
5 */
6
Patrick Delaunay8767e792021-11-19 15:12:07 +01007#define LOG_CATEGORY UCLASS_CLK
8
Peng Fan2d9bd932019-07-31 07:01:54 +00009#include <common.h>
Patrick Delaunay283dadf2021-11-19 15:12:06 +010010#include <clk.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000011#include <clk-uclass.h>
Patrick Delaunay8767e792021-11-19 15:12:07 +010012#include <log.h>
Patrick Delaunay283dadf2021-11-19 15:12:06 +010013#include <malloc.h>
14#include <asm/io.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000015#include <dm/device.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070016#include <dm/devres.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000017#include <linux/clk-provider.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <linux/err.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000019
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
Sean Andersonaa1e85f2020-06-24 06:41:07 -040030 if (mux)
31 return clk_mux_get_parent(mux);
32 else
33 return 0;
Peng Fan2d9bd932019-07-31 07:01:54 +000034}
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
Simon Glass46e5f612021-03-25 10:26:09 +130043 if (!mux || !mux_ops)
44 return -ENOSYS;
45
46 return mux_ops->set_parent(mux, parent);
Peng Fan2d9bd932019-07-31 07:01:54 +000047}
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
Sean Andersonaa1e85f2020-06-24 06:41:07 -040056 if (rate && rate_ops)
57 return rate_ops->get_rate(rate);
58 else
59 return clk_get_parent_rate(clk);
Peng Fan2d9bd932019-07-31 07:01:54 +000060}
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
Sean Andersonaa1e85f2020-06-24 06:41:07 -040069 if (rate && rate_ops)
70 return rate_ops->set_rate(clk_rate, rate);
71 else
72 return clk_get_rate(clk);
Peng Fan2d9bd932019-07-31 07:01:54 +000073}
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
Sean Andersonaa1e85f2020-06-24 06:41:07 -040082 if (gate && gate_ops)
83 return gate_ops->enable(gate);
84 else
85 return 0;
Peng Fan2d9bd932019-07-31 07:01:54 +000086}
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
Sean Andersonaa1e85f2020-06-24 06:41:07 -040095 if (gate && gate_ops)
96 return gate_ops->disable(gate);
97 else
98 return 0;
Peng Fan2d9bd932019-07-31 07:01:54 +000099}
100
Peng Fan2d9bd932019-07-31 07:01:54 +0000101struct 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;
Sean Andersonaa1e85f2020-06-24 06:41:07 -0400114
115 if (!num_parents || (num_parents != 1 && !mux))
116 return ERR_PTR(-EINVAL);
Peng Fan2d9bd932019-07-31 07:01:54 +0000117
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;
Peng Fan2d9bd932019-07-31 07:01:54 +0000125 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 }
Peng Fan2d9bd932019-07-31 07:01:54 +0000133
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;
Peng Fan2d9bd932019-07-31 07:01:54 +0000147 gate->data = (ulong)composite;
148 }
149
150 clk = &composite->clk;
Dario Binacchi1a62dc12020-04-13 14:36:27 +0200151 clk->flags = flags;
Peng Fan2d9bd932019-07-31 07:01:54 +0000152 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
Sean Andersoncfc2f022020-06-24 06:41:06 -0400159 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
Peng Fan2d9bd932019-07-31 07:01:54 +0000166 return clk;
167
168err:
169 kfree(composite);
170 return clk;
171}
172
Sean Andersonaa1e85f2020-06-24 06:41:07 -0400173static 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
Peng Fan2d9bd932019-07-31 07:01:54 +0000181U_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};