Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/clk/allwinner/aw_clk_prediv_mux.c
39537 views
1
/*-
2
* Copyright (c) 2017 Emmanuel Vadot <[email protected]>
3
*
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
6
* are met:
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
12
*
13
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
20
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
* SUCH DAMAGE.
24
*/
25
26
#include <sys/param.h>
27
#include <sys/systm.h>
28
#include <sys/bus.h>
29
30
#include <dev/clk/clk.h>
31
32
#include <dev/clk/allwinner/aw_clk.h>
33
#include <dev/clk/allwinner/aw_clk_prediv_mux.h>
34
35
#include "clkdev_if.h"
36
37
/*
38
* clknode for clocks matching the formula :
39
*
40
* clk = clkin / prediv / div
41
*
42
* and where prediv is conditional
43
*
44
*/
45
46
struct aw_clk_prediv_mux_sc {
47
uint32_t offset;
48
49
uint32_t mux_shift;
50
uint32_t mux_mask;
51
52
struct aw_clk_factor div;
53
struct aw_clk_factor prediv;
54
55
uint32_t flags;
56
};
57
58
#define WRITE4(_clk, off, val) \
59
CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
60
#define READ4(_clk, off, val) \
61
CLKDEV_READ_4(clknode_get_device(_clk), off, val)
62
#define MODIFY4(_clk, off, clr, set ) \
63
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
64
#define DEVICE_LOCK(_clk) \
65
CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
66
#define DEVICE_UNLOCK(_clk) \
67
CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
68
69
static int
70
aw_clk_prediv_mux_init(struct clknode *clk, device_t dev)
71
{
72
struct aw_clk_prediv_mux_sc *sc;
73
uint32_t val;
74
75
sc = clknode_get_softc(clk);
76
77
DEVICE_LOCK(clk);
78
READ4(clk, sc->offset, &val);
79
DEVICE_UNLOCK(clk);
80
81
/* Init the current parent */
82
val = (val & sc->mux_mask) >> sc->mux_shift;
83
clknode_init_parent_idx(clk, val);
84
85
return (0);
86
}
87
88
static int
89
aw_clk_prediv_mux_set_mux(struct clknode *clk, int index)
90
{
91
struct aw_clk_prediv_mux_sc *sc;
92
uint32_t val;
93
94
sc = clknode_get_softc(clk);
95
96
DEVICE_LOCK(clk);
97
READ4(clk, sc->offset, &val);
98
val &= ~sc->mux_mask;
99
val |= index << sc->mux_shift;
100
WRITE4(clk, sc->offset, val);
101
DEVICE_UNLOCK(clk);
102
103
return (0);
104
}
105
106
static int
107
aw_clk_prediv_mux_recalc(struct clknode *clk, uint64_t *freq)
108
{
109
struct aw_clk_prediv_mux_sc *sc;
110
uint32_t val, div, prediv;
111
112
sc = clknode_get_softc(clk);
113
114
DEVICE_LOCK(clk);
115
READ4(clk, sc->offset, &val);
116
DEVICE_UNLOCK(clk);
117
118
div = aw_clk_get_factor(val, &sc->div);
119
prediv = aw_clk_get_factor(val, &sc->prediv);
120
121
*freq = *freq / prediv / div;
122
return (0);
123
}
124
125
static clknode_method_t aw_prediv_mux_clknode_methods[] = {
126
/* Device interface */
127
CLKNODEMETHOD(clknode_init, aw_clk_prediv_mux_init),
128
CLKNODEMETHOD(clknode_set_mux, aw_clk_prediv_mux_set_mux),
129
CLKNODEMETHOD(clknode_recalc_freq, aw_clk_prediv_mux_recalc),
130
CLKNODEMETHOD_END
131
};
132
133
DEFINE_CLASS_1(aw_prediv_mux_clknode, aw_prediv_mux_clknode_class,
134
aw_prediv_mux_clknode_methods, sizeof(struct aw_clk_prediv_mux_sc),
135
clknode_class);
136
137
int
138
aw_clk_prediv_mux_register(struct clkdom *clkdom, struct aw_clk_prediv_mux_def *clkdef)
139
{
140
struct clknode *clk;
141
struct aw_clk_prediv_mux_sc *sc;
142
143
clk = clknode_create(clkdom, &aw_prediv_mux_clknode_class, &clkdef->clkdef);
144
if (clk == NULL)
145
return (1);
146
147
sc = clknode_get_softc(clk);
148
149
sc->offset = clkdef->offset;
150
151
sc->mux_shift = clkdef->mux_shift;
152
sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift;
153
154
sc->div.shift = clkdef->div.shift;
155
sc->div.mask = ((1 << clkdef->div.width) - 1) << sc->div.shift;
156
sc->div.value = clkdef->div.value;
157
sc->div.cond_shift = clkdef->div.cond_shift;
158
sc->div.cond_mask = ((1 << clkdef->div.cond_width) - 1) << sc->div.shift;
159
sc->div.cond_value = clkdef->div.cond_value;
160
sc->div.flags = clkdef->div.flags;
161
162
sc->prediv.shift = clkdef->prediv.shift;
163
sc->prediv.mask = ((1 << clkdef->prediv.width) - 1) << sc->prediv.shift;
164
sc->prediv.value = clkdef->prediv.value;
165
sc->prediv.cond_shift = clkdef->prediv.cond_shift;
166
if (clkdef->prediv.cond_width != 0)
167
sc->prediv.cond_mask = ((1 << clkdef->prediv.cond_width) - 1) << sc->prediv.shift;
168
else
169
sc->prediv.cond_mask = clkdef->prediv.cond_mask;
170
sc->prediv.cond_value = clkdef->prediv.cond_value;
171
sc->prediv.flags = clkdef->prediv.flags;
172
173
sc->flags = clkdef->flags;
174
175
clknode_register(clkdom, clk);
176
177
return (0);
178
}
179
180