wifi: rtw89: add support for hardware rfkill
authorKuan-Chung Chen <damon.chen@realtek.com>
Wed, 24 Jul 2024 05:26:24 +0000 (13:26 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Fri, 2 Aug 2024 01:19:42 +0000 (09:19 +0800)
Add support for ieee80211::rfkill_poll ops. This enables periodic
monitoring of the hardware rfkill state, triggering updates when the
status changes.

Signed-off-by: Kuan-Chung Chen <damon.chen@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20240724052626.12774-3-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/mac80211.c
drivers/net/wireless/realtek/rtw89/reg.h
drivers/net/wireless/realtek/rtw89/rtw8851b.c
drivers/net/wireless/realtek/rtw89/rtw8852a.c
drivers/net/wireless/realtek/rtw89/rtw8852b.c
drivers/net/wireless/realtek/rtw89/rtw8852bt.c
drivers/net/wireless/realtek/rtw89/rtw8852c.c
drivers/net/wireless/realtek/rtw89/rtw8922a.c

index 86b6febedc25440c772acf1db39b96e28ecb39ab..45952994ffa6537869eb3aae446ef9a519305348 100644 (file)
@@ -3217,6 +3217,7 @@ static void rtw89_track_work(struct work_struct *work)
        rtw89_phy_edcca_track(rtwdev);
        rtw89_tas_track(rtwdev);
        rtw89_chanctx_track(rtwdev);
+       rtw89_core_rfkill_poll(rtwdev, false);
 
        if (rtwdev->lps_enabled && !rtwdev->btc.lps)
                rtw89_enter_lps_track(rtwdev);
@@ -4499,6 +4500,70 @@ static int rtw89_chip_board_info_setup(struct rtw89_dev *rtwdev)
        return 0;
 }
 
+static bool rtw89_chip_has_rfkill(struct rtw89_dev *rtwdev)
+{
+       return !!rtwdev->chip->rfkill_init;
+}
+
+static void rtw89_core_rfkill_init(struct rtw89_dev *rtwdev)
+{
+       const struct rtw89_rfkill_regs *regs = rtwdev->chip->rfkill_init;
+
+       rtw89_write16_mask(rtwdev, regs->pinmux.addr,
+                          regs->pinmux.mask, regs->pinmux.data);
+       rtw89_write16_mask(rtwdev, regs->mode.addr,
+                          regs->mode.mask, regs->mode.data);
+}
+
+static bool rtw89_core_rfkill_get(struct rtw89_dev *rtwdev)
+{
+       const struct rtw89_reg_def *reg = &rtwdev->chip->rfkill_get;
+
+       return !rtw89_read8_mask(rtwdev, reg->addr, reg->mask);
+}
+
+static void rtw89_rfkill_polling_init(struct rtw89_dev *rtwdev)
+{
+       if (!rtw89_chip_has_rfkill(rtwdev))
+               return;
+
+       rtw89_core_rfkill_init(rtwdev);
+       rtw89_core_rfkill_poll(rtwdev, true);
+       wiphy_rfkill_start_polling(rtwdev->hw->wiphy);
+}
+
+static void rtw89_rfkill_polling_deinit(struct rtw89_dev *rtwdev)
+{
+       if (!rtw89_chip_has_rfkill(rtwdev))
+               return;
+
+       wiphy_rfkill_stop_polling(rtwdev->hw->wiphy);
+}
+
+void rtw89_core_rfkill_poll(struct rtw89_dev *rtwdev, bool force)
+{
+       bool prev, blocked;
+
+       if (!rtw89_chip_has_rfkill(rtwdev))
+               return;
+
+       prev = test_bit(RTW89_FLAG_HW_RFKILL_STATE, rtwdev->flags);
+       blocked = rtw89_core_rfkill_get(rtwdev);
+
+       if (!force && prev == blocked)
+               return;
+
+       rtw89_info(rtwdev, "rfkill hardware state changed to %s\n",
+                  blocked ? "disable" : "enable");
+
+       if (blocked)
+               set_bit(RTW89_FLAG_HW_RFKILL_STATE, rtwdev->flags);
+       else
+               clear_bit(RTW89_FLAG_HW_RFKILL_STATE, rtwdev->flags);
+
+       wiphy_rfkill_set_hw_state(rtwdev->hw->wiphy, blocked);
+}
+
 int rtw89_chip_info_setup(struct rtw89_dev *rtwdev)
 {
        int ret;
@@ -4654,6 +4719,8 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
                goto err_unregister_hw;
        }
 
