1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2023 Linaro Ltd.
* Sam Protsenko <semen.protsenko@linaro.org>
*
* This file includes utility functions to register clocks to common
* clock framework for Samsung platforms.
*/
#include <dm.h>
#include "clk.h"
static void samsung_clk_register_mux(void __iomem *base, unsigned int cmu_id,
const struct samsung_mux_clock *clk_list,
unsigned int nr_clk)
{
unsigned int cnt;
for (cnt = 0; cnt < nr_clk; cnt++) {
struct clk *clk;
const struct samsung_mux_clock *m;
unsigned long clk_id;
m = &clk_list[cnt];
clk = clk_register_mux(NULL, m->name, m->parent_names,
m->num_parents, m->flags, base + m->offset, m->shift,
m->width, m->mux_flags);
clk_id = SAMSUNG_TO_CLK_ID(cmu_id, m->id);
clk_dm(clk_id, clk);
}
}
static void samsung_clk_register_div(void __iomem *base, unsigned int cmu_id,
const struct samsung_div_clock *clk_list,
unsigned int nr_clk)
{
unsigned int cnt;
for (cnt = 0; cnt < nr_clk; cnt++) {
struct clk *clk;
const struct samsung_div_clock *d;
unsigned long clk_id;
d = &clk_list[cnt];
clk = clk_register_divider(NULL, d->name, d->parent_name,
d->flags, base + d->offset, d->shift,
d->width, d->div_flags);
clk_id = SAMSUNG_TO_CLK_ID(cmu_id, d->id);
clk_dm(clk_id, clk);
}
}
static void samsung_clk_register_gate(void __iomem *base, unsigned int cmu_id,
const struct samsung_gate_clock *clk_list,
unsigned int nr_clk)
{
unsigned int cnt;
for (cnt = 0; cnt < nr_clk; cnt++) {
struct clk *clk;
const struct samsung_gate_clock *g;
unsigned long clk_id;
g = &clk_list[cnt];
clk = clk_register_gate(NULL, g->name, g->parent_name,
g->flags, base + g->offset, g->bit_idx,
g->gate_flags, NULL);
clk_id = SAMSUNG_TO_CLK_ID(cmu_id, g->id);
clk_dm(clk_id, clk);
}
}
typedef void (*samsung_clk_register_fn)(void __iomem *base, unsigned int cmu_id,
const void *clk_list,
unsigned int nr_clk);
static const samsung_clk_register_fn samsung_clk_register_fns[] = {
[S_CLK_MUX] = (samsung_clk_register_fn)samsung_clk_register_mux,
[S_CLK_DIV] = (samsung_clk_register_fn)samsung_clk_register_div,
[S_CLK_GATE] = (samsung_clk_register_fn)samsung_clk_register_gate,
[S_CLK_PLL] = (samsung_clk_register_fn)samsung_clk_register_pll,
};
/**
* samsung_cmu_register_clocks() - Register provided clock groups
* @base: Base address of CMU registers
* @cmu_id: CMU index number
* @clk_groups: list of clock groups
* @nr_groups: count of clock groups in @clk_groups
*
* Having the array of clock groups @clk_groups makes it possible to keep a
* correct clocks registration order.
*/
static void samsung_cmu_register_clocks(void __iomem *base, unsigned int cmu_id,
const struct samsung_clk_group *clk_groups,
unsigned int nr_groups)
{
unsigned int i;
for (i = 0; i < nr_groups; i++) {
const struct samsung_clk_group *g = &clk_groups[i];
samsung_clk_register_fns[g->type](base, cmu_id,
g->clk_list, g->nr_clk);
}
}
/**
* samsung_cmu_register_one - Register all CMU clocks
* @dev: CMU device
* @cmu_id: CMU index number
* @clk_groups: list of CMU clock groups
* @nr_groups: count of CMU clock groups in @clk_groups
*
* Return: 0 on success or negative value on error.
*/
int samsung_cmu_register_one(struct udevice *dev, unsigned int cmu_id,
const struct samsung_clk_group *clk_groups,
unsigned int nr_groups)
{
void __iomem *base;
base = dev_read_addr_ptr(dev);
if (!base)
return -EINVAL;
samsung_cmu_register_clocks(base, cmu_id, clk_groups, nr_groups);
return 0;
}
|