Bringing up MM6108 over SDIO on x86_64 with OpenWrt

Hey there,

I’m working on getting my Alfa Networks AHM26108D module working in my Dell Wyse 3040. I’ve been able to boot it up, but it does not seem to initialize the device even though it shows it during probe. I built OpenWrt from the GitHub MorseMicro/openwrt repo, branch mm/v23.05.5. Here’s the relevant portion of dmesg:

[    0.270293] sdhci: Secure Digital Host Controller Interface driver
[    0.270323] sdhci: Copyright(c) Pierre Ossman
[    0.270407] sdhci-pci 0000:00:11.0: SDHCI controller found [8086:2295] (rev 36)
[    0.272133] mmc0: SDHCI controller on PCI [0000:00:11.0] using ADMA
[    0.294140] mmc1: SDHCI controller on ACPI [80860F14:00] using ADMA
[    0.506656] mmc1: new HS200 MMC card at address 0001
[    0.508228] mmcblk1: mmc1:0001 H8G4a 7.28 GiB 
[    0.511458] mmcblk1boot0: mmc1:0001 H8G4a 4.00 MiB 
[    0.511955] mmcblk1boot1: mmc1:0001 H8G4a 4.00 MiB 
[    0.512233] mmcblk1rpmb: mmc1:0001 H8G4a 4.00 MiB, chardev (244:0)
[    0.519801] mmc0: new high speed SDIO card at address 0001
[    6.381654] morsechipreset: unable to reset as MM_RESET not in gpio-line-names in device tree
[    6.735739] Morse Micro Dot11ah driver registration. Version 0-rel_1_15_3_2025_Apr_16
[    6.797270] morse micro driver registration. Version 0-rel_1_16_4_2025_Sep_18
[    6.932316] morse_sdio mmc0:0001:1: sdio new func 1 vendor 0x325b device 0x306 block 0x8/0x8
[    6.932843] morse_sdio mmc0:0001:2: sdio new func 2 vendor 0x325b device 0x306 block 0x200/0x200
[    6.934396] morse_sdio mmc0:0001:2: morse_of_probe: Device node not found
[    6.934732] morse_sdio mmc0:0001:2: morse_of_probe: No pin configs found
[    6.935903] morse_sdio_probe failed. The driver has not been loaded!

I’m not using a device tree, just ACPI device enumeration, so I’m not sure how to tell the driver to look at a specific device.

Thanks a bunch,
Anthony

Hello!

Unfortunately the driver requires a reset-gpio be provided for the SDIO interface, to correctly reset the chip on driver removal. At the moment, this is done only by looking for the node in devicetree containing a morse compatible.

A bit of a nasty shortcut/hack could be to remove the call to morse_sdio_reset in sdio.c which is the only place the reset gpio is referenced, then adjust morse_of_probe to always return 0.
Note that doing this could cause instability when removing and reinserting the kernel module. For OpenWrt, this should only happen when configuration which sets module parameters (eg, country code and some advanced options), changes.

In the near future, keep an eye out for products using our second generation chip which supports USB, and won’t require this reset gpio!

Awesome!

Thanks for the pointers, I was able to get it working! Here’s my (barely tested) patch to morse_driver in case anyone is interested in doing this themselves.

diff --git a/of.c b/of.c
index 9325705..bbb6056 100644
--- a/of.c
+++ b/of.c
@@ -16,6 +16,9 @@ int morse_of_probe(struct device *dev, struct morse_hw_cfg *cfg,
 	const struct of_device_id *of_id;
 	int gpio_pin;
 
+	/* Default to sentinel value in case of no DT */
+	cfg->mm_reset_gpio = -1;
+
 	if (np) {
 		of_id = of_match_node(match_table, np);
 		if (of_id) {
@@ -52,6 +55,7 @@ int morse_of_probe(struct device *dev, struct morse_hw_cfg *cfg,
 	} else {
 		dev_err(dev, "%s: Device node not found\n", __func__);
 	}
-	dev_info(dev, "%s: No pin configs found\n", __func__);
-	return -ENOENT;
+	dev_info(dev, "%s: No pin configs found. ACPI workaround\n", __func__);
+	/* On non-DT systems this is expected; continue with defaults */
+	return 0;
 }
diff --git a/sdio.c b/sdio.c
index 35ffcbf..40238f7 100644
--- a/sdio.c
+++ b/sdio.c
@@ -671,8 +671,14 @@ static int morse_sdio_reset(int reset_pin, struct sdio_func *func)
 	/* Let runtime PM know the card is powered off */
 	pm_runtime_put(&card->dev);
 
-	morse_hw_reset(reset_pin);
-	mdelay(20);
+	/* If no external reset GPIO is defined (ACPI/x86),
+	* skip toggling a non-existing pin and rely on host MMC reset. */
+	if (reset_pin >= 0) {
+		morse_hw_reset(reset_pin);
+		mdelay(20);
+	} else {
+		dev_info(&func->dev, "No external reset GPIO; using host reset only\n");
+	}
 
 	sdio_claim_host(func);
 	sdio_disable_func(func);

Thanks again,
Anthony

1 Like