wl12xx: FM WLAN coexistence
authorShahar Levi <shahar_levi@ti.com>
Mon, 11 Apr 2011 12:41:46 +0000 (15:41 +0300)
committerLuciano Coelho <coelho@ti.com>
Mon, 2 May 2011 07:26:06 +0000 (10:26 +0300)
Add support to FM WLAN coexistence (STA only).  Some WiFi harmonics
may interfere with FM operation, to avoid this problem special
coexistence techniques are activated around some FM frequencies.

Signed-off-by: Shahar Levi <shahar_levi@ti.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/wl12xx/acx.c
drivers/net/wireless/wl12xx/acx.h
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/main.c

index a5c9c0a..8a39d1e 100644 (file)
@@ -1626,3 +1626,43 @@ out:
        kfree(acx);
        return ret;
 }
+
+int wl1271_acx_fm_coex(struct wl1271 *wl)
+{
+       struct wl1271_acx_fm_coex *acx;
+       int ret;
+
+       wl1271_debug(DEBUG_ACX, "acx fm coex setting");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->enable = wl->conf.fm_coex.enable;
+       acx->swallow_period = wl->conf.fm_coex.swallow_period;
+       acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1;
+       acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2;
+       acx->m_divider_fref_set_1 =
+               cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1);
+       acx->m_divider_fref_set_2 =
+               cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2);
+       acx->coex_pll_stabilization_time =
+               cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time);
+       acx->ldo_stabilization_time =
+               cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time);
+       acx->fm_disturbed_band_margin =
+               wl->conf.fm_coex.fm_disturbed_band_margin;
+       acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff;
+
+       ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx fm coex setting failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
index 942908c..2dde034 100644 (file)
@@ -1179,6 +1179,65 @@ struct wl1271_acx_inconnection_sta {
        u8 padding1[2];
 } __packed;
 
