blob: 199ca6eaa370a87bfce567ee72a40024c562b48f [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
Patrick Delaunay283dadf2021-11-19 15:12:06 +01009#include <clk.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000010#include <clk-uclass.h>
Patrick Delaunay8767e792021-11-19 15:12:07 +010011#include <log.h>
Patrick Delaunay283dadf2021-11-19 15:12:06 +010012#include <malloc.h>
13#include <asm/io.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000014#include <dm/device.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070015#include <dm/devres.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000016#include <linux/clk-provider.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070017#include <linux/err.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000018
19#include "clk.h"
20
21#define UBOOT_DM_CLK_COMPOSITE "clk_composite"
22
23static u8 clk_composite_get_parent(struct clk *clk)
24{
25 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
26 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
27 struct clk *mux = composite->mux;
28
Sean Andersonaa1e85f2020-06-24 06:41:07 -040029 if (mux)
30 return clk_mux_get_parent(mux);
31 else
32 return 0;
Peng Fan2d9bd932019-07-31 07:01:54 +000033}
34
35static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
36{
37 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
38 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
39 const struct clk_ops *mux_ops = composite->mux_ops;
40 struct clk *mux = composite->mux;
41
Simon Glass46e5f612021-03-25 10:26:09 +130042 if (!mux || !mux_ops)
43 return -ENOSYS;
44
45 return mux_ops->set_parent(mux, parent);
Peng Fan2d9bd932019-07-31 07:01:54 +000046}
47
48static unsigned long clk_composite_recalc_rate(struct clk *clk)
49{
50 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
51 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
52 const struct clk_ops *rate_ops = composite->rate_ops;
53 struct clk *rate = composite->rate;
54
Sean Andersonaa1e85f2020-06-24 06:41:07 -040055 if (rate && rate_ops)
56 return rate_ops->get_rate(rate);
57 else
58 return clk_get_parent_rate(clk);
Peng Fan2d9bd932019-07-31 07:01:54 +000059}
60
61static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate)
62{
63 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
64 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
65 const struct clk_ops *rate_ops = composite->rate_ops;
66 struct clk *clk_rate = composite->rate;
67
Igor Prusov46c81902023-12-06 02:23:33 +030068 if (rate && rate_ops && rate_ops->set_rate)
Sean Andersonaa1e85f2020-06-24 06:41:07 -040069 return rate_ops->set_rate(clk_rate, rate);
70 else
71 return clk_get_rate(clk);
Peng Fan2d9bd932019-07-31 07:01:54 +000072}
73
74static int clk_composite_enable(struct clk *clk)
75{
76 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
77 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
78 const struct clk_ops *gate_ops = composite->gate_ops;
79 struct clk *gate = composite->gate;
80
Sean Andersonaa1e85f2020-06-24 06:41:07 -040081 if (gate && gate_ops)
82 return gate_ops->enable(gate);
83 else
84 return 0;
Peng Fan2d9bd932019-07-31 07:01:54 +000085}
86
87static int clk_composite_disable(struct clk *clk)
88{
89 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
90 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
91 const struct clk_ops *gate_ops = composite->gate_ops;
92 struct clk *gate = composite->gate;
93
Sean Andersonaa1e85f2020-06-24 06:41:07 -040094 if (gate && gate_ops)
95 return gate_ops->disable(gate);
96 else
97 return 0;
Peng Fan2d9bd932019-07-31 07:01:54 +000098}
99
Peng Fan2d9bd932019-07-31 07:01:54 +0000100struct clk *clk_register_composite(struct device *dev, const char *name,
101 const char * const *parent_names,
102 int num_parents, struct clk *mux,
103 const struct clk_ops *mux_ops,
104 struct clk *rate,
105 const struct clk_ops *rate_ops,
106 struct clk *gate,
107 const struct clk_ops *gate_ops,
108 unsigned long flags)
109{
110 struct clk *clk;
111 struct clk_composite *composite;
112 int ret;
Sean Andersonaa1e85f2020-06-24 06:41:07 -0400113
114 if (!num_parents || (num_parents != 1 && !mux))
115 return ERR_PTR(-EINVAL);
Peng Fan2d9bd932019-07-31 07:01:54 +0000116
117 composite = kzalloc(sizeof(*composite), GFP_KERNEL);
118 if (!composite)
119 return ERR_PTR(-ENOMEM);
120
121 if (mux && mux_ops) {
122 composite->mux = mux;
123 composite->mux_ops = mux_ops;
Peng Fan2d9bd932019-07-31 07:01:54 +0000124 mux->data = (ulong)composite;
125 }
126
127 if (rate && rate_ops) {
128 if (!rate_ops->get_rate) {
129 clk = ERR_PTR(-EINVAL);
130 goto err;
131 }
Peng Fan2d9bd932019-07-31 07:01:54 +0000132
133 composite->rate = rate;
134 composite->rate_ops = rate_ops;
135 rate->data = (ulong)composite;
136 }
137
138 if (gate && gate_ops) {
139 if (!gate_ops->enable || !gate_ops->disable) {
140 clk = ERR_PTR(-EINVAL);
141 goto err;
142 }
143
144 composite->gate = gate;
145 composite->gate_ops = gate_ops;
Peng Fan2d9bd932019-07-31 07:01:54 +0000146 gate->data = (ulong)composite;
147 }
148
149 clk = &composite->clk;
Dario Binacchi1a62dc12020-04-13 14:36:27 +0200150 clk->flags = flags;
Peng Fan2d9bd932019-07-31 07:01:54 +0000151 ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
152 parent_names[clk_composite_get_parent(clk)]);
153 if (ret) {
154 clk = ERR_PTR(ret);
155 goto err;
156 }
157
Sean Andersoncfc2f022020-06-24 06:41:06 -0400158 if (composite->mux)
159 composite->mux->dev = clk->dev;
160 if (composite->rate)
161 composite->rate->dev = clk->dev;
162 if (composite->gate)
163 composite->gate->dev = clk->dev;
164
Peng Fan2d9bd932019-07-31 07:01:54 +0000165 return clk;
166
167err:
168 kfree(composite);
169 return clk;
170}
171
Sean Andersonaa1e85f2020-06-24 06:41:07 -0400172static const struct clk_ops clk_composite_ops = {
173 .set_parent = clk_composite_set_parent,
174 .get_rate = clk_composite_recalc_rate,
175 .set_rate = clk_composite_set_rate,
176 .enable = clk_composite_enable,
177 .disable = clk_composite_disable,
178};
179
Peng Fan2d9bd932019-07-31 07:01:54 +0000180U_BOOT_DRIVER(clk_composite) = {
181 .name = UBOOT_DM_CLK_COMPOSITE,
182 .id = UCLASS_CLK,
183 .ops = &clk_composite_ops,
184 .flags = DM_FLAG_PRE_RELOC,
185};