Module Name: src Committed By: jmcneill Date: Sun Oct 22 13:56:49 UTC 2017
Modified Files: src/sys/dev/fdt: fdtvar.h files.fdt Added Files: src/sys/dev/fdt: fdt_mmc_pwrseq.c mmc_pwrseq_simple.c Log Message: Add support for simple MMC power sequence provider bindings. To generate a diff of this commit: cvs rdiff -u -r0 -r1.1 src/sys/dev/fdt/fdt_mmc_pwrseq.c \ src/sys/dev/fdt/mmc_pwrseq_simple.c cvs rdiff -u -r1.26 -r1.27 src/sys/dev/fdt/fdtvar.h cvs rdiff -u -r1.21 -r1.22 src/sys/dev/fdt/files.fdt Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/fdt/fdtvar.h diff -u src/sys/dev/fdt/fdtvar.h:1.26 src/sys/dev/fdt/fdtvar.h:1.27 --- src/sys/dev/fdt/fdtvar.h:1.26 Fri Aug 25 12:28:10 2017 +++ src/sys/dev/fdt/fdtvar.h Sun Oct 22 13:56:49 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: fdtvar.h,v 1.26 2017/08/25 12:28:10 jmcneill Exp $ */ +/* $NetBSD: fdtvar.h,v 1.27 2017/10/22 13:56:49 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -185,6 +185,15 @@ struct fdtbus_phy_controller_func { int (*enable)(device_t, void *, bool); }; +struct fdtbus_mmc_pwrseq; + +struct fdtbus_mmc_pwrseq_func { + void (*pre_power_on)(device_t); + void (*post_power_on)(device_t); + void (*power_off)(device_t); + void (*reset)(device_t); +}; + struct fdt_console { int (*match)(int); void (*consinit)(struct fdt_attach_args *, u_int); @@ -225,6 +234,8 @@ int fdtbus_register_power_controller(de const struct fdtbus_power_controller_func *); int fdtbus_register_phy_controller(device_t, int, const struct fdtbus_phy_controller_func *); +int fdtbus_register_mmc_pwrseq(device_t, int, + const struct fdtbus_mmc_pwrseq_func *); int fdtbus_get_reg(int, u_int, bus_addr_t *, bus_size_t *); int fdtbus_get_reg_byname(int, const char *, bus_addr_t *, @@ -278,6 +289,12 @@ struct fdtbus_phy *fdtbus_phy_get_index( void fdtbus_phy_put(struct fdtbus_phy *); int fdtbus_phy_enable(struct fdtbus_phy *, bool); +struct fdtbus_mmc_pwrseq *fdtbus_mmc_pwrseq_get(int); +void fdtbus_mmc_pwrseq_pre_power_on(struct fdtbus_mmc_pwrseq *); +void fdtbus_mmc_pwrseq_post_power_on(struct fdtbus_mmc_pwrseq *); +void fdtbus_mmc_pwrseq_power_off(struct fdtbus_mmc_pwrseq *); +void fdtbus_mmc_pwrseq_reset(struct fdtbus_mmc_pwrseq *); + int fdtbus_todr_attach(device_t, int, todr_chip_handle_t); void fdtbus_power_reset(void); Index: src/sys/dev/fdt/files.fdt diff -u src/sys/dev/fdt/files.fdt:1.21 src/sys/dev/fdt/files.fdt:1.22 --- src/sys/dev/fdt/files.fdt:1.21 Sat Sep 23 23:54:30 2017 +++ src/sys/dev/fdt/files.fdt Sun Oct 22 13:56:49 2017 @@ -1,4 +1,4 @@ -# $NetBSD: files.fdt,v 1.21 2017/09/23 23:54:30 jmcneill Exp $ +# $NetBSD: files.fdt,v 1.22 2017/10/22 13:56:49 jmcneill Exp $ include "external/bsd/libfdt/conf/files.libfdt" @@ -41,6 +41,7 @@ file dev/fdt/fdt_dma.c fdtbus file dev/fdt/fdt_gpio.c fdtbus file dev/fdt/fdt_i2c.c fdtbus file dev/fdt/fdt_intr.c fdtbus +file dev/fdt/fdt_mmc_pwrseq.c fdtbus file dev/fdt/fdt_phy.c fdtbus file dev/fdt/fdt_power.c fdtbus file dev/fdt/fdt_regulator.c fdtbus @@ -52,5 +53,9 @@ device cpus { } : fdtbus attach cpus at fdt file dev/fdt/cpus.c cpus +device mmcpwrseq +attach mmcpwrseq at fdt +file dev/fdt/mmc_pwrseq_simple.c mmcpwrseq + define fdt_display_timing file dev/fdt/display_timing.c fdt_display_timing Added files: Index: src/sys/dev/fdt/fdt_mmc_pwrseq.c diff -u /dev/null src/sys/dev/fdt/fdt_mmc_pwrseq.c:1.1 --- /dev/null Sun Oct 22 13:56:49 2017 +++ src/sys/dev/fdt/fdt_mmc_pwrseq.c Sun Oct 22 13:56:49 2017 @@ -0,0 +1,120 @@ +/* $NetBSD: fdt_mmc_pwrseq.c,v 1.1 2017/10/22 13:56:49 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> + * 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 ``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 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. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: fdt_mmc_pwrseq.c,v 1.1 2017/10/22 13:56:49 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kmem.h> + +#include <libfdt.h> +#include <dev/fdt/fdtvar.h> + +struct fdtbus_mmc_pwrseq { + device_t mps_dev; + int mps_phandle; + const struct fdtbus_mmc_pwrseq_func *mps_funcs; + + struct fdtbus_mmc_pwrseq *mps_next; +}; + +static struct fdtbus_mmc_pwrseq *fdtbus_mps = NULL; + +int +fdtbus_register_mmc_pwrseq(device_t dev, int phandle, + const struct fdtbus_mmc_pwrseq_func *funcs) +{ + struct fdtbus_mmc_pwrseq *mps; + + mps = kmem_alloc(sizeof(*mps), KM_SLEEP); + mps->mps_dev = dev; + mps->mps_phandle = phandle; + mps->mps_funcs = funcs; + + mps->mps_next = fdtbus_mps; + fdtbus_mps = mps; + + return 0; +} + +static struct fdtbus_mmc_pwrseq * +fdtbus_get_mmc_pwrseq(int phandle) +{ + struct fdtbus_mmc_pwrseq *mps; + + for (mps = fdtbus_mps; mps; mps = mps->mps_next) { + if (mps->mps_phandle == phandle) { + return mps; + } + } + + return NULL; +} + +struct fdtbus_mmc_pwrseq * +fdtbus_mmc_pwrseq_get(int phandle) +{ + const u_int *p; + int mps_phandle; + + p = fdtbus_get_prop(phandle, "mmc-pwrseq", NULL); + if (p == NULL) + return NULL; + + mps_phandle = fdtbus_get_phandle_from_native(be32toh(p[0])); + return fdtbus_get_mmc_pwrseq(mps_phandle); +} + +void +fdtbus_mmc_pwrseq_pre_power_on(struct fdtbus_mmc_pwrseq *mps) +{ + if (mps->mps_funcs->pre_power_on) + mps->mps_funcs->pre_power_on(mps->mps_dev); +} + +void +fdtbus_mmc_pwrseq_post_power_on(struct fdtbus_mmc_pwrseq *mps) +{ + if (mps->mps_funcs->post_power_on) + mps->mps_funcs->post_power_on(mps->mps_dev); +} + +void +fdtbus_mmc_pwrseq_power_off(struct fdtbus_mmc_pwrseq *mps) +{ + if (mps->mps_funcs->power_off) + mps->mps_funcs->power_off(mps->mps_dev); +} + +void +fdtbus_mmc_pwrseq_reset(struct fdtbus_mmc_pwrseq *mps) +{ + if (mps->mps_funcs->reset) + mps->mps_funcs->reset(mps->mps_dev); +} Index: src/sys/dev/fdt/mmc_pwrseq_simple.c diff -u /dev/null src/sys/dev/fdt/mmc_pwrseq_simple.c:1.1 --- /dev/null Sun Oct 22 13:56:49 2017 +++ src/sys/dev/fdt/mmc_pwrseq_simple.c Sun Oct 22 13:56:49 2017 @@ -0,0 +1,165 @@ +/* $NetBSD: mmc_pwrseq_simple.c,v 1.1 2017/10/22 13:56:49 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> + * 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 ``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 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. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: mmc_pwrseq_simple.c,v 1.1 2017/10/22 13:56:49 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/gpio.h> + +#include <dev/fdt/fdtvar.h> + +#define MMCPWRSEQ_MAX_PINS 32 + +static const char * const compatible[] = { + "mmc-pwrseq-simple", + NULL +}; + +struct mmcpwrseq_softc { + device_t sc_dev; + int sc_phandle; + struct clk *sc_clk; + struct fdtbus_gpio_pin *sc_pins[MMCPWRSEQ_MAX_PINS]; + u_int sc_npins; + u_int sc_post_power_on_delay_ms; + u_int sc_power_off_delay_us; +}; + +static void +mmcpwrseq_pre_power_on(device_t dev) +{ + struct mmcpwrseq_softc * const sc = device_private(dev); + int error; + + if (sc->sc_clk) { + error = clk_enable(sc->sc_clk); + if (error != 0) { + aprint_error_dev(dev, "failed to enable clock: %d\n", + error); + } + } + + for (u_int n = 0; n < sc->sc_npins; n++) + fdtbus_gpio_write(sc->sc_pins[n], 1); +} + +static void +mmcpwrseq_post_power_on(device_t dev) +{ + struct mmcpwrseq_softc * const sc = device_private(dev); + + for (u_int n = 0; n < sc->sc_npins; n++) + fdtbus_gpio_write(sc->sc_pins[n], 0); + + if (sc->sc_post_power_on_delay_ms > 0) + kpause("mmcpwrseq", false, + mstohz(sc->sc_post_power_on_delay_ms), NULL); +} + +static void +mmcpwrseq_power_off(device_t dev) +{ + struct mmcpwrseq_softc * const sc = device_private(dev); + + for (u_int n = 0; n < sc->sc_npins; n++) + fdtbus_gpio_write(sc->sc_pins[n], 1); + + if (sc->sc_power_off_delay_us > 0) + delay(sc->sc_power_off_delay_us); +} + +static const struct fdtbus_mmc_pwrseq_func mmcpwrseq_funcs = { + .pre_power_on = mmcpwrseq_pre_power_on, + .post_power_on = mmcpwrseq_post_power_on, + .power_off = mmcpwrseq_power_off, +}; + +static int +mmcpwrseq_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +mmcpwrseq_attach(device_t parent, device_t self, void *aux) +{ + struct mmcpwrseq_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + + sc->sc_dev = self; + sc->sc_phandle = phandle; + + /* Optional external clock provider */ + if (of_hasprop(phandle, "clocks")) { + sc->sc_clk = fdtbus_clock_get(phandle, "ext_clock"); + if (sc->sc_clk == NULL) { + aprint_error(": couldn't acquire ext_clock\n"); + return; + } + } + + /* Optional reset GPIOs */ + if (of_hasprop(phandle, "reset-gpios")) { + for (sc->sc_npins = 0; + sc->sc_npins < MMCPWRSEQ_MAX_PINS; + sc->sc_npins++) { + sc->sc_pins[sc->sc_npins] = + fdtbus_gpio_acquire_index(phandle, + "reset-gpios", sc->sc_npins, GPIO_PIN_OUTPUT); + if (sc->sc_pins[sc->sc_npins] == NULL) + break; + } + if (sc->sc_npins == 0) { + aprint_error(": couldn't get reset GPIOs\n"); + return; + } + } + + /* Delay in ms after powering the card and de-asserting reset GPIOs */ + of_getprop_uint32(phandle, "post-power-on-delay-ms", + &sc->sc_post_power_on_delay_ms); + /* Delay in us after asserting the reset GPIOs during power off */ + of_getprop_uint32(phandle, "power-off-delay-us", + &sc->sc_power_off_delay_us); + + aprint_naive("\n"); + aprint_normal("\n"); + + fdtbus_register_mmc_pwrseq(self, phandle, &mmcpwrseq_funcs); +} + +CFATTACH_DECL_NEW(mmcpwrseq, sizeof(struct mmcpwrseq_softc), + mmcpwrseq_match, mmcpwrseq_attach, NULL, NULL);