1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2021, Bootlin
4 */
5
6 #include <drivers/clk.h>
7 #include <drivers/clk_dt.h>
8 #include <libfdt.h>
9 #include <malloc.h>
10 #include <stdint.h>
11
12 struct fixed_clock_data {
13 unsigned long rate;
14 };
15
fixed_clk_get_rate(struct clk * clk,unsigned long parent_rate __unused)16 static unsigned long fixed_clk_get_rate(struct clk *clk,
17 unsigned long parent_rate __unused)
18 {
19 struct fixed_clock_data *d = clk->priv;
20
21 return d->rate;
22 }
23
24 static const struct clk_ops fixed_clk_clk_ops = {
25 .get_rate = fixed_clk_get_rate,
26 };
27
fixed_clock_probe(const void * fdt,int offs,const void * compat_data __unused)28 static TEE_Result fixed_clock_probe(const void *fdt, int offs,
29 const void *compat_data __unused)
30 {
31 const uint32_t *freq = NULL;
32 const char *name = NULL;
33 struct clk *clk = NULL;
34 TEE_Result res = TEE_ERROR_GENERIC;
35 struct fixed_clock_data *fcd = NULL;
36
37 name = fdt_get_name(fdt, offs, NULL);
38 if (!name)
39 name = "fixed-clock";
40
41 clk = clk_alloc(name, &fixed_clk_clk_ops, NULL, 0);
42 if (!clk)
43 return TEE_ERROR_OUT_OF_MEMORY;
44
45 fcd = calloc(1, sizeof(struct fixed_clock_data));
46 if (!fcd) {
47 res = TEE_ERROR_OUT_OF_MEMORY;
48 goto free_clk;
49 }
50
51 freq = fdt_getprop(fdt, offs, "clock-frequency", NULL);
52 if (!freq) {
53 res = TEE_ERROR_BAD_FORMAT;
54 goto free_fcd;
55 }
56
57 fcd->rate = fdt32_to_cpu(*freq);
58 clk->priv = fcd;
59
60 res = clk_register(clk);
61 if (res)
62 goto free_fcd;
63
64 res = clk_dt_register_clk_provider(fdt, offs, clk_dt_get_simple_clk,
65 clk);
66 if (!res)
67 return TEE_SUCCESS;
68
69 free_fcd:
70 free(fcd);
71 free_clk:
72 clk_free(clk);
73
74 return res;
75 }
76
77 CLK_DT_DECLARE(fixed_clock, "fixed-clock", fixed_clock_probe);
78