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