1297627Sjmcneill/*- 2297627Sjmcneill * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> 3297627Sjmcneill * All rights reserved. 4297627Sjmcneill * 5297627Sjmcneill * Redistribution and use in source and binary forms, with or without 6297627Sjmcneill * modification, are permitted provided that the following conditions 7297627Sjmcneill * are met: 8297627Sjmcneill * 1. Redistributions of source code must retain the above copyright 9297627Sjmcneill * notice, this list of conditions and the following disclaimer. 10297627Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 11297627Sjmcneill * notice, this list of conditions and the following disclaimer in the 12297627Sjmcneill * documentation and/or other materials provided with the distribution. 13297627Sjmcneill * 14297627Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15297627Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16297627Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17297627Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18297627Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19297627Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20297627Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21297627Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22297627Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23297627Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24297627Sjmcneill * SUCH DAMAGE. 25297627Sjmcneill * 26297627Sjmcneill * $FreeBSD: releng/11.0/sys/arm/allwinner/clk/aw_codecclk.c 297627 2016-04-06 23:11:03Z jmcneill $ 27297627Sjmcneill */ 28297627Sjmcneill 29297627Sjmcneill/* 30297627Sjmcneill * Allwinner CODEC clock 31297627Sjmcneill */ 32297627Sjmcneill 33297627Sjmcneill#include <sys/cdefs.h> 34297627Sjmcneill__FBSDID("$FreeBSD: releng/11.0/sys/arm/allwinner/clk/aw_codecclk.c 297627 2016-04-06 23:11:03Z jmcneill $"); 35297627Sjmcneill 36297627Sjmcneill#include <sys/param.h> 37297627Sjmcneill#include <sys/systm.h> 38297627Sjmcneill#include <sys/bus.h> 39297627Sjmcneill#include <sys/rman.h> 40297627Sjmcneill#include <sys/kernel.h> 41297627Sjmcneill#include <sys/module.h> 42297627Sjmcneill#include <machine/bus.h> 43297627Sjmcneill 44297627Sjmcneill#include <dev/ofw/ofw_bus.h> 45297627Sjmcneill#include <dev/ofw/ofw_bus_subr.h> 46297627Sjmcneill#include <dev/ofw/ofw_subr.h> 47297627Sjmcneill 48297627Sjmcneill#include <dev/extres/clk/clk_gate.h> 49297627Sjmcneill#include <dev/extres/hwreset/hwreset.h> 50297627Sjmcneill 51297627Sjmcneill#include "clkdev_if.h" 52297627Sjmcneill 53297627Sjmcneill#define SCLK_GATING_SHIFT 31 54297627Sjmcneill 55297627Sjmcneillstatic struct ofw_compat_data compat_data[] = { 56297627Sjmcneill { "allwinner,sun4i-a10-codec-clk", 1 }, 57297627Sjmcneill { NULL, 0 } 58297627Sjmcneill}; 59297627Sjmcneill 60297627Sjmcneillstatic int 61297627Sjmcneillaw_codecclk_create(device_t dev, bus_addr_t paddr, struct clkdom *clkdom, 62297627Sjmcneill const char *pclkname, const char *clkname, int index) 63297627Sjmcneill{ 64297627Sjmcneill const char *parent_names[1] = { pclkname }; 65297627Sjmcneill struct clk_gate_def def; 66297627Sjmcneill 67297627Sjmcneill memset(&def, 0, sizeof(def)); 68297627Sjmcneill def.clkdef.id = index; 69297627Sjmcneill def.clkdef.name = clkname; 70297627Sjmcneill def.clkdef.parent_names = parent_names; 71297627Sjmcneill def.clkdef.parent_cnt = 1; 72297627Sjmcneill def.offset = paddr; 73297627Sjmcneill def.shift = SCLK_GATING_SHIFT; 74297627Sjmcneill def.mask = 1; 75297627Sjmcneill def.on_value = 1; 76297627Sjmcneill def.off_value = 0; 77297627Sjmcneill 78297627Sjmcneill return (clknode_gate_register(clkdom, &def)); 79297627Sjmcneill} 80297627Sjmcneill 81297627Sjmcneillstatic int 82297627Sjmcneillaw_codecclk_probe(device_t dev) 83297627Sjmcneill{ 84297627Sjmcneill if (!ofw_bus_status_okay(dev)) 85297627Sjmcneill return (ENXIO); 86297627Sjmcneill 87297627Sjmcneill if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 88297627Sjmcneill return (ENXIO); 89297627Sjmcneill 90297627Sjmcneill device_set_desc(dev, "Allwinner CODEC Clock"); 91297627Sjmcneill return (BUS_PROBE_DEFAULT); 92297627Sjmcneill} 93297627Sjmcneill 94297627Sjmcneillstatic int 95297627Sjmcneillaw_codecclk_attach(device_t dev) 96297627Sjmcneill{ 97297627Sjmcneill struct clkdom *clkdom; 98297627Sjmcneill const char **names; 99297627Sjmcneill int nout, error; 100297627Sjmcneill uint32_t *indices; 101297627Sjmcneill clk_t clk_parent; 102297627Sjmcneill bus_addr_t paddr; 103297627Sjmcneill bus_size_t psize; 104297627Sjmcneill phandle_t node; 105297627Sjmcneill 106297627Sjmcneill node = ofw_bus_get_node(dev); 107297627Sjmcneill indices = NULL; 108297627Sjmcneill 109297627Sjmcneill if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) { 110297627Sjmcneill device_printf(dev, "cannot parse 'reg' property\n"); 111297627Sjmcneill return (ENXIO); 112297627Sjmcneill } 113297627Sjmcneill 114297627Sjmcneill clkdom = clkdom_create(dev); 115297627Sjmcneill 116297627Sjmcneill nout = clk_parse_ofw_out_names(dev, node, &names, &indices); 117297627Sjmcneill if (nout != 1) { 118297627Sjmcneill device_printf(dev, "must have exactly one output clock\n"); 119297627Sjmcneill error = ENOENT; 120297627Sjmcneill goto fail; 121297627Sjmcneill } 122297627Sjmcneill 123297627Sjmcneill error = clk_get_by_ofw_index(dev, 0, &clk_parent); 124297627Sjmcneill if (error != 0) { 125297627Sjmcneill device_printf(dev, "cannot parse clock parent\n"); 126297627Sjmcneill return (ENXIO); 127297627Sjmcneill } 128297627Sjmcneill 129297627Sjmcneill error = aw_codecclk_create(dev, paddr, clkdom, 130297627Sjmcneill clk_get_name(clk_parent), names[0], 1); 131297627Sjmcneill 132297627Sjmcneill if (clkdom_finit(clkdom) != 0) { 133297627Sjmcneill device_printf(dev, "cannot finalize clkdom initialization\n"); 134297627Sjmcneill error = ENXIO; 135297627Sjmcneill goto fail; 136297627Sjmcneill } 137297627Sjmcneill 138297627Sjmcneill if (bootverbose) 139297627Sjmcneill clkdom_dump(clkdom); 140297627Sjmcneill 141297627Sjmcneill return (0); 142297627Sjmcneill 143297627Sjmcneillfail: 144297627Sjmcneill return (error); 145297627Sjmcneill} 146297627Sjmcneill 147297627Sjmcneillstatic device_method_t aw_codecclk_methods[] = { 148297627Sjmcneill /* Device interface */ 149297627Sjmcneill DEVMETHOD(device_probe, aw_codecclk_probe), 150297627Sjmcneill DEVMETHOD(device_attach, aw_codecclk_attach), 151297627Sjmcneill 152297627Sjmcneill DEVMETHOD_END 153297627Sjmcneill}; 154297627Sjmcneill 155297627Sjmcneillstatic driver_t aw_codecclk_driver = { 156297627Sjmcneill "aw_codecclk", 157297627Sjmcneill aw_codecclk_methods, 158297627Sjmcneill 0 159297627Sjmcneill}; 160297627Sjmcneill 161297627Sjmcneillstatic devclass_t aw_codecclk_devclass; 162297627Sjmcneill 163297627SjmcneillEARLY_DRIVER_MODULE(aw_codecclk, simplebus, aw_codecclk_driver, 164297627Sjmcneill aw_codecclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 165