* [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver
@ 2025-02-12 15:46 Alexis Lothoré
2025-02-12 15:46 ` [PATCH 01/12] dt-bindings: bluetooth: describe wilc 3000 bluetooth chip Alexis Lothoré
` (12 more replies)
0 siblings, 13 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
Hello,
WILC3000 ([1]) is a combo chip exposing 802.11b/g/n and Bluetooth 5.
Support for the wlan part has recently been integrated upstream ([2]) in
the existing wilc1000 driver. This new series aims to bring support for
the bluetooth side.
The WILC3000 chip is controlled through a SDIO or SPI bus for the wlan
part (similarly to wilc1000), and uses standard HCI commands over a UART
bus for the bluetooth operations. This work is based on the code
available in the vendor kernel ([3]), in which bluetooth is managed
directly in the wireless driver, and relies on user to trigger the
hardware configuration (chardev manipulations + hciattach). The series
brings a new dedicated bluetooth driver to support the bluetooth feature
from the chip, without relying on the user to perform the device
bringup. However, getting completely rid of the wlan driver dependency
is not possible: it is still needed for early BT CPU configuration and
BT firmware download, so the new driver still have a dependency of the
wlan one, with an approach similar to the one used by the rsi driver.
- Patch 1 brings the new dt binding
- Patch 2-9 prepares the wlan side, either by exposing the needed
functions to initialize BT, or by mitigating behavior which would
prevent BT and WLAN from runnning in parallel
- Patch 10 brings the new bluetooth driver
- Patch 11 updates the device tree description for sama5d27_wlsom1_ek
board (which I used to validate this series) to use the new driver
- Patch 12 adds a new entry for this driver in the MAINTAINERS files
This series has been tested with WILC3000 both in SDIO mode (with the
chip embedded on the sama5d27_wlsom1_ek) and SPI mode (custom wiring on
an SPI on the same eval board, with a WILC3000-SD).
Since this works needs new code in both the existing wlan driver and the
new driver, I have included both linux-wireless and bluetooth mailing
lists, while keeping the entire series for clarity, but let me know if
you want to proceed differently.
[1] https://www.microchip.com/en-us/product/atwilc3000
[2] https://lore.kernel.org/linux-wireless/20241004114551.40236-1-marex@denx.de/
[3] https://github.com/linux4microchip/linux/tree/linux-6.6-mchp/drivers/net/wireless/microchip/wilc1000
---
Alexis Lothoré (12):
dt-bindings: bluetooth: describe wilc 3000 bluetooth chip
wifi: wilc1000: add a read-modify-write API for registers accesses
wifi: wilc1000: add lock to prevent concurrent firmware startup
wifi: wilc1000: allow to use acquire/release bus in other parts of driver
wifi: wilc1000: do not depend on power save flag to wake up chip
wifi: wilc1000: remove timeout parameter from set_power_mgmt
wifi: wilc1000: reorganize makefile objs into sorted list
wifi: wilc1000: add basic functions to allow bluetooth bringup
wifi: wilc1000: disable firmware power save if bluetooth is in use
bluetooth: hci_wilc: add wilc hci driver
ARM: dts: at91-sama5d27_wlsom1: update bluetooth chip description
MAINTAINERS: add entry for new wilc3000 bluetooth driver
.../net/bluetooth/microchip,wilc3000-bt.yaml | 41 +++
MAINTAINERS | 7 +
.../boot/dts/microchip/at91-sama5d27_wlsom1.dtsi | 8 +
.../boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts | 10 -
drivers/bluetooth/Kconfig | 13 +
drivers/bluetooth/Makefile | 3 +-
drivers/bluetooth/hci_uart.h | 1 +
drivers/bluetooth/hci_wilc.c | 333 ++++++++++++++++++++
drivers/net/wireless/microchip/wilc1000/Kconfig | 3 +
drivers/net/wireless/microchip/wilc1000/Makefile | 11 +-
drivers/net/wireless/microchip/wilc1000/bt.c | 345 +++++++++++++++++++++
drivers/net/wireless/microchip/wilc1000/cfg80211.c | 7 +-
drivers/net/wireless/microchip/wilc1000/hif.c | 2 +-
drivers/net/wireless/microchip/wilc1000/hif.h | 2 +-
drivers/net/wireless/microchip/wilc1000/netdev.c | 14 +
drivers/net/wireless/microchip/wilc1000/netdev.h | 5 +
drivers/net/wireless/microchip/wilc1000/sdio.c | 101 ++++--
drivers/net/wireless/microchip/wilc1000/spi.c | 43 +++
drivers/net/wireless/microchip/wilc1000/wlan.c | 154 ++++-----
drivers/net/wireless/microchip/wilc1000/wlan.h | 23 ++
include/net/wilc.h | 19 ++
21 files changed, 996 insertions(+), 149 deletions(-)
---
base-commit: 95f6f2d73dc40ab53a94756689ce5cfd2f23361a
change-id: 20240828-wilc3000_bt-fa452f2a93ad
Best regards,
--
Alexis Lothoré, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 01/12] dt-bindings: bluetooth: describe wilc 3000 bluetooth chip
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-13 9:25 ` Krzysztof Kozlowski
2025-02-12 15:46 ` [PATCH 02/12] wifi: wilc1000: add a read-modify-write API for registers accesses Alexis Lothoré
` (11 subsequent siblings)
12 siblings, 1 reply; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
WILC3000 is a combo chip providing 802.11b/g/n and Bluetooth 5. The wlan
part is exposed either through SDIO or SPI interface, and the bluetooth
part is exposed through uart. The notable peculiarity of this chip is
that the bluetooth part is not fully autonomous: its firmware is not
loaded through UART interface but through SDIO/SPI interface, so the
bluetooth description needs a reference to the wlan part to get access
to the corresponding bus.
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
.../net/bluetooth/microchip,wilc3000-bt.yaml | 41 ++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/bluetooth/microchip,wilc3000-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/microchip,wilc3000-bt.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2a83ca3ad90b26fd619b574bc343bee9654a1e43
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/bluetooth/microchip,wilc3000-bt.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/bluetooth/microchip,wilc3000-bt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip Bluetooth chips
+
+description:
+ This binding describes UART-attached Microchip bluetooth chips. These
+ chips are dual-radio chips supporting WiFi and Bluetooth. The bluetooth
+ side works with standard HCI commands over 4-wires UART (with flow
+ control)
+
+maintainers:
+ - Alexis Lothoré <alexis.lothore@bootlin.com>
+
+properties:
+ compatible:
+ enum:
+ - microchip,wilc3000-bt
+
+ wlan:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle to the wlan part of the combo chip
+
+required:
+ - compatible
+ - wlan
+
+additionalProperties: false
+
+examples:
+ - |
+ serial {
+ bluetooth {
+ compatible = "microchip,wilc3000-bt";
+ wlan = <&wifi>;
+ };
+ };
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 02/12] wifi: wilc1000: add a read-modify-write API for registers accesses
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
2025-02-12 15:46 ` [PATCH 01/12] dt-bindings: bluetooth: describe wilc 3000 bluetooth chip Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 15:46 ` [PATCH 03/12] wifi: wilc1000: add lock to prevent concurrent firmware startup Alexis Lothoré
` (10 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
Many places in wilc driver need to modify a single bit in a register,
and then perform the following sequence: read the register, set/reset
the needed bit, write the register. This sequence is performed in
multiple places in the driver, with a varying amount of checks around
possible errors.
Replace all those sequences with a new hif_rmw_reg helper. Make sure to
perform the write only if needed.
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
Since the registers meaning and effect is pretty opaque, this commit
tries to remain conservative and converts only the "real"
read-modify-write sequences: bare writes seemingly trying to affect a
single bit but actually affecting the whole register are left untouched.
---
drivers/net/wireless/microchip/wilc1000/sdio.c | 68 ++++++------
drivers/net/wireless/microchip/wilc1000/spi.c | 18 +++
drivers/net/wireless/microchip/wilc1000/wlan.c | 145 +++++++++----------------
drivers/net/wireless/microchip/wilc1000/wlan.h | 3 +
4 files changed, 105 insertions(+), 129 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c
index af970f9991110807ebd880681ad0e8aaf8a0b9bc..7eab1c493774e197e43bdf265063aa8c5e6dff14 100644
--- a/drivers/net/wireless/microchip/wilc1000/sdio.c
+++ b/drivers/net/wireless/microchip/wilc1000/sdio.c
@@ -916,6 +916,7 @@ static int wilc_sdio_sync_ext(struct wilc *wilc, int nint)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
struct wilc_sdio *sdio_priv = wilc->bus_data;
+ u32 int_en_mask = 0;
if (nint > MAX_NUM_INT) {
dev_err(&func->dev, "Too many interrupts (%d)...\n", nint);
@@ -923,61 +924,42 @@ static int wilc_sdio_sync_ext(struct wilc *wilc, int nint)
}
if (sdio_priv->irq_gpio) {
- u32 reg;
int ret, i;
/**
* interrupt pin mux select
**/
- ret = wilc_sdio_read_reg(wilc, WILC_PIN_MUX_0, ®);
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_PIN_MUX_0, BIT(8),
+ BIT(8));
if (ret) {
- dev_err(&func->dev, "Failed read reg (%08x)...\n",
- WILC_PIN_MUX_0);
- return ret;
- }
- reg |= BIT(8);
- ret = wilc_sdio_write_reg(wilc, WILC_PIN_MUX_0, reg);
- if (ret) {
- dev_err(&func->dev, "Failed write reg (%08x)...\n",
- WILC_PIN_MUX_0);
+ dev_err(&func->dev, "Failed to set interrupt mux\n");
return ret;
}
/**
* interrupt enable
**/
- ret = wilc_sdio_read_reg(wilc, WILC_INTR_ENABLE, ®);
- if (ret) {
- dev_err(&func->dev, "Failed read reg (%08x)...\n",
- WILC_INTR_ENABLE);
- return ret;
- }
-
for (i = 0; (i < 5) && (nint > 0); i++, nint--)
- reg |= BIT((27 + i));
- ret = wilc_sdio_write_reg(wilc, WILC_INTR_ENABLE, reg);
+ int_en_mask |= BIT(WILC_INTR_ENABLE_BIT_BASE + i);
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_INTR_ENABLE,
+ int_en_mask, int_en_mask);
if (ret) {
- dev_err(&func->dev, "Failed write reg (%08x)...\n",
- WILC_INTR_ENABLE);
+ dev_err(&func->dev, "Failed to enable interrupts\n");
return ret;
}
- if (nint) {
- ret = wilc_sdio_read_reg(wilc, WILC_INTR2_ENABLE, ®);
- if (ret) {
- dev_err(&func->dev,
- "Failed read reg (%08x)...\n",
- WILC_INTR2_ENABLE);
- return ret;
- }
+ if (nint) {
+ int_en_mask = 0;
for (i = 0; (i < 3) && (nint > 0); i++, nint--)
- reg |= BIT(i);
+ int_en_mask |= BIT(i);
- ret = wilc_sdio_write_reg(wilc, WILC_INTR2_ENABLE, reg);
+ ret = wilc->hif_func->hif_rmw_reg(wilc,
+ WILC_INTR2_ENABLE,
+ int_en_mask,
+ int_en_mask);
if (ret) {
dev_err(&func->dev,
- "Failed write reg (%08x)...\n",
- WILC_INTR2_ENABLE);
+ "Failed to enable internal interrupts\n");
return ret;
}
}
@@ -985,6 +967,23 @@ static int wilc_sdio_sync_ext(struct wilc *wilc, int nint)
return 0;
}
+static int wilc_sdio_rmw_reg(struct wilc *wilc, u32 reg, u32 mask, u32 data)
+{
+ u32 old_val, new_val;
+ int ret = 0;
+
+ ret = wilc_sdio_read_reg(wilc, reg, &old_val);
+ if (ret)
+ return ret;
+
+ new_val = old_val & ~mask;
+ new_val |= data;
+ if (new_val != old_val)
+ ret = wilc_sdio_write_reg(wilc, reg, new_val);
+
+ return ret;
+}
+
/* Global sdio HIF function table */
static const struct wilc_hif_func wilc_hif_sdio = {
.hif_init = wilc_sdio_init,
@@ -1003,6 +1002,7 @@ static const struct wilc_hif_func wilc_hif_sdio = {
.disable_interrupt = wilc_sdio_disable_interrupt,
.hif_reset = wilc_sdio_reset,
.hif_is_init = wilc_sdio_is_init,
+ .hif_rmw_reg = wilc_sdio_rmw_reg
};
static int wilc_sdio_suspend(struct device *dev)
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 5bcabb7decea0fc8d0065a240f4acefabca3346a..aae4262045ff3e5f3668493ef235486e601996f7 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -1355,6 +1355,23 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
return 0;
}
+static int wilc_spi_rmw_reg(struct wilc *wilc, u32 reg, u32 mask, u32 data)
+{
+ u32 old_val, new_val;
+ int ret = 0;
+
+ ret = wilc_spi_read_reg(wilc, reg, &old_val);
+ if (ret)
+ return ret;
+
+ new_val = old_val & ~mask;
+ new_val |= data;
+ if (new_val != old_val)
+ ret = wilc_spi_write_reg(wilc, reg, new_val);
+
+ return ret;
+}
+
/* Global spi HIF function table */
static const struct wilc_hif_func wilc_hif_spi = {
.hif_init = wilc_spi_init,
@@ -1371,4 +1388,5 @@ static const struct wilc_hif_func wilc_hif_spi = {
.hif_sync_ext = wilc_spi_sync_ext,
.hif_reset = wilc_spi_reset,
.hif_is_init = wilc_spi_is_init,
+ .hif_rmw_reg = wilc_spi_rmw_reg
};
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 9d80adc45d6be14c8818e8ef1643db6875cf57d2..f2b13bd44273ebe2ee474eda047e82bf1287bd6e 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -578,53 +578,27 @@ static int chip_allow_sleep_wilc1000(struct wilc *wilc)
pr_warn("FW not responding\n");
/* Clear bit 1 */
- ret = hif_func->hif_read_reg(wilc, wakeup_reg, ®);
+ ret = wilc->hif_func->hif_rmw_reg(wilc, wakeup_reg, wakeup_bit, 0);
if (ret)
return ret;
- if (reg & wakeup_bit) {
- reg &= ~wakeup_bit;
- ret = hif_func->hif_write_reg(wilc, wakeup_reg, reg);
- if (ret)
- return ret;
- }
- ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, ®);
+ ret = wilc->hif_func->hif_rmw_reg(wilc, from_host_to_fw_reg,
+ from_host_to_fw_bit, 0);
if (ret)
return ret;
- if (reg & from_host_to_fw_bit) {
- reg &= ~from_host_to_fw_bit;
- ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, reg);
- if (ret)
- return ret;
- }
return 0;
}
static int chip_allow_sleep_wilc3000(struct wilc *wilc)
{
- u32 reg = 0;
int ret;
- const struct wilc_hif_func *hif_func = wilc->hif_func;
+ u32 wake_bit = wilc->io_type == WILC_HIF_SDIO ? WILC_SDIO_WAKEUP_BIT :
+ WILC_SPI_WAKEUP_BIT;
- if (wilc->io_type == WILC_HIF_SDIO) {
- ret = hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, ®);
- if (ret)
- return ret;
- ret = hif_func->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG,
- reg & ~WILC_SDIO_WAKEUP_BIT);
- if (ret)
- return ret;
- } else {
- ret = hif_func->hif_read_reg(wilc, WILC_SPI_WAKEUP_REG, ®);
- if (ret)
- return ret;
- ret = hif_func->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG,
- reg & ~WILC_SPI_WAKEUP_BIT);
- if (ret)
- return ret;
- }
- return 0;
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_SDIO_WAKEUP_REG, wake_bit,
+ 0);
+ return ret;
}
static int chip_allow_sleep(struct wilc *wilc)
@@ -699,10 +673,10 @@ static int chip_wakeup_wilc1000(struct wilc *wilc)
static int chip_wakeup_wilc3000(struct wilc *wilc)
{
- u32 wakeup_reg_val, clk_status_reg_val, trials = 0;
- u32 wakeup_reg, wakeup_bit;
+ u32 clk_status_reg_val, trials = 0;
u32 clk_status_reg, clk_status_bit;
- int wake_seq_trials = 5;
+ int wake_seq_trials = 5, ret;
+ u32 wakeup_reg, wakeup_bit;
const struct wilc_hif_func *hif_func = wilc->hif_func;
if (wilc->io_type == WILC_HIF_SDIO) {
@@ -717,10 +691,12 @@ static int chip_wakeup_wilc3000(struct wilc *wilc)
clk_status_bit = WILC3000_SPI_CLK_STATUS_BIT;
}
- hif_func->hif_read_reg(wilc, wakeup_reg, &wakeup_reg_val);
do {
- hif_func->hif_write_reg(wilc, wakeup_reg, wakeup_reg_val |
- wakeup_bit);
+ ret = hif_func->hif_rmw_reg(wilc, wakeup_reg, wakeup_bit,
+ wakeup_bit);
+ if (ret)
+ dev_warn(wilc->dev, "Failed to set wake bit\n");
+
/* Check the clock status */
hif_func->hif_read_reg(wilc, clk_status_reg,
&clk_status_reg_val);
@@ -745,8 +721,10 @@ static int chip_wakeup_wilc3000(struct wilc *wilc)
* edge on the next loop
*/
if ((clk_status_reg_val & clk_status_bit) == 0) {
- hif_func->hif_write_reg(wilc, wakeup_reg,
- wakeup_reg_val & (~wakeup_bit));
+ ret = hif_func->hif_rmw_reg(wilc, wakeup_reg,
+ wakeup_bit, 0);
+ if (ret)
+ dev_warn(wilc->dev, "Failed to set CLK bit\n");
/* added wait before wakeup sequence retry */
usleep_range(200, 300);
}
@@ -996,11 +974,11 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
break;
if (entries == 0) {
- ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®);
+ ret = wilc->hif_func->hif_rmw_reg(wilc,
+ WILC_HOST_TX_CTRL, BIT(0), 0);
if (ret)
- break;
- reg &= ~BIT(0);
- ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
+ dev_warn(wilc->dev,
+ "Failed to reset TX CTRL bit\n");
}
} while (0);
@@ -1267,9 +1245,12 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
if (ret)
return ret;
- wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);
- reg &= ~BIT(10);
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_GLB_RESET_0, BIT(10), 0);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to reset WLAN CPU\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return ret;
+ }
wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);
if (reg & BIT(10))
pr_err("%s: Failed to reset\n", __func__);
@@ -1357,16 +1338,12 @@ int wilc_wlan_start(struct wilc *wilc)
if (ret)
goto release;
- wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);
- if ((reg & BIT(10)) == BIT(10)) {
- reg &= ~BIT(10);
- wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
- wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);
- }
-
- reg |= BIT(10);
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
- wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_GLB_RESET_0, BIT(10), 0);
+ if (!ret)
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_GLB_RESET_0,
+ BIT(10), BIT(10));
+ if (ret)
+ dev_warn(wilc->dev, "Failed to reset WLAN CPU\n");
release:
rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY);
@@ -1375,44 +1352,31 @@ int wilc_wlan_start(struct wilc *wilc)
int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
{
- u32 reg = 0;
int ret, rv;
ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
if (ret)
return ret;
- ret = wilc->hif_func->hif_read_reg(wilc, GLOBAL_MODE_CONTROL, ®);
- if (ret)
- goto release;
-
- reg &= ~WILC_GLOBAL_MODE_ENABLE_WIFI;
- ret = wilc->hif_func->hif_write_reg(wilc, GLOBAL_MODE_CONTROL, reg);
- if (ret)
- goto release;
-
- ret = wilc->hif_func->hif_read_reg(wilc, PWR_SEQ_MISC_CTRL, ®);
- if (ret)
- goto release;
-
- reg &= ~WILC_PWR_SEQ_ENABLE_WIFI_SLEEP;
- ret = wilc->hif_func->hif_write_reg(wilc, PWR_SEQ_MISC_CTRL, reg);
- if (ret)
- goto release;
-
- ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®);
+ ret = wilc->hif_func->hif_rmw_reg(wilc, GLOBAL_MODE_CONTROL,
+ WILC_GLOBAL_MODE_ENABLE_WIFI, 0);
if (ret) {
- netdev_err(vif->ndev, "Error while reading reg\n");
+ netdev_err(vif->ndev, "Failed to disable wlan control\n");
goto release;
}
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
- (reg | WILC_ABORT_REQ_BIT));
+ ret = wilc->hif_func->hif_rmw_reg(wilc, PWR_SEQ_MISC_CTRL,
+ WILC_PWR_SEQ_ENABLE_WIFI_SLEEP, 0);
if (ret) {
- netdev_err(vif->ndev, "Error while writing reg\n");
+ netdev_err(vif->ndev, "Failed to unmux wlan power seq\n");
goto release;
}
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_GP_REG_0,
+ WILC_ABORT_REQ_BIT, 1);
+ if (ret)
+ netdev_err(vif->ndev, "Failed to stop wlan CPU\n");
+
ret = 0;
release:
/* host comm is disabled - we can't issue sleep command anymore: */
@@ -1641,19 +1605,10 @@ static int init_chip(struct net_device *dev)
goto release;
if ((wilc->chipid & 0xfff) != 0xa0) {
- ret = wilc->hif_func->hif_read_reg(wilc,
- WILC_CORTUS_RESET_MUX_SEL,
- ®);
- if (ret) {
- netdev_err(dev, "fail read reg 0x1118\n");
- goto release;
- }
- reg |= BIT(0);
- ret = wilc->hif_func->hif_write_reg(wilc,
- WILC_CORTUS_RESET_MUX_SEL,
- reg);
+ ret = wilc->hif_func->hif_rmw_reg(wilc,
+ WILC_CORTUS_RESET_MUX_SEL, BIT(0), BIT(0));
if (ret) {
- netdev_err(dev, "fail write reg 0x1118\n");
+ netdev_err(dev, "Failed to enable WLAN global reset\n");
goto release;
}
ret = wilc->hif_func->hif_write_reg(wilc,
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h
index b9e7f9222eadde6d736e1d0a403f84ec19399632..65e79371014d9e60755cb0aa38e04d351e67bcfb 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.h
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.h
@@ -58,6 +58,7 @@
#define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88)
#define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00)
#define WILC_INTR_ENABLE WILC_INTR_REG_BASE
+#define WILC_INTR_ENABLE_BIT_BASE 27
#define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4)
#define WILC_INTR_POLARITY (WILC_INTR_REG_BASE + 0x10)
@@ -403,6 +404,7 @@ struct wilc_hif_func {
void (*disable_interrupt)(struct wilc *nic);
int (*hif_reset)(struct wilc *wilc);
bool (*hif_is_init)(struct wilc *wilc);
+ int (*hif_rmw_reg)(struct wilc *wilc, u32 reg, u32 mask, u32 data);
};
#define WILC_MAX_CFG_FRAME_SIZE 1468
@@ -472,4 +474,5 @@ int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
int wilc_wlan_init(struct net_device *dev);
int wilc_get_chipid(struct wilc *wilc);
int wilc_load_mac_from_nv(struct wilc *wilc);
+
#endif
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 03/12] wifi: wilc1000: add lock to prevent concurrent firmware startup
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
2025-02-12 15:46 ` [PATCH 01/12] dt-bindings: bluetooth: describe wilc 3000 bluetooth chip Alexis Lothoré
2025-02-12 15:46 ` [PATCH 02/12] wifi: wilc1000: add a read-modify-write API for registers accesses Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 15:46 ` [PATCH 04/12] wifi: wilc1000: allow to use acquire/release bus in other parts of driver Alexis Lothoré
` (9 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
wilc1000 driver supports WILC3000, a combo wifi/bluetooth chip. This
chip needs a firmware for each radio. Before bringing support for the
bluetooth side (and so, before adding bluetooth firmware load and
start), add a dedicated lock around firmware loading and startup for
wlan side. The bluetooth part will also use this lock to ensure that
both firmware are not being loaded/started at the same time.
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
drivers/net/wireless/microchip/wilc1000/cfg80211.c | 2 ++
drivers/net/wireless/microchip/wilc1000/netdev.c | 5 +++++
drivers/net/wireless/microchip/wilc1000/netdev.h | 2 ++
3 files changed, 9 insertions(+)
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index e7aa0f9919232350761d51cbb1b5be87ca39e855..393fff618f919c5a6d3f4a7d894b187399455fb8 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1736,6 +1736,7 @@ static void wlan_init_locks(struct wilc *wl)
mutex_init(&wl->cfg_cmd_lock);
mutex_init(&wl->vif_mutex);
mutex_init(&wl->deinit_lock);
+ mutex_init(&wl->radio_fw_start);
spin_lock_init(&wl->txq_spinlock);
mutex_init(&wl->txq_add_to_head_cs);
@@ -1755,6 +1756,7 @@ void wlan_deinit_locks(struct wilc *wilc)
mutex_destroy(&wilc->txq_add_to_head_cs);
mutex_destroy(&wilc->vif_mutex);
mutex_destroy(&wilc->deinit_lock);
+ mutex_destroy(&wilc->radio_fw_start);
cleanup_srcu_struct(&wilc->srcu);
}
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c
index af298021e05041ba4b16a94c8ee768407a208dfc..d24859d12ccd535c966a9b7f46378ac3b3a21d7b 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.c
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.c
@@ -4,6 +4,7 @@
* All rights reserved.
*/
+#include "linux/mutex.h"
#include <linux/irq.h>
#include <linux/kthread.h>
#include <linux/firmware.h>
@@ -534,6 +535,8 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
goto fail_irq_init;
}
+ mutex_lock(&wl->radio_fw_start);
+
ret = wilc_wlan_get_firmware(dev);
if (ret)
goto fail_irq_enable;
@@ -562,6 +565,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
netdev_err(dev, "Failed to configure firmware\n");
goto fail_fw_start;
}
+ mutex_unlock(&wl->radio_fw_start);
wl->initialized = true;
return 0;
@@ -569,6 +573,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
wilc_wlan_stop(wl, vif);
fail_irq_enable:
+ mutex_unlock(&wl->radio_fw_start);
if (!wl->dev_irq_num &&
wl->hif_func->disable_interrupt)
wl->hif_func->disable_interrupt(wl);
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h
index 95bc8b8fe65a584615b6b9021d08d11e4b36408b..5837f8ffe548dad1b756cdbd8543636f2be0e9b0 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.h
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.h
@@ -287,6 +287,8 @@ struct wilc {
struct ieee80211_supported_band band;
u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)];
u8 nv_mac_address[ETH_ALEN];
+ /* Lock to prevent concurrent start of wlan/bluetooth firmware */
+ struct mutex radio_fw_start;
};
struct wilc_wfi_mon_priv {
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 04/12] wifi: wilc1000: allow to use acquire/release bus in other parts of driver
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (2 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 03/12] wifi: wilc1000: add lock to prevent concurrent firmware startup Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 15:46 ` [PATCH 05/12] wifi: wilc1000: do not depend on power save flag to wake up chip Alexis Lothoré
` (8 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
acquire_bus/release_bus is currently used only in wlan.c when needing to
access the main bus (SDIO or SPI). For wilc3000, the bluetooth part will
also need to perform some operations on the main bus (eg: bluetooth
firmware loading), so expose acquire/release_bus.
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 5 +++--
drivers/net/wireless/microchip/wilc1000/wlan.h | 3 +++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index f2b13bd44273ebe2ee474eda047e82bf1287bd6e..a697caf73ac3ed06602c029c17773f50e3f8edb5 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -743,7 +743,7 @@ static int chip_wakeup(struct wilc *wilc)
return chip_wakeup_wilc3000(wilc);
}
-static inline int acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
+int acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
{
int ret = 0;
@@ -757,12 +757,13 @@ static inline int acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
return ret;
}
-static inline int release_bus(struct wilc *wilc, enum bus_release release)
+int release_bus(struct wilc *wilc, enum bus_release release)
{
int ret = 0;
if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode)
ret = chip_allow_sleep(wilc);
+
mutex_unlock(&wilc->hif_cs);
return ret;
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h
index 65e79371014d9e60755cb0aa38e04d351e67bcfb..e45c2db0f5cd2de6844993dde15034ebbd93e73b 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.h
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.h
@@ -475,4 +475,7 @@ int wilc_wlan_init(struct net_device *dev);
int wilc_get_chipid(struct wilc *wilc);
int wilc_load_mac_from_nv(struct wilc *wilc);
+int acquire_bus(struct wilc *wilc, enum bus_acquire acquire);
+int release_bus(struct wilc *wilc, enum bus_release release);
+
#endif
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 05/12] wifi: wilc1000: do not depend on power save flag to wake up chip
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (3 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 04/12] wifi: wilc1000: allow to use acquire/release bus in other parts of driver Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 15:46 ` [PATCH 06/12] wifi: wilc1000: remove timeout parameter from set_power_mgmt Alexis Lothoré
` (7 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
The wilc chips family has at least two mechanisms dedicated to power save:
- a firmware configuration message, currently wired to the
set_power_mgmt_ops of the cfg80211_ops structure (and so, configured
through iw)
- dedicated raw registers which allow to wake up the chip each time we
need to communicate with it and to allow it again to sleep once done:
those registers are currently manipulated almost any time we are about
to use the SDIO/SPI bus to drive the chip.
Those mechanisms are currently coupled together, and so the second
mechanism is driven only if the first one is enabled, but it is wrong:
even without the power save feature being configured in the wlan
firmware, there are cases where the wake up and clock registers need to
be written correctly, otherwise the chip stays unresponsive. The
downstream driver seems to acknowledge this issue, since the flag
matching the first feature has been completely removed.
Decouple those two features by removing the condition on the powersave
flag in acquire_bus/release_bus to make sure that the wakeup/allow_sleep
registers are actually written when the passed enums
(WILC_BUS_ACQUIRE_AND_WAKEUP, WILC_BUS_RELEASE_ALLOW_SLEEP) explicitly
require those writes.
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index a697caf73ac3ed06602c029c17773f50e3f8edb5..1031f8153c76ca5761c1e91d03ba357a5c915774 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -748,7 +748,7 @@ int acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
int ret = 0;
mutex_lock(&wilc->hif_cs);
- if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode) {
+ if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP) {
ret = chip_wakeup(wilc);
if (ret)
mutex_unlock(&wilc->hif_cs);
@@ -761,7 +761,7 @@ int release_bus(struct wilc *wilc, enum bus_release release)
{
int ret = 0;
- if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode)
+ if (release == WILC_BUS_RELEASE_ALLOW_SLEEP)
ret = chip_allow_sleep(wilc);
mutex_unlock(&wilc->hif_cs);
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 06/12] wifi: wilc1000: remove timeout parameter from set_power_mgmt
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (4 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 05/12] wifi: wilc1000: do not depend on power save flag to wake up chip Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 15:46 ` [PATCH 07/12] wifi: wilc1000: reorganize makefile objs into sorted list Alexis Lothoré
` (6 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
While the timeout parameter is part for the cfg80211 ops set_power_mgmt,
wilc currently does not uses it (it processes only the boolean value).
Remove the unused parameter from the driver-specific function.
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
drivers/net/wireless/microchip/wilc1000/cfg80211.c | 2 +-
drivers/net/wireless/microchip/wilc1000/hif.c | 2 +-
drivers/net/wireless/microchip/wilc1000/hif.h | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index 393fff618f919c5a6d3f4a7d894b187399455fb8..ff8c1a40634cee9960777eb017f6b2905e6399a5 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1348,7 +1348,7 @@ static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
if (!priv->hif_drv)
return -EIO;
- wilc_set_power_mgmt(vif, enabled, timeout);
+ wilc_set_power_mgmt(vif, enabled);
return 0;
}
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c
index bba53307b960d996032f56affead0cd0922902a4..3b14d560bc295844d873ed966592f031f6b50206 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.c
+++ b/drivers/net/wireless/microchip/wilc1000/hif.c
@@ -1932,7 +1932,7 @@ int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
return result;
}
-int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled)
{
struct wilc *wilc = vif->wilc;
struct wid wid;
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h
index 96eeaf31d23777e0392699240479b341529bfd42..5ecf6ba293a598823d09de43b597f8d54d375a7c 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.h
+++ b/drivers/net/wireless/microchip/wilc1000/hif.h
@@ -192,7 +192,7 @@ int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]);
int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr);
int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
struct station_parameters *params);
-int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
+int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled);
int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
u8 *mc_list);
int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan,
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 07/12] wifi: wilc1000: reorganize makefile objs into sorted list
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (5 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 06/12] wifi: wilc1000: remove timeout parameter from set_power_mgmt Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 15:46 ` [PATCH 08/12] wifi: wilc1000: add basic functions to allow bluetooth bringup Alexis Lothoré
` (5 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
Put one object per line and sort them by alphabetical order
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
drivers/net/wireless/microchip/wilc1000/Makefile | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/Makefile b/drivers/net/wireless/microchip/wilc1000/Makefile
index c3c9e34c1eaa93e7f6f13c6e4701f800408e8f89..9a2602b4a1494309ba06e4b553a8fc76a3f5433e 100644
--- a/drivers/net/wireless/microchip/wilc1000/Makefile
+++ b/drivers/net/wireless/microchip/wilc1000/Makefile
@@ -1,8 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_WILC1000) += wilc1000.o
-wilc1000-objs := cfg80211.o netdev.o mon.o \
- hif.o wlan_cfg.o wlan.o
+wilc1000-objs := \
+ cfg80211.o \
+ hif.o \
+ mon.o \
+ netdev.o \
+ wlan.o \
+ wlan_cfg.o
+
obj-$(CONFIG_WILC1000_SDIO) += wilc1000-sdio.o
wilc1000-sdio-objs += sdio.o
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 08/12] wifi: wilc1000: add basic functions to allow bluetooth bringup
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (6 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 07/12] wifi: wilc1000: reorganize makefile objs into sorted list Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 15:46 ` [PATCH 09/12] wifi: wilc1000: disable firmware power save if bluetooth is in use Alexis Lothoré
` (4 subsequent siblings)
12 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
Despite using a dedicated uart bus as main interface for bluetooth
operations, WILC3000 needs some initialization to be done over the wlan
bus (either SPI or SDIO) before being able to process HCI commands.
Those operations mostly consists in:
- some internal registers configuration
- a bluetooth firmware download
- bluetooth firmware start
Some of those operations also need to consider whether wlan is running
or not (eg: some coex registers need to be explicitly written if wlan
is not already running)
Add two set of APIs to fulfill those needs:
- two getters (one for sdio, one for spi) to allow retrieving an opaque
handle on wilc structure
- some init/shutdown APIs, consuming this opaque wilc struct and
actually performing the needed bluetooth initialization steps
The new code in charge of bluetooth initialization is driven by a
dedicated Kconfig, which will be selected by the new bluetooth driver
Kconfig coming in the next commits. The wilc driver then exposes a few
new functions to allow the future bluetooth driver to request the chip
initialization:
- wilc_<sdio|spi>_get_by_phandle : returns an opaque handle on the wilc
structure
- wilc_bt_init: use the handle returned previously and request bluetooth
initialization
- wilc_put: once done, give back the handle
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
The bluetooth init sequence is heavily inspired from Microchip
downstream kernel, see [1]. While the downstream kernel relies on user
to trigger the bluetooth init sequence (through a chardev), this version
is autonomous and supposed to be triggered by the actual bluetooth
driver in the next commits.
[1] https://github.com/linux4microchip/linux/blob/linux-6.6-mchp/drivers/net/wireless/microchip/wilc1000/bt.c
---
drivers/net/wireless/microchip/wilc1000/Kconfig | 3 +
drivers/net/wireless/microchip/wilc1000/Makefile | 1 +
drivers/net/wireless/microchip/wilc1000/bt.c | 322 +++++++++++++++++++++++
drivers/net/wireless/microchip/wilc1000/netdev.c | 9 +
drivers/net/wireless/microchip/wilc1000/sdio.c | 33 +++
drivers/net/wireless/microchip/wilc1000/spi.c | 25 ++
drivers/net/wireless/microchip/wilc1000/wlan.h | 17 ++
include/net/wilc.h | 19 ++
8 files changed, 429 insertions(+)
diff --git a/drivers/net/wireless/microchip/wilc1000/Kconfig b/drivers/net/wireless/microchip/wilc1000/Kconfig
index 62cfcdc9aacc007893db85840b5a3a8d11b7ac07..8e7b072a9882094d60ea0d8f85f9df171957cedb 100644
--- a/drivers/net/wireless/microchip/wilc1000/Kconfig
+++ b/drivers/net/wireless/microchip/wilc1000/Kconfig
@@ -46,3 +46,6 @@ config WILC1000_HW_OOB_INTR
mechanism for SDIO host controllers that don't support SDIO interrupt.
Select this option If the SDIO host controller in your platform
doesn't support SDIO time division interrupt.
+
+config WILC_BT
+ bool
diff --git a/drivers/net/wireless/microchip/wilc1000/Makefile b/drivers/net/wireless/microchip/wilc1000/Makefile
index 9a2602b4a1494309ba06e4b553a8fc76a3f5433e..4eb510eedd91e92932e4d611b16a6088d3e3b987 100644
--- a/drivers/net/wireless/microchip/wilc1000/Makefile
+++ b/drivers/net/wireless/microchip/wilc1000/Makefile
@@ -9,6 +9,7 @@ wilc1000-objs := \
wlan.o \
wlan_cfg.o
+wilc1000-$(CONFIG_WILC_BT) += bt.o
obj-$(CONFIG_WILC1000_SDIO) += wilc1000-sdio.o
wilc1000-sdio-objs += sdio.o
diff --git a/drivers/net/wireless/microchip/wilc1000/bt.c b/drivers/net/wireless/microchip/wilc1000/bt.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0f68a5479a5bd6f70e2390a35512037dc6c332b
--- /dev/null
+++ b/drivers/net/wireless/microchip/wilc1000/bt.c
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/dev_printk.h>
+#include <linux/mutex.h>
+#include <linux/firmware.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <net/wilc.h>
+#include "netdev.h"
+#include "wlan_if.h"
+#include "wlan.h"
+
+#define FW_WILC3000_BLE "mchp/wilc3000_ble_firmware.bin"
+
+static int wilc_bt_power_down(struct wilc *wilc)
+{
+ int ret;
+
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc, GLOBAL_MODE_CONTROL, BIT(1), 0);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to disable BT mode\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return ret;
+ }
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc, COE_AUTO_PS_ON_NULL_PKT,
+ BIT(30), 0);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to disable awake coexistence null frames\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return ret;
+ }
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc, COE_AUTO_PS_OFF_NULL_PKT,
+ BIT(30), 0);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to disable doze coexistence null frames\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return ret;
+ }
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc, PWR_SEQ_MISC_CTRL, BIT(29), 0);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to disable bluetooth wake-up\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return ret;
+ }
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+
+ if (!wilc->initialized) {
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ ret = wilc->hif_func->hif_deinit(wilc);
+ release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ }
+
+ return 0;
+}
+
+static int wilc_bt_power_up(struct wilc *wilc)
+{
+ int ret;
+
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (!wilc->initialized) {
+ ret = wilc->hif_func->hif_rmw_reg(wilc, COE_AUTO_PS_ON_NULL_PKT,
+ BIT(30), 0);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to disable awake coexistence null frames\n");
+ goto fail;
+ }
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc,
+ COE_AUTO_PS_OFF_NULL_PKT, BIT(30), 0);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to disable awake coexistence null frames\n");
+ goto fail;
+ }
+ }
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc, PWR_SEQ_MISC_CTRL, BIT(29),
+ BIT(29));
+ if (ret) {
+ dev_err(wilc->dev, "Failed to enable bluetooth wake-up\n");
+ goto fail;
+ }
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+
+ return 0;
+
+fail:
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ wilc_bt_power_down(wilc);
+ return ret;
+}
+
+static int wilc_bt_firmware_download(struct wilc *wilc)
+{
+ const struct firmware *wilc_bt_firmware;
+ u32 addr, size, size2, blksz;
+ size_t buffer_size;
+ const u8 *buffer;
+ u8 *dma_buffer;
+ u32 offset;
+ int ret = 0;
+
+ dev_info(wilc->dev, "Bluetooth firmware: %s\n", FW_WILC3000_BLE);
+ ret = request_firmware(&wilc_bt_firmware, FW_WILC3000_BLE, wilc->dev);
+ if (ret) {
+ dev_err(wilc->dev, "%s - firmware not available. Skip!\n",
+ FW_WILC3000_BLE);
+ return ret;
+ }
+
+ buffer = wilc_bt_firmware->data;
+ buffer_size = (size_t)wilc_bt_firmware->size;
+ if (buffer_size <= 0) {
+ dev_err(wilc->dev, "Firmware size = 0!\n");
+ ret = -EINVAL;
+ goto out_release_firmware;
+ }
+
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_BT_BOOTROM_CONFIGURATION,
+ WILC_BT_BOOTROM_DISABLE);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to disable BT bootrom\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ goto out_release_firmware;
+ }
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_BT_RESET_MUX,
+ WILC_BT_ENABLE_GLOBAL_RESET,
+ WILC_BT_ENABLE_GLOBAL_RESET);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to configure reset for BT CPU\n");
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ goto out_release_firmware;
+ }
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_BT_CPU_CONFIGURATION,
+ WILC_BT_CPU_ENABLE,
+ WILC_BT_CPU_ENABLE);
+ if (!ret)
+ ret = wilc->hif_func->hif_rmw_reg(wilc,
+ WILC_BT_CPU_CONFIGURATION,
+ WILC_BT_CPU_ENABLE, 0);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to disable BT CPU\n");
+ goto out_release_firmware;
+ }
+
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+
+ /* blocks of sizes > 512 causes the wifi to hang! */
+ blksz = (1ul << 9);
+ /* Allocate a DMA coherent buffer. */
+ dma_buffer = kmalloc(blksz, GFP_KERNEL);
+ if (!dma_buffer) {
+ ret = -ENOMEM;
+ dev_err(wilc->dev,
+ "Can't allocate buffer for BT firmware download\n");
+ goto out_free_buffer;
+ }
+ dev_info(wilc->dev, "Downloading BT firmware size = %zu ...\n",
+ buffer_size);
+
+ offset = 0;
+ addr = WILC_BT_IRAM;
+ size = buffer_size;
+ offset = 0;
+
+ while (((int)size) && (offset < buffer_size)) {
+ if (size <= blksz)
+ size2 = size;
+ else
+ size2 = blksz;
+
+ /* Copy firmware into a DMA coherent buffer */
+ memcpy(dma_buffer, &buffer[offset], size2);
+
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+
+ ret = wilc->hif_func->hif_block_tx(wilc, addr, dma_buffer,
+ size2);
+
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+
+ if (ret)
+ break;
+
+ addr += size2;
+ offset += size2;
+ size -= size2;
+ }
+
+ if (ret) {
+ dev_err(wilc->dev, "Failed to download BT firmware\n");
+ goto out_free_buffer;
+ }
+ dev_info(wilc->dev, "Finished downloading firmware\n");
+
+out_free_buffer:
+ kfree(dma_buffer);
+out_release_firmware:
+ release_firmware(wilc_bt_firmware);
+return ret;
+}
+
+static int wilc_bt_start(struct wilc *wilc)
+{
+ int ret;
+
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+
+ dev_info(wilc->dev, "Starting BT firmware\n");
+ /*
+ * Write the firmware download complete magic at
+ * location 0xFFFF000C (Cortus map) or C000C (AHB map).
+ * This will let the boot-rom code execute from RAM.
+ */
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC_BT_FW_MAGIC_LOC,
+ WILC_BT_FW_MAGIC);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to write BT firmware magic\n");
+ return ret;
+ }
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_BT_CPU_CONFIGURATION,
+ WILC_BT_CPU_BOOT, 0);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to disable BT CPU");
+ return ret;
+ }
+
+ msleep(100);
+
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_BT_CPU_CONFIGURATION,
+ WILC_BT_CPU_BOOT, WILC_BT_CPU_BOOT);
+ if (ret) {
+ dev_err(wilc->dev, "Failed to enable BT CPU");
+ return ret;
+ }
+ /* An additional wait to give BT firmware time to do
+ * CPLL update as the time measured since the start of
+ * BT FW till the end of function "rf_nmi_init_tuner"
+ * was 71.2 ms
+ */
+ msleep(100);
+
+ dev_info(wilc->dev, "BT Start Succeeded\n");
+
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+
+ return 0;
+}
+
+int wilc_bt_init(void *wilc_wl_priv)
+{
+ struct wilc *wilc = (struct wilc *)wilc_wl_priv;
+ int ret;
+
+ if (!wilc->hif_func->hif_is_init(wilc)) {
+ dev_info(wilc->dev, "Initializing bus before starting BT");
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ ret = wilc->hif_func->hif_init(wilc, false);
+ release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ if (ret)
+ return ret;
+ }
+
+ mutex_lock(&wilc->radio_fw_start);
+ ret = wilc_bt_power_up(wilc);
+ if (ret) {
+ dev_err(wilc->dev, "Error powering up bluetooth chip\n");
+ goto hif_deinit;
+ }
+ ret = wilc_bt_firmware_download(wilc);
+ if (ret) {
+ dev_err(wilc->dev, "Error downloading firmware\n");
+ goto power_down;
+ }
+ ret = wilc_bt_start(wilc);
+ if (ret) {
+ dev_err(wilc->dev, "Error starting bluetooth firmware\n");
+ goto power_down;
+ }
+ mutex_unlock(&wilc->radio_fw_start);
+ return 0;
+
+power_down:
+ wilc_bt_power_down(wilc);
+hif_deinit:
+ mutex_unlock(&wilc->radio_fw_start);
+ if (!wilc->initialized)
+ wilc->hif_func->hif_deinit(wilc);
+ return ret;
+}
+EXPORT_SYMBOL(wilc_bt_init);
+
+int wilc_bt_shutdown(void *wilc_wl_priv)
+{
+ struct wilc *wilc = (struct wilc *)wilc_wl_priv;
+ int ret;
+
+ mutex_lock(&wilc->radio_fw_start);
+ ret = wilc->hif_func->hif_rmw_reg(wilc, WILC_BT_CPU_CONFIGURATION,
+ WILC_BT_CPU_ENABLE, 0);
+ if (ret)
+ dev_warn(wilc->dev, "Failed to disable BT CPU\n");
+ if (wilc_bt_power_down(wilc))
+ dev_warn(wilc->dev, "Failed to power down BT CPU\n");
+ if (!wilc->initialized)
+ wilc->hif_func->hif_deinit(wilc);
+ mutex_unlock(&wilc->radio_fw_start);
+
+ return 0;
+}
+EXPORT_SYMBOL(wilc_bt_shutdown);
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c
index d24859d12ccd535c966a9b7f46378ac3b3a21d7b..2f1f68b2156a937a240167d820603ff708507401 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.c
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.c
@@ -10,6 +10,7 @@
#include <linux/firmware.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
+#include <net/wilc.h>
#include "cfg80211.h"
#include "wlan_cfg.h"
@@ -1024,6 +1025,14 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
}
EXPORT_SYMBOL_GPL(wilc_netdev_ifc_init);
+void wilc_put(void *wilc_wl_priv)
+{
+ struct wilc *wilc = (struct wilc *)wilc_wl_priv;
+
+ put_device(wilc->dev);
+}
+EXPORT_SYMBOL_GPL(wilc_put);
+
MODULE_DESCRIPTION("Atmel WILC1000 core wireless driver");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER));
diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c
index 7eab1c493774e197e43bdf265063aa8c5e6dff14..78789682f145aa06f30d274efc75805e583c0b43 100644
--- a/drivers/net/wireless/microchip/wilc1000/sdio.c
+++ b/drivers/net/wireless/microchip/wilc1000/sdio.c
@@ -5,11 +5,16 @@
*/
#include <linux/clk.h>
+#include "linux/device.h"
+#include "linux/device/driver.h"
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio.h>
#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <net/wilc.h>
#include "netdev.h"
#include "cfg80211.h"
@@ -1072,5 +1077,33 @@ static struct sdio_driver wilc_sdio_driver = {
};
module_sdio_driver(wilc_sdio_driver);
+static int find_wilc_device(struct device *dev, const void *data)
+{
+ struct device_node *target_node = (struct device_node *)data;
+ struct sdio_func *func = container_of(dev, struct sdio_func, dev);
+
+ return func->card->dev.of_node == target_node ? 1 : 0;
+}
+
+void *wilc_sdio_get_byphandle(struct device_node *wlan_node)
+{
+ struct wilc *wilc;
+ struct device *wilc_dev;
+
+ /* Search in devices bound to the driver if any has a device_node
+ * matching the targeted one
+ */
+ wilc_dev = driver_find_device(&wilc_sdio_driver.drv, NULL,
+ (void *)wlan_node, find_wilc_device);
+ if (!wilc_dev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ get_device(wilc_dev);
+ wilc = (struct wilc *)dev_get_drvdata(wilc_dev);
+
+ return wilc;
+}
+EXPORT_SYMBOL(wilc_sdio_get_byphandle);
+
MODULE_DESCRIPTION("Atmel WILC1000 SDIO wireless driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index aae4262045ff3e5f3668493ef235486e601996f7..93082de3d6ba4cf545a3ec741d8ed16c5372d69b 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -4,11 +4,16 @@
* All rights reserved.
*/
+#include "linux/device/driver.h"
+#include "linux/of.h"
+#include "linux/of_platform.h"
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/crc7.h>
#include <linux/crc-itu-t.h>
#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <net/wilc.h>
#include "netdev.h"
#include "cfg80211.h"
@@ -1390,3 +1395,23 @@ static const struct wilc_hif_func wilc_hif_spi = {
.hif_is_init = wilc_spi_is_init,
.hif_rmw_reg = wilc_spi_rmw_reg
};
+
+void *wilc_spi_get_byphandle(struct device_node *wlan_node)
+{
+ struct wilc *wilc;
+ struct device *wilc_dev;
+
+ /* Search in devices bound to the driver if any has a device_node
+ * matching the targeted one
+ */
+ wilc_dev = driver_find_device_by_of_node(&wilc_spi_driver.driver,
+ wlan_node);
+ if (!wilc_dev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ get_device(wilc_dev);
+ wilc = (struct wilc *)dev_get_drvdata(wilc_dev);
+
+ return wilc;
+}
+EXPORT_SYMBOL(wilc_spi_get_byphandle);
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h
index e45c2db0f5cd2de6844993dde15034ebbd93e73b..74381f81e3f236cc55d3af3e7906ed7fb7d790ed 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.h
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.h
@@ -116,6 +116,21 @@
#define WILC_SPI_CLOCKLESS_ADDR_LIMIT 0x30
+#define WILC_BT_RESET_MUX 0x3b0090
+#define WILC_BT_ENABLE_GLOBAL_RESET BIT(0)
+
+#define WILC_BT_CPU_CONFIGURATION 0x3b0400
+#define WILC_BT_CPU_ENABLE BIT(2)
+#define WILC_BT_CPU_BOOT (BIT(3) | WILC_BT_CPU_ENABLE)
+
+#define WILC_BT_IRAM 0x400000
+
+#define WILC_BT_BOOTROM_CONFIGURATION 0x4f0000
+#define WILC_BT_BOOTROM_DISABLE 0x71
+
+#define WILC_BT_FW_MAGIC_LOC 0x4f000c
+#define WILC_BT_FW_MAGIC 0x10add09e
+
/* Functions IO enables bits */
#define WILC_SDIO_CCCR_IO_EN_FUNC1 BIT(1)
@@ -174,6 +189,8 @@
#define GLOBAL_MODE_CONTROL 0x1614
#define PWR_SEQ_MISC_CTRL 0x3008
+#define COE_AUTO_PS_ON_NULL_PKT 0x160468
+#define COE_AUTO_PS_OFF_NULL_PKT 0x16046C
#define WILC_GLOBAL_MODE_ENABLE_WIFI BIT(0)
#define WILC_PWR_SEQ_ENABLE_WIFI_SLEEP BIT(28)
diff --git a/include/net/wilc.h b/include/net/wilc.h
new file mode 100644
index 0000000000000000000000000000000000000000..60c69d4d8442907c05e644ecd646b24ccd161f47
--- /dev/null
+++ b/include/net/wilc.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __WILC_HEADER_H
+#define __WILC_HEADER_H
+
+#include <linux/of.h>
+
+#if defined(CONFIG_WILC1000_SDIO) || defined(CONFIG_WILC1000_SDIO_MODULE)
+void *wilc_sdio_get_byphandle(struct device_node *wlan_node);
+#endif
+#if defined(CONFIG_WILC1000_SPI) || defined(CONFIG_WILC1000_SPI_MODULE)
+void *wilc_spi_get_byphandle(struct device_node *wlan_node);
+#endif
+void wilc_put(void *wilc_wl_priv);
+
+int wilc_bt_init(void *wilc_wl_priv);
+int wilc_bt_shutdown(void *wilc_wl_priv);
+
+#endif
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 09/12] wifi: wilc1000: disable firmware power save if bluetooth is in use
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (7 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 08/12] wifi: wilc1000: add basic functions to allow bluetooth bringup Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-16 16:07 ` Simon Horman
2025-02-12 15:46 ` [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver Alexis Lothoré
` (3 subsequent siblings)
12 siblings, 1 reply; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
If the wlan interface exposed by wilc driver has power save enabled
(either explicitly with iw dev wlan set power_save on, or because
kernel is built with CONFIG_CFG80211_DEFAULT_PS), it will send a power
management command to the wlan firmware when corresponding interface is
brought up. The bluetooth part, if used, is supposed to work
independently from the WLAN CPU. Unfortunately, this power save
management, if applied by the WLAN side, disrupts bluetooth operations
(the bluetooth CPU does not answer any command anymore on the UART
interface)
Make sure that the bluetooth part can work independently by disabling
power save in wlan firmware when bluetooth is in use.
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
drivers/net/wireless/microchip/wilc1000/bt.c | 29 +++++++++++++++++++---
drivers/net/wireless/microchip/wilc1000/cfg80211.c | 5 +++-
drivers/net/wireless/microchip/wilc1000/netdev.h | 3 +++
3 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/bt.c b/drivers/net/wireless/microchip/wilc1000/bt.c
index b0f68a5479a5bd6f70e2390a35512037dc6c332b..f0eb5fb506eddf0f6f4f3f0b182eaa650c1c7a87 100644
--- a/drivers/net/wireless/microchip/wilc1000/bt.c
+++ b/drivers/net/wireless/microchip/wilc1000/bt.c
@@ -7,6 +7,7 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <net/wilc.h>
+#include "cfg80211.h"
#include "netdev.h"
#include "wlan_if.h"
#include "wlan.h"
@@ -261,22 +262,36 @@ static int wilc_bt_start(struct wilc *wilc)
int wilc_bt_init(void *wilc_wl_priv)
{
struct wilc *wilc = (struct wilc *)wilc_wl_priv;
+ struct wilc_vif *vif;
int ret;
+ wilc->bt_enabled = true;
+
if (!wilc->hif_func->hif_is_init(wilc)) {
dev_info(wilc->dev, "Initializing bus before starting BT");
acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
ret = wilc->hif_func->hif_init(wilc, false);
release_bus(wilc, WILC_BUS_RELEASE_ONLY);
- if (ret)
+ if (ret) {
+ wilc->bt_enabled = false;
return ret;
+ }
}
+ /* Power save feature managed by WLAN firmware may disrupt
+ * operations from the bluetooth CPU, so disable it while bluetooth
+ * is in use (if enabled, it will be enabled back when bluetooth is
+ * not used anymore)
+ */
+ vif = wilc_get_wl_to_vif(wilc);
+ if (wilc->power_save_mode && wilc_set_power_mgmt(vif, false))
+ goto hif_deinit;
+
mutex_lock(&wilc->radio_fw_start);
ret = wilc_bt_power_up(wilc);
if (ret) {
dev_err(wilc->dev, "Error powering up bluetooth chip\n");
- goto hif_deinit;
+ goto reenable_power_save;
}
ret = wilc_bt_firmware_download(wilc);
if (ret) {
@@ -293,10 +308,14 @@ int wilc_bt_init(void *wilc_wl_priv)
power_down:
wilc_bt_power_down(wilc);
-hif_deinit:
+reenable_power_save:
+ if (wilc->power_save_mode_request)
+ wilc_set_power_mgmt(vif, true);
mutex_unlock(&wilc->radio_fw_start);
+hif_deinit:
if (!wilc->initialized)
wilc->hif_func->hif_deinit(wilc);
+ wilc->bt_enabled = false;
return ret;
}
EXPORT_SYMBOL(wilc_bt_init);
@@ -304,6 +323,7 @@ EXPORT_SYMBOL(wilc_bt_init);
int wilc_bt_shutdown(void *wilc_wl_priv)
{
struct wilc *wilc = (struct wilc *)wilc_wl_priv;
+ struct wilc_vif *vif;
int ret;
mutex_lock(&wilc->radio_fw_start);
@@ -313,6 +333,9 @@ int wilc_bt_shutdown(void *wilc_wl_priv)
dev_warn(wilc->dev, "Failed to disable BT CPU\n");
if (wilc_bt_power_down(wilc))
dev_warn(wilc->dev, "Failed to power down BT CPU\n");
+ vif = wilc_get_wl_to_vif(wilc);
+ if (wilc->power_save_mode_request && wilc_set_power_mgmt(vif, true))
+ dev_warn(wilc->dev, "Failed to set back wlan power save\n");
if (!wilc->initialized)
wilc->hif_func->hif_deinit(wilc);
mutex_unlock(&wilc->radio_fw_start);
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index ff8c1a40634cee9960777eb017f6b2905e6399a5..04cff3561aad847a3f58a09766d0ef0fa61603e0 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1344,11 +1344,14 @@ static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc_priv *priv = &vif->priv;
+ struct wilc *wilc = vif->wilc;
if (!priv->hif_drv)
return -EIO;
- wilc_set_power_mgmt(vif, enabled);
+ wilc->power_save_mode_request = enabled;
+ if (!wilc->bt_enabled)
+ wilc_set_power_mgmt(vif, enabled);
return 0;
}
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h
index 5837f8ffe548dad1b756cdbd8543636f2be0e9b0..4c297eb95eeb143fc2f1248e616ee307afa52dbd 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.h
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.h
@@ -213,6 +213,7 @@ struct wilc {
struct clk *rtc_clk;
bool initialized;
u32 chipid;
+ bool power_save_mode_request;
bool power_save_mode;
int dev_irq_num;
int close;
@@ -289,6 +290,8 @@ struct wilc {
u8 nv_mac_address[ETH_ALEN];
/* Lock to prevent concurrent start of wlan/bluetooth firmware */
struct mutex radio_fw_start;
+ /* Is the bluetooth part in use ? */
+ bool bt_enabled;
};
struct wilc_wfi_mon_priv {
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (8 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 09/12] wifi: wilc1000: disable firmware power save if bluetooth is in use Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 16:14 ` Luiz Augusto von Dentz
2025-02-13 9:24 ` Krzysztof Kozlowski
2025-02-12 15:46 ` [PATCH 11/12] ARM: dts: at91-sama5d27_wlsom1: update bluetooth chip description Alexis Lothoré
` (2 subsequent siblings)
12 siblings, 2 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
WILC3000 is a combo chip providing 802.11b/g/n and Bluetooth 5.0
capabilities. The wifi side is used either over SDIO or SPI, and the
bluetooth side is used over uart, with standard hci. The wifi side is
already supported by Linux.
Add a dedicated bluetooth driver to support the bluetooth feature from
wilc3000 chip. Similarly to other supported bluetooth chips, wilc
devices need a firmware to be uploaded before being able to use
bluetooth. However, the major difference is that the firmware needs to
be uploaded through the wifi bus (SDIO or SPI). This constraint makes
this new driver depends on the corresponding wilc wlan driver for the
bluetooth setup. Once the basic BT initialization has been performed,
both side can be used independently, and in parallel.
Since this creates a dependency to some wlan driver, create a dedicated
module (hci_wilc) rather than integrating wilc bluetooth support in
hci_uart, to avoid propagating this dependency.
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
drivers/bluetooth/Kconfig | 13 ++
drivers/bluetooth/Makefile | 3 +-
drivers/bluetooth/hci_uart.h | 1 +
drivers/bluetooth/hci_wilc.c | 333 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 349 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 4ab32abf0f48644715d4c27ec0d2fdaccef62b76..a96607fb0cc8fed2ccb1811a4b1b4fe586396b07 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -147,6 +147,19 @@ config BT_HCIUART_NOKIA
Say Y here to compile support for Nokia's H4+ protocol.
+config BT_HCIUART_WILC
+ tristate "WILC protocol support"
+ depends on (WILC1000_SDIO || WILC1000_SPI)
+ select WILC_BT
+ depends on BT_HCIUART
+ depends on BT_HCIUART_SERDEV
+ select BT_HCIUART_H4
+ help
+ The WILC uart protocol allows interacting with wilc3000 chips
+ with HCI over UART. The bluetooth firmware needs to be uploaded
+ to the chip through the main bus, so this driver needs the
+ corresponding wlan driver.
+
config BT_HCIUART_BCSP
bool "BCSP protocol support"
depends on BT_HCIUART
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 81856512ddd030ba8172ff106b80b4b951188cbd..a1e69884acf4ce91f02ff5592541616048b07e31 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -35,10 +35,11 @@ obj-$(CONFIG_BT_NXPUART) += btnxpuart.o
obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
obj-$(CONFIG_BT_HCIRSI) += btrsi.o
-
btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
+obj-$(CONFIG_BT_HCIUART_WILC) += hci_wilc.o
+
hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_SERDEV) += hci_serdev.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index fbf3079b92a5339154f8847ff36b3c08ef49e2bb..83fc48be4335e0946853fdec32c38bf2fb195009 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -35,6 +35,7 @@
#define HCI_UART_NOKIA 10
#define HCI_UART_MRVL 11
#define HCI_UART_AML 12
+#define HCI_UART_WILC 13
#define HCI_UART_RAW_DEVICE 0
#define HCI_UART_RESET_ON_INIT 1
diff --git a/drivers/bluetooth/hci_wilc.c b/drivers/bluetooth/hci_wilc.c
new file mode 100644
index 0000000000000000000000000000000000000000..97dc4620c74ef0733469839adda7890bda90406e
--- /dev/null
+++ b/drivers/bluetooth/hci_wilc.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Bluetooth HCI UART driver for WILC devices
+ *
+ */
+#include "linux/bitops.h"
+#include "linux/byteorder/generic.h"
+#include "linux/err.h"
+#include "linux/gfp_types.h"
+#include "net/bluetooth/bluetooth.h"
+#include "net/bluetooth/hci.h"
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/of.h>
+#include <linux/serdev.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/wilc.h>
+
+#include "hci_uart.h"
+
+#define WILC_BT_UART_MANUFACTURER 205
+#define WILC_UART_DEFAULT_BAUDRATE 115200
+#define WILC_UART_BAUDRATE 460800
+
+#define HCI_VERSION_BOOTROM 0xFF
+#define HCI_VERSION_FIRMWARE 0x06
+
+#define HCI_VENDOR_CMD_WRITE_MEM 0xFC52
+#define HCI_VENDOR_CMD_UPDATE_UART 0xFC53
+#define HCI_VENDOR_CMD_UPDATE_ADDR 0xFC54
+#define HCI_VENDOR_CMD_RESET 0xFC55
+#define HCI_VENDOR_CMD_READ_REG 0xFC01
+
+struct wilc_adapter {
+ struct hci_uart hu;
+ struct device *dev;
+ void *wlan_priv;
+ bool flow_control;
+};
+
+struct wilc_data {
+ struct sk_buff *rx_skb;
+ struct sk_buff_head txq;
+};
+
+struct hci_update_uart_param {
+ __le32 baudrate;
+ __u8 flow_control;
+} __packed;
+
+static int wilc_open(struct hci_uart *hu)
+{
+ struct wilc_data *wdata;
+
+ BT_DBG("hci_wilc: open");
+ wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
+ if (!wdata)
+ return -ENOMEM;
+ skb_queue_head_init(&wdata->txq);
+ hu->priv = wdata;
+
+ return 0;
+}
+
+static int wilc_close(struct hci_uart *hu)
+{
+ struct wilc_data *wdata = hu->priv;
+
+ BT_DBG("hci_wilc: close");
+ skb_queue_purge(&wdata->txq);
+ kfree_skb(wdata->rx_skb);
+ kfree(wdata);
+ hu->priv = NULL;
+ return 0;
+}
+
+static int wilc_flush(struct hci_uart *hu)
+{
+ struct wilc_data *wdata = hu->priv;
+
+ BT_DBG("hci_wilc: flush");
+ skb_queue_purge(&wdata->txq);
+ return 0;
+}
+
+static const struct h4_recv_pkt wilc_bt_recv_pkts[] = {
+ { H4_RECV_ACL, .recv = hci_recv_frame },
+ { H4_RECV_SCO, .recv = hci_recv_frame },
+ { H4_RECV_EVENT, .recv = hci_recv_frame },
+};
+
+static int wilc_recv(struct hci_uart *hu, const void *data, int len)
+{
+ struct wilc_data *wdata = hu->priv;
+ int err;
+
+ if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
+ return -EUNATCH;
+ wdata->rx_skb = h4_recv_buf(hu->hdev, wdata->rx_skb, data, len,
+ wilc_bt_recv_pkts,
+ ARRAY_SIZE(wilc_bt_recv_pkts));
+ if (IS_ERR(wdata->rx_skb)) {
+ err = PTR_ERR(wdata->rx_skb);
+ bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
+ wdata->rx_skb = NULL;
+ }
+
+ return len;
+}
+
+static int wilc_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+ struct wilc_data *wdata = hu->priv;
+
+ BT_DBG("hci_wilc: enqueue skb %pK", skb);
+ memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
+ skb_queue_tail(&wdata->txq, skb);
+ return 0;
+}
+
+static struct sk_buff *wilc_dequeue(struct hci_uart *hu)
+{
+ struct wilc_data *wdata = hu->priv;
+
+ BT_DBG("hci_wilc: dequeue skb");
+ return skb_dequeue(&wdata->txq);
+}
+
+static int _set_uart_settings(struct hci_uart *hu, unsigned int speed,
+ bool flow_control)
+{
+ struct hci_update_uart_param param;
+ int ret;
+
+ param.baudrate = cpu_to_le32(speed);
+ param.flow_control = flow_control ? 1 : 0;
+ ret = __hci_cmd_sync_status(hu->hdev, HCI_VENDOR_CMD_UPDATE_UART,
+ sizeof(param), ¶m, HCI_CMD_TIMEOUT);
+ if (ret) {
+ BT_ERR("Failed to update UART settings");
+ return ret;
+ }
+
+ serdev_device_set_baudrate(hu->serdev, speed);
+ serdev_device_set_flow_control(hu->serdev, flow_control);
+
+ return 0;
+}
+
+static int wilc_set_baudrate(struct hci_uart *hu, unsigned int speed)
+{
+ struct wilc_adapter *wilc_adapter;
+
+ BT_INFO("WILC uart settings update request: speed=%d", speed);
+ wilc_adapter = serdev_device_get_drvdata(hu->serdev);
+
+ return _set_uart_settings(hu, speed, wilc_adapter->flow_control);
+}
+
+static int check_firmware_running(struct hci_uart *hu)
+{
+ struct hci_rp_read_local_version *version;
+ struct sk_buff *skb;
+ int ret = 0;
+
+ BT_DBG("Resetting bluetooth chip");
+ ret = __hci_cmd_sync_status(hu->hdev, HCI_OP_RESET, 0, NULL,
+ HCI_CMD_TIMEOUT);
+ if (ret) {
+ BT_ERR("Can not reset wilc");
+ return ret;
+ }
+
+ BT_DBG("Checking chip state");
+ skb = __hci_cmd_sync(hu->hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_CMD_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("Error while checking bootrom");
+ return PTR_ERR(skb);
+ }
+
+ if (skb->len != sizeof(struct hci_rp_read_local_version)) {
+ BT_ERR("Can not read local version");
+ return -1;
+ }
+ version = (struct hci_rp_read_local_version *)skb->data;
+ BT_DBG("Status: 0x%1X, HCI version: 0x%1X", version->status,
+ version->hci_ver);
+ kfree_skb(skb);
+ if (version->hci_ver != HCI_VERSION_FIRMWARE) {
+ BT_ERR("Bluetooth firmware is not running !");
+ if (version->hci_ver == HCI_VERSION_BOOTROM)
+ BT_WARN("Bootrom is running");
+ return 1;
+ }
+ BT_DBG("Firmware is running");
+ return 0;
+}
+
+static int wilc_setup(struct hci_uart *hu)
+{
+ struct wilc_adapter *wilc_adapter;
+ int ret;
+
+ BT_DBG("hci_wilc: setup");
+ serdev_device_set_baudrate(hu->serdev, WILC_UART_DEFAULT_BAUDRATE);
+ serdev_device_set_flow_control(hu->serdev, false);
+ ret = check_firmware_running(hu);
+ if (ret)
+ return ret;
+
+ BT_DBG("Updating firmware uart settings");
+
+ wilc_adapter = serdev_device_get_drvdata(hu->serdev);
+ ret = _set_uart_settings(&wilc_adapter->hu, WILC_UART_BAUDRATE, true);
+ if (ret) {
+ BT_ERR("Failed to reconfigure firmware uart settings");
+ return ret;
+ }
+ wilc_adapter->flow_control = true;
+
+ BT_INFO("Wilc successfully initialized");
+ return ret;
+}
+
+static const struct hci_uart_proto wilc_bt_proto = {
+ .id = HCI_UART_WILC,
+ .name = "Microchip",
+ .manufacturer = WILC_BT_UART_MANUFACTURER,
+ .init_speed = WILC_UART_DEFAULT_BAUDRATE,
+ .open = wilc_open,
+ .close = wilc_close,
+ .flush = wilc_flush,
+ .recv = wilc_recv,
+ .enqueue = wilc_enqueue,
+ .dequeue = wilc_dequeue,
+ .setup = wilc_setup,
+ .set_baudrate = wilc_set_baudrate,
+};
+
+static int wilc_bt_serdev_probe(struct serdev_device *serdev)
+{
+ struct wilc_adapter *wilc_adapter;
+ struct device_node *wlan_node;
+ void *wlan = NULL;
+ int ret;
+
+ wilc_adapter = kzalloc(sizeof(*wilc_adapter), GFP_KERNEL);
+ if (!wilc_adapter)
+ return -ENOMEM;
+
+ wlan_node = of_parse_phandle(serdev->dev.of_node, "wlan", 0);
+ if (!wlan_node) {
+ BT_ERR("Can not run wilc bluetooth without wlan node");
+ ret = -EINVAL;
+ goto exit_free_adapter;
+ }
+
+#if IS_ENABLED(CONFIG_WILC1000_SDIO)
+ wlan = wilc_sdio_get_byphandle(wlan_node);
+#endif
+#if IS_ENABLED(CONFIG_WILC1000_SPI)
+ if (!wlan || wlan == ERR_PTR(-EPROBE_DEFER))
+ wlan = wilc_spi_get_byphandle(wlan_node);
+#endif
+ if (IS_ERR(wlan)) {
+ pr_warn("Can not initialize bluetooth: %pe\n", wlan);
+ ret = PTR_ERR(wlan);
+ goto exit_put_wlan_node;
+ }
+
+ of_node_put(wlan_node);
+ wilc_adapter->wlan_priv = wlan;
+ ret = wilc_bt_init(wlan);
+ if (ret) {
+ pr_err("Failed to initialize bluetooth firmware (%d)\n", ret);
+ goto exit_put_wlan;
+ }
+
+ wilc_adapter->dev = &serdev->dev;
+ wilc_adapter->hu.serdev = serdev;
+ wilc_adapter->flow_control = false;
+ serdev_device_set_drvdata(serdev, wilc_adapter);
+ ret = hci_uart_register_device(&wilc_adapter->hu, &wilc_bt_proto);
+ if (ret) {
+ dev_err(&serdev->dev, "Failed to register hci device");
+ goto exit_deinit_bt;
+ }
+
+ dev_info(&serdev->dev, "WILC hci interface registered");
+ return 0;
+
+exit_deinit_bt:
+ wilc_bt_shutdown(wlan);
+exit_put_wlan:
+ wilc_put(wlan);
+exit_put_wlan_node:
+ of_node_put(wlan_node);
+exit_free_adapter:
+ kfree(wilc_adapter);
+ return ret;
+}
+
+static void wilc_bt_serdev_remove(struct serdev_device *serdev)
+{
+ struct wilc_adapter *wilc_adapter = serdev_device_get_drvdata(serdev);
+
+ hci_uart_unregister_device(&wilc_adapter->hu);
+ wilc_bt_shutdown(wilc_adapter->wlan_priv);
+ wilc_put(wilc_adapter->wlan_priv);
+ kfree(wilc_adapter);
+}
+
+static const struct of_device_id wilc_bt_of_match[] = {
+ { .compatible = "microchip,wilc3000-bt" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, wilc_bt_of_match);
+
+static struct serdev_device_driver wilc_bt_serdev_driver = {
+ .probe = wilc_bt_serdev_probe,
+ .remove = wilc_bt_serdev_remove,
+ .driver = {
+ .name = "hci_uart_wilc",
+ .of_match_table = of_match_ptr(wilc_bt_of_match),
+ },
+};
+
+module_serdev_device_driver(wilc_bt_serdev_driver)
+MODULE_AUTHOR("Alexis Lothoré <alexis.lothore@bootlin.com>");
+MODULE_DESCRIPTION("Bluetooth HCI Uart for WILC devices");
+MODULE_LICENSE("GPL");
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 11/12] ARM: dts: at91-sama5d27_wlsom1: update bluetooth chip description
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (9 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 15:46 ` [PATCH 12/12] MAINTAINERS: add entry for new wilc3000 bluetooth driver Alexis Lothoré
2025-02-12 22:08 ` [PATCH 00/12] bluetooth: hci_wilc: add new " Rob Herring (Arm)
12 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
The SAMA5D27 WLSOM1 plaftorm embeds a wilc3000 chip exposing 802.11b/g/n
and bluetooth 5. The current description for this chip does not expose
the bluetooth part: it only configures the relevant flexcom peripheral
to set it as uart, and relies on user to trigger the corresponding hci
device creation in kernel through hci_attach. Now that a bluetooth
driver is available and handles the device creation, replace the bare
uart description with a proper bluetooth node.
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi | 8 ++++++++
arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts | 10 ----------
2 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi
index ef11606a82b31c2f745141cdac1318805f473273..10d48a9ef92c9621a8885feebda6119d3f61af75 100644
--- a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi
+++ b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi
@@ -50,10 +50,18 @@ wifi_pwrseq: wifi_pwrseq {
&flx1 {
atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+ status = "okay";
uart6: serial@200 {
pinctrl-0 = <&pinctrl_flx1_default>;
pinctrl-names = "default";
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "okay";
+ bluetooth: bluetooth@0 {
+ compatible = "microchip,wilc3000-bt";
+ wlan = <&wilc>;
+ };
};
};
diff --git a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts
index 15239834d886edbf9e732ac461a92ac9eea42ae5..8b89ee0b47ccb6e60b67f3e4db6caa827ce9c0bc 100644
--- a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts
+++ b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts
@@ -85,16 +85,6 @@ uart5: serial@200 {
};
};
-&flx1 {
- status = "okay";
-
- uart6: serial@200 {
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "okay";
- };
-};
-
&macb0 {
status = "okay";
};
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 12/12] MAINTAINERS: add entry for new wilc3000 bluetooth driver
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (10 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 11/12] ARM: dts: at91-sama5d27_wlsom1: update bluetooth chip description Alexis Lothoré
@ 2025-02-12 15:46 ` Alexis Lothoré
2025-02-12 22:08 ` [PATCH 00/12] bluetooth: hci_wilc: add new " Rob Herring (Arm)
12 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 15:46 UTC (permalink / raw)
To: Alexis Lothoré, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ajay Singh,
Claudiu Beznea, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Nicolas Ferre,
Alexandre Belloni
Cc: Marek Vasut, Thomas Petazzoni, linux-bluetooth, devicetree,
linux-kernel, linux-wireless, netdev, linux-arm-kernel
Add MAINTAINERS entry for the new bluetooth driver in
drivers/bluetooth/hci_wilc.c
Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 82b227c3939a49996498f4e829541eb5380ab2b3..2f02aecc21e96a2f9e6ff2de3864bb2d2b964127 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15526,6 +15526,13 @@ L: linux-wireless@vger.kernel.org
S: Supported
F: drivers/net/wireless/microchip/wilc1000/
+MICROCHIP WILC3000 BLUETOOTH DRIVER
+M: Alexis Lothoré <alexis.lothore@bootlin.com>
+L: linux-bluetooth@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/net/bluetooth/microchip,wilc3000-bt.yaml
+F: drivers/bluetooth/hci_wilc.c
+
MICROSEMI MIPS SOCS
M: Alexandre Belloni <alexandre.belloni@bootlin.com>
M: UNGLinuxDriver@microchip.com
--
2.48.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver
2025-02-12 15:46 ` [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver Alexis Lothoré
@ 2025-02-12 16:14 ` Luiz Augusto von Dentz
2025-02-12 17:01 ` Alexis Lothoré
2025-02-13 9:24 ` Krzysztof Kozlowski
1 sibling, 1 reply; 22+ messages in thread
From: Luiz Augusto von Dentz @ 2025-02-12 16:14 UTC (permalink / raw)
To: Alexis Lothoré
Cc: Alexandre Belloni, Eric Dumazet, Thomas Petazzoni, Claudiu Beznea,
Marek Vasut, Rob Herring, Ajay Singh, Jakub Kicinski, Paolo Abeni,
Kalle Valo, devicetree, Conor Dooley, Marcel Holtmann,
linux-arm-kernel, netdev, linux-wireless, linux-kernel,
linux-bluetooth, Simon Horman, Krzysztof Kozlowski,
David S. Miller
Hi Alexis,
On Wed, Feb 12, 2025 at 10:47 AM Alexis Lothoré
<alexis.lothore@bootlin.com> wrote:
>
> WILC3000 is a combo chip providing 802.11b/g/n and Bluetooth 5.0
> capabilities. The wifi side is used either over SDIO or SPI, and the
> bluetooth side is used over uart, with standard hci. The wifi side is
> already supported by Linux.
>
> Add a dedicated bluetooth driver to support the bluetooth feature from
> wilc3000 chip. Similarly to other supported bluetooth chips, wilc
> devices need a firmware to be uploaded before being able to use
> bluetooth. However, the major difference is that the firmware needs to
> be uploaded through the wifi bus (SDIO or SPI). This constraint makes
> this new driver depends on the corresponding wilc wlan driver for the
> bluetooth setup. Once the basic BT initialization has been performed,
> both side can be used independently, and in parallel.
>
> Since this creates a dependency to some wlan driver, create a dedicated
> module (hci_wilc) rather than integrating wilc bluetooth support in
> hci_uart, to avoid propagating this dependency.
>
> Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
> ---
> drivers/bluetooth/Kconfig | 13 ++
> drivers/bluetooth/Makefile | 3 +-
> drivers/bluetooth/hci_uart.h | 1 +
> drivers/bluetooth/hci_wilc.c | 333 +++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 349 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 4ab32abf0f48644715d4c27ec0d2fdaccef62b76..a96607fb0cc8fed2ccb1811a4b1b4fe586396b07 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -147,6 +147,19 @@ config BT_HCIUART_NOKIA
>
> Say Y here to compile support for Nokia's H4+ protocol.
>
> +config BT_HCIUART_WILC
> + tristate "WILC protocol support"
> + depends on (WILC1000_SDIO || WILC1000_SPI)
> + select WILC_BT
> + depends on BT_HCIUART
> + depends on BT_HCIUART_SERDEV
> + select BT_HCIUART_H4
> + help
> + The WILC uart protocol allows interacting with wilc3000 chips
> + with HCI over UART. The bluetooth firmware needs to be uploaded
> + to the chip through the main bus, so this driver needs the
> + corresponding wlan driver.
> +
> config BT_HCIUART_BCSP
> bool "BCSP protocol support"
> depends on BT_HCIUART
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 81856512ddd030ba8172ff106b80b4b951188cbd..a1e69884acf4ce91f02ff5592541616048b07e31 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -35,10 +35,11 @@ obj-$(CONFIG_BT_NXPUART) += btnxpuart.o
> obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
>
> obj-$(CONFIG_BT_HCIRSI) += btrsi.o
> -
> btmrvl-y := btmrvl_main.o
> btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
>
> +obj-$(CONFIG_BT_HCIUART_WILC) += hci_wilc.o
> +
> hci_uart-y := hci_ldisc.o
> hci_uart-$(CONFIG_BT_HCIUART_SERDEV) += hci_serdev.o
> hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index fbf3079b92a5339154f8847ff36b3c08ef49e2bb..83fc48be4335e0946853fdec32c38bf2fb195009 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -35,6 +35,7 @@
> #define HCI_UART_NOKIA 10
> #define HCI_UART_MRVL 11
> #define HCI_UART_AML 12
> +#define HCI_UART_WILC 13
>
> #define HCI_UART_RAW_DEVICE 0
> #define HCI_UART_RESET_ON_INIT 1
> diff --git a/drivers/bluetooth/hci_wilc.c b/drivers/bluetooth/hci_wilc.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..97dc4620c74ef0733469839adda7890bda90406e
> --- /dev/null
> +++ b/drivers/bluetooth/hci_wilc.c
> @@ -0,0 +1,333 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Bluetooth HCI UART driver for WILC devices
> + *
> + */
> +#include "linux/bitops.h"
> +#include "linux/byteorder/generic.h"
> +#include "linux/err.h"
> +#include "linux/gfp_types.h"
> +#include "net/bluetooth/bluetooth.h"
> +#include "net/bluetooth/hci.h"
> +#include <linux/module.h>
> +#include <linux/firmware.h>
> +#include <linux/of.h>
> +#include <linux/serdev.h>
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +#include <net/wilc.h>
> +
> +#include "hci_uart.h"
> +
> +#define WILC_BT_UART_MANUFACTURER 205
> +#define WILC_UART_DEFAULT_BAUDRATE 115200
> +#define WILC_UART_BAUDRATE 460800
> +
> +#define HCI_VERSION_BOOTROM 0xFF
> +#define HCI_VERSION_FIRMWARE 0x06
> +
> +#define HCI_VENDOR_CMD_WRITE_MEM 0xFC52
> +#define HCI_VENDOR_CMD_UPDATE_UART 0xFC53
> +#define HCI_VENDOR_CMD_UPDATE_ADDR 0xFC54
> +#define HCI_VENDOR_CMD_RESET 0xFC55
> +#define HCI_VENDOR_CMD_READ_REG 0xFC01
> +
> +struct wilc_adapter {
> + struct hci_uart hu;
> + struct device *dev;
> + void *wlan_priv;
> + bool flow_control;
> +};
> +
> +struct wilc_data {
> + struct sk_buff *rx_skb;
> + struct sk_buff_head txq;
> +};
> +
> +struct hci_update_uart_param {
> + __le32 baudrate;
> + __u8 flow_control;
> +} __packed;
> +
> +static int wilc_open(struct hci_uart *hu)
> +{
> + struct wilc_data *wdata;
> +
> + BT_DBG("hci_wilc: open");
Afaik you don't need to include the function name with the likes of
pr_debug/BT_DBG, that said you should really be using bt_dev_dbg if
you have hu->hdev set at this point, and this is valid for all other
places where BT_DBG could be replaced with bt_dev_dbg.
> + wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
> + if (!wdata)
> + return -ENOMEM;
Add an empty after something like an if statement to make it clearer
that it is not under the same scope.
> + skb_queue_head_init(&wdata->txq);
> + hu->priv = wdata;
> +
> + return 0;
> +}
> +
> +static int wilc_close(struct hci_uart *hu)
> +{
> + struct wilc_data *wdata = hu->priv;
> +
> + BT_DBG("hci_wilc: close");
> + skb_queue_purge(&wdata->txq);
> + kfree_skb(wdata->rx_skb);
> + kfree(wdata);
> + hu->priv = NULL;
> + return 0;
> +}
> +
> +static int wilc_flush(struct hci_uart *hu)
> +{
> + struct wilc_data *wdata = hu->priv;
> +
> + BT_DBG("hci_wilc: flush");
> + skb_queue_purge(&wdata->txq);
> + return 0;
> +}
> +
> +static const struct h4_recv_pkt wilc_bt_recv_pkts[] = {
> + { H4_RECV_ACL, .recv = hci_recv_frame },
> + { H4_RECV_SCO, .recv = hci_recv_frame },
> + { H4_RECV_EVENT, .recv = hci_recv_frame },
> +};
> +
> +static int wilc_recv(struct hci_uart *hu, const void *data, int len)
> +{
> + struct wilc_data *wdata = hu->priv;
> + int err;
> +
> + if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
> + return -EUNATCH;
Ditto, add empty line
> + wdata->rx_skb = h4_recv_buf(hu->hdev, wdata->rx_skb, data, len,
> + wilc_bt_recv_pkts,
> + ARRAY_SIZE(wilc_bt_recv_pkts));
> + if (IS_ERR(wdata->rx_skb)) {
> + err = PTR_ERR(wdata->rx_skb);
> + bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
> + wdata->rx_skb = NULL;
> + }
> +
> + return len;
> +}
> +
> +static int wilc_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> +{
> + struct wilc_data *wdata = hu->priv;
> +
> + BT_DBG("hci_wilc: enqueue skb %pK", skb);
> + memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
> + skb_queue_tail(&wdata->txq, skb);
> + return 0;
> +}
> +
> +static struct sk_buff *wilc_dequeue(struct hci_uart *hu)
> +{
> + struct wilc_data *wdata = hu->priv;
> +
> + BT_DBG("hci_wilc: dequeue skb");
> + return skb_dequeue(&wdata->txq);
> +}
> +
> +static int _set_uart_settings(struct hci_uart *hu, unsigned int speed,
> + bool flow_control)
> +{
> + struct hci_update_uart_param param;
> + int ret;
> +
> + param.baudrate = cpu_to_le32(speed);
> + param.flow_control = flow_control ? 1 : 0;
> + ret = __hci_cmd_sync_status(hu->hdev, HCI_VENDOR_CMD_UPDATE_UART,
> + sizeof(param), ¶m, HCI_CMD_TIMEOUT);
> + if (ret) {
> + BT_ERR("Failed to update UART settings");
> + return ret;
> + }
> +
> + serdev_device_set_baudrate(hu->serdev, speed);
> + serdev_device_set_flow_control(hu->serdev, flow_control);
> +
> + return 0;
> +}
> +
> +static int wilc_set_baudrate(struct hci_uart *hu, unsigned int speed)
> +{
> + struct wilc_adapter *wilc_adapter;
> +
> + BT_INFO("WILC uart settings update request: speed=%d", speed);
> + wilc_adapter = serdev_device_get_drvdata(hu->serdev);
> +
> + return _set_uart_settings(hu, speed, wilc_adapter->flow_control);
> +}
> +
> +static int check_firmware_running(struct hci_uart *hu)
> +{
> + struct hci_rp_read_local_version *version;
> + struct sk_buff *skb;
> + int ret = 0;
> +
> + BT_DBG("Resetting bluetooth chip");
> + ret = __hci_cmd_sync_status(hu->hdev, HCI_OP_RESET, 0, NULL,
> + HCI_CMD_TIMEOUT);
> + if (ret) {
> + BT_ERR("Can not reset wilc");
> + return ret;
> + }
> +
> + BT_DBG("Checking chip state");
> + skb = __hci_cmd_sync(hu->hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
> + HCI_CMD_TIMEOUT);
> + if (IS_ERR(skb)) {
> + BT_ERR("Error while checking bootrom");
> + return PTR_ERR(skb);
> + }
> +
> + if (skb->len != sizeof(struct hci_rp_read_local_version)) {
> + BT_ERR("Can not read local version");
> + return -1;
> + }
Ditto, add an empty line.
> + version = (struct hci_rp_read_local_version *)skb->data;
> + BT_DBG("Status: 0x%1X, HCI version: 0x%1X", version->status,
> + version->hci_ver);
> + kfree_skb(skb);
> + if (version->hci_ver != HCI_VERSION_FIRMWARE) {
> + BT_ERR("Bluetooth firmware is not running !");
> + if (version->hci_ver == HCI_VERSION_BOOTROM)
> + BT_WARN("Bootrom is running");
> + return 1;
> + }
Ditto
> + BT_DBG("Firmware is running");
> + return 0;
> +}
> +
> +static int wilc_setup(struct hci_uart *hu)
> +{
> + struct wilc_adapter *wilc_adapter;
> + int ret;
> +
> + BT_DBG("hci_wilc: setup");
> + serdev_device_set_baudrate(hu->serdev, WILC_UART_DEFAULT_BAUDRATE);
> + serdev_device_set_flow_control(hu->serdev, false);
> + ret = check_firmware_running(hu);
> + if (ret)
> + return ret;
> +
> + BT_DBG("Updating firmware uart settings");
> +
> + wilc_adapter = serdev_device_get_drvdata(hu->serdev);
> + ret = _set_uart_settings(&wilc_adapter->hu, WILC_UART_BAUDRATE, true);
> + if (ret) {
> + BT_ERR("Failed to reconfigure firmware uart settings");
> + return ret;
> + }
Ditto
> + wilc_adapter->flow_control = true;
> +
> + BT_INFO("Wilc successfully initialized");
> + return ret;
> +}
> +
> +static const struct hci_uart_proto wilc_bt_proto = {
> + .id = HCI_UART_WILC,
> + .name = "Microchip",
> + .manufacturer = WILC_BT_UART_MANUFACTURER,
> + .init_speed = WILC_UART_DEFAULT_BAUDRATE,
> + .open = wilc_open,
> + .close = wilc_close,
> + .flush = wilc_flush,
> + .recv = wilc_recv,
> + .enqueue = wilc_enqueue,
> + .dequeue = wilc_dequeue,
> + .setup = wilc_setup,
> + .set_baudrate = wilc_set_baudrate,
> +};
> +
> +static int wilc_bt_serdev_probe(struct serdev_device *serdev)
> +{
> + struct wilc_adapter *wilc_adapter;
> + struct device_node *wlan_node;
> + void *wlan = NULL;
> + int ret;
> +
> + wilc_adapter = kzalloc(sizeof(*wilc_adapter), GFP_KERNEL);
> + if (!wilc_adapter)
> + return -ENOMEM;
> +
> + wlan_node = of_parse_phandle(serdev->dev.of_node, "wlan", 0);
> + if (!wlan_node) {
> + BT_ERR("Can not run wilc bluetooth without wlan node");
> + ret = -EINVAL;
> + goto exit_free_adapter;
> + }
> +
> +#if IS_ENABLED(CONFIG_WILC1000_SDIO)
> + wlan = wilc_sdio_get_byphandle(wlan_node);
> +#endif
> +#if IS_ENABLED(CONFIG_WILC1000_SPI)
> + if (!wlan || wlan == ERR_PTR(-EPROBE_DEFER))
> + wlan = wilc_spi_get_byphandle(wlan_node);
> +#endif
> + if (IS_ERR(wlan)) {
> + pr_warn("Can not initialize bluetooth: %pe\n", wlan);
> + ret = PTR_ERR(wlan);
> + goto exit_put_wlan_node;
> + }
> +
> + of_node_put(wlan_node);
> + wilc_adapter->wlan_priv = wlan;
> + ret = wilc_bt_init(wlan);
> + if (ret) {
> + pr_err("Failed to initialize bluetooth firmware (%d)\n", ret);
> + goto exit_put_wlan;
> + }
> +
> + wilc_adapter->dev = &serdev->dev;
> + wilc_adapter->hu.serdev = serdev;
> + wilc_adapter->flow_control = false;
> + serdev_device_set_drvdata(serdev, wilc_adapter);
> + ret = hci_uart_register_device(&wilc_adapter->hu, &wilc_bt_proto);
> + if (ret) {
> + dev_err(&serdev->dev, "Failed to register hci device");
> + goto exit_deinit_bt;
> + }
> +
> + dev_info(&serdev->dev, "WILC hci interface registered");
> + return 0;
> +
> +exit_deinit_bt:
> + wilc_bt_shutdown(wlan);
> +exit_put_wlan:
> + wilc_put(wlan);
> +exit_put_wlan_node:
> + of_node_put(wlan_node);
> +exit_free_adapter:
> + kfree(wilc_adapter);
> + return ret;
> +}
> +
> +static void wilc_bt_serdev_remove(struct serdev_device *serdev)
> +{
> + struct wilc_adapter *wilc_adapter = serdev_device_get_drvdata(serdev);
> +
> + hci_uart_unregister_device(&wilc_adapter->hu);
> + wilc_bt_shutdown(wilc_adapter->wlan_priv);
> + wilc_put(wilc_adapter->wlan_priv);
> + kfree(wilc_adapter);
> +}
> +
> +static const struct of_device_id wilc_bt_of_match[] = {
> + { .compatible = "microchip,wilc3000-bt" },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, wilc_bt_of_match);
> +
> +static struct serdev_device_driver wilc_bt_serdev_driver = {
> + .probe = wilc_bt_serdev_probe,
> + .remove = wilc_bt_serdev_remove,
> + .driver = {
> + .name = "hci_uart_wilc",
> + .of_match_table = of_match_ptr(wilc_bt_of_match),
> + },
> +};
> +
> +module_serdev_device_driver(wilc_bt_serdev_driver)
> +MODULE_AUTHOR("Alexis Lothoré <alexis.lothore@bootlin.com>");
> +MODULE_DESCRIPTION("Bluetooth HCI Uart for WILC devices");
> +MODULE_LICENSE("GPL");
>
> --
> 2.48.0
Once you address these comments please fill free to add:
Reviewed-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver
2025-02-12 16:14 ` Luiz Augusto von Dentz
@ 2025-02-12 17:01 ` Alexis Lothoré
0 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-12 17:01 UTC (permalink / raw)
To: Luiz Augusto von Dentz
Cc: Alexandre Belloni, Eric Dumazet, Thomas Petazzoni, Claudiu Beznea,
Marek Vasut, Rob Herring, Ajay Singh, Jakub Kicinski, Paolo Abeni,
Kalle Valo, devicetree, Conor Dooley, Marcel Holtmann,
linux-arm-kernel, netdev, linux-wireless, linux-kernel,
linux-bluetooth, Simon Horman, Krzysztof Kozlowski,
David S. Miller
Hi Luiz,
thanks for the prompt review !
On 2/12/25 17:14, Luiz Augusto von Dentz wrote:
[...]
>> +static int wilc_open(struct hci_uart *hu)
>> +{
>> + struct wilc_data *wdata;
>> +
>> + BT_DBG("hci_wilc: open");
>
> Afaik you don't need to include the function name with the likes of
> pr_debug/BT_DBG, that said you should really be using bt_dev_dbg if
> you have hu->hdev set at this point, and this is valid for all other
> places where BT_DBG could be replaced with bt_dev_dbg.
I observe that BT_DBG does not bring any kind of prefix to the emitted log. But
indeed, bt_dev_dbg looks definitely better for my purpose, I'll update all those
logs with it.
>> + wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
>> + if (!wdata)
>> + return -ENOMEM;
>
> Add an empty after something like an if statement to make it clearer
> that it is not under the same scope.
True, that will be fixed.
[...]
>
> Once you address these comments please fill free to add:
>
> Reviewed-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thanks. I'll delay v2 for a few days to let other people review the series.
Alexis
--
Alexis Lothoré, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
` (11 preceding siblings ...)
2025-02-12 15:46 ` [PATCH 12/12] MAINTAINERS: add entry for new wilc3000 bluetooth driver Alexis Lothoré
@ 2025-02-12 22:08 ` Rob Herring (Arm)
12 siblings, 0 replies; 22+ messages in thread
From: Rob Herring (Arm) @ 2025-02-12 22:08 UTC (permalink / raw)
To: Alexis Lothoré
Cc: Alexandre Belloni, Eric Dumazet, Thomas Petazzoni, Claudiu Beznea,
Marek Vasut, Ajay Singh, Jakub Kicinski, Paolo Abeni,
Marcel Holtmann, devicetree, Conor Dooley, Kalle Valo,
Luiz Augusto von Dentz, linux-arm-kernel, netdev, linux-wireless,
linux-kernel, linux-bluetooth, Simon Horman, Krzysztof Kozlowski,
David S. Miller
On Wed, 12 Feb 2025 16:46:19 +0100, Alexis Lothoré wrote:
> Hello,
>
> WILC3000 ([1]) is a combo chip exposing 802.11b/g/n and Bluetooth 5.
> Support for the wlan part has recently been integrated upstream ([2]) in
> the existing wilc1000 driver. This new series aims to bring support for
> the bluetooth side.
>
> The WILC3000 chip is controlled through a SDIO or SPI bus for the wlan
> part (similarly to wilc1000), and uses standard HCI commands over a UART
> bus for the bluetooth operations. This work is based on the code
> available in the vendor kernel ([3]), in which bluetooth is managed
> directly in the wireless driver, and relies on user to trigger the
> hardware configuration (chardev manipulations + hciattach). The series
> brings a new dedicated bluetooth driver to support the bluetooth feature
> from the chip, without relying on the user to perform the device
> bringup. However, getting completely rid of the wlan driver dependency
> is not possible: it is still needed for early BT CPU configuration and
> BT firmware download, so the new driver still have a dependency of the
> wlan one, with an approach similar to the one used by the rsi driver.
>
> - Patch 1 brings the new dt binding
> - Patch 2-9 prepares the wlan side, either by exposing the needed
> functions to initialize BT, or by mitigating behavior which would
> prevent BT and WLAN from runnning in parallel
> - Patch 10 brings the new bluetooth driver
> - Patch 11 updates the device tree description for sama5d27_wlsom1_ek
> board (which I used to validate this series) to use the new driver
> - Patch 12 adds a new entry for this driver in the MAINTAINERS files
>
> This series has been tested with WILC3000 both in SDIO mode (with the
> chip embedded on the sama5d27_wlsom1_ek) and SPI mode (custom wiring on
> an SPI on the same eval board, with a WILC3000-SD).
>
> Since this works needs new code in both the existing wlan driver and the
> new driver, I have included both linux-wireless and bluetooth mailing
> lists, while keeping the entire series for clarity, but let me know if
> you want to proceed differently.
>
> [1] https://www.microchip.com/en-us/product/atwilc3000
> [2] https://lore.kernel.org/linux-wireless/20241004114551.40236-1-marex@denx.de/
> [3] https://github.com/linux4microchip/linux/tree/linux-6.6-mchp/drivers/net/wireless/microchip/wilc1000
>
> ---
> Alexis Lothoré (12):
> dt-bindings: bluetooth: describe wilc 3000 bluetooth chip
> wifi: wilc1000: add a read-modify-write API for registers accesses
> wifi: wilc1000: add lock to prevent concurrent firmware startup
> wifi: wilc1000: allow to use acquire/release bus in other parts of driver
> wifi: wilc1000: do not depend on power save flag to wake up chip
> wifi: wilc1000: remove timeout parameter from set_power_mgmt
> wifi: wilc1000: reorganize makefile objs into sorted list
> wifi: wilc1000: add basic functions to allow bluetooth bringup
> wifi: wilc1000: disable firmware power save if bluetooth is in use
> bluetooth: hci_wilc: add wilc hci driver
> ARM: dts: at91-sama5d27_wlsom1: update bluetooth chip description
> MAINTAINERS: add entry for new wilc3000 bluetooth driver
>
> .../net/bluetooth/microchip,wilc3000-bt.yaml | 41 +++
> MAINTAINERS | 7 +
> .../boot/dts/microchip/at91-sama5d27_wlsom1.dtsi | 8 +
> .../boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts | 10 -
> drivers/bluetooth/Kconfig | 13 +
> drivers/bluetooth/Makefile | 3 +-
> drivers/bluetooth/hci_uart.h | 1 +
> drivers/bluetooth/hci_wilc.c | 333 ++++++++++++++++++++
> drivers/net/wireless/microchip/wilc1000/Kconfig | 3 +
> drivers/net/wireless/microchip/wilc1000/Makefile | 11 +-
> drivers/net/wireless/microchip/wilc1000/bt.c | 345 +++++++++++++++++++++
> drivers/net/wireless/microchip/wilc1000/cfg80211.c | 7 +-
> drivers/net/wireless/microchip/wilc1000/hif.c | 2 +-
> drivers/net/wireless/microchip/wilc1000/hif.h | 2 +-
> drivers/net/wireless/microchip/wilc1000/netdev.c | 14 +
> drivers/net/wireless/microchip/wilc1000/netdev.h | 5 +
> drivers/net/wireless/microchip/wilc1000/sdio.c | 101 ++++--
> drivers/net/wireless/microchip/wilc1000/spi.c | 43 +++
> drivers/net/wireless/microchip/wilc1000/wlan.c | 154 ++++-----
> drivers/net/wireless/microchip/wilc1000/wlan.h | 23 ++
> include/net/wilc.h | 19 ++
> 21 files changed, 996 insertions(+), 149 deletions(-)
> ---
> base-commit: 95f6f2d73dc40ab53a94756689ce5cfd2f23361a
> change-id: 20240828-wilc3000_bt-fa452f2a93ad
>
> Best regards,
> --
> Alexis Lothoré, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>
>
My bot found new DTB warnings on the .dts files added or changed in this
series.
Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.
If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:
pip3 install dtschema --upgrade
New warnings running 'make CHECK_DTBS=y for arch/arm/boot/dts/microchip/' for 20250212-wilc3000_bt-v1-0-9609b784874e@bootlin.com:
arch/arm/boot/dts/microchip/at91-sama5d3_eds.dtb: nand-controller: #address-cells: 1 was expected
from schema $id: http://devicetree.org/schemas/mtd/nand-controller.yaml#
arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dtb: serial@200: Unevaluated properties are not allowed ('bluetooth@0' was unexpected)
from schema $id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml#
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver
2025-02-12 15:46 ` [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver Alexis Lothoré
2025-02-12 16:14 ` Luiz Augusto von Dentz
@ 2025-02-13 9:24 ` Krzysztof Kozlowski
2025-02-13 15:30 ` Alexis Lothoré
1 sibling, 1 reply; 22+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-13 9:24 UTC (permalink / raw)
To: Alexis Lothoré
Cc: Alexandre Belloni, Eric Dumazet, Thomas Petazzoni, Claudiu Beznea,
Marek Vasut, Rob Herring, Ajay Singh, Jakub Kicinski, Paolo Abeni,
Kalle Valo, devicetree, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, linux-arm-kernel, netdev, linux-wireless,
linux-kernel, linux-bluetooth, Simon Horman, Krzysztof Kozlowski,
David S. Miller
On Wed, Feb 12, 2025 at 04:46:29PM +0100, Alexis Lothoré wrote:
> +#include "linux/bitops.h"
> +#include "linux/byteorder/generic.h"
> +#include "linux/err.h"
> +#include "linux/gfp_types.h"
> +#include "net/bluetooth/bluetooth.h"
> +#include "net/bluetooth/hci.h"
Keep some order here. Why some are <> some "", why net is mixed with
linux...
> +#include <linux/module.h>
> +#include <linux/firmware.h>
> +#include <linux/of.h>
> +#include <linux/serdev.h>
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +#include <net/wilc.h>
> +
> +#include "hci_uart.h"
> +
...
> +static const struct hci_uart_proto wilc_bt_proto = {
> + .id = HCI_UART_WILC,
> + .name = "Microchip",
> + .manufacturer = WILC_BT_UART_MANUFACTURER,
> + .init_speed = WILC_UART_DEFAULT_BAUDRATE,
> + .open = wilc_open,
> + .close = wilc_close,
> + .flush = wilc_flush,
> + .recv = wilc_recv,
> + .enqueue = wilc_enqueue,
> + .dequeue = wilc_dequeue,
> + .setup = wilc_setup,
> + .set_baudrate = wilc_set_baudrate,
> +};
> +
> +static int wilc_bt_serdev_probe(struct serdev_device *serdev)
> +{
> + struct wilc_adapter *wilc_adapter;
> + struct device_node *wlan_node;
> + void *wlan = NULL;
> + int ret;
> +
> + wilc_adapter = kzalloc(sizeof(*wilc_adapter), GFP_KERNEL);
Why not devm?
> + if (!wilc_adapter)
> + return -ENOMEM;
> +
> + wlan_node = of_parse_phandle(serdev->dev.of_node, "wlan", 0);
> + if (!wlan_node) {
> + BT_ERR("Can not run wilc bluetooth without wlan node");
> + ret = -EINVAL;
> + goto exit_free_adapter;
> + }
> +
> +#if IS_ENABLED(CONFIG_WILC1000_SDIO)
> + wlan = wilc_sdio_get_byphandle(wlan_node);
> +#endif
> +#if IS_ENABLED(CONFIG_WILC1000_SPI)
> + if (!wlan || wlan == ERR_PTR(-EPROBE_DEFER))
> + wlan = wilc_spi_get_byphandle(wlan_node);
> +#endif
> + if (IS_ERR(wlan)) {
> + pr_warn("Can not initialize bluetooth: %pe\n", wlan);
dev_warn or even dev_err_probe to handle deferral.
> + ret = PTR_ERR(wlan);
> + goto exit_put_wlan_node;
> + }
> +
> + of_node_put(wlan_node);
> + wilc_adapter->wlan_priv = wlan;
> + ret = wilc_bt_init(wlan);
> + if (ret) {
> + pr_err("Failed to initialize bluetooth firmware (%d)\n", ret);
dev_err_probe
> + goto exit_put_wlan;
> + }
> +
> + wilc_adapter->dev = &serdev->dev;
> + wilc_adapter->hu.serdev = serdev;
> + wilc_adapter->flow_control = false;
> + serdev_device_set_drvdata(serdev, wilc_adapter);
> + ret = hci_uart_register_device(&wilc_adapter->hu, &wilc_bt_proto);
> + if (ret) {
> + dev_err(&serdev->dev, "Failed to register hci device");
> + goto exit_deinit_bt;
> + }
> +
> + dev_info(&serdev->dev, "WILC hci interface registered");
Drop simple probe statuses. sysfs already provides this.
> + return 0;
> +
> +exit_deinit_bt:
> + wilc_bt_shutdown(wlan);
> +exit_put_wlan:
> + wilc_put(wlan);
> +exit_put_wlan_node:
> + of_node_put(wlan_node);
> +exit_free_adapter:
> + kfree(wilc_adapter);
> + return ret;
> +}
> +
> +static void wilc_bt_serdev_remove(struct serdev_device *serdev)
> +{
> + struct wilc_adapter *wilc_adapter = serdev_device_get_drvdata(serdev);
> +
> + hci_uart_unregister_device(&wilc_adapter->hu);
> + wilc_bt_shutdown(wilc_adapter->wlan_priv);
> + wilc_put(wilc_adapter->wlan_priv);
> + kfree(wilc_adapter);
> +}
> +
> +static const struct of_device_id wilc_bt_of_match[] = {
> + { .compatible = "microchip,wilc3000-bt" },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, wilc_bt_of_match);
> +
> +static struct serdev_device_driver wilc_bt_serdev_driver = {
> + .probe = wilc_bt_serdev_probe,
> + .remove = wilc_bt_serdev_remove,
> + .driver = {
> + .name = "hci_uart_wilc",
> + .of_match_table = of_match_ptr(wilc_bt_of_match),
Drop of_match_tr, you have warnings here.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 01/12] dt-bindings: bluetooth: describe wilc 3000 bluetooth chip
2025-02-12 15:46 ` [PATCH 01/12] dt-bindings: bluetooth: describe wilc 3000 bluetooth chip Alexis Lothoré
@ 2025-02-13 9:25 ` Krzysztof Kozlowski
2025-02-13 15:25 ` Alexis Lothoré
0 siblings, 1 reply; 22+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-13 9:25 UTC (permalink / raw)
To: Alexis Lothoré
Cc: Alexandre Belloni, Eric Dumazet, Thomas Petazzoni, Claudiu Beznea,
Marek Vasut, Rob Herring, Ajay Singh, Jakub Kicinski, Paolo Abeni,
Kalle Valo, devicetree, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, linux-arm-kernel, netdev, linux-wireless,
linux-kernel, linux-bluetooth, Simon Horman, Krzysztof Kozlowski,
David S. Miller
On Wed, Feb 12, 2025 at 04:46:20PM +0100, Alexis Lothoré wrote:
> WILC3000 is a combo chip providing 802.11b/g/n and Bluetooth 5. The wlan
> part is exposed either through SDIO or SPI interface, and the bluetooth
> part is exposed through uart. The notable peculiarity of this chip is
> that the bluetooth part is not fully autonomous: its firmware is not
> loaded through UART interface but through SDIO/SPI interface, so the
> bluetooth description needs a reference to the wlan part to get access
> to the corresponding bus.
>
> Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
> ---
> .../net/bluetooth/microchip,wilc3000-bt.yaml | 41 ++++++++++++++++++++++
> 1 file changed, 41 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/net/bluetooth/microchip,wilc3000-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/microchip,wilc3000-bt.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..2a83ca3ad90b26fd619b574bc343bee9654a1e43
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/bluetooth/microchip,wilc3000-bt.yaml
> @@ -0,0 +1,41 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/bluetooth/microchip,wilc3000-bt.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Microchip Bluetooth chips
> +
> +description:
> + This binding describes UART-attached Microchip bluetooth chips. These
> + chips are dual-radio chips supporting WiFi and Bluetooth. The bluetooth
> + side works with standard HCI commands over 4-wires UART (with flow
> + control)
> +
> +maintainers:
> + - Alexis Lothoré <alexis.lothore@bootlin.com>
> +
> +properties:
> + compatible:
> + enum:
> + - microchip,wilc3000-bt
> +
> + wlan:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description:
> + Phandle to the wlan part of the combo chip
No resources here and judging by the driver everything is part of wifi.
Either you wrote it to match driver or indeed hardware is like that. In
the first case, why this cannot be part of WiFi with phandle to serial
bus? In the second case, this needs to be proper hardware description.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 01/12] dt-bindings: bluetooth: describe wilc 3000 bluetooth chip
2025-02-13 9:25 ` Krzysztof Kozlowski
@ 2025-02-13 15:25 ` Alexis Lothoré
2025-02-14 7:47 ` Krzysztof Kozlowski
0 siblings, 1 reply; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-13 15:25 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Alexandre Belloni, Eric Dumazet, Thomas Petazzoni, Claudiu Beznea,
Marek Vasut, Rob Herring, Ajay Singh, Jakub Kicinski, Paolo Abeni,
Kalle Valo, devicetree, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, linux-arm-kernel, netdev, linux-wireless,
linux-kernel, linux-bluetooth, Simon Horman, Krzysztof Kozlowski,
David S. Miller
Hi Krzysztof,
On 2/13/25 10:25, Krzysztof Kozlowski wrote:
>> + wlan:
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description:
>> + Phandle to the wlan part of the combo chip
>
> No resources here and judging by the driver everything is part of wifi.
> Either you wrote it to match driver or indeed hardware is like that. In
> the first case, why this cannot be part of WiFi with phandle to serial
> bus? In the second case, this needs to be proper hardware description
First, I'd like to reclarify what the chip exactly is, to make sure that we are
talking about the same thing. The wilc3000 ([1]) is a single physical device
packaging two different discrete modules inside (one for 802.11, one for
bluetooth). The WLAN part has its own binding integrated in upstream kernel
([2]) and is based on a similar chip in the same family (wilc1000, which only
have 802.11, and so only SPI/SDIO, no UART).
Now that it is said, no, I did not write this binding only aiming to match the
new driver. I tried to base this description on how similar WLAN/BT combo chips
are usually described (based on those which have existing bindings), and they
seem to describe distinctly the two internal parts of those chips as well. For
those who use HCI commands over uart for the bluetooth part, they expose a
dedicated child node of a serial controller (distinct from the wlan part,
described as another node on PCI/SDIO/SPI/etc). The hardware architecture for
wilc3000 is similar to those, so since the serial bus is the primary interface
to operate the bluetooth part inside the chip, doesn't it makes sense to have it
under a serial controller node (and then to refer to wlan for the additional
operations needed on sdio/spi), than the other way around ?
About the lack of other resources in the new node: there are indeed additional
resources that affect bluetooth, but I am not sure how it should be handled:
there are for example a reset input and a chip enable input exposed by this
chip, which in fact do not only affect the WLAN part but the two parts inside
the chip. But those are currently described and handled by the WLAN part. I
guess that an improvement regarding this point could then be to move those out
of the wlan binding, and find a way to describe it as shared resources between
those two parts of the chip, but how should it be handled ? Is it ok to remove
those from an existing binding (and if so, where to put those ? It is not
bluetooth specific neither) ? Is the issue rather about current WILC3000 binding
kind of mixing overall chip description and internal wlan part description ?
Thanks,
Alexis
[1]
https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/IEEE-802.11-b-g-n-Link-Controller-Module-with-Integrated-Bluetooth-5.0-DS70005327B.pdf
[2]
https://elixir.bootlin.com/linux/v6.12.6/source/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml
> Best regards,
> Krzysztof
>
--
Alexis Lothoré, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver
2025-02-13 9:24 ` Krzysztof Kozlowski
@ 2025-02-13 15:30 ` Alexis Lothoré
0 siblings, 0 replies; 22+ messages in thread
From: Alexis Lothoré @ 2025-02-13 15:30 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Alexandre Belloni, Eric Dumazet, Thomas Petazzoni, Claudiu Beznea,
Marek Vasut, Rob Herring, Ajay Singh, Jakub Kicinski, Paolo Abeni,
Kalle Valo, devicetree, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, linux-arm-kernel, netdev, linux-wireless,
linux-kernel, linux-bluetooth, Simon Horman, Krzysztof Kozlowski,
David S. Miller
Hi Krzysztof,
On 2/13/25 10:24, Krzysztof Kozlowski wrote:
> On Wed, Feb 12, 2025 at 04:46:29PM +0100, Alexis Lothoré wrote:
>> +#include "linux/bitops.h"
>> +#include "linux/byteorder/generic.h"
>> +#include "linux/err.h"
>> +#include "linux/gfp_types.h"
>> +#include "net/bluetooth/bluetooth.h"
>> +#include "net/bluetooth/hci.h"
>
> Keep some order here. Why some are <> some "", why net is mixed with
> linux...
[...]
>> + wilc_adapter = kzalloc(sizeof(*wilc_adapter), GFP_KERNEL);
>
> Why not devm?
[...]
>> + if (IS_ERR(wlan)) {
>> + pr_warn("Can not initialize bluetooth: %pe\n", wlan);
>
> dev_warn or even dev_err_probe to handle deferral.
[...]
>> + dev_info(&serdev->dev, "WILC hci interface registered");
>
> Drop simple probe statuses. sysfs already provides this.
[...]
>> +static struct serdev_device_driver wilc_bt_serdev_driver = {
>> + .probe = wilc_bt_serdev_probe,
>> + .remove = wilc_bt_serdev_remove,
>> + .driver = {
>> + .name = "hci_uart_wilc",
>> + .of_match_table = of_match_ptr(wilc_bt_of_match),
>
> Drop of_match_tr, you have warnings here.
Thanks for the review, true for all raised points, which will be handled in next
rev.
Alexis
>
> Best regards,
> Krzysztof
>
--
Alexis Lothoré, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 01/12] dt-bindings: bluetooth: describe wilc 3000 bluetooth chip
2025-02-13 15:25 ` Alexis Lothoré
@ 2025-02-14 7:47 ` Krzysztof Kozlowski
0 siblings, 0 replies; 22+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-14 7:47 UTC (permalink / raw)
To: Alexis Lothoré
Cc: Alexandre Belloni, Eric Dumazet, Thomas Petazzoni, Claudiu Beznea,
Marek Vasut, Rob Herring, Ajay Singh, Jakub Kicinski, Paolo Abeni,
Kalle Valo, devicetree, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, linux-arm-kernel, netdev, linux-wireless,
linux-kernel, linux-bluetooth, Simon Horman, Krzysztof Kozlowski,
David S. Miller
On 13/02/2025 16:25, Alexis Lothoré wrote:
> Hi Krzysztof,
>
> On 2/13/25 10:25, Krzysztof Kozlowski wrote:
>>> + wlan:
>>> + $ref: /schemas/types.yaml#/definitions/phandle
>>> + description:
>>> + Phandle to the wlan part of the combo chip
>>
>> No resources here and judging by the driver everything is part of wifi.
>> Either you wrote it to match driver or indeed hardware is like that. In
>> the first case, why this cannot be part of WiFi with phandle to serial
>> bus? In the second case, this needs to be proper hardware description
>
> First, I'd like to reclarify what the chip exactly is, to make sure that we are
> talking about the same thing. The wilc3000 ([1]) is a single physical device
> packaging two different discrete modules inside (one for 802.11, one for
> bluetooth). The WLAN part has its own binding integrated in upstream kernel
> ([2]) and is based on a similar chip in the same family (wilc1000, which only
> have 802.11, and so only SPI/SDIO, no UART).
>
> Now that it is said, no, I did not write this binding only aiming to match the
> new driver. I tried to base this description on how similar WLAN/BT combo chips
> are usually described (based on those which have existing bindings), and they
> seem to describe distinctly the two internal parts of those chips as well. For
Yes, because BT part is isolated enough that you datasheet tells which
resources belong to it and DT describes these resources.
You do not have any resources here.
> those who use HCI commands over uart for the bluetooth part, they expose a
> dedicated child node of a serial controller (distinct from the wlan part,
> described as another node on PCI/SDIO/SPI/etc). The hardware architecture for
> wilc3000 is similar to those, so since the serial bus is the primary interface
> to operate the bluetooth part inside the chip, doesn't it makes sense to have it
> under a serial controller node (and then to refer to wlan for the additional
> operations needed on sdio/spi), than the other way around ?
There is little benefit in describing one device in two places. This
even lead to probe ordering issues and power sequencing problems, for
example being explicitly addressed by recent power sequencing work from
Bartosz by creating *third* node...
You have no resources here, so I cannot even imagine inventing something
in that third (PMU) node.
But anyway in case of WCN devices, the reason of power sequencing
patches, BT and WiFi are separate, can be enabled separately, can be
even shipped one without another (I think).
Not your case. Your BT needs WiFi to load firmware.
>
> About the lack of other resources in the new node: there are indeed additional
> resources that affect bluetooth, but I am not sure how it should be handled:
You sent us then incomplete hardware description. So you got review like
this.
> there are for example a reset input and a chip enable input exposed by this
> chip, which in fact do not only affect the WLAN part but the two parts inside
> the chip. But those are currently described and handled by the WLAN part. I
So everything is already defined in WiFi part and this node is not
really necessary.
> guess that an improvement regarding this point could then be to move those out
> of the wlan binding, and find a way to describe it as shared resources between
> those two parts of the chip, but how should it be handled ? Is it ok to remove
> those from an existing binding (and if so, where to put those ? It is not
> bluetooth specific neither) ? Is the issue rather about current WILC3000 binding
> kind of mixing overall chip description and internal wlan part description ?
Datasheet shows this as one device, not two, not three.
Reset and chip enable, based on datasheet, are not specific to BT. They
reset/enable entire chip, I assume, so it is even better proof that your
HW description is not correct.
How this device is supposed to work if you do not enable WiFi - do not
deassert reset from Wifi driver? BT will stay in reset. Really, and
that's correct hardware representation?
This is exactly the power sequencing problem one more time and you keep
asking exactly the same questions and repeating exactly the same
mistakes. This is incomplete and, IMO, incorrect hardware description.
Read all previous discussions, read/listen/watch the talks about power
sequencing (there were two on LPCs - one with Abel to describe the
problem, year later to solve it).
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 09/12] wifi: wilc1000: disable firmware power save if bluetooth is in use
2025-02-12 15:46 ` [PATCH 09/12] wifi: wilc1000: disable firmware power save if bluetooth is in use Alexis Lothoré
@ 2025-02-16 16:07 ` Simon Horman
0 siblings, 0 replies; 22+ messages in thread
From: Simon Horman @ 2025-02-16 16:07 UTC (permalink / raw)
To: Alexis Lothoré
Cc: Alexandre Belloni, Eric Dumazet, Thomas Petazzoni, Claudiu Beznea,
Marek Vasut, Rob Herring, Ajay Singh, Jakub Kicinski, Paolo Abeni,
Kalle Valo, devicetree, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, linux-arm-kernel, netdev, linux-wireless,
linux-kernel, linux-bluetooth, Krzysztof Kozlowski,
David S. Miller
On Wed, Feb 12, 2025 at 04:46:28PM +0100, Alexis Lothoré wrote:
> If the wlan interface exposed by wilc driver has power save enabled
> (either explicitly with iw dev wlan set power_save on, or because
> kernel is built with CONFIG_CFG80211_DEFAULT_PS), it will send a power
> management command to the wlan firmware when corresponding interface is
> brought up. The bluetooth part, if used, is supposed to work
> independently from the WLAN CPU. Unfortunately, this power save
> management, if applied by the WLAN side, disrupts bluetooth operations
> (the bluetooth CPU does not answer any command anymore on the UART
> interface)
>
> Make sure that the bluetooth part can work independently by disabling
> power save in wlan firmware when bluetooth is in use.
>
> Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com>
> ---
> drivers/net/wireless/microchip/wilc1000/bt.c | 29 +++++++++++++++++++---
> drivers/net/wireless/microchip/wilc1000/cfg80211.c | 5 +++-
> drivers/net/wireless/microchip/wilc1000/netdev.h | 3 +++
> 3 files changed, 33 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/wireless/microchip/wilc1000/bt.c b/drivers/net/wireless/microchip/wilc1000/bt.c
> index b0f68a5479a5bd6f70e2390a35512037dc6c332b..f0eb5fb506eddf0f6f4f3f0b182eaa650c1c7a87 100644
> --- a/drivers/net/wireless/microchip/wilc1000/bt.c
> +++ b/drivers/net/wireless/microchip/wilc1000/bt.c
> @@ -7,6 +7,7 @@
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> #include <net/wilc.h>
> +#include "cfg80211.h"
> #include "netdev.h"
> #include "wlan_if.h"
> #include "wlan.h"
> @@ -261,22 +262,36 @@ static int wilc_bt_start(struct wilc *wilc)
> int wilc_bt_init(void *wilc_wl_priv)
> {
> struct wilc *wilc = (struct wilc *)wilc_wl_priv;
> + struct wilc_vif *vif;
> int ret;
>
> + wilc->bt_enabled = true;
> +
> if (!wilc->hif_func->hif_is_init(wilc)) {
> dev_info(wilc->dev, "Initializing bus before starting BT");
> acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
> ret = wilc->hif_func->hif_init(wilc, false);
> release_bus(wilc, WILC_BUS_RELEASE_ONLY);
> - if (ret)
> + if (ret) {
> + wilc->bt_enabled = false;
> return ret;
> + }
> }
>
> + /* Power save feature managed by WLAN firmware may disrupt
> + * operations from the bluetooth CPU, so disable it while bluetooth
> + * is in use (if enabled, it will be enabled back when bluetooth is
> + * not used anymore)
> + */
> + vif = wilc_get_wl_to_vif(wilc);
> + if (wilc->power_save_mode && wilc_set_power_mgmt(vif, false))
> + goto hif_deinit;
Hi Alexis,
Jumping to hif_deinit will result in the function returning ret.
But ret may not not be initialised until a few lines below.
Flagged by Smatch.
> +
> mutex_lock(&wilc->radio_fw_start);
> ret = wilc_bt_power_up(wilc);
> if (ret) {
> dev_err(wilc->dev, "Error powering up bluetooth chip\n");
> - goto hif_deinit;
> + goto reenable_power_save;
> }
> ret = wilc_bt_firmware_download(wilc);
> if (ret) {
> @@ -293,10 +308,14 @@ int wilc_bt_init(void *wilc_wl_priv)
>
> power_down:
> wilc_bt_power_down(wilc);
> -hif_deinit:
> +reenable_power_save:
> + if (wilc->power_save_mode_request)
> + wilc_set_power_mgmt(vif, true);
> mutex_unlock(&wilc->radio_fw_start);
> +hif_deinit:
> if (!wilc->initialized)
> wilc->hif_func->hif_deinit(wilc);
> + wilc->bt_enabled = false;
> return ret;
> }
> EXPORT_SYMBOL(wilc_bt_init);
...
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2025-02-16 16:09 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-12 15:46 [PATCH 00/12] bluetooth: hci_wilc: add new bluetooth driver Alexis Lothoré
2025-02-12 15:46 ` [PATCH 01/12] dt-bindings: bluetooth: describe wilc 3000 bluetooth chip Alexis Lothoré
2025-02-13 9:25 ` Krzysztof Kozlowski
2025-02-13 15:25 ` Alexis Lothoré
2025-02-14 7:47 ` Krzysztof Kozlowski
2025-02-12 15:46 ` [PATCH 02/12] wifi: wilc1000: add a read-modify-write API for registers accesses Alexis Lothoré
2025-02-12 15:46 ` [PATCH 03/12] wifi: wilc1000: add lock to prevent concurrent firmware startup Alexis Lothoré
2025-02-12 15:46 ` [PATCH 04/12] wifi: wilc1000: allow to use acquire/release bus in other parts of driver Alexis Lothoré
2025-02-12 15:46 ` [PATCH 05/12] wifi: wilc1000: do not depend on power save flag to wake up chip Alexis Lothoré
2025-02-12 15:46 ` [PATCH 06/12] wifi: wilc1000: remove timeout parameter from set_power_mgmt Alexis Lothoré
2025-02-12 15:46 ` [PATCH 07/12] wifi: wilc1000: reorganize makefile objs into sorted list Alexis Lothoré
2025-02-12 15:46 ` [PATCH 08/12] wifi: wilc1000: add basic functions to allow bluetooth bringup Alexis Lothoré
2025-02-12 15:46 ` [PATCH 09/12] wifi: wilc1000: disable firmware power save if bluetooth is in use Alexis Lothoré
2025-02-16 16:07 ` Simon Horman
2025-02-12 15:46 ` [PATCH 10/12] bluetooth: hci_wilc: add wilc hci driver Alexis Lothoré
2025-02-12 16:14 ` Luiz Augusto von Dentz
2025-02-12 17:01 ` Alexis Lothoré
2025-02-13 9:24 ` Krzysztof Kozlowski
2025-02-13 15:30 ` Alexis Lothoré
2025-02-12 15:46 ` [PATCH 11/12] ARM: dts: at91-sama5d27_wlsom1: update bluetooth chip description Alexis Lothoré
2025-02-12 15:46 ` [PATCH 12/12] MAINTAINERS: add entry for new wilc3000 bluetooth driver Alexis Lothoré
2025-02-12 22:08 ` [PATCH 00/12] bluetooth: hci_wilc: add new " Rob Herring (Arm)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).