1297667Ssgalabov/*- 2297667Ssgalabov * Copyright (c) 2016 Stanislav Galabov 3297667Ssgalabov * All rights reserved. 4297667Ssgalabov * 5297667Ssgalabov * Redistribution and use in source and binary forms, with or without 6297667Ssgalabov * modification, are permitted provided that the following conditions 7297667Ssgalabov * are met: 8297667Ssgalabov * 1. Redistributions of source code must retain the above copyright 9297667Ssgalabov * notice, this list of conditions, and the following disclaimer, 10297667Ssgalabov * without modification, immediately at the beginning of the file. 11297667Ssgalabov * 2. The name of the author may not be used to endorse or promote products 12297667Ssgalabov * derived from this software without specific prior written permission. 13297667Ssgalabov * 14297667Ssgalabov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15297667Ssgalabov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16297667Ssgalabov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17297667Ssgalabov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 18297667Ssgalabov * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19297667Ssgalabov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20297667Ssgalabov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21297667Ssgalabov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22297667Ssgalabov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23297667Ssgalabov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24297667Ssgalabov * SUCH DAMAGE. 25297667Ssgalabov * 26297667Ssgalabov */ 27297667Ssgalabov 28297667Ssgalabov#include <sys/cdefs.h> 29297667Ssgalabov__FBSDID("$FreeBSD$"); 30297667Ssgalabov 31297667Ssgalabov#include <sys/param.h> 32297667Ssgalabov#include <sys/kernel.h> 33297667Ssgalabov#include <sys/bus.h> 34297667Ssgalabov#include <sys/module.h> 35297667Ssgalabov 36297667Ssgalabov#include <dev/fdt/fdt_common.h> 37297667Ssgalabov#include <dev/ofw/openfirm.h> 38297667Ssgalabov#include <dev/ofw/ofw_bus.h> 39297667Ssgalabov#include <dev/ofw/ofw_bus_subr.h> 40297667Ssgalabov#include <dev/fdt/fdt_clock.h> 41297667Ssgalabov 42297667Ssgalabov#include <mips/mediatek/mtk_sysctl.h> 43297667Ssgalabov 44297667Ssgalabov#include "fdt_clock_if.h" 45297667Ssgalabov 46297667Ssgalabovstatic const struct ofw_compat_data compat_data[] = { 47297667Ssgalabov { "ralink,rt2880-clock", 1 }, 48297667Ssgalabov 49297667Ssgalabov /* Sentinel */ 50297667Ssgalabov { NULL, 0 } 51297667Ssgalabov}; 52297667Ssgalabov 53297667Ssgalabovstatic int 54297667Ssgalabovmtk_clock_probe(device_t dev) 55297667Ssgalabov{ 56297667Ssgalabov 57297667Ssgalabov if (!ofw_bus_status_okay(dev)) 58297667Ssgalabov return (ENXIO); 59297667Ssgalabov 60297667Ssgalabov if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 61297667Ssgalabov return (ENXIO); 62297667Ssgalabov 63297667Ssgalabov device_set_desc(dev, "MTK Clock Controller"); 64297667Ssgalabov 65297667Ssgalabov return (0); 66297667Ssgalabov} 67297667Ssgalabov 68297667Ssgalabovstatic int 69297667Ssgalabovmtk_clock_attach(device_t dev) 70297667Ssgalabov{ 71297667Ssgalabov 72297667Ssgalabov if (device_get_unit(dev) != 0) { 73297667Ssgalabov device_printf(dev, "Only one clock control allowed\n"); 74297667Ssgalabov return (ENXIO); 75297667Ssgalabov } 76297667Ssgalabov 77297667Ssgalabov fdt_clock_register_provider(dev); 78297667Ssgalabov 79297667Ssgalabov return (0); 80297667Ssgalabov} 81297667Ssgalabov 82297667Ssgalabov#define CLOCK_ENABLE 1 83297667Ssgalabov#define CLOCK_DISABLE 0 84297667Ssgalabov 85297667Ssgalabovstatic int 86297667Ssgalabovmtk_clock_set(device_t dev, int index, int value) 87297667Ssgalabov{ 88297667Ssgalabov uint32_t mask; 89297667Ssgalabov 90297667Ssgalabov /* Clock config register holds 32 clock gating bits */ 91297667Ssgalabov if (index < 0 || index > 31) 92297667Ssgalabov return (EINVAL); 93297667Ssgalabov 94297667Ssgalabov mask = (1u << index); 95297667Ssgalabov 96297667Ssgalabov if (value == CLOCK_ENABLE) 97297667Ssgalabov mtk_sysctl_clr_set(SYSCTL_CLKCFG1, 0, mask); 98297667Ssgalabov else 99297667Ssgalabov mtk_sysctl_clr_set(SYSCTL_CLKCFG1, mask, 0); 100297667Ssgalabov 101297667Ssgalabov return (0); 102297667Ssgalabov} 103297667Ssgalabov 104297667Ssgalabovstatic int 105297667Ssgalabovmtk_clock_enable(device_t dev, int index) 106297667Ssgalabov{ 107297667Ssgalabov 108297667Ssgalabov return mtk_clock_set(dev, index, CLOCK_ENABLE); 109297667Ssgalabov} 110297667Ssgalabov 111297667Ssgalabovstatic int 112297667Ssgalabovmtk_clock_disable(device_t dev, int index) 113297667Ssgalabov{ 114297667Ssgalabov 115297667Ssgalabov return mtk_clock_set(dev, index, CLOCK_DISABLE); 116297667Ssgalabov} 117297667Ssgalabov 118297667Ssgalabovstatic int 119297667Ssgalabovmtk_clock_get_info(device_t dev, int index, struct fdt_clock_info *info) 120297667Ssgalabov{ 121297667Ssgalabov uint32_t mask; 122297667Ssgalabov 123297667Ssgalabov if (index < 0 || index > 31 || info == NULL) 124297667Ssgalabov return (EINVAL); 125297667Ssgalabov 126297667Ssgalabov if (mtk_sysctl_get(SYSCTL_CLKCFG1) & mask) 127297667Ssgalabov info->flags = FDT_CIFLAG_RUNNING; 128297667Ssgalabov else 129297667Ssgalabov info->flags = 0; 130297667Ssgalabov 131297667Ssgalabov return (0); 132297667Ssgalabov} 133297667Ssgalabov 134297667Ssgalabovstatic device_method_t mtk_clock_methods[] = { 135297667Ssgalabov DEVMETHOD(device_probe, mtk_clock_probe), 136297667Ssgalabov DEVMETHOD(device_attach, mtk_clock_attach), 137297667Ssgalabov 138297667Ssgalabov /* fdt_clock interface */ 139297667Ssgalabov DEVMETHOD(fdt_clock_enable, mtk_clock_enable), 140297667Ssgalabov DEVMETHOD(fdt_clock_disable, mtk_clock_disable), 141297667Ssgalabov DEVMETHOD(fdt_clock_get_info, mtk_clock_get_info), 142297667Ssgalabov 143297667Ssgalabov DEVMETHOD_END 144297667Ssgalabov}; 145297667Ssgalabov 146297667Ssgalabovstatic driver_t mtk_clock_driver = { 147297667Ssgalabov "clkctrl", 148297667Ssgalabov mtk_clock_methods, 149297667Ssgalabov 0, 150297667Ssgalabov}; 151297667Ssgalabovstatic devclass_t mtk_clock_devclass; 152297667Ssgalabov 153297667SsgalabovEARLY_DRIVER_MODULE(mtk_clock, simplebus, mtk_clock_driver, mtk_clock_devclass, 154297667Ssgalabov 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_EARLY); 155297667Ssgalabov 156297667SsgalabovMODULE_DEPEND(mtk_clock, mtk_sysctl, 1, 1, 1); 157