+       rtw89_rfkill_polling_init(rtwdev);
+
        return 0;
 
 err_unregister_hw:
@@ -4668,6 +4735,7 @@ static void rtw89_core_unregister_hw(struct rtw89_dev *rtwdev)
 {
        struct ieee80211_hw *hw = rtwdev->hw;
 
+       rtw89_rfkill_polling_deinit(rtwdev);
        ieee80211_unregister_hw(hw);
        rtw89_core_clr_supported_band(rtwdev);
 }
index 0a09360515dca657e52d303e8af7c018350b1b22..a0d0bf53d961c8d584891e96d51e02a0d5bfbccf 100644 (file)
@@ -4069,6 +4069,11 @@ struct rtw89_rrsr_cfgs {
        struct rtw89_reg3_def rsc;
 };
 
+struct rtw89_rfkill_regs {
+       struct rtw89_reg3_def pinmux;
+       struct rtw89_reg3_def mode;
+};
+
 struct rtw89_dig_regs {
        u32 seg0_pd_reg;
        u32 pd_lower_bound_mask;
@@ -4260,6 +4265,8 @@ struct rtw89_chip_info {
        const struct rtw89_rrsr_cfgs *rrsr_cfgs;
        struct rtw89_reg_def bss_clr_vld;
        u32 bss_clr_map_reg;
+       const struct rtw89_rfkill_regs *rfkill_init;
+       struct rtw89_reg_def rfkill_get;
        u32 dma_ch_mask;
        const struct rtw89_edcca_regs *edcca_regs;
        const struct wiphy_wowlan_support *wowlan_stub;
@@ -4618,6 +4625,7 @@ enum rtw89_flags {
        RTW89_FLAG_WOWLAN,
        RTW89_FLAG_FORBIDDEN_TRACK_WROK,
        RTW89_FLAG_CHANGING_INTERFACE,
+       RTW89_FLAG_HW_RFKILL_STATE,
 
        NUM_OF_RTW89_FLAGS,
 };
@@ -6506,6 +6514,7 @@ int rtw89_core_sta_remove(struct rtw89_dev *rtwdev,
 void rtw89_core_set_tid_config(struct rtw89_dev *rtwdev,
                               struct ieee80211_sta *sta,
                               struct cfg80211_tid_config *tid_config);
+void rtw89_core_rfkill_poll(struct rtw89_dev *rtwdev, bool force);
 void rtw89_check_quirks(struct rtw89_dev *rtwdev, const struct dmi_system_id *quirks);
 int rtw89_core_init(struct rtw89_dev *rtwdev);
 void rtw89_core_deinit(struct rtw89_dev *rtwdev);
index 1508693032cb209c770f6ce610961bc5afb26ed0..b95fa288c5f5b839426e0cfaa65fed5efba6647c 100644 (file)
@@ -1147,6 +1147,22 @@ static void rtw89_set_rekey_data(struct ieee80211_hw *hw,
 }
 #endif
 
+static void rtw89_ops_rfkill_poll(struct ieee80211_hw *hw)
+{
+       struct rtw89_dev *rtwdev = hw->priv;
+
+       mutex_lock(&rtwdev->mutex);
+
+       /* wl_disable GPIO get floating when entering LPS */
+       if (test_bit(RTW89_FLAG_RUNNING, rtwdev->flags))
+               goto out;
+
+       rtw89_core_rfkill_poll(rtwdev, false);
+
+out:
+       mutex_unlock(&rtwdev->mutex);
+}
+
 const struct ieee80211_ops rtw89_ops = {
        .tx                     = rtw89_ops_tx,
        .wake_tx_queue          = rtw89_ops_wake_tx_queue,
@@ -1193,5 +1209,6 @@ const struct ieee80211_ops rtw89_ops = {
        .set_wakeup             = rtw89_ops_set_wakeup,
        .set_rekey_data         = rtw89_set_rekey_data,
 #endif
+       .rfkill_poll            = rtw89_ops_rfkill_poll,
 };
 EXPORT_SYMBOL(rtw89_ops);
index 15b17e2cf99bd7cea6845c8e42d9552a963425e0..7afec48c4056eecf780f79b3b36f4578351b8ee7 100644 (file)
 #define B_AX_DBG_SEL0_16BIT BIT(11)
 #define B_AX_DBG_SEL0 GENMASK(7, 0)
 
+#define R_AX_GPIO_EXT_CTRL 0x0060
+#define B_AX_GPIO_MOD_15_TO_8_MASK GENMASK(31, 24)
+#define B_AX_GPIO_MOD_9 BIT(25)
+#define B_AX_GPIO_IO_SEL_15_TO_8_MASK GENMASK(23, 16)
+#define B_AX_GPIO_IO_SEL_9 BIT(17)
+#define B_AX_GPIO_OUT_15_TO_8_MASK GENMASK(15, 8)
+#define B_AX_GPIO_IN_15_TO_8_MASK GENMASK(7, 0)
+#define B_AX_GPIO_IN_9 BIT(1)
+
 #define R_AX_SYS_SDIO_CTRL 0x0070
 #define B_AX_PCIE_DIS_L2_CTRL_LDO_HCI BIT(15)
 #define B_AX_PCIE_DIS_WLSUS_AFT_PDN BIT(14)
 
 #define R_AX_GPIO0_7_FUNC_SEL 0x02D0
 
+#define R_AX_GPIO8_15_FUNC_SEL 0x02D4
+#define B_AX_PINMUX_GPIO9_FUNC_SEL_MASK GENMASK(7, 4)
+
 #define R_AX_EECS_EESK_FUNC_SEL 0x02D8
 #define B_AX_PINMUX_EESK_FUNC_SEL_MASK GENMASK(7, 4)
 
 #define R_BE_EFUSE_CTRL_1_V1 0x0034
 #define B_BE_EF_DATA_MASK GENMASK(31, 0)
 
+#define R_BE_GPIO_EXT_CTRL 0x0060
+#define B_BE_GPIO_MOD_15_TO_8_MASK GENMASK(31, 24)
+#define B_BE_GPIO_MOD_9 BIT(25)
+#define B_BE_GPIO_IO_SEL_15_TO_8_MASK GENMASK(23, 16)
+#define B_BE_GPIO_IO_SEL_9 BIT(17)
+#define B_BE_GPIO_OUT_15_TO_8_MASK GENMASK(15, 8)
+#define B_BE_GPIO_IN_15_TO_8_MASK GENMASK(7, 0)
+#define B_BE_GPIO_IN_9 BIT(1)
+
 #define R_BE_WL_BT_PWR_CTRL 0x0068
 #define B_BE_ISO_BD2PP BIT(31)
 #define B_BE_LDOV12B_EN BIT(30)
 #define B_BE_REG_CK40M_EN BIT(1)
 #define B_BE_REG_CK640M_EN BIT(0)
 
+#define R_BE_GPIO8_15_FUNC_SEL 0x02D4
+#define B_BE_PINMUX_GPIO9_FUNC_SEL_MASK GENMASK(7, 4)
+
 #define R_BE_WLAN_XTAL_SI_CTRL 0x0270
 #define B_BE_WL_XTAL_SI_CMD_POLL BIT(31)
 #define B_BE_WL_XTAL_SI_CHIPID_MASK GENMASK(30, 28)
index 40cf84a79c464c34b0e185a01adb28420ae30849..b8f57a602dcf1d135c55af8843dfa057f14ac127 100644 (file)
@@ -185,6 +185,15 @@ static const struct rtw89_rrsr_cfgs rtw8851b_rrsr_cfgs = {
        .rsc = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_RSC_MASK, 2},
 };
 
+static const struct rtw89_rfkill_regs rtw8851b_rfkill_regs = {
+       .pinmux = {R_AX_GPIO8_15_FUNC_SEL,
+                  B_AX_PINMUX_GPIO9_FUNC_SEL_MASK,
+                  0xf},
+       .mode = {R_AX_GPIO_EXT_CTRL + 2,
+                (B_AX_GPIO_MOD_9 | B_AX_GPIO_IO_SEL_9) >> 16,
+                0x0},
+};
+
 static const struct rtw89_dig_regs rtw8851b_dig_regs = {
        .seg0_pd_reg = R_SEG0R_PD_V1,
        .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
@@ -2524,6 +2533,8 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
        .rrsr_cfgs              = &rtw8851b_rrsr_cfgs,
        .bss_clr_vld            = {R_BSS_CLR_MAP_V1, B_BSS_CLR_MAP_VLD0},
        .bss_clr_map_reg        = R_BSS_CLR_MAP_V1,
+       .rfkill_init            = &rtw8851b_rfkill_regs,
+       .rfkill_get             = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9},
        .dma_ch_mask            = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) |
                                  BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) |
                                  BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI),
