xref: /freebsd/sys/dev/clk/rockchip/rk_clk_gate.c (revision be82b3a0bf72ed3b5f01ac9fcd8dcd3802e3c742)
177f22241SEmmanuel Vadot /*-
277f22241SEmmanuel Vadot  * SPDX-License-Identifier: BSD-2-Clause
377f22241SEmmanuel Vadot  *
477f22241SEmmanuel Vadot  * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
577f22241SEmmanuel Vadot  * All rights reserved.
677f22241SEmmanuel Vadot  *
777f22241SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
877f22241SEmmanuel Vadot  * modification, are permitted provided that the following conditions
977f22241SEmmanuel Vadot  * are met:
1077f22241SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
1177f22241SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
1277f22241SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
1377f22241SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
1477f22241SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
1577f22241SEmmanuel Vadot  *
1677f22241SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1777f22241SEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1877f22241SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1977f22241SEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2077f22241SEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2177f22241SEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2277f22241SEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2377f22241SEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2477f22241SEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2577f22241SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2677f22241SEmmanuel Vadot  * SUCH DAMAGE.
2777f22241SEmmanuel Vadot  */
2877f22241SEmmanuel Vadot 
2977f22241SEmmanuel Vadot #include <sys/param.h>
3077f22241SEmmanuel Vadot #include <sys/systm.h>
3177f22241SEmmanuel Vadot #include <sys/bus.h>
3277f22241SEmmanuel Vadot 
33*be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
3477f22241SEmmanuel Vadot 
3577f22241SEmmanuel Vadot #include <dev/clk/rockchip/rk_clk_gate.h>
3677f22241SEmmanuel Vadot 
3777f22241SEmmanuel Vadot #include "clkdev_if.h"
3877f22241SEmmanuel Vadot 
3977f22241SEmmanuel Vadot #define	WR4(_clk, off, val)						\
4077f22241SEmmanuel Vadot 	CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
4177f22241SEmmanuel Vadot #define	RD4(_clk, off, val)						\
4277f22241SEmmanuel Vadot 	CLKDEV_READ_4(clknode_get_device(_clk), off, val)
4377f22241SEmmanuel Vadot #define	MD4(_clk, off, clr, set )					\
4477f22241SEmmanuel Vadot 	CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
4577f22241SEmmanuel Vadot #define	DEVICE_LOCK(_clk)						\
4677f22241SEmmanuel Vadot 	CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
4777f22241SEmmanuel Vadot #define	DEVICE_UNLOCK(_clk)						\
4877f22241SEmmanuel Vadot 	CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
4977f22241SEmmanuel Vadot 
5077f22241SEmmanuel Vadot static int rk_clk_gate_init(struct clknode *clk, device_t dev);
5177f22241SEmmanuel Vadot static int rk_clk_gate_set_gate(struct clknode *clk, bool enable);
5277f22241SEmmanuel Vadot struct rk_clk_gate_sc {
5377f22241SEmmanuel Vadot 	uint32_t	offset;
5477f22241SEmmanuel Vadot 	uint32_t	shift;
5577f22241SEmmanuel Vadot 	uint32_t	mask;
5677f22241SEmmanuel Vadot 	uint32_t	on_value;
5777f22241SEmmanuel Vadot 	uint32_t	off_value;
5877f22241SEmmanuel Vadot 	int		gate_flags;
5977f22241SEmmanuel Vadot 	bool		ungated;
6077f22241SEmmanuel Vadot };
6177f22241SEmmanuel Vadot 
6277f22241SEmmanuel Vadot static clknode_method_t rk_clk_gate_methods[] = {
6377f22241SEmmanuel Vadot 	/* Device interface */
6477f22241SEmmanuel Vadot 	CLKNODEMETHOD(clknode_init,	rk_clk_gate_init),
6577f22241SEmmanuel Vadot 	CLKNODEMETHOD(clknode_set_gate,	rk_clk_gate_set_gate),
6677f22241SEmmanuel Vadot 	CLKNODEMETHOD_END
6777f22241SEmmanuel Vadot };
6877f22241SEmmanuel Vadot DEFINE_CLASS_1(rk_clk_gate, rk_clk_gate_class, rk_clk_gate_methods,
6977f22241SEmmanuel Vadot    sizeof(struct rk_clk_gate_sc), clknode_class);
7077f22241SEmmanuel Vadot 
7177f22241SEmmanuel Vadot static int
rk_clk_gate_init(struct clknode * clk,device_t dev)7277f22241SEmmanuel Vadot rk_clk_gate_init(struct clknode *clk, device_t dev)
7377f22241SEmmanuel Vadot {
7477f22241SEmmanuel Vadot 	uint32_t reg;
7577f22241SEmmanuel Vadot 	struct rk_clk_gate_sc *sc;
7677f22241SEmmanuel Vadot 	int rv;
7777f22241SEmmanuel Vadot 
7877f22241SEmmanuel Vadot 	sc = clknode_get_softc(clk);
7977f22241SEmmanuel Vadot 	DEVICE_LOCK(clk);
8077f22241SEmmanuel Vadot 	rv = RD4(clk, sc->offset, &reg);
8177f22241SEmmanuel Vadot 	DEVICE_UNLOCK(clk);
8277f22241SEmmanuel Vadot 	if (rv != 0)
8377f22241SEmmanuel Vadot 		return (rv);
8477f22241SEmmanuel Vadot 	reg = (reg >> sc->shift) & sc->mask;
8577f22241SEmmanuel Vadot 	sc->ungated = reg == sc->on_value ? 1 : 0;
8677f22241SEmmanuel Vadot 	clknode_init_parent_idx(clk, 0);
8777f22241SEmmanuel Vadot 	return(0);
8877f22241SEmmanuel Vadot }
8977f22241SEmmanuel Vadot 
9077f22241SEmmanuel Vadot static int
rk_clk_gate_set_gate(struct clknode * clk,bool enable)9177f22241SEmmanuel Vadot rk_clk_gate_set_gate(struct clknode *clk, bool enable)
9277f22241SEmmanuel Vadot {
9377f22241SEmmanuel Vadot 	uint32_t reg;
9477f22241SEmmanuel Vadot 	struct rk_clk_gate_sc *sc;
9577f22241SEmmanuel Vadot 	int rv;
9677f22241SEmmanuel Vadot 
9777f22241SEmmanuel Vadot 	sc = clknode_get_softc(clk);
9877f22241SEmmanuel Vadot 	sc->ungated = enable;
9977f22241SEmmanuel Vadot 	DEVICE_LOCK(clk);
10077f22241SEmmanuel Vadot 	rv = MD4(clk, sc->offset, sc->mask << sc->shift,
10177f22241SEmmanuel Vadot 	    ((sc->ungated ? sc->on_value : sc->off_value) << sc->shift) |
10277f22241SEmmanuel Vadot 	    RK_CLK_GATE_MASK);
10377f22241SEmmanuel Vadot 	if (rv != 0) {
10477f22241SEmmanuel Vadot 		DEVICE_UNLOCK(clk);
10577f22241SEmmanuel Vadot 		return (rv);
10677f22241SEmmanuel Vadot 	}
10777f22241SEmmanuel Vadot 	RD4(clk, sc->offset, &reg);
10877f22241SEmmanuel Vadot 	DEVICE_UNLOCK(clk);
10977f22241SEmmanuel Vadot 	return(0);
11077f22241SEmmanuel Vadot }
11177f22241SEmmanuel Vadot 
11277f22241SEmmanuel Vadot int
rk_clk_gate_register(struct clkdom * clkdom,struct rk_clk_gate_def * clkdef)11377f22241SEmmanuel Vadot rk_clk_gate_register(struct clkdom *clkdom, struct rk_clk_gate_def *clkdef)
11477f22241SEmmanuel Vadot {
11577f22241SEmmanuel Vadot 	struct clknode *clk;
11677f22241SEmmanuel Vadot 	struct rk_clk_gate_sc *sc;
11777f22241SEmmanuel Vadot 
11877f22241SEmmanuel Vadot 	clk = clknode_create(clkdom, &rk_clk_gate_class, &clkdef->clkdef);
11977f22241SEmmanuel Vadot 	if (clk == NULL)
12077f22241SEmmanuel Vadot 		return (1);
12177f22241SEmmanuel Vadot 
12277f22241SEmmanuel Vadot 	sc = clknode_get_softc(clk);
12377f22241SEmmanuel Vadot 	sc->offset = clkdef->offset;
12477f22241SEmmanuel Vadot 	sc->shift = clkdef->shift;
12577f22241SEmmanuel Vadot 	sc->mask =  clkdef->mask;
12677f22241SEmmanuel Vadot 	sc->on_value = clkdef->on_value;
12777f22241SEmmanuel Vadot 	sc->off_value = clkdef->off_value;
12877f22241SEmmanuel Vadot 	sc->gate_flags = clkdef->gate_flags;
12977f22241SEmmanuel Vadot 
13077f22241SEmmanuel Vadot 	clknode_register(clkdom, clk);
13177f22241SEmmanuel Vadot 	return (0);
13277f22241SEmmanuel Vadot }
133