git: 693af80b7435 - stable/13 - sdhci_xenon: split driver file into generic file and fdt parts

From: Marcin Wojtas <mw_at_FreeBSD.org>
Date: Tue, 29 Mar 2022 22:59:56 UTC
The branch stable/13 has been updated by mw:

URL: https://cgit.FreeBSD.org/src/commit/?id=693af80b74359d38417ae5da7a1f02c83ec8332a

commit 693af80b74359d38417ae5da7a1f02c83ec8332a
Author:     Bartlomiej Grzesik <bag@semihalf.com>
AuthorDate: 2021-07-15 12:29:15 +0000
Commit:     Marcin Wojtas <mw@FreeBSD.org>
CommitDate: 2022-03-29 22:24:27 +0000

    sdhci_xenon: split driver file into generic file and fdt parts
    
    This patch splits driver code into two seperate files sdhci_xenon.c
    and sdhci_xenon_fdt.c. This will allow future implementation of ACPI
    discovery of sdhci on Xenon chips.
    
    Reviewed by: mw
    Sponsored by: Semihalf
    Differential revision: https://reviews.freebsd.org/D31599
    
    (cherry picked from commit d78e464d23304084be17cb8db8981558f2829d6c)
---
 sys/conf/files.arm64            |   3 +-
 sys/dev/sdhci/sdhci_xenon.c     | 206 ++++++++++++----------------------------
 sys/dev/sdhci/sdhci_xenon.h     |  29 ++++++
 sys/dev/sdhci/sdhci_xenon_fdt.c | 173 +++++++++++++++++++++++++++++++++
 4 files changed, 264 insertions(+), 147 deletions(-)

diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index b694ed091d88..f1a2efe16448 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -263,7 +263,8 @@ dev/psci/smccc.c				standard
 
 dev/safexcel/safexcel.c				optional safexcel fdt
 
-dev/sdhci/sdhci_xenon.c				optional sdhci_xenon sdhci fdt
+dev/sdhci/sdhci_xenon.c				optional sdhci_xenon sdhci
+dev/sdhci/sdhci_xenon_fdt.c			optional sdhci_xenon sdhci fdt
 
 dev/uart/uart_cpu_arm64.c			optional uart
 dev/uart/uart_dev_mu.c				optional uart uart_mu
diff --git a/sys/dev/sdhci/sdhci_xenon.c b/sys/dev/sdhci/sdhci_xenon.c
index d88514d8fd8f..6dc0974c4e4e 100644
--- a/sys/dev/sdhci/sdhci_xenon.c
+++ b/sys/dev/sdhci/sdhci_xenon.c
@@ -48,17 +48,12 @@ __FBSDID("$FreeBSD$");
 #include <machine/resource.h>
 
 #include <dev/extres/regulator/regulator.h>
-#include <dev/fdt/fdt_common.h>
-#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_bus_subr.h>
 
 #include <dev/mmc/bridge.h>
-#include <dev/mmc/mmc_fdt_helpers.h>
 #include <dev/mmc/mmcbrvar.h>
 #include <dev/mmc/mmcreg.h>
 
 #include <dev/sdhci/sdhci.h>
-#include <dev/sdhci/sdhci_fdt_gpio.h>
 #include <dev/sdhci/sdhci_xenon.h>
 
 #include "mmcbr_if.h"
@@ -69,34 +64,6 @@ __FBSDID("$FreeBSD$");
 
 #define	MAX_SLOTS		6
 
-static struct ofw_compat_data compat_data[] = {
-	{ "marvell,armada-3700-sdhci",	1 },
-#ifdef SOC_MARVELL_8K
-	{ "marvell,armada-cp110-sdhci",	1 },
-	{ "marvell,armada-ap806-sdhci",	1 },
-	{ "marvell,armada-ap807-sdhci",	1 },
-#endif
-	{ NULL, 0 }
-};
-
-struct sdhci_xenon_softc {
-	device_t	dev;		/* Controller device */
-	int		slot_id;	/* Controller ID */
-	phandle_t	node;		/* FDT node */
-	struct resource *irq_res;	/* IRQ resource */
-	void		*intrhand;	/* Interrupt handle */
-	struct sdhci_fdt_gpio *gpio;	/* GPIO pins for CD detection. */
-
-	struct sdhci_slot *slot;	/* SDHCI internal data */
-	struct resource	*mem_res;	/* Memory resource */
-
-	uint8_t		znr;		/* PHY ZNR */
-	uint8_t		zpr;		/* PHY ZPR */
-	bool		slow_mode;	/* PHY slow mode */
-
-	struct mmc_helper	mmc_helper; /* MMC helper for parsing FDT */
-};
-
 static uint8_t
 sdhci_xenon_read_1(device_t dev, struct sdhci_slot *slot __unused,
     bus_size_t off)
