am18xx_aclk.c revision 1.1 1 1.1 yurix /* $NetBSD $ */
2 1.1 yurix
3 1.1 yurix /*-
4 1.1 yurix * Copyright (c) 2026 The NetBSD Foundation, Inc.
5 1.1 yurix * All rights reserved.
6 1.1 yurix *
7 1.1 yurix * This code is derived from software contributed to The NetBSD Foundation
8 1.1 yurix * by Yuri Honegger.
9 1.1 yurix *
10 1.1 yurix * Redistribution and use in source and binary forms, with or without
11 1.1 yurix * modification, are permitted provided that the following conditions
12 1.1 yurix * are met:
13 1.1 yurix * 1. Redistributions of source code must retain the above copyright
14 1.1 yurix * notice, this list of conditions and the following disclaimer.
15 1.1 yurix * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 yurix * notice, this list of conditions and the following disclaimer in the
17 1.1 yurix * documentation and/or other materials provided with the distribution.
18 1.1 yurix *
19 1.1 yurix * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 yurix * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 yurix * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 yurix * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 yurix * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 yurix * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 yurix * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 yurix * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 yurix * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 yurix * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 yurix * POSSIBILITY OF SUCH DAMAGE.
30 1.1 yurix */
31 1.1 yurix
32 1.1 yurix /*
33 1.1 yurix * Drivers for the async clock gates in the syscfg block of the TI AM1808.
34 1.1 yurix */
35 1.1 yurix
36 1.1 yurix #include <sys/param.h>
37 1.1 yurix #include <sys/bus.h>
38 1.1 yurix #include <sys/cdefs.h>
39 1.1 yurix #include <sys/device.h>
40 1.1 yurix
41 1.1 yurix #include <dev/clk/clk_backend.h>
42 1.1 yurix #include <dev/fdt/fdtvar.h>
43 1.1 yurix #include <dev/fdt/syscon.h>
44 1.1 yurix
45 1.1 yurix #include <arm/fdt/arm_fdtvar.h>
46 1.1 yurix
47 1.1 yurix struct am18xx_aclk_config {
48 1.1 yurix struct clk *clk; /* double wrap clk because the config must be const */
49 1.1 yurix uint32_t mask;
50 1.1 yurix };
51 1.1 yurix
52 1.1 yurix struct am18xx_aclk_softc {
53 1.1 yurix struct clk_domain sc_clkdom;
54 1.1 yurix const struct am18xx_aclk_config *sc_config;
55 1.1 yurix struct clk *sc_parent_clk;
56 1.1 yurix };
57 1.1 yurix
58 1.1 yurix static int am18xx_aclk_match(device_t, cfdata_t, void *);
59 1.1 yurix static void am18xx_aclk_attach(device_t, device_t, void *);
60 1.1 yurix static struct clk * am18xx_aclk_decode(device_t, int, const void *, size_t);
61 1.1 yurix static struct clk * am18xx_aclk_clk_get(void *, const char *);
62 1.1 yurix static u_int am18xx_aclk_clk_get_rate(void *, struct clk *);
63 1.1 yurix static struct clk * am18xx_aclk_clk_get_parent(void *, struct clk *);
64 1.1 yurix
65 1.1 yurix CFATTACH_DECL_NEW(am18xxaclk, sizeof(struct am18xx_aclk_softc),
66 1.1 yurix am18xx_aclk_match, am18xx_aclk_attach, NULL, NULL);
67 1.1 yurix
68 1.1 yurix #define AM18XX_ACLK_CFGCHIP3 0xC
69 1.1 yurix #define AM18XX_ACLK_CFGCHIP3_ASYNC3_CLKSRC __BIT(4)
70 1.1 yurix #define AM18XX_ACLK_CFGCHIP3_ASYNC1_CLKSRC __BIT(2)
71 1.1 yurix
72 1.1 yurix static struct clk am18xx_aclk_async1_clk = {
73 1.1 yurix .name = "async1",
74 1.1 yurix .flags = 0
75 1.1 yurix };
76 1.1 yurix static struct clk am18xx_aclk_async3_clk = {
77 1.1 yurix .name = "async3",
78 1.1 yurix .flags = 0
79 1.1 yurix };
80 1.1 yurix
81 1.1 yurix static const struct am18xx_aclk_config am18xx_aclk_async1_config = {
82 1.1 yurix .clk = &am18xx_aclk_async1_clk,
83 1.1 yurix .mask = AM18XX_ACLK_CFGCHIP3_ASYNC1_CLKSRC,
84 1.1 yurix };
85 1.1 yurix static const struct am18xx_aclk_config am18xx_aclk_async3_config = {
86 1.1 yurix .clk = &am18xx_aclk_async3_clk,
87 1.1 yurix .mask = AM18XX_ACLK_CFGCHIP3_ASYNC3_CLKSRC,
88 1.1 yurix };
89 1.1 yurix
90 1.1 yurix static const struct fdtbus_clock_controller_func am18xx_aclk_clk_fdt_funcs = {
91 1.1 yurix .decode = am18xx_aclk_decode,
92 1.1 yurix };
93 1.1 yurix
94 1.1 yurix static const struct clk_funcs am18xx_aclk_clk_funcs = {
95 1.1 yurix .get = am18xx_aclk_clk_get,
96 1.1 yurix .get_rate = am18xx_aclk_clk_get_rate,
97 1.1 yurix .get_parent = am18xx_aclk_clk_get_parent,
98 1.1 yurix };
99 1.1 yurix
100 1.1 yurix static const struct device_compatible_entry compat_data[] = {
101 1.1 yurix { .compat = "ti,da850-async1-clksrc",
102 1.1 yurix .data = &am18xx_aclk_async1_config },
103 1.1 yurix { .compat = "ti,da850-async3-clksrc",
104 1.1 yurix .data = &am18xx_aclk_async3_config },
105 1.1 yurix DEVICE_COMPAT_EOL
106 1.1 yurix };
107 1.1 yurix
108 1.1 yurix static struct clk *
109 1.1 yurix am18xx_aclk_clk_get(void *priv, const char *name)
110 1.1 yurix {
111 1.1 yurix struct am18xx_aclk_softc * const sc = priv;
112 1.1 yurix
113 1.1 yurix if (strcmp(sc->sc_config->clk->name, name) == 0) {
114 1.1 yurix return sc->sc_config->clk;
115 1.1 yurix }
116 1.1 yurix
117 1.1 yurix return NULL;
118 1.1 yurix }
119 1.1 yurix
120 1.1 yurix static u_int
121 1.1 yurix am18xx_aclk_clk_get_rate(void *priv, struct clk *clkp)
122 1.1 yurix {
123 1.1 yurix struct am18xx_aclk_softc * const sc = priv;
124 1.1 yurix
125 1.1 yurix return clk_get_rate(sc->sc_parent_clk);
126 1.1 yurix }
127 1.1 yurix
128 1.1 yurix static struct clk *
129 1.1 yurix am18xx_aclk_clk_get_parent(void *priv, struct clk *clkp)
130 1.1 yurix {
131 1.1 yurix struct am18xx_aclk_softc * const sc = priv;
132 1.1 yurix
133 1.1 yurix return sc->sc_parent_clk;
134 1.1 yurix }
135 1.1 yurix
136 1.1 yurix static struct clk *
137 1.1 yurix am18xx_aclk_decode(device_t dev, int cc_phandle, const void *data, size_t len)
138 1.1 yurix {
139 1.1 yurix struct am18xx_aclk_softc * const sc = device_private(dev);
140 1.1 yurix
141 1.1 yurix return sc->sc_config->clk;
142 1.1 yurix }
143 1.1 yurix
144 1.1 yurix int
145 1.1 yurix am18xx_aclk_match(device_t parent, cfdata_t cf, void *aux)
146 1.1 yurix {
147 1.1 yurix struct fdt_attach_args * const faa = aux;
148 1.1 yurix
149 1.1 yurix return of_compatible_match(faa->faa_phandle, compat_data);
150 1.1 yurix }
151 1.1 yurix
152 1.1 yurix void
153 1.1 yurix am18xx_aclk_attach(device_t parent, device_t self, void *aux)
154 1.1 yurix {
155 1.1 yurix struct am18xx_aclk_softc * const sc = device_private(self);
156 1.1 yurix struct fdt_attach_args * const faa = aux;
157 1.1 yurix const int phandle = faa->faa_phandle;
158 1.1 yurix
159 1.1 yurix sc->sc_config = of_compatible_lookup(phandle, compat_data)->data;
160 1.1 yurix
161 1.1 yurix /* ensure we have a clock parent */
162 1.1 yurix sc->sc_parent_clk = fdtbus_clock_get_index(phandle, 0);
163 1.1 yurix if (sc->sc_parent_clk == NULL) {
164 1.1 yurix aprint_error(": couldn't get parent clock");
165 1.1 yurix return;
166 1.1 yurix }
167 1.1 yurix
168 1.1 yurix /* ensure clock gate bits are as expected */
169 1.1 yurix struct syscon *syscon = fdtbus_syscon_lookup(OF_parent(phandle));
170 1.1 yurix if (syscon == NULL) {
171 1.1 yurix aprint_error(": couldn't get syscon registers\n");
172 1.1 yurix return;
173 1.1 yurix }
174 1.1 yurix syscon_lock(syscon);
175 1.1 yurix uint32_t cfgchip_reg3 = syscon_read_4(syscon, AM18XX_ACLK_CFGCHIP3);
176 1.1 yurix syscon_unlock(syscon);
177 1.1 yurix if ((cfgchip_reg3 & sc->sc_config->mask) != 0) {
178 1.1 yurix aprint_error(": unexpected clock gate bits\n");
179 1.1 yurix return;
180 1.1 yurix }
181 1.1 yurix
182 1.1 yurix /* attach a clock controller */
183 1.1 yurix sc->sc_clkdom.name = device_xname(self);
184 1.1 yurix sc->sc_clkdom.funcs = &am18xx_aclk_clk_funcs;
185 1.1 yurix sc->sc_clkdom.priv = sc;
186 1.1 yurix
187 1.1 yurix sc->sc_config->clk->domain = &sc->sc_clkdom;
188 1.1 yurix clk_attach(sc->sc_config->clk);
189 1.1 yurix
190 1.1 yurix fdtbus_register_clock_controller(self, phandle, &am18xx_aclk_clk_fdt_funcs);
191 1.1 yurix
192 1.1 yurix aprint_normal("\n");
193 1.1 yurix }
194