index 08e148328c6227db09a37c8bf9ee9d5136807b2d..88f8f2f4c6e2ba773428186a5f2d4107a9e9d4e1 100644 (file)
@@ -478,6 +478,15 @@ static const struct rtw89_rrsr_cfgs rtw8852a_rrsr_cfgs = {
        .rsc = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_RSC_MASK, 2},
 };
 
+static const struct rtw89_rfkill_regs rtw8852a_rfkill_regs = {
+       .pinmux = {R_AX_GPIO8_15_FUNC_SEL,
+                  B_AX_PINMUX_GPIO9_FUNC_SEL_MASK,
+                  0xf},
+       .mode = {R_AX_GPIO_EXT_CTRL + 2,
+                (B_AX_GPIO_MOD_9 | B_AX_GPIO_IO_SEL_9) >> 16,
+                0x0},
+};
+
 static const struct rtw89_dig_regs rtw8852a_dig_regs = {
        .seg0_pd_reg = R_SEG0R_PD,
        .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
@@ -2240,6 +2249,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
        .rrsr_cfgs              = &rtw8852a_rrsr_cfgs,
        .bss_clr_vld            = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0},
        .bss_clr_map_reg        = R_BSS_CLR_MAP,
+       .rfkill_init            = &rtw8852a_rfkill_regs,
+       .rfkill_get             = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9},
        .dma_ch_mask            = 0,
        .edcca_regs             = &rtw8852a_edcca_regs,
 #ifdef CONFIG_PM
