wifi: brcmfmac: Add optional lpo clock enable support
authorJacobe Zang <jacobe.zang@wesion.com>
Tue, 10 Sep 2024 03:04:13 +0000 (11:04 +0800)
committerKalle Valo <kvalo@kernel.org>
Wed, 18 Sep 2024 13:53:47 +0000 (16:53 +0300)
WiFi modules often require 32kHz clock to function. Add support to
enable the clock to PCIe driver and move "brcm,bcm4329-fmac" check
to the top of brcmf_of_probe. Change function prototypes from void
to int and add appropriate errno's for return values that will be
send to bus when error occurred.

Co-developed-by: Ondrej Jirman <megi@xff.cz>
Signed-off-by: Ondrej Jirman <megi@xff.cz>
Co-developed-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Reviewed-by: Sai Krishna <saikrishnag@marvell.com>
Signed-off-by: Jacobe Zang <jacobe.zang@wesion.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Tested-by: Sebastian Reichel <sebastian.reichel@collabora.com> # On RK3588 EVB1
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://patch.msgid.link/20240910-wireless-mainline-v14-3-9d80fea5326d@wesion.com
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c

index d35262335eaf79fabb74c1e3363e916466d1ffc8..17f6b33beabd87c92acc0e8c97def8fe90e8cfe2 100644 (file)
@@ -947,8 +947,8 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
 
        /* try to attach to the target device */
        sdiodev->bus = brcmf_sdio_probe(sdiodev);
-       if (!sdiodev->bus) {
-               ret = -ENODEV;
+       if (IS_ERR(sdiodev->bus)) {
+               ret = PTR_ERR(sdiodev->bus);
                goto out;
        }
        brcmf_sdiod_host_fixup(sdiodev->func2->card->host);
index b24faae35873dc0cfeec9fde148db6cf24a6a55e..58d50918dd177dec6641ead123135657234137f2 100644 (file)
@@ -561,7 +561,8 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
        if (!found) {
                /* No platform data for this device, try OF and DMI data */
                brcmf_dmi_probe(settings, chip, chiprev);
-               brcmf_of_probe(dev, bus_type, settings);
+               if (brcmf_of_probe(dev, bus_type, settings) == -EPROBE_DEFER)
+                       return ERR_PTR(-EPROBE_DEFER);
                brcmf_acpi_probe(dev, bus_type, settings);
        }
        return settings;
index e2611f164fa88ff57a2f7c1ad40534a31afa2938..b90e23bb93661f13d7a5d9c318066b8eebab6f3e 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_net.h>
+#include <linux/clk.h>
 
 #include <defs.h>
 #include "debug.h"
@@ -65,12 +66,13 @@ static int brcmf_of_get_country_codes(struct device *dev,
        return 0;
 }
 
-void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
-                   struct brcmf_mp_device *settings)
+int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+                  struct brcmf_mp_device *settings)
 {
        struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio;
        struct device_node *root, *np = dev->of_node;
        struct of_phandle_args oirq;
+       struct clk *clk;
        const char *prop;
        int irq;
        int err;
@@ -106,7 +108,7 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
                board_type = devm_kstrdup(dev, tmp, GFP_KERNEL);
                if (!board_type) {
                        of_node_put(root);
-                       return;
+                       return 0;
                }
                strreplace(board_type, '/', '-');
                settings->board_type = board_type;
@@ -114,8 +116,15 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
                of_node_put(root);
        }
 
+       clk = devm_clk_get_optional_enabled(dev, "lpo");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       brcmf_dbg(INFO, "%s LPO clock\n", clk ? "enable" : "no");
+       clk_set_rate(clk, 32768);
+
        if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
-               return;
+               return 0;
 
        err = brcmf_of_get_country_codes(dev, settings);
        if (err)
@@ -124,23 +133,25 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
        of_get_mac_address(np, settings->mac);
 
        if (bus_type != BRCMF_BUSTYPE_SDIO)
-               return;
+               return 0;
 
        if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
                sdio->drive_strength = val;
 
        /* make sure there are interrupts defined in the node */
        if (of_irq_parse_one(np, 0, &oirq))
-               return;
+               return 0;
 
        irq = irq_create_of_mapping(&oirq);
        if (!irq) {
                brcmf_err("interrupt could not be mapped\n");
-               return;
+               return 0;
        }
        irqf = irq_get_trigger_type(irq);
 
        sdio->oob_irq_supported = true;
        sdio->oob_irq_nr = irq;
        sdio->oob_irq_flags = irqf;
