blob: a5626c33d1e3e67b5f792adb36173c6ab49913ed [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>
8#include <asm/io.h>
9#include <malloc.h>
10#include <clk-uclass.h>
11#include <dm/device.h>
12#include <linux/clk-provider.h>
13#include <clk.h>
14
15#include "clk.h"
16
17#define UBOOT_DM_CLK_COMPOSITE "clk_composite"
18
19static u8 clk_composite_get_parent(struct clk *clk)
20{
21 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
22 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
23 struct clk *mux = composite->mux;
24
25 return clk_mux_get_parent(mux);
26}
27
28static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
29{
30 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
31 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
32 const struct clk_ops *mux_ops = composite->mux_ops;
33 struct clk *mux = composite->mux;
34
35 return mux_ops->set_parent(mux, parent);
36}
37
38static unsigned long clk_composite_recalc_rate(struct clk *clk)
39{
40 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
41 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
42 const struct clk_ops *rate_ops = composite->rate_ops;
43 struct clk *rate = composite->rate;
44
45 return rate_ops->get_rate(rate);
46}
47
48static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate)
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 *clk_rate = composite->rate;
54
55 return rate_ops->set_rate(clk_rate, rate);
56}
57
58static int clk_composite_enable(struct clk *clk)
59{
60 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
61 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
62 const struct clk_ops *gate_ops = composite->gate_ops;
63 struct clk *gate = composite->gate;
64
65 return gate_ops->enable(gate);
66}
67
68static int clk_composite_disable(struct clk *clk)
69{
70 struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
71 (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
72 const struct clk_ops *gate_ops = composite->gate_ops;
73 struct clk *gate = composite->gate;
74
75 gate_ops->disable(gate);
76
77 return 0;
78}
79
80struct clk_ops clk_composite_ops = {
81 /* This will be set according to clk_register_composite */
82};
83
84struct clk *clk_register_composite(struct device *dev, const char *name,
85 const char * const *parent_names,
86 int num_parents, struct clk *mux,
87 const struct clk_ops *mux_ops,
88 struct clk *rate,
89 const struct clk_ops *rate_ops,
90 struct clk *gate,
91 const struct clk_ops *gate_ops,
92 unsigned long flags)
93{
94 struct clk *clk;
95 struct clk_composite *composite;
96 int ret;
97 struct clk_ops *composite_ops = &clk_composite_ops;
98
99 composite = kzalloc(sizeof(*composite), GFP_KERNEL);
100 if (!composite)
101 return ERR_PTR(-ENOMEM);
102
103 if (mux && mux_ops) {
104 composite->mux = mux;
105 composite->mux_ops = mux_ops;
106 if (mux_ops->set_parent)
107 composite_ops->set_parent = clk_composite_set_parent;
108 mux->data = (ulong)composite;
109 }
110
111 if (rate && rate_ops) {
112 if (!rate_ops->get_rate) {
113 clk = ERR_PTR(-EINVAL);
114 goto err;
115 }
116 composite_ops->get_rate = clk_composite_recalc_rate;
117
118 /* .set_rate requires either .round_rate or .determine_rate */
119 if (rate_ops->set_rate)
120 composite_ops->set_rate = clk_composite_set_rate;
121
122 composite->rate = rate;
123 composite->rate_ops = rate_ops;
124 rate->data = (ulong)composite;
125 }
126
127 if (gate && gate_ops) {
128 if (!gate_ops->enable || !gate_ops->disable) {
129 clk = ERR_PTR(-EINVAL);
130 goto err;
131 }
132
133 composite->gate = gate;
134 composite->gate_ops = gate_ops;
135 composite_ops->enable = clk_composite_enable;
136 composite_ops->disable = clk_composite_disable;
137 gate->data = (ulong)composite;
138 }
139
140 clk = &composite->clk;
141 ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
142 parent_names[clk_composite_get_parent(clk)]);
143 if (ret) {
144 clk = ERR_PTR(ret);
145 goto err;
146 }
147
148 return clk;
149
150err:
151 kfree(composite);
152 return clk;
153}
154
155U_BOOT_DRIVER(clk_composite) = {
156 .name = UBOOT_DM_CLK_COMPOSITE,
157 .id = UCLASS_CLK,
158 .ops = &clk_composite_ops,
159 .flags = DM_FLAG_PRE_RELOC,
160};