1804e32d7SClément Léger // SPDX-License-Identifier: BSD-2-Clause
2804e32d7SClément Léger /*
3804e32d7SClément Léger * Copyright (c) 2021, Bootlin
4804e32d7SClément Léger */
5804e32d7SClément Léger
6804e32d7SClément Léger #include <drivers/clk.h>
7804e32d7SClément Léger #include <drivers/clk_dt.h>
8804e32d7SClément Léger #include <libfdt.h>
9804e32d7SClément Léger #include <malloc.h>
10804e32d7SClément Léger #include <stdint.h>
11804e32d7SClément Léger
12804e32d7SClément Léger struct fixed_clock_data {
13804e32d7SClément Léger unsigned long rate;
14804e32d7SClément Léger };
15804e32d7SClément Léger
fixed_clk_get_rate(struct clk * clk,unsigned long parent_rate __unused)16804e32d7SClément Léger static unsigned long fixed_clk_get_rate(struct clk *clk,
17804e32d7SClément Léger unsigned long parent_rate __unused)
18804e32d7SClément Léger {
19804e32d7SClément Léger struct fixed_clock_data *d = clk->priv;
20804e32d7SClément Léger
21804e32d7SClément Léger return d->rate;
22804e32d7SClément Léger }
23804e32d7SClément Léger
24804e32d7SClément Léger static const struct clk_ops fixed_clk_clk_ops = {
25804e32d7SClément Léger .get_rate = fixed_clk_get_rate,
26804e32d7SClément Léger };
27804e32d7SClément Léger
fixed_clock_probe(const void * fdt,int offs,const void * compat_data __unused)28*ced0ec63SEtienne Carriere static TEE_Result fixed_clock_probe(const void *fdt, int offs,
297e6a39feSEtienne Carriere const void *compat_data __unused)
30804e32d7SClément Léger {
31804e32d7SClément Léger const uint32_t *freq = NULL;
32804e32d7SClément Léger const char *name = NULL;
33804e32d7SClément Léger struct clk *clk = NULL;
34804e32d7SClément Léger TEE_Result res = TEE_ERROR_GENERIC;
35804e32d7SClément Léger struct fixed_clock_data *fcd = NULL;
36804e32d7SClément Léger
37804e32d7SClément Léger name = fdt_get_name(fdt, offs, NULL);
38804e32d7SClément Léger if (!name)
39804e32d7SClément Léger name = "fixed-clock";
40804e32d7SClément Léger
41804e32d7SClément Léger clk = clk_alloc(name, &fixed_clk_clk_ops, NULL, 0);
42804e32d7SClément Léger if (!clk)
43804e32d7SClément Léger return TEE_ERROR_OUT_OF_MEMORY;
44804e32d7SClément Léger
45804e32d7SClément Léger fcd = calloc(1, sizeof(struct fixed_clock_data));
46804e32d7SClément Léger if (!fcd) {
47804e32d7SClément Léger res = TEE_ERROR_OUT_OF_MEMORY;
48804e32d7SClément Léger goto free_clk;
49804e32d7SClément Léger }
50804e32d7SClément Léger
51804e32d7SClément Léger freq = fdt_getprop(fdt, offs, "clock-frequency", NULL);
52804e32d7SClément Léger if (!freq) {
53804e32d7SClément Léger res = TEE_ERROR_BAD_FORMAT;
54804e32d7SClément Léger goto free_fcd;
55804e32d7SClément Léger }
56804e32d7SClément Léger
57804e32d7SClément Léger fcd->rate = fdt32_to_cpu(*freq);
58804e32d7SClément Léger clk->priv = fcd;
59804e32d7SClément Léger
60804e32d7SClément Léger res = clk_register(clk);
61804e32d7SClément Léger if (res)
62804e32d7SClément Léger goto free_fcd;
63804e32d7SClément Léger
64804e32d7SClément Léger res = clk_dt_register_clk_provider(fdt, offs, clk_dt_get_simple_clk,
65804e32d7SClément Léger clk);
66804e32d7SClément Léger if (!res)
67804e32d7SClément Léger return TEE_SUCCESS;
68804e32d7SClément Léger
69804e32d7SClément Léger free_fcd:
70804e32d7SClément Léger free(fcd);
71804e32d7SClément Léger free_clk:
72804e32d7SClément Léger clk_free(clk);
73804e32d7SClément Léger
74804e32d7SClément Léger return res;
75804e32d7SClément Léger }
76804e32d7SClément Léger
77*ced0ec63SEtienne Carriere CLK_DT_DECLARE(fixed_clock, "fixed-clock", fixed_clock_probe);
78