1 1.3 thorpej /* $NetBSD: bcm2835_aux.c,v 1.3 2021/01/27 03:10:19 thorpej Exp $ */ 2 1.1 skrll 3 1.1 skrll /*- 4 1.1 skrll * Copyright (c) 2017 Jared D. McNeill <jmcneill (at) invisible.ca> 5 1.1 skrll * All rights reserved. 6 1.1 skrll * 7 1.1 skrll * Redistribution and use in source and binary forms, with or without 8 1.1 skrll * modification, are permitted provided that the following conditions 9 1.1 skrll * are met: 10 1.1 skrll * 1. Redistributions of source code must retain the above copyright 11 1.1 skrll * notice, this list of conditions and the following disclaimer. 12 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 skrll * notice, this list of conditions and the following disclaimer in the 14 1.1 skrll * documentation and/or other materials provided with the distribution. 15 1.1 skrll * 16 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 skrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 skrll * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 skrll * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 skrll * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.1 skrll * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.1 skrll * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.1 skrll * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 skrll * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 skrll * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 skrll * SUCH DAMAGE. 27 1.1 skrll */ 28 1.1 skrll 29 1.1 skrll #include <sys/cdefs.h> 30 1.3 thorpej __KERNEL_RCSID(0, "$NetBSD: bcm2835_aux.c,v 1.3 2021/01/27 03:10:19 thorpej Exp $"); 31 1.1 skrll 32 1.1 skrll #include <sys/param.h> 33 1.1 skrll #include <sys/systm.h> 34 1.1 skrll #include <sys/device.h> 35 1.1 skrll #include <sys/kmem.h> 36 1.1 skrll #include <sys/bus.h> 37 1.1 skrll 38 1.1 skrll #include <dev/clk/clk_backend.h> 39 1.1 skrll 40 1.1 skrll #include <dev/fdt/fdtvar.h> 41 1.1 skrll 42 1.1 skrll /* Registers */ 43 1.1 skrll #define BCMAUX_AUXIRQ_REG 0x00 44 1.1 skrll #define BCMAUX_AUXENB_REG 0x04 45 1.1 skrll 46 1.1 skrll /* Clock IDs */ 47 1.1 skrll #define BCMAUX_CLOCK_UART 0 48 1.1 skrll #define BCMAUX_CLOCK_SPI1 1 49 1.1 skrll #define BCMAUX_CLOCK_SPI2 2 50 1.1 skrll #define BCMAUX_NCLOCK 3 51 1.1 skrll 52 1.1 skrll static int bcmaux_match(device_t, cfdata_t, void *); 53 1.1 skrll static void bcmaux_attach(device_t, device_t, void *); 54 1.1 skrll 55 1.2 aymeric static struct clk *bcmaux_decode(device_t, int, const void *, size_t); 56 1.1 skrll 57 1.1 skrll static const struct fdtbus_clock_controller_func bcmaux_fdt_funcs = { 58 1.1 skrll .decode = bcmaux_decode 59 1.1 skrll }; 60 1.1 skrll 61 1.1 skrll static struct clk *bcmaux_get(void *, const char *); 62 1.1 skrll static void bcmaux_put(void *, struct clk *); 63 1.1 skrll static u_int bcmaux_get_rate(void *, struct clk *); 64 1.1 skrll static int bcmaux_enable(void *, struct clk *); 65 1.1 skrll static int bcmaux_disable(void *, struct clk *); 66 1.1 skrll 67 1.1 skrll static const struct clk_funcs bcmaux_clk_funcs = { 68 1.1 skrll .get = bcmaux_get, 69 1.1 skrll .put = bcmaux_put, 70 1.1 skrll .get_rate = bcmaux_get_rate, 71 1.1 skrll .enable = bcmaux_enable, 72 1.1 skrll .disable = bcmaux_disable, 73 1.1 skrll }; 74 1.1 skrll 75 1.1 skrll struct bcmaux_clk { 76 1.1 skrll struct clk base; 77 1.1 skrll uint32_t mask; 78 1.1 skrll }; 79 1.1 skrll 80 1.1 skrll struct bcmaux_softc { 81 1.1 skrll device_t sc_dev; 82 1.1 skrll int sc_phandle; 83 1.1 skrll bus_space_tag_t sc_bst; 84 1.1 skrll bus_space_handle_t sc_bsh; 85 1.1 skrll 86 1.1 skrll struct clk *sc_pclk; 87 1.1 skrll 88 1.1 skrll struct clk_domain sc_clkdom; 89 1.1 skrll struct bcmaux_clk sc_clk[BCMAUX_NCLOCK]; 90 1.1 skrll }; 91 1.1 skrll 92 1.1 skrll #define BCMAUX_READ(sc, reg) \ 93 1.1 skrll bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 94 1.1 skrll #define BCMAUX_WRITE(sc, reg, val) \ 95 1.1 skrll bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 96 1.1 skrll 97 1.1 skrll CFATTACH_DECL_NEW(bcmaux_fdt, sizeof(struct bcmaux_softc), 98 1.1 skrll bcmaux_match, bcmaux_attach, NULL, NULL); 99 1.1 skrll 100 1.3 thorpej static const struct device_compatible_entry compat_data[] = { 101 1.3 thorpej { .compat = "brcm,bcm2835-aux" }, 102 1.3 thorpej DEVICE_COMPAT_EOL 103 1.3 thorpej }; 104 1.3 thorpej 105 1.1 skrll static int 106 1.1 skrll bcmaux_match(device_t parent, cfdata_t cf, void *aux) 107 1.1 skrll { 108 1.1 skrll const struct fdt_attach_args *faa = aux; 109 1.1 skrll 110 1.3 thorpej return of_compatible_match(faa->faa_phandle, compat_data); 111 1.1 skrll } 112 1.1 skrll 113 1.1 skrll static void 114 1.1 skrll bcmaux_attach(device_t parent, device_t self, void *aux) 115 1.1 skrll { 116 1.1 skrll struct bcmaux_softc * const sc = device_private(self); 117 1.1 skrll const struct fdt_attach_args *faa = aux; 118 1.1 skrll const int phandle = faa->faa_phandle; 119 1.1 skrll bus_addr_t addr; 120 1.1 skrll bus_size_t size; 121 1.1 skrll 122 1.1 skrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 123 1.1 skrll aprint_error(": couldn't get registers\n"); 124 1.1 skrll return; 125 1.1 skrll } 126 1.1 skrll 127 1.1 skrll sc->sc_dev = self; 128 1.1 skrll sc->sc_phandle = phandle; 129 1.1 skrll sc->sc_clkdom.funcs = &bcmaux_clk_funcs; 130 1.1 skrll sc->sc_clkdom.priv = sc; 131 1.1 skrll sc->sc_pclk = fdtbus_clock_get_index(phandle, 0); 132 1.1 skrll if (sc->sc_pclk == NULL) { 133 1.1 skrll aprint_error(": couldn't get parent clock\n"); 134 1.1 skrll return; 135 1.1 skrll } 136 1.1 skrll sc->sc_bst = faa->faa_bst; 137 1.1 skrll if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 138 1.1 skrll aprint_error(": couldn't map registers\n"); 139 1.1 skrll return; 140 1.1 skrll } 141 1.1 skrll 142 1.1 skrll sc->sc_clk[BCMAUX_CLOCK_UART].base.domain = &sc->sc_clkdom; 143 1.1 skrll sc->sc_clk[BCMAUX_CLOCK_UART].base.name = "aux_uart"; 144 1.1 skrll sc->sc_clk[BCMAUX_CLOCK_UART].mask = __BIT(0); 145 1.1 skrll 146 1.1 skrll sc->sc_clk[BCMAUX_CLOCK_SPI1].base.domain = &sc->sc_clkdom; 147 1.1 skrll sc->sc_clk[BCMAUX_CLOCK_SPI1].base.name = "aux_spi1"; 148 1.1 skrll sc->sc_clk[BCMAUX_CLOCK_SPI1].mask = __BIT(1); 149 1.1 skrll 150 1.1 skrll sc->sc_clk[BCMAUX_CLOCK_SPI2].base.domain = &sc->sc_clkdom; 151 1.1 skrll sc->sc_clk[BCMAUX_CLOCK_SPI2].base.name = "aux_spi2"; 152 1.1 skrll sc->sc_clk[BCMAUX_CLOCK_SPI2].mask = __BIT(2); 153 1.1 skrll 154 1.1 skrll aprint_naive("\n"); 155 1.1 skrll aprint_normal("\n"); 156 1.1 skrll 157 1.1 skrll fdtbus_register_clock_controller(self, phandle, &bcmaux_fdt_funcs); 158 1.1 skrll } 159 1.1 skrll 160 1.1 skrll static struct clk * 161 1.2 aymeric bcmaux_decode(device_t dev, int cc_phandle, const void *data, size_t len) 162 1.1 skrll { 163 1.1 skrll struct bcmaux_softc * const sc = device_private(dev); 164 1.1 skrll u_int clkid; 165 1.1 skrll 166 1.1 skrll if (len != 4) 167 1.1 skrll return NULL; 168 1.1 skrll 169 1.1 skrll clkid = be32dec(data); 170 1.1 skrll if (clkid >= BCMAUX_NCLOCK) 171 1.1 skrll return NULL; 172 1.1 skrll 173 1.1 skrll return &sc->sc_clk[clkid].base; 174 1.1 skrll } 175 1.1 skrll 176 1.1 skrll static struct clk * 177 1.1 skrll bcmaux_get(void *priv, const char *name) 178 1.1 skrll { 179 1.1 skrll struct bcmaux_softc * const sc = priv; 180 1.1 skrll 181 1.1 skrll for (size_t i = 0; i < BCMAUX_NCLOCK; i++) { 182 1.1 skrll if (strcmp(name, sc->sc_clk[i].base.name) == 0) 183 1.1 skrll return &sc->sc_clk[i].base; 184 1.1 skrll } 185 1.1 skrll 186 1.1 skrll return NULL; 187 1.1 skrll } 188 1.1 skrll 189 1.1 skrll static void 190 1.1 skrll bcmaux_put(void *priv, struct clk *clk) 191 1.1 skrll { 192 1.1 skrll } 193 1.1 skrll 194 1.1 skrll static u_int 195 1.1 skrll bcmaux_get_rate(void *priv, struct clk *clk) 196 1.1 skrll { 197 1.1 skrll struct bcmaux_softc * const sc = priv; 198 1.1 skrll 199 1.1 skrll return clk_get_rate(sc->sc_pclk); 200 1.1 skrll } 201 1.1 skrll 202 1.1 skrll static int 203 1.1 skrll bcmaux_enable(void *priv, struct clk *clk) 204 1.1 skrll { 205 1.1 skrll struct bcmaux_softc * const sc = priv; 206 1.1 skrll struct bcmaux_clk *auxclk = (struct bcmaux_clk *)clk; 207 1.1 skrll uint32_t val; 208 1.1 skrll 209 1.1 skrll val = BCMAUX_READ(sc, BCMAUX_AUXENB_REG); 210 1.1 skrll val |= auxclk->mask; 211 1.1 skrll BCMAUX_WRITE(sc, BCMAUX_AUXENB_REG, val); 212 1.1 skrll 213 1.1 skrll return 0; 214 1.1 skrll } 215 1.1 skrll 216 1.1 skrll static int 217 1.1 skrll bcmaux_disable(void *priv, struct clk *clk) 218 1.1 skrll { 219 1.1 skrll struct bcmaux_softc * const sc = priv; 220 1.1 skrll struct bcmaux_clk *auxclk = (struct bcmaux_clk *)clk; 221 1.1 skrll uint32_t val; 222 1.1 skrll 223 1.1 skrll val = BCMAUX_READ(sc, BCMAUX_AUXENB_REG); 224 1.1 skrll val &= ~auxclk->mask; 225 1.1 skrll BCMAUX_WRITE(sc, BCMAUX_AUXENB_REG, val); 226 1.1 skrll 227 1.1 skrll return 0; 228 1.1 skrll } 229