Page MenuHomeFreeBSD

D58103.diff
No OneTemporary

D58103.diff

diff --git a/sys/dev/clk/clk_fixed.h b/sys/dev/clk/clk_fixed.h
--- a/sys/dev/clk/clk_fixed.h
+++ b/sys/dev/clk/clk_fixed.h
@@ -1,33 +1,14 @@
-/*-
+/*
* Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * SPDX-License-Identifier: BSD-2-Clause
*/
#ifndef _DEV_CLK_FIXED_H_
#define _DEV_CLK_FIXED_H_
#include <dev/clk/clk.h>
+#include <dev/gpio/gpiobusvar.h>
/*
* A fixed clock can represent several different real-world objects, including
@@ -43,6 +24,8 @@
uint32_t mult;
uint32_t div;
int fixed_flags;
+ struct gpiobus_pin *gpio_pin;
+ bool have_gpio;
};
int clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef);
diff --git a/sys/dev/clk/clk_fixed.c b/sys/dev/clk/clk_fixed.c
--- a/sys/dev/clk/clk_fixed.c
+++ b/sys/dev/clk/clk_fixed.c
@@ -1,27 +1,7 @@
-/*-
+/*
* Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
- * All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * SPDX-License-Identifier: BSD-2-Clause
*/
#include <sys/cdefs.h>
@@ -29,6 +9,7 @@
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/bus.h>
+#include <sys/gpio.h>
#include <sys/kernel.h>
#include <sys/kobj.h>
#include <sys/malloc.h>
@@ -39,33 +20,49 @@
#include <machine/bus.h>
+#include <dev/gpio/gpiobusvar.h>
+
#ifdef FDT
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/regulator/regulator.h>
#endif
#include <dev/clk/clk_fixed.h>
#define CLK_TYPE_FIXED 1
#define CLK_TYPE_FIXED_FACTOR 2
+#define CLK_TYPE_GATED_FIXED 3
+
+#define CLK_FIXED_OK 0
+#define CLK_FIXED_NEW_PASS 1
+#define CLK_FIXED_FAIL 2
static int clknode_fixed_init(struct clknode *clk, device_t dev);
static int clknode_fixed_recalc(struct clknode *clk, uint64_t *freq);
static int clknode_fixed_set_freq(struct clknode *clk, uint64_t fin,
uint64_t *fout, int flags, int *stop);
+static int clknode_fixed_set_gate(struct clknode *clk, bool enable);
+static int clknode_fixed_get_gate(struct clknode *clk, bool *enable);
struct clknode_fixed_sc {
- int fixed_flags;
- uint64_t freq;
- uint32_t mult;
- uint32_t div;
+ int fixed_flags;
+ uint64_t freq;
+ uint32_t mult;
+ uint32_t div;
+ struct gpiobus_pin *gpio_pin;
+ bool have_gpio;
};
static clknode_method_t clknode_fixed_methods[] = {
/* Device interface */
CLKNODEMETHOD(clknode_init, clknode_fixed_init),
CLKNODEMETHOD(clknode_recalc_freq, clknode_fixed_recalc),
- CLKNODEMETHOD(clknode_set_freq, clknode_fixed_set_freq),
+ CLKNODEMETHOD(clknode_set_freq, clknode_fixed_set_freq),
+ CLKNODEMETHOD(clknode_get_gate, clknode_fixed_get_gate),
+ CLKNODEMETHOD(clknode_set_gate, clknode_fixed_set_gate),
+
CLKNODEMETHOD_END
};
DEFINE_CLASS_1(clknode_fixed, clknode_fixed_class, clknode_fixed_methods,
@@ -116,6 +113,52 @@
return (0);
}
+static int
+clknode_fixed_set_gate(struct clknode *clk, bool enable)
+{
+ struct clknode_fixed_sc *sc;
+ device_t dev;
+ int rv;
+
+ sc = clknode_get_softc(clk);
+ dev = clknode_get_device(clk);
+
+ if (!sc->have_gpio)
+ return (0);
+
+ rv = GPIO_PIN_SET(sc->gpio_pin->dev, sc->gpio_pin->pin, enable ? 1: 0);
+ if (rv != 0) {
+ device_printf(dev, "Cannot set GPIO pin: %d\n", rv);
+ return (rv);
+ }
+ return(0);
+}
+
+static int
+clknode_fixed_get_gate(struct clknode *clk, bool *enabled)
+{
+ struct clknode_fixed_sc *sc;
+ device_t dev;
+ uint32_t val;
+ int rv;
+
+ sc = clknode_get_softc(clk);
+ dev = clknode_get_device(clk);
+
+ if (!sc->have_gpio) {
+ *enabled = true;
+ return (0);
+ }
+
+ rv = GPIO_PIN_GET(sc->gpio_pin->dev, sc->gpio_pin->pin, &val);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get GPIO pin: %d\n", rv);
+ return (rv);
+ }
+ *enabled = val != 0;
+ return(0);
+}
+
int
clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef)
{
@@ -124,6 +167,7 @@
clk = clknode_create(clkdom, &clknode_fixed_class, &clkdef->clkdef);
if (clk == NULL)
+
return (1);
sc = clknode_get_softc(clk);
@@ -131,6 +175,8 @@
sc->freq = clkdef->freq;
sc->mult = clkdef->mult;
sc->div = clkdef->div;
+ sc->gpio_pin = clkdef->gpio_pin;
+ sc->have_gpio = clkdef->have_gpio;
clknode_register(clkdom, clk);
return (0);
@@ -141,14 +187,192 @@
static struct ofw_compat_data compat_data[] = {
{"fixed-clock", CLK_TYPE_FIXED},
{"fixed-factor-clock", CLK_TYPE_FIXED_FACTOR},
+ {"gated-fixed-clock", CLK_TYPE_GATED_FIXED},
{NULL, 0},
};
struct clk_fixed_softc {
- device_t dev;
- struct clkdom *clkdom;
+ device_t dev;
+ phandle_t node;
+ struct clkdom *clkdom;
+ bool attach_done;
+
+ struct clk_fixed_def def;
+
+ bool have_clk;
+ bool clk_done;
+
+ bool have_gpio;
+ bool gpio_done;
+
+ bool have_reg;
+ bool reg_done;
+ regulator_t reg_vdd;
};
+
+static int
+clk_fixed_init_fixed(struct clk_fixed_softc *sc)
+{
+ uint32_t freq, flags;
+ int rv;
+
+ sc->def.clkdef.id = 1;
+ rv = OF_getencprop(sc->node, "clock-frequency", &freq, sizeof(freq));
+ if (rv <= 0) {
+ device_printf(sc->dev, "Cannot get output frequency: %d\n", rv);
+ return (ENXIO);
+ }
+ sc->def.freq = freq;
+
+ if (!sc->have_gpio)
+ return (0);
+
+ rv = GPIO_PIN_GETFLAGS(sc->def.gpio_pin->dev, sc->def.gpio_pin->pin,
+ &flags);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get GPIO flags: %d\n", rv);
+ return (ENXIO);
+ }
+ if ((flags & GPIO_PIN_OUTPUT) == 0) {
+ flags |= GPIO_PIN_OUTPUT;
+ flags &= ~GPIO_PIN_INPUT;
+ rv = GPIO_PIN_SETFLAGS(sc->def.gpio_pin->dev,
+ sc->def.gpio_pin->pin, GPIO_PIN_OUTPUT);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot set GPIO flags: %d\n",
+ rv);
+ return (ENXIO);
+ }
+ }
+
+ return (0);
+}
+
+
+static int
+clk_fixed_init_fixed_factor(struct clk_fixed_softc *sc)
+{
+ int rv;
+
+ sc->have_clk = true;
+ sc->def.clkdef.id = 1;
+ sc->def.clkdef.parent_cnt = 1;
+
+ rv = OF_getencprop(sc->node, "clock-mult", &sc->def.mult,
+ sizeof(sc->def.mult));
+ if (rv <= 0)
+ return (ENXIO);
+ rv = OF_getencprop(sc->node, "clock-div", &sc->def.div,
+ sizeof(sc->def.div));
+ if (rv <= 0)
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+clk_fixed_get_clk(struct clk_fixed_softc *sc)
+{
+ int rv;
+ clk_t parent;
+
+ if (sc->clk_done)
+ return (CLK_FIXED_OK);
+
+ /* Get name of parent clock */
+ rv = clk_get_by_ofw_index(sc->dev, 0, 0, &parent);
+ if (rv == ENODEV) {
+ /* clk is not yet available */
+ return (CLK_FIXED_NEW_PASS);
+ }
+
+ if (rv != 0) {
+ /* No property exist */
+ device_printf(sc->dev, "Cannot get parent clock: %d\n", rv);
+ panic("no clock"); /* XXX or return (CLK_FIXED_FAIL); */
+ }
+
+ sc->def.clkdef.parent_names = malloc(sizeof(char *), M_OFWPROP,
+ M_WAITOK);
+ sc->def.clkdef.parent_names[0] = clk_get_name(parent);
+ clk_release(parent);
+ sc->clk_done = true;
+ return (CLK_FIXED_OK);
+}
+
+static int
+clk_fixed_get_gpio(struct clk_fixed_softc * sc)
+{
+ int rv;
+
+ if (sc->gpio_done)
+ return (CLK_FIXED_OK);
+
+ rv = gpio_pin_get_by_ofw_property(sc->dev, sc->node, "enable-gpios",
+ &sc->def.gpio_pin);
+ if (rv == ENOENT) {
+ /* No property exist */
+ sc->gpio_done = true;
+ return (CLK_FIXED_OK);
+ }
+
+ if (rv == ENODEV) {
+ /* GPIO ctrl is not yet available */
+ sc->have_gpio = true;
+ return (CLK_FIXED_NEW_PASS);
+ }
+
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get GPIO pin: %d\n", rv);
+ sc->gpio_done = true;
+ return (CLK_FIXED_FAIL);
+ }
+ sc->have_gpio = true;
+ sc->gpio_done = true;
+
+ return (CLK_FIXED_OK);
+}
+
+static int
+clk_fixed_get_regulator(struct clk_fixed_softc * sc)
+{
+ int rv;
+
+ if (sc->reg_done)
+ return (CLK_FIXED_OK);
+
+ rv = regulator_get_by_ofw_property(sc->dev, sc->node, "vdd-supply",
+ &sc->reg_vdd);
+ if (rv == ENOENT) {
+ /* No property exist */
+ sc->reg_done = true;
+ return (CLK_FIXED_OK);
+ }
+ if (rv == ENODEV) {
+ /* GPIO ctrl is not yet available */
+ sc->have_reg = true;
+ return (CLK_FIXED_NEW_PASS);
+ }
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get GPIO pin: %d\n", rv);
+ sc->reg_done = true;
+ return (CLK_FIXED_FAIL);
+ }
+
+ rv = regulator_enable(sc->reg_vdd);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'vdd' regulator: %d\n",
+ rv);
+ sc->reg_done = true;
+ return (CLK_FIXED_FAIL);
+ }
+ sc->have_reg = true;
+ sc->reg_done = true;
+
+ return (CLK_FIXED_OK);
+}
+
static int
clk_fixed_probe(device_t dev)
{
@@ -157,11 +381,12 @@
clk_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
switch (clk_type) {
case CLK_TYPE_FIXED:
+ case CLK_TYPE_GATED_FIXED:
if (!OF_hasprop(ofw_bus_get_node(dev), "clock-frequency")) {
- if (bootverbose) {
+ if (bootverbose)
device_printf(dev,
- "clock-fixed has no clock-frequency\n");
- }
+ "(gated-)clock-fixed has no "
+ "clock-frequency\n");
return (ENXIO);
}
device_set_desc(dev, "Fixed clock");
@@ -179,44 +404,60 @@
return (BUS_PROBE_DEFAULT);
}
-static int
-clk_fixed_init_fixed(struct clk_fixed_softc *sc, phandle_t node,
- struct clk_fixed_def *def)
+static void
+clk_fixed_new_pass(device_t dev)
{
- uint32_t freq;
+ struct clk_fixed_softc * sc;
int rv;
- def->clkdef.id = 1;
- rv = OF_getencprop(node, "clock-frequency", &freq, sizeof(freq));
- if (rv <= 0)
- return (ENXIO);
- def->freq = freq;
- return (0);
-}
+ sc = device_get_softc(dev);
+ if (sc->attach_done)
+ return;
+
+ /* Try to get and configure GPIO. */
+ rv = 0;
+ if (sc->have_clk && !sc->clk_done)
+ rv = clk_fixed_get_clk(sc);
+ if (rv == CLK_FIXED_FAIL)
+ goto fail;
-static int
-clk_fixed_init_fixed_factor(struct clk_fixed_softc *sc, phandle_t node,
- struct clk_fixed_def *def)
-{
- int rv;
- clk_t parent;
+ if (sc->have_gpio && !sc->gpio_done)
+ rv = clk_fixed_get_gpio(sc);
+ if (rv == CLK_FIXED_FAIL)
+ goto fail;
- def->clkdef.id = 1;
- rv = OF_getencprop(node, "clock-mult", &def->mult, sizeof(def->mult));
- if (rv <= 0)
- return (ENXIO);
- rv = OF_getencprop(node, "clock-div", &def->div, sizeof(def->div));
- if (rv <= 0)
- return (ENXIO);
- /* Get name of parent clock */
- rv = clk_get_by_ofw_index(sc->dev, 0, 0, &parent);
- if (rv != 0)
- return (ENXIO);
- def->clkdef.parent_names = malloc(sizeof(char *), M_OFWPROP, M_WAITOK);
- def->clkdef.parent_names[0] = clk_get_name(parent);
- def->clkdef.parent_cnt = 1;
- clk_release(parent);
- return (0);
+ if (sc->have_reg && !sc->reg_done)
+ rv = clk_fixed_get_regulator(sc);
+ if (rv == CLK_FIXED_FAIL)
+ goto fail;
+
+ if ((sc->have_gpio && !sc->gpio_done) ||
+ (sc->have_reg && !sc->reg_done)) {
+ bus_generic_new_pass(dev);
+ return;
+ }
+
+ sc->clkdom = clkdom_create(dev);
+ KASSERT(sc->clkdom != NULL, ("Clock domain is NULL"));
+
+ rv = clknode_fixed_register(sc->clkdom, &sc->def);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot register fixed clock.\n");
+ goto fail;
+ }
+
+ rv = clkdom_finit(sc->clkdom);
+ if (rv != 0) {
+ device_printf(sc->dev, "Clk domain finit fails.\n");
+ goto fail;
+ }
+
+ if (bootverbose)
+ clkdom_dump(sc->clkdom);
+
+fail:
+ sc->attach_done = true;
+ return;
}
static int
@@ -224,35 +465,49 @@
{
struct clk_fixed_softc *sc;
intptr_t clk_type;
- phandle_t node;
- struct clk_fixed_def def;
int rv;
sc = device_get_softc(dev);
sc->dev = dev;
- node = ofw_bus_get_node(dev);
+ sc->node = ofw_bus_get_node(dev);
+
clk_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
- bzero(&def, sizeof(def));
- if (clk_type == CLK_TYPE_FIXED)
- rv = clk_fixed_init_fixed(sc, node, &def);
+ if (clk_type == CLK_TYPE_FIXED || clk_type == CLK_TYPE_GATED_FIXED)
+ rv = clk_fixed_init_fixed(sc);
else if (clk_type == CLK_TYPE_FIXED_FACTOR)
- rv = clk_fixed_init_fixed_factor(sc, node, &def);
+ rv = clk_fixed_init_fixed_factor(sc);
else
rv = ENXIO;
if (rv != 0) {
- device_printf(sc->dev, "Cannot FDT parameters.\n");
+ device_printf(sc->dev, "Cannot read FDT parameters.\n");
goto fail;
}
- rv = clk_parse_ofw_clk_name(dev, node, &def.clkdef.name);
+
+ rv = clk_parse_ofw_clk_name(dev, sc->node, &sc->def.clkdef.name);
if (rv != 0) {
device_printf(sc->dev, "Cannot parse clock name.\n");
goto fail;
}
+
+ if (clk_type == CLK_TYPE_GATED_FIXED) {
+ /* Try to get and configure GPIO. */
+ rv = clk_fixed_get_gpio(sc);
+ if (rv == CLK_FIXED_FAIL)
+ goto fail;
+
+ /* Try to get and configure GPIO. */
+ rv = clk_fixed_get_regulator(sc);
+ if (rv == CLK_FIXED_FAIL)
+ goto fail;
+
+ if (!sc->gpio_done || !sc->reg_done)
+ return (0);
+ }
sc->clkdom = clkdom_create(dev);
KASSERT(sc->clkdom != NULL, ("Clock domain is NULL"));
- rv = clknode_fixed_register(sc->clkdom, &def);
+ rv = clknode_fixed_register(sc->clkdom, &sc->def);
if (rv != 0) {
device_printf(sc->dev, "Cannot register fixed clock.\n");
rv = ENXIO;
@@ -268,15 +523,12 @@
if (bootverbose)
clkdom_dump(sc->clkdom);
-
- OF_prop_free(__DECONST(char *, def.clkdef.name));
- OF_prop_free(def.clkdef.parent_names);
- bus_attach_children(dev);
+ sc->attach_done = true;
return (0);
fail:
- OF_prop_free(__DECONST(char *, def.clkdef.name));
- OF_prop_free(def.clkdef.parent_names);
+ OF_prop_free(__DECONST(char *, sc->def.clkdef.name));
+ OF_prop_free(sc->def.clkdef.parent_names);
return (rv);
}
@@ -285,6 +537,9 @@
DEVMETHOD(device_probe, clk_fixed_probe),
DEVMETHOD(device_attach, clk_fixed_attach),
+ /* Bus interface */
+ DEVMETHOD(bus_new_pass, clk_fixed_new_pass),
+
DEVMETHOD_END
};

File Metadata

Mime Type
text/plain
Expires
Mon, Jul 13, 12:34 AM (15 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34886138
Default Alt Text
D58103.diff (15 KB)

Event Timeline