+/*
+ * ACX_FM_COEX_CFG
+ * set the FM co-existence parameters.
+ */
+struct wl1271_acx_fm_coex {
+       struct acx_header header;
+       /* enable(1) / disable(0) the FM Coex feature */
+       u8 enable;
+       /*
+        * Swallow period used in COEX PLL swallowing mechanism.
+        * 0xFF = use FW default
+        */
+       u8 swallow_period;
+       /*
+        * The N divider used in COEX PLL swallowing mechanism for Fref of
+        * 38.4/19.2 Mhz. 0xFF = use FW default
+        */
+       u8 n_divider_fref_set_1;
+       /*
+        * The N divider used in COEX PLL swallowing mechanism for Fref of
+        * 26/52 Mhz. 0xFF = use FW default
+        */
+       u8 n_divider_fref_set_2;
+       /*
+        * The M divider used in COEX PLL swallowing mechanism for Fref of
+        * 38.4/19.2 Mhz. 0xFFFF = use FW default
+        */
+       __le16 m_divider_fref_set_1;
+       /*
+        * The M divider used in COEX PLL swallowing mechanism for Fref of
+        * 26/52 Mhz. 0xFFFF = use FW default
+        */
+       __le16 m_divider_fref_set_2;
+       /*
+        * The time duration in uSec required for COEX PLL to stabilize.
+        * 0xFFFFFFFF = use FW default
+        */
+       __le32 coex_pll_stabilization_time;
+       /*
+        * The time duration in uSec required for LDO to stabilize.
+        * 0xFFFFFFFF = use FW default
+        */
+       __le16 ldo_stabilization_time;
+       /*
+        * The disturbed frequency band margin around the disturbed frequency
+        * center (single sided).
+        * For example, if 2 is configured, the following channels will be
+        * considered disturbed channel:
+        *   80 +- 0.1 MHz, 91 +- 0.1 MHz, 98 +- 0.1 MHz, 102 +- 0.1 MH
+        * 0xFF = use FW default
+        */
+       u8 fm_disturbed_band_margin;
+       /*
+        * The swallow clock difference of the swallowing mechanism.
+        * 0xFF = use FW default
+        */
+       u8 swallow_clk_diff;
+} __packed;
+
 enum {
        ACX_WAKE_UP_CONDITIONS      = 0x0002,
        ACX_MEM_CFG                 = 0x0003,
@@ -1208,6 +1267,7 @@ enum {
        ACX_BCN_DTIM_OPTIONS        = 0x0031,
        ACX_SG_ENABLE               = 0x0032,
        ACX_SG_CFG                  = 0x0033,
+       ACX_FM_COEX_CFG             = 0x0034,
        ACX_BEACON_FILTER_TABLE     = 0x0038,
        ACX_ARP_IP_FILTER           = 0x0039,
        ACX_ROAMING_STATISTICS_TBL  = 0x003B,
@@ -1318,5 +1378,6 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
 int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl);
 int wl1271_acx_config_ps(struct wl1271 *wl);
 int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
+int wl1271_acx_fm_coex(struct wl1271 *wl);
 
 #endif /* __WL1271_ACX_H__ */
index 5551d9d..a4e0acf 100644 (file)
@@ -1199,6 +1199,19 @@ struct conf_memory_settings {
        u8 tx_min;
 };
 
+struct conf_fm_coex {
+       u8 enable;
+       u8 swallow_period;
+       u8 n_divider_fref_set_1;
+       u8 n_divider_fref_set_2;
+       u16 m_divider_fref_set_1;
+       u16 m_divider_fref_set_2;
+       u32 coex_pll_stabilization_time;
+       u16 ldo_stabilization_time;
+       u8 fm_disturbed_band_margin;
+       u8 swallow_clk_diff;
+};
+
 struct conf_drv_settings {
        struct conf_sg_settings sg;
        struct conf_rx_settings rx;
@@ -1212,6 +1225,7 @@ struct conf_drv_settings {
        struct conf_ht_setting ht;
        struct conf_memory_settings mem_wl127x;
        struct conf_memory_settings mem_wl128x;
+       struct conf_fm_coex fm_coex;
        u8 hci_io_ds;
 };
 
index ab3b1e2..46fd721 100644 (file)
@@ -356,6 +356,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
        if (ret < 0)
                return ret;
 
+       /* FM WLAN coexistence */
+       ret = wl1271_acx_fm_coex(wl);
+       if (ret < 0)
+               return ret;
+
        /* Beacons and broadcast settings */
        ret = wl1271_init_beacon_broadcast(wl);
        if (ret < 0)
index 53a8e23..8a7a8c5 100644 (file)
@@ -320,6 +320,18 @@ static struct conf_drv_settings default_conf = {
                .min_req_rx_blocks            = 22,
                .tx_min                       = 27,
        },
+       .fm_coex = {
+               .enable                       = true,
+               .swallow_period               = 5,
+               .n_divider_fref_set_1         = 0xff,       /* default */
+               .n_divider_fref_set_2         = 12,
+               .m_divider_fref_set_1         = 148,
+               .m_divider_fref_set_2         = 0xffff,     /* default */
+               .coex_pll_stabilization_time  = 0xffffffff, /* default */
+               .ldo_stabilization_time       = 0xffff,     /* default */
+               .fm_disturbed_band_margin     = 0xff,       /* default */
+               .swallow_clk_diff             = 0xff,       /* default */
+       },
        .hci_io_ds = HCI_IO_DS_6MA,
 };
 
@@ -508,6 +520,11 @@ static int wl1271_plt_init(struct wl1271 *wl)
        if (ret < 0)
                goto out_free_memmap;
 
+       /* FM WLAN coexistence */
+       ret = wl1271_acx_fm_coex(wl);
+       if (ret < 0)
+               goto out_free_memmap;
+
        /* Energy detection */
        ret = wl1271_init_energy_detection(wl);
        if (ret < 0)