@@ -182,16 +149,7 @@ sdhci_xenon_get_ro(device_t bus, device_t dev)
 {
 	struct sdhci_xenon_softc *sc = device_get_softc(bus);
 
-	return (sdhci_generic_get_ro(bus, dev) ^
-	    (sc->mmc_helper.props & MMC_PROP_WP_INVERTED));
-}
-
-static bool
-sdhci_xenon_get_card_present(device_t dev, struct sdhci_slot *slot)
-{
-	struct sdhci_xenon_softc *sc = device_get_softc(dev);
-
-	return (sdhci_fdt_gpio_get_present(sc->gpio));
+	return (sdhci_generic_get_ro(bus, dev) ^ sc->wp_inverted);
 }
 
 static void
@@ -387,19 +345,19 @@ sdhci_xenon_update_ios(device_t brdev, device_t reqdev)
 		if (bootverbose)
 			device_printf(sc->dev, "Powering down sd/mmc\n");
 
-		if (sc->mmc_helper.vmmc_supply)
-			regulator_disable(sc->mmc_helper.vmmc_supply);
-		if (sc->mmc_helper.vqmmc_supply)
-			regulator_disable(sc->mmc_helper.vqmmc_supply);
+		if (sc->vmmc_supply)
+			regulator_disable(sc->vmmc_supply);
+		if (sc->vqmmc_supply)
+			regulator_disable(sc->vqmmc_supply);
 		break;
 	case power_up:
 		if (bootverbose)
 			device_printf(sc->dev, "Powering up sd/mmc\n");
 
-		if (sc->mmc_helper.vmmc_supply)
-			regulator_enable(sc->mmc_helper.vmmc_supply);
-		if (sc->mmc_helper.vqmmc_supply)
-			regulator_enable(sc->mmc_helper.vqmmc_supply);
+		if (sc->vmmc_supply)
+			regulator_enable(sc->vmmc_supply);
+		if (sc->vqmmc_supply)
+			regulator_enable(sc->vqmmc_supply);
 		break;
 	};
 
@@ -432,8 +390,8 @@ sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev)
 
 	sc = device_get_softc(brdev);
 
-	if (sc->mmc_helper.vqmmc_supply == NULL)
-		return EOPNOTSUPP;
+	if (sc->vqmmc_supply == NULL && !sc->skip_regulators)
+		return (EOPNOTSUPP);
 
 	err = 0;
 
@@ -445,15 +403,17 @@ sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev)
 		hostctrl2 &= ~SDHCI_CTRL2_S18_ENABLE;
 		bus_write_2(sc->mem_res, SDHCI_HOST_CONTROL2, hostctrl2);
 
