blob: e6653bdf49e480e49854145fd25f3c46e967af29 [file] [log] [blame]
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +03001/*
2 * Copyright 2024 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#include <errno.h>
7
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +03008#include <common/debug.h>
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +03009#include <drivers/clk.h>
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +030010#include <s32cc-clk-modules.h>
11#include <s32cc-clk-utils.h>
12
13#define MAX_STACK_DEPTH (15U)
14
15static int update_stack_depth(unsigned int *depth)
16{
17 if (*depth == 0U) {
18 return -ENOMEM;
19 }
20
21 (*depth)--;
22 return 0;
23}
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +030024
25static int s32cc_clk_enable(unsigned long id)
26{
27 return -ENOTSUP;
28}
29
30static void s32cc_clk_disable(unsigned long id)
31{
32}
33
34static bool s32cc_clk_is_enabled(unsigned long id)
35{
36 return false;
37}
38
39static unsigned long s32cc_clk_get_rate(unsigned long id)
40{
41 return 0;
42}
43
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +030044static int set_module_rate(const struct s32cc_clk_obj *module,
45 unsigned long rate, unsigned long *orate,
46 unsigned int *depth);
47
48static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate,
49 unsigned long *orate, unsigned int *depth)
50{
51 struct s32cc_osc *osc = s32cc_obj2osc(module);
52 int ret;
53
54 ret = update_stack_depth(depth);
55 if (ret != 0) {
56 return ret;
57 }
58
59 if ((osc->freq != 0UL) && (rate != osc->freq)) {
60 ERROR("Already initialized oscillator. freq = %lu\n",
61 osc->freq);
62 return -EINVAL;
63 }
64
65 osc->freq = rate;
66 *orate = osc->freq;
67
68 return 0;
69}
70
71static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate,
72 unsigned long *orate, unsigned int *depth)
73{
74 const struct s32cc_clk *clk = s32cc_obj2clk(module);
75 int ret;
76
77 ret = update_stack_depth(depth);
78 if (ret != 0) {
79 return ret;
80 }
81
82 if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) &&
83 ((rate < clk->min_freq) || (rate > clk->max_freq))) {
84 ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n",
85 rate, clk->min_freq, clk->max_freq);
86 return -EINVAL;
87 }
88
89 if (clk->module != NULL) {
90 return set_module_rate(clk->module, rate, orate, depth);
91 }
92
93 if (clk->pclock != NULL) {
94 return set_clk_freq(&clk->pclock->desc, rate, orate, depth);
95 }
96
97 return -EINVAL;
98}
99
100static int set_module_rate(const struct s32cc_clk_obj *module,
101 unsigned long rate, unsigned long *orate,
102 unsigned int *depth)
103{
104 int ret = 0;
105
106 ret = update_stack_depth(depth);
107 if (ret != 0) {
108 return ret;
109 }
110
111 switch (module->type) {
112 case s32cc_clk_t:
113 ret = set_clk_freq(module, rate, orate, depth);
114 break;
115 case s32cc_osc_t:
116 ret = set_osc_freq(module, rate, orate, depth);
117 break;
118 default:
119 ret = -EINVAL;
120 break;
121 }
122
123 return ret;
124}
125
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300126static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
127 unsigned long *orate)
128{
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300129 unsigned int depth = MAX_STACK_DEPTH;
130 const struct s32cc_clk *clk;
131 int ret;
132
133 clk = s32cc_get_arch_clk(id);
134 if (clk == NULL) {
135 return -EINVAL;
136 }
137
138 ret = set_module_rate(&clk->desc, rate, orate, &depth);
139 if (ret != 0) {
140 ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
141 rate, id);
142 }
143
144 return ret;
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300145}
146
147static int s32cc_clk_get_parent(unsigned long id)
148{
149 return -ENOTSUP;
150}
151
152static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
153{
154 return -ENOTSUP;
155}
156
157void s32cc_clk_register_drv(void)
158{
159 static const struct clk_ops s32cc_clk_ops = {
160 .enable = s32cc_clk_enable,
161 .disable = s32cc_clk_disable,
162 .is_enabled = s32cc_clk_is_enabled,
163 .get_rate = s32cc_clk_get_rate,
164 .set_rate = s32cc_clk_set_rate,
165 .get_parent = s32cc_clk_get_parent,
166 .set_parent = s32cc_clk_set_parent,
167 };
168
169 clk_register(&s32cc_clk_ops);
170}
171