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, ®);
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, ®);
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