-		uvolt = 3300000;
-		err = regulator_set_voltage(sc->mmc_helper.vqmmc_supply,
-		    uvolt, uvolt);
-		if (err != 0) {
-			device_printf(sc->dev,
-			    "Cannot set vqmmc to %d<->%d\n",
-			    uvolt,
-			    uvolt);
-			return (err);
+		if (!sc->skip_regulators) {
+			uvolt = 3300000;
+			err = regulator_set_voltage(sc->vqmmc_supply,
+			    uvolt, uvolt);
+			if (err != 0) {
+				device_printf(sc->dev,
+				    "Cannot set vqmmc to %d<->%d\n",
+				    uvolt,
+				    uvolt);
+				return (err);
+			}
 		}
 
 		/*
@@ -466,25 +426,27 @@ sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev)
 		hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2);
 		if (!(hostctrl2 & SDHCI_CTRL2_S18_ENABLE))
 			return (0);
-		return EAGAIN;
+		return (EAGAIN);
 	case vccq_180:
 		if (!(slot->host.caps & MMC_CAP_SIGNALING_180)) {
-			return EINVAL;
+			return (EINVAL);
 		}
 		if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE)
 			return (0);
 		hostctrl2 |= SDHCI_CTRL2_S18_ENABLE;
 		bus_write_2(sc->mem_res, SDHCI_HOST_CONTROL2, hostctrl2);
 
-		uvolt = 1800000;
-		err = regulator_set_voltage(sc->mmc_helper.vqmmc_supply,
-		    uvolt, uvolt);
-		if (err != 0) {
-			device_printf(sc->dev,
-			    "Cannot set vqmmc to %d<->%d\n",
-			    uvolt,
-			    uvolt);
-			return (err);
+		if (!sc->skip_regulators) {
+			uvolt = 1800000;
+			err = regulator_set_voltage(sc->vqmmc_supply,
+				uvolt, uvolt);
+			if (err != 0) {
+				device_printf(sc->dev,
+					"Cannot set vqmmc to %d<->%d\n",
+					uvolt,
+					uvolt);
+				return (err);
+			}
 		}
 
 		/*
@@ -497,62 +459,46 @@ sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev)
 		hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2);
 		if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE)
 			return (0);
-		return EAGAIN;
+		return (EAGAIN);
 	default:
 		device_printf(brdev,
 		    "Attempt to set unsupported signaling voltage\n");
-		return EINVAL;
+		return (EINVAL);
 	}
 }
 
 static void
-sdhci_xenon_fdt_parse(device_t dev, struct sdhci_slot *slot)
+sdhci_xenon_parse_prop(device_t dev)
 {
-	struct sdhci_xenon_softc *sc = device_get_softc(dev);
-	pcell_t cid;
+	struct sdhci_xenon_softc *sc;
+	uint64_t val;
 
-	mmc_fdt_parse(dev, 0, &sc->mmc_helper, &slot->host);
+	sc = device_get_softc(dev);
+	val = 0;
 
-	/* Allow dts to patch quirks, slots, and max-frequency. */
-	if ((OF_getencprop(sc->node, "quirks", &cid, sizeof(cid))) > 0)
-		slot->quirks = cid;
-	if (OF_hasprop(sc->node, "marvell,xenon-phy-slow-mode"))
-		sc->slow_mode = true;
+	if (device_get_property(dev, "quirks", &val, sizeof(val)) > 0)
+		sc->slot->quirks = val;
 	sc->znr = XENON_ZNR_DEF_VALUE;
-	if ((OF_getencprop(sc->node, "marvell,xenon-phy-znr", &cid,
-	    sizeof(cid))) > 0)
-		sc->znr = cid & XENON_ZNR_MASK;
+	if (device_get_property(dev, "marvell,xenon-phy-znr",
+	    &val, sizeof(val)) > 0)
+		sc->znr = val & XENON_ZNR_MASK;
 	sc->zpr = XENON_ZPR_DEF_VALUE;
-	if ((OF_getencprop(sc->node, "marvell,xenon-phy-zpr", &cid,
-	    sizeof(cid))) > 0)
-		sc->zpr = cid & XENON_ZPR_MASK;
-}
-
-static int
-sdhci_xenon_probe(device_t dev)
-{
-	if (!ofw_bus_status_okay(dev))
-		return (ENXIO);
-
-	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
-		return (ENXIO);
-
-	device_set_desc(dev, "Armada Xenon SDHCI controller");
-
-	return (0);
+	if (device_get_property(dev, "marvell,xenon-phy-zpr",
+	    &val, sizeof(val)) > 0)
+		sc->zpr = val & XENON_ZPR_MASK;
+	if (device_has_property(dev, "marvell,xenon-phy-slow-mode"))
+		sc->slow_mode = true;
 }
 
-static int
+int
 sdhci_xenon_attach(device_t dev)
 {
 	struct sdhci_xenon_softc *sc = device_get_softc(dev);
-	struct sdhci_slot *slot;
 	int err, rid;
 	uint32_t reg;
 
 	sc->dev = dev;
 	sc->slot_id = 0;
-	sc->node = ofw_bus_get_node(dev);
 
 	/* Allocate IRQ. */
 	rid = 0;
@@ -574,27 +520,11 @@ sdhci_xenon_attach(device_t dev)
 		return (ENOMEM);
 	}
 
-	slot = malloc(sizeof(*slot), M_DEVBUF, M_ZERO | M_WAITOK);
-
-	/*
-	 * Set up any gpio pin handling described in the FDT data. This cannot
-	 * fail; see comments in sdhci_fdt_gpio.h for details.
-	 */
-	sc->gpio = sdhci_fdt_gpio_setup(dev, slot);
+	sdhci_xenon_parse_prop(dev);
 
-	sdhci_xenon_fdt_parse(dev, slot);
-
-	slot->max_clk = XENON_MMC_MAX_CLK;
-	if (slot->host.f_max > 0)
-		slot->max_clk = slot->host.f_max;
-	/* Check if the device is flagged as non-removable. */
-	if (sc->mmc_helper.props & MMC_PROP_NON_REMOVABLE) {
-		slot->opt |= SDHCI_NON_REMOVABLE;
-		if (bootverbose)
-			device_printf(dev, "Non-removable media\n");
-	}
-
-	sc->slot = slot;
+	sc->slot->max_clk = XENON_MMC_MAX_CLK;
+	if (sc->slot->host.f_max > 0)
+		sc->slot->max_clk = sc->slot->host.f_max;
 
 	if (sdhci_init_slot(dev, sc->slot, 0))
 		goto fail;
