1*77f22241SEmmanuel Vadot /*- 2*77f22241SEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause 3*77f22241SEmmanuel Vadot * 4*77f22241SEmmanuel Vadot * Copyright 2016 Michal Meloun <mmel@FreeBSD.org> 5*77f22241SEmmanuel Vadot * All rights reserved. 6*77f22241SEmmanuel Vadot * 7*77f22241SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 8*77f22241SEmmanuel Vadot * modification, are permitted provided that the following conditions 9*77f22241SEmmanuel Vadot * are met: 10*77f22241SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 11*77f22241SEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 12*77f22241SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 13*77f22241SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 14*77f22241SEmmanuel Vadot * documentation and/or other materials provided with the distribution. 15*77f22241SEmmanuel Vadot * 16*77f22241SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*77f22241SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*77f22241SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*77f22241SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*77f22241SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*77f22241SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*77f22241SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*77f22241SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*77f22241SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*77f22241SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*77f22241SEmmanuel Vadot * SUCH DAMAGE. 27*77f22241SEmmanuel Vadot */ 28*77f22241SEmmanuel Vadot 29*77f22241SEmmanuel Vadot #include <sys/param.h> 30*77f22241SEmmanuel Vadot #include <sys/systm.h> 31*77f22241SEmmanuel Vadot #include <sys/bus.h> 32*77f22241SEmmanuel Vadot 33*77f22241SEmmanuel Vadot #include <dev/extres/clk/clk.h> 34*77f22241SEmmanuel Vadot 35*77f22241SEmmanuel Vadot #include <dev/clk/rockchip/rk_clk_gate.h> 36*77f22241SEmmanuel Vadot 37*77f22241SEmmanuel Vadot #include "clkdev_if.h" 38*77f22241SEmmanuel Vadot 39*77f22241SEmmanuel Vadot #define WR4(_clk, off, val) \ 40*77f22241SEmmanuel Vadot CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) 41*77f22241SEmmanuel Vadot #define RD4(_clk, off, val) \ 42*77f22241SEmmanuel Vadot CLKDEV_READ_4(clknode_get_device(_clk), off, val) 43*77f22241SEmmanuel Vadot #define MD4(_clk, off, clr, set ) \ 44*77f22241SEmmanuel Vadot CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) 45*77f22241SEmmanuel Vadot #define DEVICE_LOCK(_clk) \ 46*77f22241SEmmanuel Vadot CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) 47*77f22241SEmmanuel Vadot #define DEVICE_UNLOCK(_clk) \ 48*77f22241SEmmanuel Vadot CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) 49*77f22241SEmmanuel Vadot 50*77f22241SEmmanuel Vadot static int rk_clk_gate_init(struct clknode *clk, device_t dev); 51*77f22241SEmmanuel Vadot static int rk_clk_gate_set_gate(struct clknode *clk, bool enable); 52*77f22241SEmmanuel Vadot struct rk_clk_gate_sc { 53*77f22241SEmmanuel Vadot uint32_t offset; 54*77f22241SEmmanuel Vadot uint32_t shift; 55*77f22241SEmmanuel Vadot uint32_t mask; 56*77f22241SEmmanuel Vadot uint32_t on_value; 57*77f22241SEmmanuel Vadot uint32_t off_value; 58*77f22241SEmmanuel Vadot int gate_flags; 59*77f22241SEmmanuel Vadot bool ungated; 60*77f22241SEmmanuel Vadot }; 61*77f22241SEmmanuel Vadot 62*77f22241SEmmanuel Vadot static clknode_method_t rk_clk_gate_methods[] = { 63*77f22241SEmmanuel Vadot /* Device interface */ 64*77f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_init, rk_clk_gate_init), 65*77f22241SEmmanuel Vadot CLKNODEMETHOD(clknode_set_gate, rk_clk_gate_set_gate), 66*77f22241SEmmanuel Vadot CLKNODEMETHOD_END 67*77f22241SEmmanuel Vadot }; 68*77f22241SEmmanuel Vadot DEFINE_CLASS_1(rk_clk_gate, rk_clk_gate_class, rk_clk_gate_methods, 69*77f22241SEmmanuel Vadot sizeof(struct rk_clk_gate_sc), clknode_class); 70*77f22241SEmmanuel Vadot 71*77f22241SEmmanuel Vadot static int 72*77f22241SEmmanuel Vadot rk_clk_gate_init(struct clknode *clk, device_t dev) 73*77f22241SEmmanuel Vadot { 74*77f22241SEmmanuel Vadot uint32_t reg; 75*77f22241SEmmanuel Vadot struct rk_clk_gate_sc *sc; 76*77f22241SEmmanuel Vadot int rv; 77*77f22241SEmmanuel Vadot 78*77f22241SEmmanuel Vadot sc = clknode_get_softc(clk); 79*77f22241SEmmanuel Vadot DEVICE_LOCK(clk); 80*77f22241SEmmanuel Vadot rv = RD4(clk, sc->offset, ®); 81*77f22241SEmmanuel Vadot DEVICE_UNLOCK(clk); 82*77f22241SEmmanuel Vadot if (rv != 0) 83*77f22241SEmmanuel Vadot return (rv); 84*77f22241SEmmanuel Vadot reg = (reg >> sc->shift) & sc->mask; 85*77f22241SEmmanuel Vadot sc->ungated = reg == sc->on_value ? 1 : 0; 86*77f22241SEmmanuel Vadot clknode_init_parent_idx(clk, 0); 87*77f22241SEmmanuel Vadot return(0); 88*77f22241SEmmanuel Vadot } 89*77f22241SEmmanuel Vadot 90*77f22241SEmmanuel Vadot static int 91*77f22241SEmmanuel Vadot rk_clk_gate_set_gate(struct clknode *clk, bool enable) 92*77f22241SEmmanuel Vadot { 93*77f22241SEmmanuel Vadot uint32_t reg; 94*77f22241SEmmanuel Vadot struct rk_clk_gate_sc *sc; 95*77f22241SEmmanuel Vadot int rv; 96*77f22241SEmmanuel Vadot 97*77f22241SEmmanuel Vadot sc = clknode_get_softc(clk); 98*77f22241SEmmanuel Vadot sc->ungated = enable; 99*77f22241SEmmanuel Vadot DEVICE_LOCK(clk); 100*77f22241SEmmanuel Vadot rv = MD4(clk, sc->offset, sc->mask << sc->shift, 101*77f22241SEmmanuel Vadot ((sc->ungated ? sc->on_value : sc->off_value) << sc->shift) | 102*77f22241SEmmanuel Vadot RK_CLK_GATE_MASK); 103*77f22241SEmmanuel Vadot if (rv != 0) { 104*77f22241SEmmanuel Vadot DEVICE_UNLOCK(clk); 105*77f22241SEmmanuel Vadot return (rv); 106*77f22241SEmmanuel Vadot } 107*77f22241SEmmanuel Vadot RD4(clk, sc->offset, ®); 108*77f22241SEmmanuel Vadot DEVICE_UNLOCK(clk); 109*77f22241SEmmanuel Vadot return(0); 110*77f22241SEmmanuel Vadot } 111*77f22241SEmmanuel Vadot 112*77f22241SEmmanuel Vadot int 113*77f22241SEmmanuel Vadot rk_clk_gate_register(struct clkdom *clkdom, struct rk_clk_gate_def *clkdef) 114*77f22241SEmmanuel Vadot { 115*77f22241SEmmanuel Vadot struct clknode *clk; 116*77f22241SEmmanuel Vadot struct rk_clk_gate_sc *sc; 117*77f22241SEmmanuel Vadot 118*77f22241SEmmanuel Vadot clk = clknode_create(clkdom, &rk_clk_gate_class, &clkdef->clkdef); 119*77f22241SEmmanuel Vadot if (clk == NULL) 120*77f22241SEmmanuel Vadot return (1); 121*77f22241SEmmanuel Vadot 122*77f22241SEmmanuel Vadot sc = clknode_get_softc(clk); 123*77f22241SEmmanuel Vadot sc->offset = clkdef->offset; 124*77f22241SEmmanuel Vadot sc->shift = clkdef->shift; 125*77f22241SEmmanuel Vadot sc->mask = clkdef->mask; 126*77f22241SEmmanuel Vadot sc->on_value = clkdef->on_value; 127*77f22241SEmmanuel Vadot sc->off_value = clkdef->off_value; 128*77f22241SEmmanuel Vadot sc->gate_flags = clkdef->gate_flags; 129*77f22241SEmmanuel Vadot 130*77f22241SEmmanuel Vadot clknode_register(clkdom, clk); 131*77f22241SEmmanuel Vadot return (0); 132*77f22241SEmmanuel Vadot } 133