154b96380SRuslan Bukin /*- 254b96380SRuslan Bukin * SPDX-License-Identifier: BSD-2-Clause 354b96380SRuslan Bukin * 454b96380SRuslan Bukin * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com> 5*35f93203SCristian Marussi * Copyright (c) 2023 Arm Ltd 654b96380SRuslan Bukin * 754b96380SRuslan Bukin * This work was supported by Innovate UK project 105694, "Digital Security 854b96380SRuslan Bukin * by Design (DSbD) Technology Platform Prototype". 954b96380SRuslan Bukin * 1054b96380SRuslan Bukin * Redistribution and use in source and binary forms, with or without 1154b96380SRuslan Bukin * modification, are permitted provided that the following conditions 1254b96380SRuslan Bukin * are met: 1354b96380SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 1454b96380SRuslan Bukin * notice, this list of conditions and the following disclaimer. 1554b96380SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 1654b96380SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 1754b96380SRuslan Bukin * documentation and/or other materials provided with the distribution. 1854b96380SRuslan Bukin * 1954b96380SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2054b96380SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2154b96380SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2254b96380SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2354b96380SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2454b96380SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2554b96380SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2654b96380SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2754b96380SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2854b96380SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2954b96380SRuslan Bukin * SUCH DAMAGE. 3054b96380SRuslan Bukin */ 3154b96380SRuslan Bukin 3254b96380SRuslan Bukin #include <sys/param.h> 3354b96380SRuslan Bukin #include <sys/systm.h> 3454b96380SRuslan Bukin #include <sys/bus.h> 3554b96380SRuslan Bukin #include <sys/cpu.h> 3654b96380SRuslan Bukin #include <sys/kernel.h> 3754b96380SRuslan Bukin #include <sys/module.h> 3854b96380SRuslan Bukin 39be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 4054b96380SRuslan Bukin #include <dev/fdt/simplebus.h> 4154b96380SRuslan Bukin #include <dev/fdt/fdt_common.h> 4254b96380SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 4354b96380SRuslan Bukin 4454b96380SRuslan Bukin #include "scmi.h" 4554b96380SRuslan Bukin #include "scmi_protocols.h" 4654b96380SRuslan Bukin #include "scmi_clk.h" 4754b96380SRuslan Bukin 4854b96380SRuslan Bukin struct scmi_clk_softc { 4954b96380SRuslan Bukin device_t dev; 5054b96380SRuslan Bukin device_t scmi; 5154b96380SRuslan Bukin struct clkdom *clkdom; 5254b96380SRuslan Bukin }; 5354b96380SRuslan Bukin 5454b96380SRuslan Bukin struct scmi_clknode_softc { 5554b96380SRuslan Bukin device_t dev; 5654b96380SRuslan Bukin int clock_id; 5754b96380SRuslan Bukin }; 5854b96380SRuslan Bukin 59ecd8cc84SCristian Marussi static int 6054b96380SRuslan Bukin scmi_clk_get_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t *rate) 6154b96380SRuslan Bukin { 62*35f93203SCristian Marussi struct scmi_clk_rate_get_out *out; 63*35f93203SCristian Marussi struct scmi_clk_rate_get_in *in; 6454b96380SRuslan Bukin int error; 6554b96380SRuslan Bukin 66*35f93203SCristian Marussi in = scmi_buf_get(sc->scmi, SCMI_PROTOCOL_ID_CLOCK, 67*35f93203SCristian Marussi SCMI_CLOCK_RATE_GET, sizeof(*in), sizeof(*out)); 68*35f93203SCristian Marussi if (in == NULL) 6954b96380SRuslan Bukin return (ENXIO); 7054b96380SRuslan Bukin 71*35f93203SCristian Marussi in->clock_id = clk_id; 72*35f93203SCristian Marussi error = scmi_request(sc->scmi, in, (void **)&out); 73*35f93203SCristian Marussi if (error == 0) 74*35f93203SCristian Marussi *rate = out->rate_lsb | ((uint64_t)out->rate_msb << 32); 7554b96380SRuslan Bukin 76*35f93203SCristian Marussi scmi_buf_put(sc->scmi, in); 77*35f93203SCristian Marussi 78*35f93203SCristian Marussi return (error); 7954b96380SRuslan Bukin } 8054b96380SRuslan Bukin 8154b96380SRuslan Bukin static int 8254b96380SRuslan Bukin scmi_clk_set_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t rate) 8354b96380SRuslan Bukin { 84*35f93203SCristian Marussi struct scmi_clk_rate_set_in *in; 85*35f93203SCristian Marussi void *out; 8654b96380SRuslan Bukin int error; 8754b96380SRuslan Bukin 88*35f93203SCristian Marussi in = scmi_buf_get(sc->scmi, SCMI_PROTOCOL_ID_CLOCK, 89*35f93203SCristian Marussi SCMI_CLOCK_RATE_SET, sizeof(*in), 0); 90*35f93203SCristian Marussi if (in == NULL) 9154b96380SRuslan Bukin return (ENXIO); 9254b96380SRuslan Bukin 93*35f93203SCristian Marussi in->clock_id = clk_id; 94*35f93203SCristian Marussi in->flags = SCMI_CLK_RATE_ROUND_CLOSEST; 95*35f93203SCristian Marussi in->rate_lsb = (uint32_t)rate; 96*35f93203SCristian Marussi in->rate_msb = (uint32_t)(rate >> 32); 97*35f93203SCristian Marussi 98*35f93203SCristian Marussi error = scmi_request(sc->scmi, in, &out); 99*35f93203SCristian Marussi 100*35f93203SCristian Marussi scmi_buf_put(sc->scmi, in); 101*35f93203SCristian Marussi 102*35f93203SCristian Marussi return (error); 10354b96380SRuslan Bukin } 10454b96380SRuslan Bukin 10519a7cf0cSMark Johnston static int __unused 10654b96380SRuslan Bukin scmi_clk_gate(struct scmi_clk_softc *sc, int clk_id, int enable) 10754b96380SRuslan Bukin { 108*35f93203SCristian Marussi struct scmi_clk_state_in *in; 109*35f93203SCristian Marussi void *out; 11054b96380SRuslan Bukin int error; 11154b96380SRuslan Bukin 112*35f93203SCristian Marussi in = scmi_buf_get(sc->scmi, SCMI_PROTOCOL_ID_CLOCK, 113*35f93203SCristian Marussi SCMI_CLOCK_CONFIG_SET, sizeof(*in), 0); 114*35f93203SCristian Marussi if (in == NULL) 11554b96380SRuslan Bukin return (ENXIO); 11654b96380SRuslan Bukin 117*35f93203SCristian Marussi in->clock_id = clk_id; 118*35f93203SCristian Marussi in->attributes = enable; 119*35f93203SCristian Marussi error = scmi_request(sc->scmi, in, &out); 120*35f93203SCristian Marussi 121*35f93203SCristian Marussi scmi_buf_put(sc->scmi, in); 122*35f93203SCristian Marussi 123*35f93203SCristian Marussi return (error); 12454b96380SRuslan Bukin } 12554b96380SRuslan Bukin 12654b96380SRuslan Bukin static int 12754b96380SRuslan Bukin scmi_clknode_init(struct clknode *clk, device_t dev) 12854b96380SRuslan Bukin { 12954b96380SRuslan Bukin 13054b96380SRuslan Bukin clknode_init_parent_idx(clk, 0); 13154b96380SRuslan Bukin 13254b96380SRuslan Bukin return (0); 13354b96380SRuslan Bukin } 13454b96380SRuslan Bukin 13554b96380SRuslan Bukin static int 13654b96380SRuslan Bukin scmi_clknode_recalc_freq(struct clknode *clk, uint64_t *freq) 13754b96380SRuslan Bukin { 138ecd8cc84SCristian Marussi struct scmi_clknode_softc *clk_sc; 139ecd8cc84SCristian Marussi struct scmi_clk_softc *sc; 140ecd8cc84SCristian Marussi uint64_t rate; 141ecd8cc84SCristian Marussi int ret; 14254b96380SRuslan Bukin 143ecd8cc84SCristian Marussi clk_sc = clknode_get_softc(clk); 144ecd8cc84SCristian Marussi sc = device_get_softc(clk_sc->dev); 145ecd8cc84SCristian Marussi ret = scmi_clk_get_rate(sc, clk_sc->clock_id, &rate); 146ecd8cc84SCristian Marussi if (ret == 0) 147ecd8cc84SCristian Marussi *freq = rate; 148ecd8cc84SCristian Marussi 149ecd8cc84SCristian Marussi return (ret); 15054b96380SRuslan Bukin } 15154b96380SRuslan Bukin 15254b96380SRuslan Bukin static int 15354b96380SRuslan Bukin scmi_clknode_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout, 15454b96380SRuslan Bukin int flags, int *stop) 15554b96380SRuslan Bukin { 15654b96380SRuslan Bukin struct scmi_clknode_softc *clk_sc; 15754b96380SRuslan Bukin struct scmi_clk_softc *sc; 15854b96380SRuslan Bukin 15954b96380SRuslan Bukin clk_sc = clknode_get_softc(clk); 16054b96380SRuslan Bukin sc = device_get_softc(clk_sc->dev); 16154b96380SRuslan Bukin 16254b96380SRuslan Bukin scmi_clk_set_rate(sc, clk_sc->clock_id, *fout); 16354b96380SRuslan Bukin 16454b96380SRuslan Bukin *stop = 1; 16554b96380SRuslan Bukin 16654b96380SRuslan Bukin return (0); 16754b96380SRuslan Bukin } 16854b96380SRuslan Bukin 16954b96380SRuslan Bukin static clknode_method_t scmi_clknode_methods[] = { 17054b96380SRuslan Bukin /* Device interface */ 17154b96380SRuslan Bukin CLKNODEMETHOD(clknode_init, scmi_clknode_init), 17254b96380SRuslan Bukin CLKNODEMETHOD(clknode_recalc_freq, scmi_clknode_recalc_freq), 17354b96380SRuslan Bukin CLKNODEMETHOD(clknode_set_freq, scmi_clknode_set_freq), 17454b96380SRuslan Bukin CLKNODEMETHOD_END 17554b96380SRuslan Bukin }; 17654b96380SRuslan Bukin 17754b96380SRuslan Bukin DEFINE_CLASS_1(scmi_clknode, scmi_clknode_class, scmi_clknode_methods, 17854b96380SRuslan Bukin sizeof(struct scmi_clknode_softc), clknode_class); 17954b96380SRuslan Bukin 18054b96380SRuslan Bukin static int 18154b96380SRuslan Bukin scmi_clk_add_node(struct scmi_clk_softc *sc, int index, char *clock_name) 18254b96380SRuslan Bukin { 18354b96380SRuslan Bukin struct scmi_clknode_softc *clk_sc; 18454b96380SRuslan Bukin struct clknode_init_def def; 18554b96380SRuslan Bukin struct clknode *clk; 18654b96380SRuslan Bukin 18754b96380SRuslan Bukin memset(&def, 0, sizeof(def)); 18854b96380SRuslan Bukin def.id = index; 18954b96380SRuslan Bukin def.name = clock_name; 19054b96380SRuslan Bukin def.parent_names = NULL; 19154b96380SRuslan Bukin def.parent_cnt = 0; 19254b96380SRuslan Bukin 19354b96380SRuslan Bukin clk = clknode_create(sc->clkdom, &scmi_clknode_class, &def); 19454b96380SRuslan Bukin if (clk == NULL) { 19554b96380SRuslan Bukin device_printf(sc->dev, "Cannot create clknode.\n"); 19654b96380SRuslan Bukin return (ENXIO); 19754b96380SRuslan Bukin } 19854b96380SRuslan Bukin 19954b96380SRuslan Bukin clk_sc = clknode_get_softc(clk); 20054b96380SRuslan Bukin clk_sc->dev = sc->dev; 20154b96380SRuslan Bukin clk_sc->clock_id = index; 20254b96380SRuslan Bukin 20354b96380SRuslan Bukin if (clknode_register(sc->clkdom, clk) == NULL) { 20454b96380SRuslan Bukin device_printf(sc->dev, "Could not register clock '%s'.\n", 20554b96380SRuslan Bukin def.name); 20654b96380SRuslan Bukin return (ENXIO); 20754b96380SRuslan Bukin } 20854b96380SRuslan Bukin 20954b96380SRuslan Bukin device_printf(sc->dev, "Clock '%s' registered.\n", def.name); 21054b96380SRuslan Bukin 21154b96380SRuslan Bukin return (0); 21254b96380SRuslan Bukin } 21354b96380SRuslan Bukin 21454b96380SRuslan Bukin static int 21554b96380SRuslan Bukin scmi_clk_get_name(struct scmi_clk_softc *sc, int index, char **result) 21654b96380SRuslan Bukin { 217*35f93203SCristian Marussi struct scmi_clk_name_get_out *out; 218*35f93203SCristian Marussi struct scmi_clk_name_get_in *in; 21954b96380SRuslan Bukin int error; 22054b96380SRuslan Bukin 221*35f93203SCristian Marussi in = scmi_buf_get(sc->scmi, SCMI_PROTOCOL_ID_CLOCK, 222*35f93203SCristian Marussi SCMI_CLOCK_NAME_GET, sizeof(*in), sizeof(*out)); 223*35f93203SCristian Marussi if (in == NULL) 22454b96380SRuslan Bukin return (ENXIO); 22554b96380SRuslan Bukin 226*35f93203SCristian Marussi in->clock_id = index; 227*35f93203SCristian Marussi error = scmi_request(sc->scmi, in, (void **)&out); 228*35f93203SCristian Marussi if (error == 0) { 229*35f93203SCristian Marussi char *clock_name; 23054b96380SRuslan Bukin 231*35f93203SCristian Marussi clock_name = malloc(sizeof(out->name), M_DEVBUF, M_WAITOK); 232*35f93203SCristian Marussi strncpy(clock_name, out->name, sizeof(out->name)); 23354b96380SRuslan Bukin *result = clock_name; 234*35f93203SCristian Marussi } 23554b96380SRuslan Bukin 236*35f93203SCristian Marussi scmi_buf_put(sc->scmi, in); 237*35f93203SCristian Marussi 238*35f93203SCristian Marussi return (error); 23954b96380SRuslan Bukin } 24054b96380SRuslan Bukin 24154b96380SRuslan Bukin static int 24254b96380SRuslan Bukin scmi_clk_attrs(struct scmi_clk_softc *sc, int index) 24354b96380SRuslan Bukin { 244*35f93203SCristian Marussi struct scmi_clk_attrs_out *out; 245*35f93203SCristian Marussi struct scmi_clk_attrs_in *in; 24654b96380SRuslan Bukin char *clock_name; 247*35f93203SCristian Marussi int error; 24854b96380SRuslan Bukin 249*35f93203SCristian Marussi in = scmi_buf_get(sc->scmi, SCMI_PROTOCOL_ID_CLOCK, 250*35f93203SCristian Marussi SCMI_CLOCK_ATTRIBUTES, sizeof(*in), sizeof(*out)); 251*35f93203SCristian Marussi if (in == NULL) 25254b96380SRuslan Bukin return (ENXIO); 25354b96380SRuslan Bukin 254*35f93203SCristian Marussi in->clock_id = index; 255*35f93203SCristian Marussi error = scmi_request(sc->scmi, in, (void **)&out); 256*35f93203SCristian Marussi if (error == 0) { 257*35f93203SCristian Marussi if (out->attributes & CLK_ATTRS_EXT_CLK_NAME) { 25854b96380SRuslan Bukin error = scmi_clk_get_name(sc, index, &clock_name); 25954b96380SRuslan Bukin } else { 260*35f93203SCristian Marussi clock_name = malloc(sizeof(out->clock_name), 261*35f93203SCristian Marussi M_DEVBUF, M_WAITOK); 262*35f93203SCristian Marussi strncpy(clock_name, out->clock_name, 263*35f93203SCristian Marussi sizeof(out->clock_name)); 26454b96380SRuslan Bukin } 26554b96380SRuslan Bukin 266*35f93203SCristian Marussi if (error == 0) 26754b96380SRuslan Bukin error = scmi_clk_add_node(sc, index, clock_name); 268*35f93203SCristian Marussi } 269*35f93203SCristian Marussi 270*35f93203SCristian Marussi scmi_buf_put(sc->scmi, in); 27154b96380SRuslan Bukin 27254b96380SRuslan Bukin return (error); 27354b96380SRuslan Bukin } 27454b96380SRuslan Bukin 27554b96380SRuslan Bukin static int 27654b96380SRuslan Bukin scmi_clk_discover(struct scmi_clk_softc *sc) 27754b96380SRuslan Bukin { 278*35f93203SCristian Marussi struct scmi_clk_protocol_attrs_out *out; 279*35f93203SCristian Marussi void *in; 28054b96380SRuslan Bukin int nclocks; 28154b96380SRuslan Bukin int failing; 28254b96380SRuslan Bukin int error; 28354b96380SRuslan Bukin int i; 28454b96380SRuslan Bukin 285*35f93203SCristian Marussi in = scmi_buf_get(sc->scmi, SCMI_PROTOCOL_ID_CLOCK, 286*35f93203SCristian Marussi SCMI_PROTOCOL_ATTRIBUTES, 0, sizeof(*out)); 287*35f93203SCristian Marussi if (in == NULL) 28854b96380SRuslan Bukin return (ENXIO); 28954b96380SRuslan Bukin 290*35f93203SCristian Marussi error = scmi_request(sc->scmi, in, (void **)&out); 291*35f93203SCristian Marussi if (error == 0) { 292*35f93203SCristian Marussi nclocks = (out->attributes & CLK_ATTRS_NCLOCKS_M) >> 29354b96380SRuslan Bukin CLK_ATTRS_NCLOCKS_S; 29454b96380SRuslan Bukin 29554b96380SRuslan Bukin device_printf(sc->dev, "Found %d clocks.\n", nclocks); 29654b96380SRuslan Bukin 29754b96380SRuslan Bukin failing = 0; 29854b96380SRuslan Bukin 29954b96380SRuslan Bukin for (i = 0; i < nclocks; i++) { 30054b96380SRuslan Bukin error = scmi_clk_attrs(sc, i); 30154b96380SRuslan Bukin if (error) { 30254b96380SRuslan Bukin device_printf(sc->dev, 30354b96380SRuslan Bukin "Could not process clock index %d.\n", i); 30454b96380SRuslan Bukin failing++; 305*35f93203SCristian Marussi error = 0; 30654b96380SRuslan Bukin } 30754b96380SRuslan Bukin } 30854b96380SRuslan Bukin if (failing == nclocks) 309*35f93203SCristian Marussi error = ENXIO; 310*35f93203SCristian Marussi } else { 311*35f93203SCristian Marussi error = ENXIO; 312*35f93203SCristian Marussi } 31354b96380SRuslan Bukin 314*35f93203SCristian Marussi scmi_buf_put(sc->scmi, in); 315*35f93203SCristian Marussi 316*35f93203SCristian Marussi return (error); 31754b96380SRuslan Bukin } 31854b96380SRuslan Bukin 31954b96380SRuslan Bukin static int 32054b96380SRuslan Bukin scmi_clk_init(struct scmi_clk_softc *sc) 32154b96380SRuslan Bukin { 32254b96380SRuslan Bukin int error; 32354b96380SRuslan Bukin 32454b96380SRuslan Bukin /* Create clock domain */ 32554b96380SRuslan Bukin sc->clkdom = clkdom_create(sc->dev); 32654b96380SRuslan Bukin if (sc->clkdom == NULL) 32754b96380SRuslan Bukin return (ENXIO); 32854b96380SRuslan Bukin 32954b96380SRuslan Bukin error = scmi_clk_discover(sc); 33054b96380SRuslan Bukin if (error) { 33154b96380SRuslan Bukin device_printf(sc->dev, "Could not discover clocks.\n"); 33254b96380SRuslan Bukin return (ENXIO); 33354b96380SRuslan Bukin } 33454b96380SRuslan Bukin 33554b96380SRuslan Bukin error = clkdom_finit(sc->clkdom); 33654b96380SRuslan Bukin if (error) { 33754b96380SRuslan Bukin device_printf(sc->dev, "Failed to init clock domain.\n"); 33854b96380SRuslan Bukin return (ENXIO); 33954b96380SRuslan Bukin } 34054b96380SRuslan Bukin 34154b96380SRuslan Bukin return (0); 34254b96380SRuslan Bukin } 34354b96380SRuslan Bukin 34454b96380SRuslan Bukin static int 34554b96380SRuslan Bukin scmi_clk_probe(device_t dev) 34654b96380SRuslan Bukin { 34754b96380SRuslan Bukin phandle_t node; 34854b96380SRuslan Bukin uint32_t reg; 34954b96380SRuslan Bukin int error; 35054b96380SRuslan Bukin 35154b96380SRuslan Bukin node = ofw_bus_get_node(dev); 35254b96380SRuslan Bukin 35354b96380SRuslan Bukin error = OF_getencprop(node, "reg", ®, sizeof(uint32_t)); 35454b96380SRuslan Bukin if (error < 0) 35554b96380SRuslan Bukin return (ENXIO); 35654b96380SRuslan Bukin 35754b96380SRuslan Bukin if (reg != SCMI_PROTOCOL_ID_CLOCK) 35854b96380SRuslan Bukin return (ENXIO); 35954b96380SRuslan Bukin 36054b96380SRuslan Bukin device_set_desc(dev, "SCMI Clock Management Unit"); 36154b96380SRuslan Bukin 36254b96380SRuslan Bukin return (BUS_PROBE_DEFAULT); 36354b96380SRuslan Bukin } 36454b96380SRuslan Bukin 36554b96380SRuslan Bukin static int 36654b96380SRuslan Bukin scmi_clk_attach(device_t dev) 36754b96380SRuslan Bukin { 36854b96380SRuslan Bukin struct scmi_clk_softc *sc; 36954b96380SRuslan Bukin phandle_t node; 37054b96380SRuslan Bukin 37154b96380SRuslan Bukin sc = device_get_softc(dev); 37254b96380SRuslan Bukin sc->dev = dev; 37354b96380SRuslan Bukin sc->scmi = device_get_parent(dev); 37454b96380SRuslan Bukin 37554b96380SRuslan Bukin node = ofw_bus_get_node(sc->dev); 37654b96380SRuslan Bukin 37754b96380SRuslan Bukin OF_device_register_xref(OF_xref_from_node(node), sc->dev); 37854b96380SRuslan Bukin 37954b96380SRuslan Bukin scmi_clk_init(sc); 38054b96380SRuslan Bukin 38154b96380SRuslan Bukin return (0); 38254b96380SRuslan Bukin } 38354b96380SRuslan Bukin 38454b96380SRuslan Bukin static int 38554b96380SRuslan Bukin scmi_clk_detach(device_t dev) 38654b96380SRuslan Bukin { 38754b96380SRuslan Bukin 38854b96380SRuslan Bukin return (0); 38954b96380SRuslan Bukin } 39054b96380SRuslan Bukin 39154b96380SRuslan Bukin static device_method_t scmi_clk_methods[] = { 39254b96380SRuslan Bukin /* Device interface */ 39354b96380SRuslan Bukin DEVMETHOD(device_probe, scmi_clk_probe), 39454b96380SRuslan Bukin DEVMETHOD(device_attach, scmi_clk_attach), 39554b96380SRuslan Bukin DEVMETHOD(device_detach, scmi_clk_detach), 39654b96380SRuslan Bukin DEVMETHOD_END 39754b96380SRuslan Bukin }; 39854b96380SRuslan Bukin 39954b96380SRuslan Bukin static driver_t scmi_clk_driver = { 40054b96380SRuslan Bukin "scmi_clk", 40154b96380SRuslan Bukin scmi_clk_methods, 40254b96380SRuslan Bukin sizeof(struct scmi_clk_softc), 40354b96380SRuslan Bukin }; 40454b96380SRuslan Bukin 40554b96380SRuslan Bukin EARLY_DRIVER_MODULE(scmi_clk, scmi, scmi_clk_driver, 0, 0, 40654b96380SRuslan Bukin BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 40754b96380SRuslan Bukin MODULE_VERSION(scmi_clk, 1); 408