+
+       return 0;
 }
index 10bf52253337e762492f55f941b7862d88a7de73..ae124c73fc3b7cc8c14715f0489446572c188cc0 100644 (file)
@@ -3,11 +3,12 @@
  * Copyright (c) 2014 Broadcom Corporation
  */
 #ifdef CONFIG_OF
-void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
-                   struct brcmf_mp_device *settings);
+int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+                  struct brcmf_mp_device *settings);
 #else
-static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
-                          struct brcmf_mp_device *settings)
+static int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+                         struct brcmf_mp_device *settings)
 {
+       return 0;
 }
 #endif /* CONFIG_OF */
index ce482a3877e90ac16373ec7b081261d509c8bc34..190e8990618c55685d0768f8161cc4f23256e5e1 100644 (file)
@@ -2452,6 +2452,9 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                ret = -ENOMEM;
                goto fail;
        }
+       ret = PTR_ERR_OR_ZERO(devinfo->settings);
+       if (ret < 0)
+               goto fail;
 
        bus = kzalloc(sizeof(*bus), GFP_KERNEL);
        if (!bus) {
index 1461dc453ac22e45766d2e8fd50b895e08dd0a5d..a9b4d560cbfc7177366dd7e4a8ec1372401509f2 100644 (file)
@@ -3943,7 +3943,7 @@ static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = {
        .write32 = brcmf_sdio_buscore_write32,
 };
 
-static bool
+static int
 brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
 {
        struct brcmf_sdio_dev *sdiodev;
@@ -3953,6 +3953,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
        u32 reg_val;
        u32 drivestrength;
        u32 enum_base;
+       int ret = -EBADE;
 
        sdiodev = bus->sdiodev;
        sdio_claim_host(sdiodev->func1);
@@ -4001,8 +4002,9 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
                                                   BRCMF_BUSTYPE_SDIO,
                                                   bus->ci->chip,
                                                   bus->ci->chiprev);
-       if (!sdiodev->settings) {
+       if (IS_ERR_OR_NULL(sdiodev->settings)) {
                brcmf_err("Failed to get device parameters\n");
+               ret = PTR_ERR_OR_ZERO(sdiodev->settings);
                goto fail;
        }
        /* platform specific configuration:
@@ -4071,7 +4073,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
        /* allocate header buffer */
        bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL);
        if (!bus->hdrbuf)
-               return false;
+               return -ENOMEM;
        /* Locate an appropriately-aligned portion of hdrbuf */
        bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
                                    bus->head_align);
@@ -4082,11 +4084,11 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
        if (bus->poll)
                bus->pollrate = 1;
 
-       return true;
+       return 0;
 
 fail:
        sdio_release_host(sdiodev->func1);
-       return false;
+       return ret;
 }
 
 static int
@@ -4451,8 +4453,10 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 
        /* Allocate private bus interface state */
        bus = kzalloc(sizeof(*bus), GFP_ATOMIC);
-       if (!bus)
+       if (!bus) {
+               ret = -ENOMEM;
                goto fail;
+       }
 
        bus->sdiodev = sdiodev;
        sdiodev->bus = bus;
@@ -4467,6 +4471,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
                                     dev_name(&sdiodev->func1->dev));
        if (!wq) {
                brcmf_err("insufficient memory to create txworkqueue\n");
+               ret = -ENOMEM;
                goto fail;
        }
        brcmf_sdiod_freezer_count(sdiodev);
@@ -4474,7 +4479,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
        bus->brcmf_wq = wq;
 
        /* attempt to attach to the dongle */
-       if (!(brcmf_sdio_probe_attach(bus))) {
+       ret = brcmf_sdio_probe_attach(bus);
+       if (ret < 0) {
                brcmf_err("brcmf_sdio_probe_attach failed\n");
                goto fail;
        }
@@ -4546,7 +4552,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 
 fail:
        brcmf_sdio_remove(bus);
-       return NULL;
+       return ERR_PTR(ret);
 }
 
 /* Detach and free everything */
index 8afbf529c745038151c778f6ea35e45084a8171f..2821c27f317ee094198f78b02b85e94256844d62 100644 (file)
@@ -1272,6 +1272,9 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
                ret = -ENOMEM;
                goto fail;
        }
+       ret = PTR_ERR_OR_ZERO(devinfo->settings);
+       if (ret < 0)
+               goto fail;
 
        if (!brcmf_usb_dlneeded(devinfo)) {
                ret = brcmf_alloc(devinfo->dev, devinfo->settings);