xref: /freebsd/sys/dev/qcom_clk/qcom_clk_fdiv.c (revision e34a491b35626b4209ef0a195e85a03a1089c572)
1*e34a491bSAdrian Chadd /*-
2*e34a491bSAdrian Chadd  * Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org>.
3*e34a491bSAdrian Chadd  *
4*e34a491bSAdrian Chadd  * Redistribution and use in source and binary forms, with or without
5*e34a491bSAdrian Chadd  * modification, are permitted provided that the following conditions
6*e34a491bSAdrian Chadd  * are met:
7*e34a491bSAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
8*e34a491bSAdrian Chadd  *    notice, this list of conditions and the following disclaimer.
9*e34a491bSAdrian Chadd  * 2. Redistributions in binary form must reproduce the above copyright
10*e34a491bSAdrian Chadd  *    notice, this list of conditions and the following disclaimer in the
11*e34a491bSAdrian Chadd  *    documentation and/or other materials provided with the distribution.
12*e34a491bSAdrian Chadd  *
13*e34a491bSAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*e34a491bSAdrian Chadd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*e34a491bSAdrian Chadd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*e34a491bSAdrian Chadd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*e34a491bSAdrian Chadd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*e34a491bSAdrian Chadd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*e34a491bSAdrian Chadd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*e34a491bSAdrian Chadd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*e34a491bSAdrian Chadd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*e34a491bSAdrian Chadd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*e34a491bSAdrian Chadd  * SUCH DAMAGE.
24*e34a491bSAdrian Chadd  */
25*e34a491bSAdrian Chadd 
26*e34a491bSAdrian Chadd #include <sys/cdefs.h>
27*e34a491bSAdrian Chadd __FBSDID("$FreeBSD$");
28*e34a491bSAdrian Chadd 
29*e34a491bSAdrian Chadd #include <sys/param.h>
30*e34a491bSAdrian Chadd #include <sys/systm.h>
31*e34a491bSAdrian Chadd #include <sys/bus.h>
32*e34a491bSAdrian Chadd #include <sys/lock.h>
33*e34a491bSAdrian Chadd #include <sys/mutex.h>
34*e34a491bSAdrian Chadd #include <sys/rman.h>
35*e34a491bSAdrian Chadd #include <machine/bus.h>
36*e34a491bSAdrian Chadd 
37*e34a491bSAdrian Chadd #include <dev/extres/clk/clk.h>
38*e34a491bSAdrian Chadd #include <dev/extres/clk/clk_div.h>
39*e34a491bSAdrian Chadd #include <dev/extres/clk/clk_fixed.h>
40*e34a491bSAdrian Chadd #include <dev/extres/clk/clk_mux.h>
41*e34a491bSAdrian Chadd 
42*e34a491bSAdrian Chadd #include "qcom_clk_fdiv.h"
43*e34a491bSAdrian Chadd 
44*e34a491bSAdrian Chadd #include "clkdev_if.h"
45*e34a491bSAdrian Chadd 
46*e34a491bSAdrian Chadd /*
47*e34a491bSAdrian Chadd  * This is a fixed divisor node.  It represents some divisor
48*e34a491bSAdrian Chadd  * that is setup by the boot environment and we don't have
49*e34a491bSAdrian Chadd  * any need for the driver to go and fiddle with.
50*e34a491bSAdrian Chadd  *
51*e34a491bSAdrian Chadd  * It likely should just live in the extres/clk code.
52*e34a491bSAdrian Chadd  */
53*e34a491bSAdrian Chadd 
54*e34a491bSAdrian Chadd struct qcom_clk_fdiv_sc {
55*e34a491bSAdrian Chadd 	struct clknode	*clknode;
56*e34a491bSAdrian Chadd 	uint32_t divisor;
57*e34a491bSAdrian Chadd };
58*e34a491bSAdrian Chadd 
59*e34a491bSAdrian Chadd static int
60*e34a491bSAdrian Chadd qcom_clk_fdiv_recalc(struct clknode *clk, uint64_t *freq)
61*e34a491bSAdrian Chadd {
62*e34a491bSAdrian Chadd 	struct qcom_clk_fdiv_sc *sc;
63*e34a491bSAdrian Chadd 
64*e34a491bSAdrian Chadd 	sc = clknode_get_softc(clk);
65*e34a491bSAdrian Chadd 
66*e34a491bSAdrian Chadd 	if (freq == NULL || *freq == 0) {
67*e34a491bSAdrian Chadd 		printf("%s: called; NULL or 0 frequency\n", __func__);
68*e34a491bSAdrian Chadd 		return (ENXIO);
69*e34a491bSAdrian Chadd 	}
70*e34a491bSAdrian Chadd 
71*e34a491bSAdrian Chadd 	*freq = *freq / sc->divisor;
72*e34a491bSAdrian Chadd 	return (0);
73*e34a491bSAdrian Chadd }
74*e34a491bSAdrian Chadd 
75*e34a491bSAdrian Chadd static int
76*e34a491bSAdrian Chadd qcom_clk_fdiv_init(struct clknode *clk, device_t dev)
77*e34a491bSAdrian Chadd {
78*e34a491bSAdrian Chadd 	/*
79*e34a491bSAdrian Chadd 	 * There's only a single parent here for an fixed divisor,
80*e34a491bSAdrian Chadd 	 * so just set it to 0; the caller doesn't need to supply it.
81*e34a491bSAdrian Chadd 	 */
82*e34a491bSAdrian Chadd 	clknode_init_parent_idx(clk, 0);
83*e34a491bSAdrian Chadd 
84*e34a491bSAdrian Chadd 	return(0);
85*e34a491bSAdrian Chadd }
86*e34a491bSAdrian Chadd 
87*e34a491bSAdrian Chadd static clknode_method_t qcom_clk_fdiv_methods[] = {
88*e34a491bSAdrian Chadd 	/* Device interface */
89*e34a491bSAdrian Chadd 	CLKNODEMETHOD(clknode_init,		qcom_clk_fdiv_init),
90*e34a491bSAdrian Chadd 	CLKNODEMETHOD(clknode_recalc_freq,	qcom_clk_fdiv_recalc),
91*e34a491bSAdrian Chadd 	CLKNODEMETHOD_END
92*e34a491bSAdrian Chadd };
93*e34a491bSAdrian Chadd 
94*e34a491bSAdrian Chadd DEFINE_CLASS_1(qcom_clk_fepll, qcom_clk_fdiv_class, qcom_clk_fdiv_methods,
95*e34a491bSAdrian Chadd    sizeof(struct qcom_clk_fdiv_sc), clknode_class);
96*e34a491bSAdrian Chadd 
97*e34a491bSAdrian Chadd int
98*e34a491bSAdrian Chadd qcom_clk_fdiv_register(struct clkdom *clkdom, struct qcom_clk_fdiv_def *clkdef)
99*e34a491bSAdrian Chadd {
100*e34a491bSAdrian Chadd 	struct clknode *clk;
101*e34a491bSAdrian Chadd 	struct qcom_clk_fdiv_sc *sc;
102*e34a491bSAdrian Chadd 
103*e34a491bSAdrian Chadd 	clk = clknode_create(clkdom, &qcom_clk_fdiv_class, &clkdef->clkdef);
104*e34a491bSAdrian Chadd 	if (clk == NULL)
105*e34a491bSAdrian Chadd 		return (1);
106*e34a491bSAdrian Chadd 
107*e34a491bSAdrian Chadd 	sc = clknode_get_softc(clk);
108*e34a491bSAdrian Chadd 	sc->clknode = clk;
109*e34a491bSAdrian Chadd 
110*e34a491bSAdrian Chadd 	sc->divisor = clkdef->divisor;
111*e34a491bSAdrian Chadd 
112*e34a491bSAdrian Chadd 	clknode_register(clkdom, clk);
113*e34a491bSAdrian Chadd 
114*e34a491bSAdrian Chadd 	return (0);
115*e34a491bSAdrian Chadd }
116