index a22847a311ad4741d4875378cc5f8cb2e8894e1a..ef888545d9888541107cb84de22a039508ffc4a3 100644 (file)
@@ -150,6 +150,15 @@ static const struct rtw89_rrsr_cfgs rtw8852b_rrsr_cfgs = {
        .rsc = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_RSC_MASK, 2},
 };
 
+static const struct rtw89_rfkill_regs rtw8852b_rfkill_regs = {
+       .pinmux = {R_AX_GPIO8_15_FUNC_SEL,
+                  B_AX_PINMUX_GPIO9_FUNC_SEL_MASK,
+                  0xf},
+       .mode = {R_AX_GPIO_EXT_CTRL + 2,
+                (B_AX_GPIO_MOD_9 | B_AX_GPIO_IO_SEL_9) >> 16,
+                0x0},
+};
+
 static const struct rtw89_dig_regs rtw8852b_dig_regs = {
        .seg0_pd_reg = R_SEG0R_PD_V1,
        .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
@@ -880,6 +889,8 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
        .rrsr_cfgs              = &rtw8852b_rrsr_cfgs,
        .bss_clr_vld            = {R_BSS_CLR_MAP_V1, B_BSS_CLR_MAP_VLD0},
        .bss_clr_map_reg        = R_BSS_CLR_MAP_V1,
+       .rfkill_init            = &rtw8852b_rfkill_regs,
+       .rfkill_get             = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9},
        .dma_ch_mask            = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) |
                                  BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) |
                                  BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI),
index dd9fbddc411ab275d6f9e9b5378b9c6594f5c984..8173063bcc8e27185d81eccb04ab8d500da58600 100644 (file)
@@ -148,6 +148,15 @@ static const struct rtw89_rrsr_cfgs rtw8852bt_rrsr_cfgs = {
        .rsc = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_RSC_MASK, 2},
 };
 
