xref: /netbsd-src/sys/dev/fdt/fixedclock.c (revision 6e54367a22fbc89a1139d033e95bec0c0cf0975b)
1*6e54367aSthorpej /* $NetBSD: fixedclock.c,v 1.6 2021/01/27 03:10:21 thorpej Exp $ */
2d374aef8Sjmcneill 
3d374aef8Sjmcneill /*-
4d374aef8Sjmcneill  * Copyright (c) 2017 Jared D. McNeill <jmcneill@invisible.ca>
5d374aef8Sjmcneill  * All rights reserved.
6d374aef8Sjmcneill  *
7d374aef8Sjmcneill  * Redistribution and use in source and binary forms, with or without
8d374aef8Sjmcneill  * modification, are permitted provided that the following conditions
9d374aef8Sjmcneill  * are met:
10d374aef8Sjmcneill  * 1. Redistributions of source code must retain the above copyright
11d374aef8Sjmcneill  *    notice, this list of conditions and the following disclaimer.
12d374aef8Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
13d374aef8Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
14d374aef8Sjmcneill  *    documentation and/or other materials provided with the distribution.
15d374aef8Sjmcneill  *
16d374aef8Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17d374aef8Sjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18d374aef8Sjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19d374aef8Sjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20d374aef8Sjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21d374aef8Sjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22d374aef8Sjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23d374aef8Sjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24d374aef8Sjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d374aef8Sjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d374aef8Sjmcneill  * SUCH DAMAGE.
27d374aef8Sjmcneill  */
28d374aef8Sjmcneill 
29d374aef8Sjmcneill #include <sys/cdefs.h>
30*6e54367aSthorpej __KERNEL_RCSID(0, "$NetBSD: fixedclock.c,v 1.6 2021/01/27 03:10:21 thorpej Exp $");
31d374aef8Sjmcneill 
32d374aef8Sjmcneill #include <sys/param.h>
33d374aef8Sjmcneill #include <sys/systm.h>
34d374aef8Sjmcneill #include <sys/device.h>
35d374aef8Sjmcneill #include <sys/kmem.h>
36d374aef8Sjmcneill #include <sys/bus.h>
37d374aef8Sjmcneill 
38d374aef8Sjmcneill #include <dev/clk/clk_backend.h>
39d374aef8Sjmcneill 
40d374aef8Sjmcneill #include <dev/fdt/fdtvar.h>
41d374aef8Sjmcneill 
42d374aef8Sjmcneill static int	fixedclock_match(device_t, cfdata_t, void *);
43d374aef8Sjmcneill static void	fixedclock_attach(device_t, device_t, void *);
44d374aef8Sjmcneill 
4551b425efSaymeric static struct clk *fixedclock_decode(device_t, int, const void *, size_t);
46d374aef8Sjmcneill 
47d374aef8Sjmcneill static const struct fdtbus_clock_controller_func fixedclock_fdt_funcs = {
48d374aef8Sjmcneill 	.decode = fixedclock_decode
49d374aef8Sjmcneill };
50d374aef8Sjmcneill 
51d374aef8Sjmcneill static struct clk *fixedclock_get(void *, const char *);
52d374aef8Sjmcneill static void	fixedclock_put(void *, struct clk *);
53d374aef8Sjmcneill static u_int	fixedclock_get_rate(void *, struct clk *);
54d374aef8Sjmcneill 
55d374aef8Sjmcneill static const struct clk_funcs fixedclock_clk_funcs = {
56d374aef8Sjmcneill 	.get = fixedclock_get,
57d374aef8Sjmcneill 	.put = fixedclock_put,
58d374aef8Sjmcneill 	.get_rate = fixedclock_get_rate,
59d374aef8Sjmcneill };
60d374aef8Sjmcneill 
61d374aef8Sjmcneill struct fixedclock_clk {
62d374aef8Sjmcneill 	struct clk	base;
63d374aef8Sjmcneill 	u_int		rate;
64d374aef8Sjmcneill };
65d374aef8Sjmcneill 
66d374aef8Sjmcneill struct fixedclock_softc {
67d374aef8Sjmcneill 	device_t	sc_dev;
68d374aef8Sjmcneill 	int		sc_phandle;
69d374aef8Sjmcneill 
70d374aef8Sjmcneill 	struct clk_domain sc_clkdom;
71d374aef8Sjmcneill 	struct fixedclock_clk sc_clk;
72d374aef8Sjmcneill };
73d374aef8Sjmcneill 
74d374aef8Sjmcneill CFATTACH_DECL_NEW(fclock, sizeof(struct fixedclock_softc),
75d374aef8Sjmcneill     fixedclock_match, fixedclock_attach, NULL, NULL);
76d374aef8Sjmcneill 
77*6e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
78*6e54367aSthorpej 	{ .compat = "fixed-clock" },
79*6e54367aSthorpej 	DEVICE_COMPAT_EOL
80*6e54367aSthorpej };
81*6e54367aSthorpej 
82d374aef8Sjmcneill static int
fixedclock_match(device_t parent,cfdata_t cf,void * aux)83d374aef8Sjmcneill fixedclock_match(device_t parent, cfdata_t cf, void *aux)
84d374aef8Sjmcneill {
85d374aef8Sjmcneill 	const struct fdt_attach_args *faa = aux;
86d374aef8Sjmcneill 
87*6e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
88d374aef8Sjmcneill }
89d374aef8Sjmcneill 
90d374aef8Sjmcneill static void
fixedclock_attach(device_t parent,device_t self,void * aux)91d374aef8Sjmcneill fixedclock_attach(device_t parent, device_t self, void *aux)
92d374aef8Sjmcneill {
93d374aef8Sjmcneill 	struct fixedclock_softc * const sc = device_private(self);
94d374aef8Sjmcneill 	const struct fdt_attach_args *faa = aux;
95d374aef8Sjmcneill 	const int phandle = faa->faa_phandle;
963b4803fcSjmcneill 	const char *clkname;
973b4803fcSjmcneill 
983b4803fcSjmcneill 	clkname = fdtbus_get_string(phandle, "clock-output-names");
993b4803fcSjmcneill 	if (!clkname)
1003b4803fcSjmcneill 		clkname = faa->faa_name;
101d374aef8Sjmcneill 
102d374aef8Sjmcneill 	sc->sc_dev = self;
103d374aef8Sjmcneill 	sc->sc_phandle = phandle;
104a756758dSjmcneill 	sc->sc_clkdom.name = device_xname(self);
105d374aef8Sjmcneill 	sc->sc_clkdom.funcs = &fixedclock_clk_funcs;
106d374aef8Sjmcneill 	sc->sc_clkdom.priv = sc;
107d374aef8Sjmcneill 	if (of_getprop_uint32(phandle, "clock-frequency",
108d374aef8Sjmcneill 	    &sc->sc_clk.rate) != 0) {
109d374aef8Sjmcneill 		aprint_error(": couldn't determine frequency\n");
110d374aef8Sjmcneill 		return;
111d374aef8Sjmcneill 	}
112d374aef8Sjmcneill 	sc->sc_clk.base.domain = &sc->sc_clkdom;
1133b4803fcSjmcneill 	sc->sc_clk.base.name = kmem_asprintf("%s", clkname);
114a756758dSjmcneill 	clk_attach(&sc->sc_clk.base);
115d374aef8Sjmcneill 
11610ea0ce9Sjmcneill 	aprint_naive("\n");
1173b4803fcSjmcneill 	aprint_normal(": %u Hz fixed clock (%s)\n", sc->sc_clk.rate, clkname);
118d374aef8Sjmcneill 
119d374aef8Sjmcneill 	fdtbus_register_clock_controller(self, phandle, &fixedclock_fdt_funcs);
120d374aef8Sjmcneill }
121d374aef8Sjmcneill 
122d374aef8Sjmcneill static struct clk *
fixedclock_decode(device_t dev,int cc_phandle,const void * data,size_t len)12351b425efSaymeric fixedclock_decode(device_t dev, int cc_phandle, const void *data, size_t len)
124d374aef8Sjmcneill {
125d374aef8Sjmcneill 	struct fixedclock_softc * const sc = device_private(dev);
126d374aef8Sjmcneill 
127d374aef8Sjmcneill 	/* #clock-cells for a fixed clock is always 0 */
128d374aef8Sjmcneill 	if (len != 0)
129d374aef8Sjmcneill 		return NULL;
130d374aef8Sjmcneill 
131d374aef8Sjmcneill 	return &sc->sc_clk.base;
132d374aef8Sjmcneill }
133d374aef8Sjmcneill 
134d374aef8Sjmcneill static struct clk *
fixedclock_get(void * priv,const char * name)135d374aef8Sjmcneill fixedclock_get(void *priv, const char *name)
136d374aef8Sjmcneill {
137d374aef8Sjmcneill 	struct fixedclock_softc * const sc = priv;
138d374aef8Sjmcneill 
139d374aef8Sjmcneill 	if (strcmp(name, sc->sc_clk.base.name) != 0)
140d374aef8Sjmcneill 		return NULL;
141d374aef8Sjmcneill 
142d374aef8Sjmcneill 	return &sc->sc_clk.base;
143d374aef8Sjmcneill }
144d374aef8Sjmcneill 
145d374aef8Sjmcneill static void
fixedclock_put(void * priv,struct clk * clk)146d374aef8Sjmcneill fixedclock_put(void *priv, struct clk *clk)
147d374aef8Sjmcneill {
148d374aef8Sjmcneill }
149d374aef8Sjmcneill 
150d374aef8Sjmcneill static u_int
fixedclock_get_rate(void * priv,struct clk * clk)151d374aef8Sjmcneill fixedclock_get_rate(void *priv, struct clk *clk)
152d374aef8Sjmcneill {
153d374aef8Sjmcneill 	struct fixedclock_clk *fclk = (struct fixedclock_clk *)clk;
154d374aef8Sjmcneill 
155d374aef8Sjmcneill 	return fclk->rate;
156d374aef8Sjmcneill }
157