blob: 12288e10b39c4ea5162078fd9730a9de7cb7e349 [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
7#include <common.h>
Patrick Delaunay283dadf2021-11-19 15:12:06 +01008#include <clk.h>
Peng Fan2d9bd932019-07-31 07:01:54 +00009#include <clk-uclass.h>
Patrick Delaunay283dadf2021-11-19 15:12:06 +010010#include <malloc.h>
11#include <asm/io.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000012#include <dm/device.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070013#include <dm/devres.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000014#include <linux/clk-provider.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070015#include <linux/err.h>
Peng Fan2d9bd932019-07-31 07:01:54 +000016
17#include "clk.h"
18
19#define UBOOT_DM_CLK_COMPOSITE "clk_composite"
20
21static u8 clk_composite_get_parent(struct clk *clk)
22{
23 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
24 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
25 struct clk *mux = composite->mux;
26
Sean Andersonaa1e85f2020-06-24 06:41:07 -040027 if (mux)
28 return clk_mux_get_parent(mux);
29 else
30 return 0;
Peng Fan2d9bd932019-07-31 07:01:54 +000031}
32
33static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
34{
35 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
36 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
37 const struct clk_ops *mux_ops = composite->mux_ops;
38 struct clk *mux = composite->mux;
39
Simon Glass46e5f612021-03-25 10:26:09 +130040 if (!mux || !mux_ops)
41 return -ENOSYS;
42
43 return mux_ops->set_parent(mux, parent);
Peng Fan2d9bd932019-07-31 07:01:54 +000044}
45
46static unsigned long clk_composite_recalc_rate(struct clk *clk)
47{
48 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
49 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
50 const struct clk_ops *rate_ops = composite->rate_ops;
51 struct clk *rate = composite->rate;
52
Sean Andersonaa1e85f2020-06-24 06:41:07 -040053 if (rate && rate_ops)
54 return rate_ops->get_rate(rate);
55 else
56 return clk_get_parent_rate(clk);
Peng Fan2d9bd932019-07-31 07:01:54 +000057}
58
59static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate)
60{
61 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
62 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
63 const struct clk_ops *rate_ops = composite->rate_ops;
64 struct clk *clk_rate = composite->rate;
65
Sean Andersonaa1e85f2020-06-24 06:41:07 -040066 if (rate && rate_ops)
67 return rate_ops->set_rate(clk_rate, rate);
68 else
69 return clk_get_rate(clk);
Peng Fan2d9bd932019-07-31 07:01:54 +000070}
71
72static int clk_composite_enable(struct clk *clk)
73{
74 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
75 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
76 const struct clk_ops *gate_ops = composite->gate_ops;
77 struct clk *gate = composite->gate;
78
Sean Andersonaa1e85f2020-06-24 06:41:07 -040079 if (gate && gate_ops)
80 return gate_ops->enable(gate);
81 else
82 return 0;
Peng Fan2d9bd932019-07-31 07:01:54 +000083}
84
85static int clk_composite_disable(struct clk *clk)
86{
87 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
88 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
89 const struct clk_ops *gate_ops = composite->gate_ops;
90 struct clk *gate = composite->gate;
91
Sean Andersonaa1e85f2020-06-24 06:41:07 -040092 if (gate && gate_ops)
93 return gate_ops->disable(gate);
94 else
95 return 0;
Peng Fan2d9bd932019-07-31 07:01:54 +000096}
97
Peng Fan2d9bd932019-07-31 07:01:54 +000098struct clk *clk_register_composite(struct device *dev, const char *name,
99 const char * const *parent_names,
100 int num_parents, struct clk *mux,
101 const struct clk_ops *mux_ops,
102 struct clk *rate,
103 const struct clk_ops *rate_ops,
104 struct clk *gate,
105 const struct clk_ops *gate_ops,
106 unsigned long flags)
107{
108 struct clk *clk;
109 struct clk_composite *composite;
110 int ret;
Sean Andersonaa1e85f2020-06-24 06:41:07 -0400111
112 if (!num_parents || (num_parents != 1 && !mux))
113 return ERR_PTR(-EINVAL);
Peng Fan2d9bd932019-07-31 07:01:54 +0000114
115 composite = kzalloc(sizeof(*composite), GFP_KERNEL);
116 if (!composite)
117 return ERR_PTR(-ENOMEM);
118
119 if (mux && mux_ops) {
120 composite->mux = mux;
121 composite->mux_ops = mux_ops;
Peng Fan2d9bd932019-07-31 07:01:54 +0000122 mux->data = (ulong)composite;
123 }
124
125 if (rate && rate_ops) {
126 if (!rate_ops->get_rate) {
127 clk = ERR_PTR(-EINVAL);
128 goto err;
129 }
Peng Fan2d9bd932019-07-31 07:01:54 +0000130
131 composite->rate = rate;
132 composite->rate_ops = rate_ops;
133 rate->data = (ulong)composite;
134 }
135
136 if (gate && gate_ops) {
137 if (!gate_ops->enable || !gate_ops->disable) {
138 clk = ERR_PTR(-EINVAL);
139 goto err;
140 }
141
142 composite->gate = gate;
143 composite->gate_ops = gate_ops;
Peng Fan2d9bd932019-07-31 07:01:54 +0000144 gate->data = (ulong)composite;
145 }
146
147 clk = &composite->clk;
Dario Binacchi1a62dc12020-04-13 14:36:27 +0200148 clk->flags = flags;
Peng Fan2d9bd932019-07-31 07:01:54 +0000149 ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
150 parent_names[clk_composite_get_parent(clk)]);
151 if (ret) {
152 clk = ERR_PTR(ret);
153 goto err;
154 }
155
Sean Andersoncfc2f022020-06-24 06:41:06 -0400156 if (composite->mux)
157 composite->mux->dev = clk->dev;
158 if (composite->rate)
159 composite->rate->dev = clk->dev;
160 if (composite->gate)
161 composite->gate->dev = clk->dev;
162
Peng Fan2d9bd932019-07-31 07:01:54 +0000163 return clk;
164
165err:
166 kfree(composite);
167 return clk;
168}
169
Sean Andersonaa1e85f2020-06-24 06:41:07 -0400170static const struct clk_ops clk_composite_ops = {
171 .set_parent = clk_composite_set_parent,
172 .get_rate = clk_composite_recalc_rate,
173 .set_rate = clk_composite_set_rate,
174 .enable = clk_composite_enable,
175 .disable = clk_composite_disable,
176};
177
Peng Fan2d9bd932019-07-31 07:01:54 +0000178U_BOOT_DRIVER(clk_composite) = {
179 .name = UBOOT_DM_CLK_COMPOSITE,
180 .id = UCLASS_CLK,
181 .ops = &clk_composite_ops,
182 .flags = DM_FLAG_PRE_RELOC,
183};