+static const struct rtw89_rfkill_regs rtw8852bt_rfkill_regs = {
+       .pinmux = {R_AX_GPIO8_15_FUNC_SEL,
+                  B_AX_PINMUX_GPIO9_FUNC_SEL_MASK,
+                  0xf},
+       .mode = {R_AX_GPIO_EXT_CTRL + 2,
+                (B_AX_GPIO_MOD_9 | B_AX_GPIO_IO_SEL_9) >> 16,
+                0x0},
+};
+
 static const struct rtw89_dig_regs rtw8852bt_dig_regs = {
        .seg0_pd_reg = R_SEG0R_PD_V1,
        .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
@@ -813,6 +822,8 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
        .rrsr_cfgs              = &rtw8852bt_rrsr_cfgs,
        .bss_clr_vld            = {R_BSS_CLR_MAP_V1, B_BSS_CLR_MAP_VLD0},
        .bss_clr_map_reg        = R_BSS_CLR_MAP_V1,
+       .rfkill_init            = &rtw8852bt_rfkill_regs,
+       .rfkill_get             = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9},
        .dma_ch_mask            = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) |
                                  BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) |
                                  BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI),
index 193168dc7b6c35e5423a171b73c956240b49baf7..8e500d0eb70b4fe71ca992b7ae4a5790656a5bf0 100644 (file)
@@ -147,6 +147,15 @@ static const struct rtw89_rrsr_cfgs rtw8852c_rrsr_cfgs = {
        .rsc = {R_AX_PTCL_RRSR1, B_AX_RSC_MASK, 2},
 };
 
+static const struct rtw89_rfkill_regs rtw8852c_rfkill_regs = {
+       .pinmux = {R_AX_GPIO8_15_FUNC_SEL,
+                  B_AX_PINMUX_GPIO9_FUNC_SEL_MASK,
+                  0xf},
+       .mode = {R_AX_GPIO_EXT_CTRL + 2,
+                (B_AX_GPIO_MOD_9 | B_AX_GPIO_IO_SEL_9) >> 16,
+                0x0},
+};
+
 static const struct rtw89_dig_regs rtw8852c_dig_regs = {
        .seg0_pd_reg = R_SEG0R_PD,
        .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
@@ -3022,6 +3031,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
        .rrsr_cfgs              = &rtw8852c_rrsr_cfgs,
        .bss_clr_vld            = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0},
        .bss_clr_map_reg        = R_BSS_CLR_MAP,
+       .rfkill_init            = &rtw8852c_rfkill_regs,
+       .rfkill_get             = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9},
        .dma_ch_mask            = 0,
        .edcca_regs             = &rtw8852c_edcca_regs,
 #ifdef CONFIG_PM
index 2af568a3264d3553a10cd45c7b1ef96f3dce7e1e..c763b14d43e9b49d07fe54889bf52a42f85d3d78 100644 (file)
@@ -165,6 +165,15 @@ static const struct rtw89_rrsr_cfgs rtw8922a_rrsr_cfgs = {
        .rsc = {R_BE_PTCL_RRSR1, B_BE_RSC_MASK, 2},
 };
 
+static const struct rtw89_rfkill_regs rtw8922a_rfkill_regs = {
+       .pinmux = {R_BE_GPIO8_15_FUNC_SEL,
+                  B_BE_PINMUX_GPIO9_FUNC_SEL_MASK,
+                  0xf},
+       .mode = {R_BE_GPIO_EXT_CTRL + 2,
+                (B_BE_GPIO_MOD_9 | B_BE_GPIO_IO_SEL_9) >> 16,
+                0x0},
+};
+
 static const struct rtw89_dig_regs rtw8922a_dig_regs = {
        .seg0_pd_reg = R_SEG0R_PD_V2,
        .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
@@ -2624,6 +2633,8 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
        .rrsr_cfgs              = &rtw8922a_rrsr_cfgs,
        .bss_clr_vld            = {R_BSS_CLR_VLD_V2, B_BSS_CLR_VLD0_V2},
        .bss_clr_map_reg        = R_BSS_CLR_MAP_V2,
+       .rfkill_init            = &rtw8922a_rfkill_regs,
+       .rfkill_get             = {R_BE_GPIO_EXT_CTRL, B_BE_GPIO_IN_9},
        .dma_ch_mask            = 0,
        .edcca_regs             = &rtw8922a_edcca_regs,
 #ifdef CONFIG_PM