@@ -658,14 +588,11 @@ fail:
 	return (ENXIO);
 }
 
-static int
+int
 sdhci_xenon_detach(device_t dev)
 {
 	struct sdhci_xenon_softc *sc = device_get_softc(dev);
 
-	if (sc->gpio != NULL)
-		sdhci_fdt_gpio_teardown(sc->gpio);
-
 	bus_generic_detach(dev);
 	bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
 	bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res),
@@ -680,11 +607,6 @@ sdhci_xenon_detach(device_t dev)
 }
 
 static device_method_t sdhci_xenon_methods[] = {
-	/* device_if */
-	DEVMETHOD(device_probe,		sdhci_xenon_probe),
-	DEVMETHOD(device_attach,	sdhci_xenon_attach),
-	DEVMETHOD(device_detach,	sdhci_xenon_detach),
-
 	/* Bus interface */
 	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
 	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
@@ -708,21 +630,13 @@ static device_method_t sdhci_xenon_methods[] = {
 	DEVMETHOD(sdhci_write_2,	sdhci_xenon_write_2),
 	DEVMETHOD(sdhci_write_4,	sdhci_xenon_write_4),
 	DEVMETHOD(sdhci_write_multi_4,	sdhci_xenon_write_multi_4),
-	DEVMETHOD(sdhci_get_card_present,	sdhci_xenon_get_card_present),
 	DEVMETHOD(sdhci_set_uhs_timing, sdhci_xenon_set_uhs_timing),
 
 	DEVMETHOD_END
 };
 
-static driver_t sdhci_xenon_driver = {
-	"sdhci_xenon",
-	sdhci_xenon_methods,
-	sizeof(struct sdhci_xenon_softc),
-};
-static devclass_t sdhci_xenon_devclass;
-
-DRIVER_MODULE(sdhci_xenon, simplebus, sdhci_xenon_driver, sdhci_xenon_devclass,
-    NULL, NULL);
+DEFINE_CLASS_0(sdhci_xenon, sdhci_xenon_driver, sdhci_xenon_methods,
+    sizeof(struct sdhci_xenon_softc));
 
 SDHCI_DEPEND(sdhci_xenon);
 #ifndef MMCCAM
diff --git a/sys/dev/sdhci/sdhci_xenon.h b/sys/dev/sdhci/sdhci_xenon.h
index 07ed99339b8d..9d8449b90c82 100644
--- a/sys/dev/sdhci/sdhci_xenon.h
+++ b/sys/dev/sdhci/sdhci_xenon.h
@@ -101,4 +101,33 @@
 #define	XENON_EMMC_PHY_LOGIC_TIMING_ADJUST	(XENON_EMMC_PHY_REG_BASE + 0x18)
 #define	 XENON_LOGIC_TIMING_VALUE		0x00AA8977
 
+DECLARE_CLASS(sdhci_xenon_driver);
+
+struct sdhci_xenon_softc {
+	device_t	dev;		/* Controller device */
+	int		slot_id;	/* Controller ID */
+
+	struct resource	*mem_res;	/* Memory resource */
+	struct resource *irq_res;	/* IRQ resource */
+	void		*intrhand;	/* Interrupt handle */
+
+	struct sdhci_slot *slot;	/* SDHCI internal data */
+
+	uint8_t		znr;		/* PHY ZNR */
+	uint8_t		zpr;		/* PHY ZPR */
+	bool		slow_mode;	/* PHY slow mode */
+	bool		wp_inverted;
+	bool		skip_regulators; /* Don't switch regulators */
+
+	regulator_t	vmmc_supply;
+	regulator_t	vqmmc_supply;
+
+#ifdef FDT
+	struct sdhci_fdt_gpio *gpio;	/* GPIO pins for CD detection. */
+#endif
+};
+
+device_attach_t sdhci_xenon_attach;
+device_detach_t sdhci_xenon_detach;
+
 #endif	/* _SDHCI_XENON_H_ */
diff --git a/sys/dev/sdhci/sdhci_xenon_fdt.c b/sys/dev/sdhci/sdhci_xenon_fdt.c
new file mode 100644
index 000000000000..2d96105bd7e9
--- /dev/null
+++ b/sys/dev/sdhci/sdhci_xenon_fdt.c
@@ -0,0 +1,173 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf
+ *
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+#include <sys/taskqueue.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcbrvar.h>
+#include <dev/mmc/mmcreg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/mmc/mmc_fdt_helpers.h>
+
+#include <dev/sdhci/sdhci.h>
+#include <dev/sdhci/sdhci_fdt_gpio.h>
+#include <dev/sdhci/sdhci_xenon.h>
+
+#include "mmcbr_if.h"
+#include "sdhci_if.h"
+
+#include "opt_mmccam.h"
+#include "opt_soc.h"
+
+static struct ofw_compat_data compat_data[] = {
+	{ "marvell,armada-3700-sdhci",	1 },
+#ifdef SOC_MARVELL_8K
+	{ "marvell,armada-cp110-sdhci",	1 },
+	{ "marvell,armada-ap806-sdhci",	1 },
+	{ "marvell,armada-ap807-sdhci",	1 },
+#endif
+	{ NULL, 0 }
+};
+
+static bool
+sdhci_xenon_fdt_get_card_present(device_t dev, struct sdhci_slot *slot)
+{
+	struct sdhci_xenon_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (sdhci_fdt_gpio_get_present(sc->gpio));
+}
+
+static int
+sdhci_xenon_fdt_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+		return (ENXIO);
+
+	device_set_desc(dev, "Armada Xenon SDHCI controller");
+
+	return (BUS_PROBE_SPECIFIC);
+}
+
+static void
+sdhci_xenon_fdt_parse(device_t dev, struct sdhci_slot *slot)
+{
+	struct sdhci_xenon_softc *sc;
+	struct mmc_helper mmc_helper;
+
+	sc = device_get_softc(dev);
+	memset(&mmc_helper, 0, sizeof(mmc_helper));
+
+	/* MMC helper for parsing FDT */
+	mmc_fdt_parse(dev, 0, &mmc_helper, &slot->host);
+
+	sc->skip_regulators = false;
+	sc->vmmc_supply = mmc_helper.vmmc_supply;
+	sc->vqmmc_supply = mmc_helper.vqmmc_supply;
+	sc->wp_inverted = mmc_helper.props & MMC_PROP_WP_INVERTED;
+
+	/* Check if the device is flagged as non-removable. */
+	if (mmc_helper.props & MMC_PROP_NON_REMOVABLE) {
+		slot->opt |= SDHCI_NON_REMOVABLE;
+		if (bootverbose)
+			device_printf(dev, "Non-removable media\n");
+	}
+}
+
+static int
+sdhci_xenon_fdt_attach(device_t dev)
+{
+	struct sdhci_xenon_softc *sc;
+	struct sdhci_slot *slot;
+
+	sc = device_get_softc(dev);
+	slot = malloc(sizeof(*slot), M_DEVBUF, M_ZERO | M_WAITOK);
+
+	sdhci_xenon_fdt_parse(dev, slot);
+
+	/*
+	 * Set up any gpio pin handling described in the FDT data. This cannot
+	 * fail; see comments in sdhci_fdt_gpio.h for details.
+	 */
+	sc->gpio = sdhci_fdt_gpio_setup(dev, slot);
+	sc->slot = slot;
+
+	return (sdhci_xenon_attach(dev));
+}
+
+static int
+sdhci_xenon_fdt_detach(device_t dev)
+{
+	struct sdhci_xenon_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (sc->gpio != NULL)
+		sdhci_fdt_gpio_teardown(sc->gpio);
+
+	return (sdhci_xenon_detach(dev));
+}
+
+static device_method_t sdhci_xenon_fdt_methods[] = {
+	/* device_if */
+	DEVMETHOD(device_probe,		sdhci_xenon_fdt_probe),
+	DEVMETHOD(device_attach,	sdhci_xenon_fdt_attach),
+	DEVMETHOD(device_detach,	sdhci_xenon_fdt_detach),
+
+	DEVMETHOD(sdhci_get_card_present, sdhci_xenon_fdt_get_card_present),
+
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(sdhci_xenon, sdhci_xenon_fdt_driver, sdhci_xenon_fdt_methods,
+    sizeof(struct sdhci_xenon_softc), sdhci_xenon_driver);
+
+static devclass_t sdhci_xenon_fdt_devclass;
+
+DRIVER_MODULE(sdhci_xenon, simplebus, sdhci_xenon_fdt_driver,
+    sdhci_xenon_fdt_devclass, NULL, NULL);
+
+#ifndef MMCCAM
+MMC_DECLARE_BRIDGE(sdhci_xenon_fdt);
+#endif