summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/microchip
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/microchip')
-rw-r--r--drivers/net/wireless/microchip/wilc1000/cfg80211.c144
-rw-r--r--drivers/net/wireless/microchip/wilc1000/cfg80211.h2
-rw-r--r--drivers/net/wireless/microchip/wilc1000/fw.h13
-rw-r--r--drivers/net/wireless/microchip/wilc1000/hif.c29
-rw-r--r--drivers/net/wireless/microchip/wilc1000/hif.h2
-rw-r--r--drivers/net/wireless/microchip/wilc1000/mon.c4
-rw-r--r--drivers/net/wireless/microchip/wilc1000/netdev.c99
-rw-r--r--drivers/net/wireless/microchip/wilc1000/netdev.h10
-rw-r--r--drivers/net/wireless/microchip/wilc1000/sdio.c248
-rw-r--r--drivers/net/wireless/microchip/wilc1000/spi.c35
-rw-r--r--drivers/net/wireless/microchip/wilc1000/wlan.c471
-rw-r--r--drivers/net/wireless/microchip/wilc1000/wlan.h55
12 files changed, 770 insertions, 342 deletions
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index 089102ed9ae5..e7aa0f991923 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -231,6 +231,7 @@ struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl)
}
static int set_channel(struct wiphy *wiphy,
+ struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
struct wilc *wl = wiphy_priv(wiphy);
@@ -1424,7 +1425,7 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev,
struct wilc_vif *vif = netdev_priv(dev);
int ret;
- ret = set_channel(wiphy, &settings->chandef);
+ ret = set_channel(wiphy, dev, &settings->chandef);
if (ret != 0)
netdev_err(dev, "Error in setting channel\n");
@@ -1617,23 +1618,6 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
return 0;
}
-static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
-{
- struct wilc *wl = wiphy_priv(wiphy);
-
- if (!wow && wilc_wlan_get_num_conn_ifcs(wl))
- wl->suspend_event = true;
- else
- wl->suspend_event = false;
-
- return 0;
-}
-
-static int wilc_resume(struct wiphy *wiphy)
-{
- return 0;
-}
-
static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled)
{
struct wilc *wl = wiphy_priv(wiphy);
@@ -1685,7 +1669,7 @@ static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
- int *dbm)
+ unsigned int link_id, int *dbm)
{
int ret;
struct wilc_vif *vif = netdev_priv(wdev->netdev);
@@ -1739,8 +1723,6 @@ static const struct cfg80211_ops wilc_cfg80211_ops = {
.set_power_mgmt = set_power_mgmt,
.set_cqm_rssi_config = set_cqm_rssi_config,
- .suspend = wilc_suspend,
- .resume = wilc_resume,
.set_wakeup = wilc_set_wakeup,
.set_tx_power = set_tx_power,
.get_tx_power = get_tx_power,
@@ -1776,67 +1758,10 @@ void wlan_deinit_locks(struct wilc *wilc)
cleanup_srcu_struct(&wilc->srcu);
}
-int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
- const struct wilc_hif_func *ops)
-{
- struct wilc *wl;
- struct wilc_vif *vif;
- int ret, i;
-
- wl = wilc_create_wiphy(dev);
- if (!wl)
- return -EINVAL;
-
- wlan_init_locks(wl);
-
- ret = wilc_wlan_cfg_init(wl);
- if (ret)
- goto free_wl;
-
- *wilc = wl;
- wl->io_type = io_type;
- wl->hif_func = ops;
-
- for (i = 0; i < NQUEUES; i++)
- INIT_LIST_HEAD(&wl->txq[i].txq_head.list);
-
- INIT_LIST_HEAD(&wl->rxq_head.list);
- INIT_LIST_HEAD(&wl->vif_list);
-
- wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM,
- wiphy_name(wl->wiphy));
- if (!wl->hif_workqueue) {
- ret = -ENOMEM;
- goto free_cfg;
- }
- vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE,
- NL80211_IFTYPE_STATION, false);
- if (IS_ERR(vif)) {
- ret = PTR_ERR(vif);
- goto free_hq;
- }
-
- return 0;
-
-free_hq:
- destroy_workqueue(wl->hif_workqueue);
-
-free_cfg:
- wilc_wlan_cfg_deinit(wl);
-
-free_wl:
- wlan_deinit_locks(wl);
- wiphy_unregister(wl->wiphy);
- wiphy_free(wl->wiphy);
- return ret;
-}
-EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
-
-struct wilc *wilc_create_wiphy(struct device *dev)
+static struct wilc *wilc_create_wiphy(struct device *dev)
{
struct wiphy *wiphy;
struct wilc *wl;
- int ret;
wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl));
if (!wiphy)
@@ -1879,17 +1804,66 @@ struct wilc *wilc_create_wiphy(struct device *dev)
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT);
wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
- wiphy->features |= NL80211_FEATURE_SAE;
set_wiphy_dev(wiphy, dev);
wl->wiphy = wiphy;
- ret = wiphy_register(wiphy);
- if (ret) {
- wiphy_free(wiphy);
- return NULL;
- }
return wl;
}
+int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
+ const struct wilc_hif_func *ops)
+{
+ struct wilc *wl;
+ int ret, i;
+
+ wl = wilc_create_wiphy(dev);
+ if (!wl)
+ return -EINVAL;
+
+ wlan_init_locks(wl);
+
+ ret = wilc_wlan_cfg_init(wl);
+ if (ret)
+ goto free_wl;
+
+ *wilc = wl;
+ wl->io_type = io_type;
+ wl->hif_func = ops;
+
+ for (i = 0; i < NQUEUES; i++)
+ INIT_LIST_HEAD(&wl->txq[i].txq_head.list);
+
+ INIT_LIST_HEAD(&wl->rxq_head.list);
+ INIT_LIST_HEAD(&wl->vif_list);
+
+ wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM,
+ wiphy_name(wl->wiphy));
+ if (!wl->hif_workqueue) {
+ ret = -ENOMEM;
+ goto free_cfg;
+ }
+
+ return 0;
+
+free_cfg:
+ wilc_wlan_cfg_deinit(wl);
+
+free_wl:
+ wlan_deinit_locks(wl);
+ wiphy_free(wl->wiphy);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
+
+int wilc_cfg80211_register(struct wilc *wilc)
+{
+ /* WPA3/SAE supported only on WILC1000 */
+ if (is_wilc1000(wilc->chipid))
+ wilc->wiphy->features |= NL80211_FEATURE_SAE;
+
+ return wiphy_register(wilc->wiphy);
+}
+EXPORT_SYMBOL_GPL(wilc_cfg80211_register);
+
int wilc_init_host_int(struct net_device *net)
{
int ret;
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.h b/drivers/net/wireless/microchip/wilc1000/cfg80211.h
index 8c65951cfaf9..2dc9c1c42d60 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.h
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.h
@@ -10,7 +10,7 @@
int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
const struct wilc_hif_func *ops);
-struct wilc *wilc_create_wiphy(struct device *dev);
+int wilc_cfg80211_register(struct wilc *wilc);
void wilc_deinit_host_int(struct net_device *net);
int wilc_init_host_int(struct net_device *net);
void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size);
diff --git a/drivers/net/wireless/microchip/wilc1000/fw.h b/drivers/net/wireless/microchip/wilc1000/fw.h
index 5c5cac4aab02..7a930e89614c 100644
--- a/drivers/net/wireless/microchip/wilc1000/fw.h
+++ b/drivers/net/wireless/microchip/wilc1000/fw.h
@@ -13,6 +13,12 @@
#define WILC_MAX_RATES_SUPPORTED 12
#define WILC_MAX_NUM_PMKIDS 16
#define WILC_MAX_NUM_SCANNED_CH 14
+#define WILC_NVMEM_MAX_NUM_BANK 6
+#define WILC_NVMEM_BANK_BASE 0x30000000
+#define WILC_NVMEM_LOW_BANK_OFFSET 0x102c
+#define WILC_NVMEM_HIGH_BANK_OFFSET 0x1380
+#define WILC_NVMEM_IS_BANK_USED BIT(31)
+#define WILC_NVMEM_IS_BANK_INVALID BIT(30)
struct wilc_assoc_resp {
__le16 capab_info;
@@ -127,4 +133,11 @@ struct wilc_external_auth_param {
__le32 key_mgmt_suites;
__le16 status;
} __packed;
+
+static inline u32 get_bank_offset_from_bank_index(unsigned int i)
+{
+ return (((i) < 2) ? WILC_NVMEM_LOW_BANK_OFFSET + ((i) * 32) :
+ WILC_NVMEM_HIGH_BANK_OFFSET + ((i) - 2) * 16);
+}
+
#endif
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c
index f1085ccb7eed..cb46a39ef757 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.c
+++ b/drivers/net/wireless/microchip/wilc1000/hif.c
@@ -382,7 +382,9 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss,
struct ieee80211_p2p_noa_attr noa_attr;
const struct cfg80211_bss_ies *ies;
struct wilc_join_bss_param *param;
- u8 rates_len = 0, ies_len;
+ u8 rates_len = 0;
+ int ies_len;
+ u64 ies_tsf;
int ret;
param = kzalloc(sizeof(*param), GFP_KERNEL);
@@ -398,6 +400,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss,
return NULL;
}
ies_len = ies->len;
+ ies_tsf = ies->tsf;
rcu_read_unlock();
param->beacon_period = cpu_to_le16(bss->beacon_interval);
@@ -453,7 +456,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss,
IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
(u8 *)&noa_attr, sizeof(noa_attr));
if (ret > 0) {
- param->tsf_lo = cpu_to_le32(ies->tsf);
+ param->tsf_lo = cpu_to_le32(ies_tsf);
param->noa_enabled = 1;
param->idx = noa_attr.index;
if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) {
@@ -640,7 +643,7 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
}
}
- del_timer(&hif_drv->connect_timer);
+ timer_delete(&hif_drv->connect_timer);
conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,
hif_drv->conn_info.priv);
@@ -666,7 +669,7 @@ void wilc_handle_disconnect(struct wilc_vif *vif)
struct host_if_drv *hif_drv = vif->hif_drv;
if (hif_drv->usr_scan_req.scan_result) {
- del_timer(&hif_drv->scan_timer);
+ timer_delete(&hif_drv->scan_timer);
handle_scan_done(vif, SCAN_EVENT_ABORTED);
}
@@ -710,7 +713,7 @@ static void handle_rcvd_gnrl_async_info(struct work_struct *work)
if (hif_drv->hif_state == HOST_IF_CONNECTED) {
wilc_handle_disconnect(vif);
} else if (hif_drv->usr_scan_req.scan_result) {
- del_timer(&hif_drv->scan_timer);
+ timer_delete(&hif_drv->scan_timer);
handle_scan_done(vif, SCAN_EVENT_ABORTED);
}
}
@@ -743,7 +746,7 @@ int wilc_disconnect(struct wilc_vif *vif)
conn_info = &hif_drv->conn_info;
if (scan_req->scan_result) {
- del_timer(&hif_drv->scan_timer);
+ timer_delete(&hif_drv->scan_timer);
scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->priv);
scan_req->scan_result = NULL;
}
@@ -751,7 +754,7 @@ int wilc_disconnect(struct wilc_vif *vif)
if (conn_info->conn_result) {
if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
hif_drv->hif_state == HOST_IF_EXTERNAL_AUTH)
- del_timer(&hif_drv->connect_timer);
+ timer_delete(&hif_drv->connect_timer);
conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,
conn_info->priv);
@@ -956,7 +959,7 @@ static void listen_timer_cb(struct timer_list *t)
int result;
struct host_if_msg *msg;
- del_timer(&vif->hif_drv->remain_on_ch_timer);
+ timer_delete(&vif->hif_drv->remain_on_ch_timer);
msg = wilc_alloc_work(vif, wilc_handle_listen_state_expired, false);
if (IS_ERR(msg))
@@ -1063,7 +1066,7 @@ static void handle_scan_complete(struct work_struct *work)
{
struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
- del_timer(&msg->vif->hif_drv->scan_timer);
+ timer_delete(&msg->vif->hif_drv->scan_timer);
handle_scan_done(msg->vif, SCAN_EVENT_DONE);
@@ -1293,7 +1296,7 @@ int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
return result;
}
-int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr)
+int wilc_set_mac_address(struct wilc_vif *vif, const u8 *mac_addr)
{
struct wid wid;
int result;
@@ -1301,7 +1304,7 @@ int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr)
wid.id = WID_MAC_ADDR;
wid.type = WID_STR;
wid.size = ETH_ALEN;
- wid.val = mac_addr;
+ wid.val = (u8 *)mac_addr;
result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
@@ -1548,7 +1551,7 @@ int wilc_deinit(struct wilc_vif *vif)
timer_shutdown_sync(&hif_drv->scan_timer);
timer_shutdown_sync(&hif_drv->connect_timer);
- del_timer_sync(&vif->periodic_rssi);
+ timer_delete_sync(&vif->periodic_rssi);
timer_shutdown_sync(&hif_drv->remain_on_ch_timer);
if (hif_drv->usr_scan_req.scan_result) {
@@ -1715,7 +1718,7 @@ int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie)
return -EFAULT;
}
- del_timer(&vif->hif_drv->remain_on_ch_timer);
+ timer_delete(&vif->hif_drv->remain_on_ch_timer);
return wilc_handle_roc_expired(vif, cookie);
}
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h
index 0d380586b1d9..96eeaf31d237 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.h
+++ b/drivers/net/wireless/microchip/wilc1000/hif.h
@@ -167,7 +167,7 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
u8 cipher_mode);
int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid);
int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr);
-int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr);
+int wilc_set_mac_address(struct wilc_vif *vif, const u8 *mac_addr);
int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
size_t ies_len);
int wilc_disconnect(struct wilc_vif *vif);
diff --git a/drivers/net/wireless/microchip/wilc1000/mon.c b/drivers/net/wireless/microchip/wilc1000/mon.c
index 03b7229a0ff5..c3d27aaec297 100644
--- a/drivers/net/wireless/microchip/wilc1000/mon.c
+++ b/drivers/net/wireless/microchip/wilc1000/mon.c
@@ -7,12 +7,12 @@
#include "cfg80211.h"
struct wilc_wfi_radiotap_hdr {
- struct ieee80211_radiotap_header hdr;
+ struct ieee80211_radiotap_header_fixed hdr;
u8 rate;
} __packed;
struct wilc_wfi_radiotap_cb_hdr {
- struct ieee80211_radiotap_header hdr;
+ struct ieee80211_radiotap_header_fixed hdr;
u8 rate;
u8 dump;
u16 tx_flags;
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c
index 710e29bea560..af298021e050 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.c
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.c
@@ -23,6 +23,12 @@
#define __WILC1000_FW(api) WILC1000_FW_PREFIX #api ".bin"
#define WILC1000_FW(api) __WILC1000_FW(api)
+#define WILC3000_API_VER 1
+
+#define WILC3000_FW_PREFIX "atmel/wilc3000_wifi_firmware-"
+#define __WILC3000_FW(api) WILC3000_FW_PREFIX #api ".bin"
+#define WILC3000_FW(api) __WILC3000_FW(api)
+
static irqreturn_t isr_uh_routine(int irq, void *user_data)
{
struct wilc *wilc = user_data;
@@ -195,20 +201,24 @@ static int wilc_wlan_get_firmware(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
- int chip_id;
const struct firmware *wilc_fw;
+ char *firmware;
int ret;
- chip_id = wilc_get_chipid(wilc, false);
+ if (is_wilc1000(wilc->chipid))
+ firmware = WILC1000_FW(WILC1000_API_VER);
+ else if (is_wilc3000(wilc->chipid))
+ firmware = WILC3000_FW(WILC3000_API_VER);
+ else
+ return -EINVAL;
- netdev_info(dev, "ChipID [%x] loading firmware [%s]\n", chip_id,
- WILC1000_FW(WILC1000_API_VER));
+ netdev_info(dev, "WILC%d loading firmware [%s]\n",
+ is_wilc1000(wilc->chipid) ? 1000 : 3000,
+ firmware);
- ret = request_firmware(&wilc_fw, WILC1000_FW(WILC1000_API_VER),
- wilc->dev);
+ ret = request_firmware(&wilc_fw, firmware, wilc->dev);
if (ret != 0) {
- netdev_err(dev, "%s - firmware not available\n",
- WILC1000_FW(WILC1000_API_VER));
+ netdev_err(dev, "%s - firmware not available\n", firmware);
return -EINVAL;
}
wilc->firmware = wilc_fw;
@@ -233,7 +243,7 @@ static int wilc_start_firmware(struct net_device *dev)
return 0;
}
-static int wilc1000_firmware_download(struct net_device *dev)
+static int wilc_firmware_download(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
@@ -528,7 +538,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
if (ret)
goto fail_irq_enable;
- ret = wilc1000_firmware_download(dev);
+ ret = wilc_firmware_download(dev);
if (ret)
goto fail_irq_enable;
@@ -590,7 +600,6 @@ static int wilc_mac_open(struct net_device *ndev)
struct wilc *wl = vif->wilc;
int ret = 0;
struct mgmt_frame_regs mgmt_regs = {};
- u8 addr[ETH_ALEN] __aligned(2);
if (!wl || !wl->dev) {
netdev_err(ndev, "device not ready\n");
@@ -612,20 +621,14 @@ static int wilc_mac_open(struct net_device *ndev)
wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype,
vif->idx);
- if (is_valid_ether_addr(ndev->dev_addr)) {
- ether_addr_copy(addr, ndev->dev_addr);
- wilc_set_mac_address(vif, addr);
- } else {
- wilc_get_mac_address(vif, addr);
- eth_hw_addr_set(ndev, addr);
- }
netdev_dbg(ndev, "Mac address: %pM\n", ndev->dev_addr);
-
- if (!is_valid_ether_addr(ndev->dev_addr)) {
- netdev_err(ndev, "Wrong MAC address\n");
+ ret = wilc_set_mac_address(vif, ndev->dev_addr);
+ if (ret) {
+ netdev_err(ndev, "Failed to enforce MAC address in chip");
wilc_deinit_host_int(ndev);
- wilc_wlan_deinitialize(ndev);
- return -EINVAL;
+ if (!wl->open_ifcs)
+ wilc_wlan_deinitialize(ndev);
+ return ret;
}
mgmt_regs.interface_stypes = vif->mgmt_reg_stypes;
@@ -681,7 +684,7 @@ static int wilc_set_mac_addr(struct net_device *dev, void *p)
}
srcu_read_unlock(&wilc->srcu, srcu_idx);
- result = wilc_set_mac_address(vif, (u8 *)addr->sa_data);
+ result = wilc_set_mac_address(vif, addr->sa_data);
if (result)
return result;
@@ -922,8 +925,6 @@ void wilc_netdev_cleanup(struct wilc *wilc)
wilc_wlan_cfg_deinit(wilc);
wlan_deinit_locks(wilc);
- wiphy_unregister(wilc->wiphy);
- wiphy_free(wilc->wiphy);
}
EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
@@ -948,6 +949,7 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
int vif_type, enum nl80211_iftype type,
bool rtnl_locked)
{
+ u8 mac_address[ETH_ALEN];
struct net_device *ndev;
struct wilc_vif *vif;
int ret;
@@ -972,37 +974,52 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
vif->priv.wdev.iftype = type;
vif->priv.dev = ndev;
- if (rtnl_locked)
- ret = cfg80211_register_netdevice(ndev);
- else
- ret = register_netdev(ndev);
-
- if (ret) {
- ret = -EFAULT;
- goto error;
- }
-
ndev->needs_free_netdev = true;
vif->iftype = vif_type;
vif->idx = wilc_get_available_idx(wl);
vif->mac_opened = 0;
+
+ memcpy(mac_address, wl->nv_mac_address, ETH_ALEN);
+ /* WILC firmware uses locally administered MAC address for the
+ * second virtual interface (bit 1 of first byte set), but
+ * since it is possibly not loaded/running yet, reproduce this behavior
+ * in the driver during interface creation.
+ */
+ if (vif->idx)
+ mac_address[0] |= 0x2;
+
+ eth_hw_addr_set(vif->ndev, mac_address);
+
mutex_lock(&wl->vif_mutex);
list_add_tail_rcu(&vif->list, &wl->vif_list);
wl->vif_num += 1;
mutex_unlock(&wl->vif_mutex);
synchronize_srcu(&wl->srcu);
- return vif;
-
-error:
if (rtnl_locked)
- cfg80211_unregister_netdevice(ndev);
+ ret = cfg80211_register_netdevice(ndev);
else
- unregister_netdev(ndev);
+ ret = register_netdev(ndev);
+
+ if (ret) {
+ ret = -EFAULT;
+ goto error_remove_vif;
+ }
+
+ return vif;
+
+error_remove_vif:
+ mutex_lock(&wl->vif_mutex);
+ list_del_rcu(&vif->list);
+ wl->vif_num -= 1;
+ mutex_unlock(&wl->vif_mutex);
+ synchronize_srcu(&wl->srcu);
free_netdev(ndev);
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_GPL(wilc_netdev_ifc_init);
MODULE_DESCRIPTION("Atmel WILC1000 core wireless driver");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER));
+MODULE_FIRMWARE(WILC3000_FW(WILC3000_API_VER));
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h
index 5937d6d45695..95bc8b8fe65a 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.h
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.h
@@ -14,6 +14,7 @@
#include <linux/if_arp.h>
#include <linux/gpio/consumer.h>
#include <linux/rculist.h>
+#include <uapi/linux/if_ether.h>
#include "hif.h"
#include "wlan.h"
@@ -220,6 +221,13 @@ struct wilc {
/* protect vif list */
struct mutex vif_mutex;
+ /* Sleepable RCU struct to manipulate vif list. Sleepable version is
+ * needed over the classic RCU version because the driver's current
+ * design involves some sleeping code while manipulating a vif
+ * retrieved from vif list (so in a SRCU critical section), like:
+ * - sending commands to the chip, using info from retrieved vif
+ * - registering a new monitoring net device
+ */
struct srcu_struct srcu;
u8 open_ifcs;
@@ -264,7 +272,6 @@ struct wilc {
const struct firmware *firmware;
struct device *dev;
- bool suspend_event;
struct workqueue_struct *hif_workqueue;
struct wilc_cfg cfg;
@@ -279,6 +286,7 @@ struct wilc {
struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)];
struct ieee80211_supported_band band;
u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)];
+ u8 nv_mac_address[ETH_ALEN];
};
struct wilc_wfi_mon_priv {
diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c
index d6d394693090..af970f999111 100644
--- a/drivers/net/wireless/microchip/wilc1000/sdio.c
+++ b/drivers/net/wireless/microchip/wilc1000/sdio.c
@@ -24,6 +24,9 @@ MODULE_DEVICE_TABLE(sdio, wilc_sdio_ids);
#define WILC_SDIO_BLOCK_SIZE 512
+static int wilc_sdio_init(struct wilc *wilc, bool resume);
+static int wilc_sdio_deinit(struct wilc *wilc);
+
struct wilc_sdio {
bool irq_gpio;
u32 block_size;
@@ -136,9 +139,11 @@ out:
static int wilc_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
+ struct wilc_sdio *sdio_priv;
+ struct wilc_vif *vif;
struct wilc *wilc;
int ret;
- struct wilc_sdio *sdio_priv;
+
sdio_priv = kzalloc(sizeof(*sdio_priv), GFP_KERNEL);
if (!sdio_priv)
@@ -169,19 +174,46 @@ static int wilc_sdio_probe(struct sdio_func *func,
wilc->bus_data = sdio_priv;
wilc->dev = &func->dev;
- wilc->rtc_clk = devm_clk_get_optional(&func->card->dev, "rtc");
+ wilc->rtc_clk = devm_clk_get_optional_enabled(&func->card->dev, "rtc");
if (IS_ERR(wilc->rtc_clk)) {
ret = PTR_ERR(wilc->rtc_clk);
goto dispose_irq;
}
- clk_prepare_enable(wilc->rtc_clk);
+
+ wilc_sdio_init(wilc, false);
+
+ ret = wilc_get_chipid(wilc);
+ if (ret)
+ goto dispose_irq;
+
+ ret = wilc_cfg80211_register(wilc);
+ if (ret)
+ goto dispose_irq;
+
+ ret = wilc_load_mac_from_nv(wilc);
+ if (ret) {
+ pr_err("Can not retrieve MAC address from chip\n");
+ goto unregister_wiphy;
+ }
+
+ wilc_sdio_deinit(wilc);
+
+ vif = wilc_netdev_ifc_init(wilc, "wlan%d", WILC_STATION_MODE,
+ NL80211_IFTYPE_STATION, false);
+ if (IS_ERR(vif)) {
+ ret = PTR_ERR(vif);
+ goto unregister_wiphy;
+ }
dev_info(&func->dev, "Driver Initializing success\n");
return 0;
+unregister_wiphy:
+ wiphy_unregister(wilc->wiphy);
dispose_irq:
irq_dispose_mapping(wilc->dev_irq_num);
wilc_netdev_cleanup(wilc);
+ wiphy_free(wilc->wiphy);
free:
kfree(sdio_priv->cmd53_buf);
kfree(sdio_priv);
@@ -193,8 +225,9 @@ static void wilc_sdio_remove(struct sdio_func *func)
struct wilc *wilc = sdio_get_drvdata(func);
struct wilc_sdio *sdio_priv = wilc->bus_data;
- clk_disable_unprepare(wilc->rtc_clk);
wilc_netdev_cleanup(wilc);
+ wiphy_unregister(wilc->wiphy);
+ wiphy_free(wilc->wiphy);
kfree(sdio_priv->cmd53_buf);
kfree(sdio_priv);
}
@@ -225,33 +258,6 @@ static bool wilc_sdio_is_init(struct wilc *wilc)
return sdio_priv->isinit;
}
-static int wilc_sdio_suspend(struct device *dev)
-{
- struct sdio_func *func = dev_to_sdio_func(dev);
- struct wilc *wilc = sdio_get_drvdata(func);
- int ret;
-
- dev_info(dev, "sdio suspend\n");
- chip_wakeup(wilc);
-
- if (!IS_ERR(wilc->rtc_clk))
- clk_disable_unprepare(wilc->rtc_clk);
-
- if (wilc->suspend_event) {
- host_sleep_notify(wilc);
- chip_allow_sleep(wilc);
- }
-
- ret = wilc_sdio_reset(wilc);
- if (ret) {
- dev_err(&func->dev, "Fail reset sdio\n");
- return ret;
- }
- sdio_claim_host(func);
-
- return 0;
-}
-
static int wilc_sdio_enable_interrupt(struct wilc *dev)
{
struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev);
@@ -617,7 +623,52 @@ static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
static int wilc_sdio_deinit(struct wilc *wilc)
{
+ struct sdio_func *func = dev_to_sdio_func(wilc->dev);
struct wilc_sdio *sdio_priv = wilc->bus_data;
+ struct sdio_cmd52 cmd;
+ int ret;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 1;
+
+ /* Disable all functions interrupts */
+ cmd.address = SDIO_CCCR_IENx;
+ cmd.data = 0;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev, "Failed to disable functions interrupts\n");
+ return ret;
+ }
+
+ /* Disable all functions */
+ cmd.address = SDIO_CCCR_IOEx;
+ cmd.data = 0;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed to reset all functions\n");
+ return ret;
+ }
+
+ /* Disable CSA */
+ cmd.read_write = 0;
+ cmd.address = SDIO_FBR_BASE(1);
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed to read CSA for function 1\n");
+ return ret;
+ }
+ cmd.read_write = 1;
+ cmd.address = SDIO_FBR_BASE(1);
+ cmd.data &= ~SDIO_FBR_ENABLE_CSA;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed to disable CSA for function 1\n");
+ return ret;
+ }
sdio_priv->isinit = false;
return 0;
@@ -629,7 +680,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
struct wilc_sdio *sdio_priv = wilc->bus_data;
struct sdio_cmd52 cmd;
int loop, ret;
- u32 chipid;
/**
* function 0 csa enable
@@ -718,18 +768,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
return ret;
}
- /**
- * make sure can read back chip id correctly
- **/
- if (!resume) {
- ret = wilc_sdio_read_reg(wilc, WILC_CHIPID, &chipid);
- if (ret) {
- dev_err(&func->dev, "Fail cmd read chip id...\n");
- return ret;
- }
- dev_err(&func->dev, "chipid (%08x)\n", chipid);
- }
-
sdio_priv->isinit = true;
return 0;
}
@@ -777,13 +815,19 @@ static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status)
cmd.address = WILC_SDIO_EXT_IRQ_FLAG_REG;
} else {
cmd.function = 0;
- cmd.address = WILC_SDIO_IRQ_FLAG_REG;
+ cmd.address = is_wilc1000(wilc->chipid) ?
+ WILC1000_SDIO_IRQ_FLAG_REG :
+ WILC3000_SDIO_IRQ_FLAG_REG;
}
cmd.raw = 0;
cmd.read_write = 0;
cmd.data = 0;
wilc_sdio_cmd52(wilc, &cmd);
irq_flags = cmd.data;
+
+ if (sdio_priv->irq_gpio)
+ irq_flags &= is_wilc1000(wilc->chipid) ? 0x1f : 0x0f;
+
tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data);
if (FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags))
@@ -805,22 +849,56 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val)
if (sdio_priv->irq_gpio)
reg = val & (BIT(MAX_NUM_INT) - 1);
- /* select VMM table 0 */
- if (val & SEL_VMM_TBL0)
- reg |= BIT(5);
- /* select VMM table 1 */
- if (val & SEL_VMM_TBL1)
- reg |= BIT(6);
- /* enable VMM */
- if (val & EN_VMM)
- reg |= BIT(7);
+ if (is_wilc1000(wilc->chipid)) {
+ /* select VMM table 0 */
+ if (val & SEL_VMM_TBL0)
+ reg |= BIT(5);
+ /* select VMM table 1 */
+ if (val & SEL_VMM_TBL1)
+ reg |= BIT(6);
+ /* enable VMM */
+ if (val & EN_VMM)
+ reg |= BIT(7);
+ } else {
+ if (sdio_priv->irq_gpio && reg) {
+ struct sdio_cmd52 cmd;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = WILC3000_SDIO_IRQ_FLAG_REG;
+ cmd.data = reg;
+
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xfe data (%d) ...\n",
+ __LINE__);
+ return ret;
+ }
+ }
+
+ reg = 0;
+ /* select VMM table 0 */
+ if (val & SEL_VMM_TBL0)
+ reg |= BIT(0);
+ /* select VMM table 1 */
+ if (val & SEL_VMM_TBL1)
+ reg |= BIT(1);
+ /* enable VMM */
+ if (val & EN_VMM)
+ reg |= BIT(2);
+ }
+
if (reg) {
struct sdio_cmd52 cmd;
cmd.read_write = 1;
cmd.function = 0;
cmd.raw = 0;
- cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG;
+ cmd.address = is_wilc1000(wilc->chipid) ?
+ WILC1000_SDIO_IRQ_CLEAR_FLAG_REG :
+ WILC3000_SDIO_VMM_TBL_CTRL_REG;
cmd.data = reg;
ret = wilc_sdio_cmd52(wilc, &cmd);
@@ -838,27 +916,12 @@ 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 reg;
if (nint > MAX_NUM_INT) {
dev_err(&func->dev, "Too many interrupts (%d)...\n", nint);
return -EINVAL;
}
- /**
- * Disable power sequencer
- **/
- if (wilc_sdio_read_reg(wilc, WILC_MISC, &reg)) {
- dev_err(&func->dev, "Failed read misc reg...\n");
- return -EINVAL;
- }
-
- reg &= ~BIT(8);
- if (wilc_sdio_write_reg(wilc, WILC_MISC, reg)) {
- dev_err(&func->dev, "Failed write misc reg...\n");
- return -EINVAL;
- }
-
if (sdio_priv->irq_gpio) {
u32 reg;
int ret, i;
@@ -942,22 +1005,48 @@ static const struct wilc_hif_func wilc_hif_sdio = {
.hif_is_init = wilc_sdio_is_init,
};
+static int wilc_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct wilc *wilc = sdio_get_drvdata(func);
+ int ret;
+
+ dev_info(dev, "sdio suspend\n");
+
+ if (!wilc->initialized)
+ return 0;
+
+ if (!IS_ERR(wilc->rtc_clk))
+ clk_disable_unprepare(wilc->rtc_clk);
+
+ ret = host_sleep_notify(wilc);
+ if (ret) {
+ clk_prepare_enable(wilc->rtc_clk);
+ return ret;
+ }
+
+ wilc_sdio_disable_interrupt(wilc);
+
+ return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+}
+
static int wilc_sdio_resume(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct wilc *wilc = sdio_get_drvdata(func);
dev_info(dev, "sdio resume\n");
- sdio_release_host(func);
- chip_wakeup(wilc);
- wilc_sdio_init(wilc, true);
- if (wilc->suspend_event)
- host_wakeup_notify(wilc);
+ if (!wilc->initialized)
+ return 0;
+
+ if (!IS_ERR(wilc->rtc_clk))
+ clk_prepare_enable(wilc->rtc_clk);
- chip_allow_sleep(wilc);
+ wilc_sdio_init(wilc, true);
+ wilc_sdio_enable_interrupt(wilc);
- return 0;
+ return host_wakeup_notify(wilc);
}
static const struct of_device_id wilc_of_match[] = {
@@ -981,8 +1070,7 @@ static struct sdio_driver wilc_sdio_driver = {
.of_match_table = wilc_of_match,
}
};
-module_driver(wilc_sdio_driver,
- sdio_register_driver,
- sdio_unregister_driver);
+module_sdio_driver(wilc_sdio_driver);
+
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 61c3572ce321..5bcabb7decea 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -206,9 +206,10 @@ static void wilc_wlan_power(struct wilc *wilc, bool on)
static int wilc_bus_probe(struct spi_device *spi)
{
- int ret;
- struct wilc *wilc;
struct wilc_spi *spi_priv;
+ struct wilc_vif *vif;
+ struct wilc *wilc;
+ int ret;
spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL);
if (!spi_priv)
@@ -227,12 +228,11 @@ static int wilc_bus_probe(struct spi_device *spi)
if (ret < 0)
goto netdev_cleanup;
- wilc->rtc_clk = devm_clk_get_optional(&spi->dev, "rtc");
+ wilc->rtc_clk = devm_clk_get_optional_enabled(&spi->dev, "rtc");
if (IS_ERR(wilc->rtc_clk)) {
ret = PTR_ERR(wilc->rtc_clk);
goto netdev_cleanup;
}
- clk_prepare_enable(wilc->rtc_clk);
dev_info(&spi->dev, "Selected CRC config: crc7=%s, crc16=%s\n",
enable_crc7 ? "on" : "off", enable_crc16 ? "on" : "off");
@@ -245,18 +245,36 @@ static int wilc_bus_probe(struct spi_device *spi)
if (ret)
goto power_down;
- ret = wilc_validate_chipid(wilc);
+ ret = wilc_get_chipid(wilc);
if (ret)
goto power_down;
+ ret = wilc_cfg80211_register(wilc);
+ if (ret)
+ goto power_down;
+
+ ret = wilc_load_mac_from_nv(wilc);
+ if (ret) {
+ pr_err("Can not retrieve MAC address from chip\n");
+ goto unregister_wiphy;
+ }
+
wilc_wlan_power(wilc, false);
+ vif = wilc_netdev_ifc_init(wilc, "wlan%d", WILC_STATION_MODE,
+ NL80211_IFTYPE_STATION, false);
+ if (IS_ERR(vif)) {
+ ret = PTR_ERR(vif);
+ goto unregister_wiphy;
+ }
return 0;
+unregister_wiphy:
+ wiphy_unregister(wilc->wiphy);
power_down:
- clk_disable_unprepare(wilc->rtc_clk);
wilc_wlan_power(wilc, false);
netdev_cleanup:
wilc_netdev_cleanup(wilc);
+ wiphy_free(wilc->wiphy);
free:
kfree(spi_priv);
return ret;
@@ -267,8 +285,9 @@ static void wilc_bus_remove(struct spi_device *spi)
struct wilc *wilc = spi_get_drvdata(spi);
struct wilc_spi *spi_priv = wilc->bus_data;
- clk_disable_unprepare(wilc->rtc_clk);
wilc_netdev_cleanup(wilc);
+ wiphy_unregister(wilc->wiphy);
+ wiphy_free(wilc->wiphy);
kfree(spi_priv);
}
@@ -1219,7 +1238,7 @@ static int wilc_validate_chipid(struct wilc *wilc)
dev_err(&spi->dev, "Fail cmd read chip id...\n");
return ret;
}
- if (!is_wilc1000(chipid)) {
+ if (!is_wilc1000(chipid) && !is_wilc3000(chipid)) {
dev_err(&spi->dev, "Unknown chip id 0x%x\n", chipid);
return -ENODEV;
}
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index a9e872a7b2c3..9d80adc45d6b 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -12,20 +12,6 @@
#define WAKE_UP_TRIAL_RETRY 10000
-static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
-{
- mutex_lock(&wilc->hif_cs);
- if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode)
- chip_wakeup(wilc);
-}
-
-static inline void release_bus(struct wilc *wilc, enum bus_release release)
-{
- if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode)
- chip_allow_sleep(wilc);
- mutex_unlock(&wilc->hif_cs);
-}
-
static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num,
struct txq_entry_t *tqe)
{
@@ -555,7 +541,7 @@ static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
return rqe;
}
-void chip_allow_sleep(struct wilc *wilc)
+static int chip_allow_sleep_wilc1000(struct wilc *wilc)
{
u32 reg = 0;
const struct wilc_hif_func *hif_func = wilc->hif_func;
@@ -584,7 +570,7 @@ void chip_allow_sleep(struct wilc *wilc)
while (--trials) {
ret = hif_func->hif_read_reg(wilc, to_host_from_fw_reg, &reg);
if (ret)
- return;
+ return ret;
if ((reg & to_host_from_fw_bit) == 0)
break;
}
@@ -594,28 +580,62 @@ void chip_allow_sleep(struct wilc *wilc)
/* Clear bit 1 */
ret = hif_func->hif_read_reg(wilc, wakeup_reg, &reg);
if (ret)
- return;
+ return ret;
if (reg & wakeup_bit) {
reg &= ~wakeup_bit;
ret = hif_func->hif_write_reg(wilc, wakeup_reg, reg);
if (ret)
- return;
+ return ret;
}
ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, &reg);
if (ret)
- return;
+ 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;
+ 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;
+
+ if (wilc->io_type == WILC_HIF_SDIO) {
+ ret = hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, &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, &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;
+}
+
+static int chip_allow_sleep(struct wilc *wilc)
+{
+ if (is_wilc1000(wilc->chipid))
+ return chip_allow_sleep_wilc1000(wilc);
+ else
+ return chip_allow_sleep_wilc3000(wilc);
}
-EXPORT_SYMBOL_GPL(chip_allow_sleep);
-void chip_wakeup(struct wilc *wilc)
+static int chip_wakeup_wilc1000(struct wilc *wilc)
{
u32 ret = 0;
u32 clk_status_val = 0, trials = 0;
@@ -627,15 +647,15 @@ void chip_wakeup(struct wilc *wilc)
if (wilc->io_type == WILC_HIF_SDIO) {
wakeup_reg = WILC_SDIO_WAKEUP_REG;
wakeup_bit = WILC_SDIO_WAKEUP_BIT;
- clk_status_reg = WILC_SDIO_CLK_STATUS_REG;
- clk_status_bit = WILC_SDIO_CLK_STATUS_BIT;
+ clk_status_reg = WILC1000_SDIO_CLK_STATUS_REG;
+ clk_status_bit = WILC1000_SDIO_CLK_STATUS_BIT;
from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG;
from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT;
} else {
wakeup_reg = WILC_SPI_WAKEUP_REG;
wakeup_bit = WILC_SPI_WAKEUP_BIT;
- clk_status_reg = WILC_SPI_CLK_STATUS_REG;
- clk_status_bit = WILC_SPI_CLK_STATUS_BIT;
+ clk_status_reg = WILC1000_SPI_CLK_STATUS_REG;
+ clk_status_bit = WILC1000_SPI_CLK_STATUS_BIT;
from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG;
from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT;
}
@@ -644,20 +664,20 @@ void chip_wakeup(struct wilc *wilc)
ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg,
from_host_to_fw_bit);
if (ret)
- return;
+ return ret;
/* Set wake-up bit */
ret = hif_func->hif_write_reg(wilc, wakeup_reg,
wakeup_bit);
if (ret)
- return;
+ return ret;
while (trials < WAKE_UP_TRIAL_RETRY) {
ret = hif_func->hif_read_reg(wilc, clk_status_reg,
&clk_status_val);
if (ret) {
pr_err("Bus error %d %x\n", ret, clk_status_val);
- return;
+ return ret;
}
if (clk_status_val & clk_status_bit)
break;
@@ -666,29 +686,135 @@ void chip_wakeup(struct wilc *wilc)
}
if (trials >= WAKE_UP_TRIAL_RETRY) {
pr_err("Failed to wake-up the chip\n");
- return;
+ return -ETIMEDOUT;
}
/* Sometimes spi fail to read clock regs after reading
* writing clockless registers
*/
if (wilc->io_type == WILC_HIF_SPI)
wilc->hif_func->hif_reset(wilc);
+
+ return 0;
+}
+
+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, clk_status_bit;
+ int wake_seq_trials = 5;
+ const struct wilc_hif_func *hif_func = wilc->hif_func;
+
+ if (wilc->io_type == WILC_HIF_SDIO) {
+ wakeup_reg = WILC_SDIO_WAKEUP_REG;
+ wakeup_bit = WILC_SDIO_WAKEUP_BIT;
+ clk_status_reg = WILC3000_SDIO_CLK_STATUS_REG;
+ clk_status_bit = WILC3000_SDIO_CLK_STATUS_BIT;
+ } else {
+ wakeup_reg = WILC_SPI_WAKEUP_REG;
+ wakeup_bit = WILC_SPI_WAKEUP_BIT;
+ clk_status_reg = WILC3000_SPI_CLK_STATUS_REG;
+ 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);
+ /* Check the clock status */
+ hif_func->hif_read_reg(wilc, clk_status_reg,
+ &clk_status_reg_val);
+
+ /* In case of clocks off, wait 1ms, and check it again.
+ * if still off, wait for another 1ms, for a total wait of 3ms.
+ * If still off, redo the wake up sequence
+ */
+ while ((clk_status_reg_val & clk_status_bit) == 0 &&
+ (++trials % 4) != 0) {
+ /* Wait for the chip to stabilize*/
+ usleep_range(1000, 1100);
+
+ /* Make sure chip is awake. This is an extra step that
+ * can be removed later to avoid the bus access
+ * overhead
+ */
+ hif_func->hif_read_reg(wilc, clk_status_reg,
+ &clk_status_reg_val);
+ }
+ /* in case of failure, Reset the wakeup bit to introduce a new
+ * 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));
+ /* added wait before wakeup sequence retry */
+ usleep_range(200, 300);
+ }
+ } while ((clk_status_reg_val & clk_status_bit) == 0 && wake_seq_trials-- > 0);
+ if (!wake_seq_trials)
+ dev_err(wilc->dev, "clocks still OFF. Wake up failed\n");
+
+ return 0;
+}
+
+static int chip_wakeup(struct wilc *wilc)
+{
+ if (is_wilc1000(wilc->chipid))
+ return chip_wakeup_wilc1000(wilc);
+ else
+ return chip_wakeup_wilc3000(wilc);
+}
+
+static inline 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) {
+ ret = chip_wakeup(wilc);
+ if (ret)
+ mutex_unlock(&wilc->hif_cs);
+ }
+
+ return ret;
}
-EXPORT_SYMBOL_GPL(chip_wakeup);
-void host_wakeup_notify(struct wilc *wilc)
+static inline int release_bus(struct wilc *wilc, enum bus_release release)
{
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
- wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1);
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ 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;
+}
+
+int host_wakeup_notify(struct wilc *wilc)
+{
+ int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+
+ if (ret)
+ return ret;
+
+ wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ?
+ WILC1000_CORTUS_INTERRUPT_2 :
+ WILC3000_CORTUS_INTERRUPT_2, 1);
+ return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
}
EXPORT_SYMBOL_GPL(host_wakeup_notify);
-void host_sleep_notify(struct wilc *wilc)
+int host_sleep_notify(struct wilc *wilc)
{
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
- wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1);
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+
+ if (ret)
+ return ret;
+
+ wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ?
+ WILC1000_CORTUS_INTERRUPT_1 :
+ WILC3000_CORTUS_INTERRUPT_1, 1);
+ return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
}
EXPORT_SYMBOL_GPL(host_sleep_notify);
@@ -715,6 +841,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
int srcu_idx;
u8 *txb = wilc->tx_buffer;
struct wilc_vif *vif;
+ int rv;
if (wilc->quit)
goto out_update_cnt;
@@ -785,7 +912,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
goto out_unlock;
vmm_table[i] = 0x0;
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ goto out_unlock;
+
counter = 0;
func = wilc->hif_func;
do {
@@ -818,19 +948,45 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
if (ret)
break;
- ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);
- if (ret)
- break;
+ if (is_wilc1000(wilc->chipid)) {
+ ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);
+ if (ret)
+ break;
- do {
- ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
+ do {
+ ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
+ if (ret)
+ break;
+ if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) {
+ entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg);
+ break;
+ }
+ } while (--timeout);
+ } else {
+ ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0);
if (ret)
break;
- if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) {
- entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg);
+
+ /* interrupt firmware */
+ ret = func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, 1);
+ if (ret)
break;
- }
- } while (--timeout);
+
+ do {
+ ret = func->hif_read_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, &reg);
+ if (ret)
+ break;
+ if (reg == 0) {
+ /* Get the entries */
+ ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
+ if (ret)
+ break;
+
+ entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg);
+ break;
+ }
+ } while (--timeout);
+ }
if (timeout <= 0) {
ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
break;
@@ -860,7 +1016,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
goto out_release_bus;
}
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ if (ret)
+ goto out_unlock;
offset = 0;
i = 0;
@@ -922,7 +1080,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
for (i = 0; i < NQUEUES; i++)
wilc->txq[i].fw.count += ac_pkt_num_to_chip[i];
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ goto out_unlock;
ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
if (ret)
@@ -931,7 +1091,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
ret = func->hif_block_tx_ext(wilc, 0, txb, offset);
out_release_bus:
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ if (!ret && rv)
+ ret = rv;
out_unlock:
mutex_unlock(&wilc->txq_add_to_head_cs);
@@ -1060,8 +1222,14 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
void wilc_handle_isr(struct wilc *wilc)
{
u32 int_status;
+ int ret;
+
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret) {
+ dev_err_ratelimited(wilc->dev, "Cannot acquire bus\n");
+ return;
+ }
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
wilc->hif_func->hif_read_int(wilc, &int_status);
if (int_status & DATA_INT_EXT)
@@ -1070,7 +1238,9 @@ void wilc_handle_isr(struct wilc *wilc)
if (!(int_status & (ALL_INT_EXT)))
wilc_unknown_isr_ext(wilc);
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ if (ret)
+ dev_err_ratelimited(wilc->dev, "Cannot release bus\n");
}
EXPORT_SYMBOL_GPL(wilc_handle_isr);
@@ -1082,6 +1252,7 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
u8 *dma_buffer;
int ret = 0;
u32 reg = 0;
+ int rv;
blksz = BIT(12);
@@ -1092,7 +1263,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
offset = 0;
pr_debug("%s: Downloading firmware size = %d\n", __func__, buffer_size);
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ return ret;
wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
reg &= ~BIT(10);
@@ -1101,11 +1274,17 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
if (reg & BIT(10))
pr_err("%s: Failed to reset\n", __func__);
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ ret = release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ if (ret)
+ goto fail;
+
do {
addr = get_unaligned_le32(&buffer[offset]);
size = get_unaligned_le32(&buffer[offset + 4]);
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ goto fail;
+
offset += 8;
while (((int)size) && (offset < buffer_size)) {
if (size <= blksz)
@@ -1123,7 +1302,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
offset += size2;
size -= size2;
}
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ if (!ret && rv)
+ ret = rv;
if (ret) {
pr_err("%s Bus error\n", __func__);
@@ -1142,7 +1323,7 @@ fail:
int wilc_wlan_start(struct wilc *wilc)
{
u32 reg = 0;
- int ret;
+ int ret, rv;
u32 chipid;
if (wilc->io_type == WILC_HIF_SDIO) {
@@ -1151,7 +1332,10 @@ int wilc_wlan_start(struct wilc *wilc)
} else if (wilc->io_type == WILC_HIF_SPI) {
reg = 1;
}
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ if (ret)
+ return ret;
+
ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);
if (ret)
goto release;
@@ -1160,6 +1344,9 @@ int wilc_wlan_start(struct wilc *wilc)
if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num)
reg |= WILC_HAVE_SDIO_IRQ_GPIO;
+ if (is_wilc3000(wilc->chipid))
+ reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC;
+
ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg);
if (ret)
goto release;
@@ -1182,16 +1369,18 @@ int wilc_wlan_start(struct wilc *wilc)
wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
release:
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
- return ret;
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ return ret ? ret : rv;
}
int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
{
u32 reg = 0;
- int ret;
+ int ret, rv;
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ return ret;
ret = wilc->hif_func->hif_read_reg(wilc, GLOBAL_MODE_CONTROL, &reg);
if (ret)
@@ -1227,9 +1416,9 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
ret = 0;
release:
/* host comm is disabled - we can't issue sleep command anymore: */
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY);
- return ret;
+ return ret ? ret : rv;
}
void wilc_wlan_cleanup(struct net_device *dev)
@@ -1402,19 +1591,56 @@ int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
return ret;
}
+int wilc_get_chipid(struct wilc *wilc)
+{
+ u32 chipid = 0;
+ u32 rfrevid = 0;
+
+ if (wilc->chipid == 0) {
+ wilc->hif_func->hif_read_reg(wilc, WILC3000_CHIP_ID, &chipid);
+ if (!is_wilc3000(chipid)) {
+ wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid);
+ wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID,
+ &rfrevid);
+
+ if (!is_wilc1000(chipid)) {
+ wilc->chipid = 0;
+ return -EINVAL;
+ }
+ if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */
+ if (rfrevid != 0x1)
+ chipid = WILC_1000_BASE_ID_2A_REV1;
+ } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */
+ if (rfrevid == 0x4)
+ chipid = WILC_1000_BASE_ID_2B_REV1;
+ else if (rfrevid != 0x3)
+ chipid = WILC_1000_BASE_ID_2B_REV2;
+ }
+ }
+
+ wilc->chipid = chipid;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wilc_get_chipid);
+
static int init_chip(struct net_device *dev)
{
- u32 chipid;
u32 reg;
- int ret = 0;
+ int ret, rv;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ return ret;
- chipid = wilc_get_chipid(wilc, true);
+ ret = wilc_get_chipid(wilc);
+ if (ret)
+ goto release;
- if ((chipid & 0xfff) != 0xa0) {
+ if ((wilc->chipid & 0xfff) != 0xa0) {
ret = wilc->hif_func->hif_read_reg(wilc,
WILC_CORTUS_RESET_MUX_SEL,
&reg);
@@ -1439,43 +1665,81 @@ static int init_chip(struct net_device *dev)
}
}
+ if (is_wilc3000(wilc->chipid)) {
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC3000_BOOTROM_STATUS, &reg);
+ if (ret) {
+ netdev_err(dev, "failed to read WILC3000 BootROM status register\n");
+ goto release;
+ }
+
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC3000_CORTUS_BOOT_REGISTER_2,
+ WILC_CORTUS_BOOT_FROM_IRAM);
+ if (ret) {
+ netdev_err(dev, "failed to write WILC3000 Boot register\n");
+ goto release;
+ }
+ }
+
release:
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return ret;
+ return ret ? ret : rv;
}
-u32 wilc_get_chipid(struct wilc *wilc, bool update)
+int wilc_load_mac_from_nv(struct wilc *wl)
{
- u32 chipid = 0;
- u32 rfrevid = 0;
+ int ret, rv;
+ unsigned int i;
+
+ ret = acquire_bus(wl, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ return ret;
- if (wilc->chipid == 0 || update) {
- wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid);
- wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID,
- &rfrevid);
- if (!is_wilc1000(chipid)) {
- wilc->chipid = 0;
- return wilc->chipid;
+ for (i = 0; i < WILC_NVMEM_MAX_NUM_BANK; i++) {
+ int bank_offset = get_bank_offset_from_bank_index(i);
+ u32 reg1, reg2;
+ u8 invalid;
+ u8 used;
+
+ ret = wl->hif_func->hif_read_reg(wl,
+ WILC_NVMEM_BANK_BASE + bank_offset,
+ &reg1);
+ if (ret) {
+ pr_err("Can not read address %d lower part", i);
+ break;
}
- if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */
- if (rfrevid != 0x1)
- chipid = WILC_1000_BASE_ID_2A_REV1;
- } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */
- if (rfrevid == 0x4)
- chipid = WILC_1000_BASE_ID_2B_REV1;
- else if (rfrevid != 0x3)
- chipid = WILC_1000_BASE_ID_2B_REV2;
+ ret = wl->hif_func->hif_read_reg(wl,
+ WILC_NVMEM_BANK_BASE + bank_offset + 4,
+ &reg2);
+ if (ret) {
+ pr_err("Can not read address %d upper part", i);
+ break;
}
- wilc->chipid = chipid;
+ used = FIELD_GET(WILC_NVMEM_IS_BANK_USED, reg1);
+ invalid = FIELD_GET(WILC_NVMEM_IS_BANK_INVALID, reg1);
+ if (!used || invalid)
+ continue;
+
+ wl->nv_mac_address[0] = FIELD_GET(GENMASK(23, 16), reg1);
+ wl->nv_mac_address[1] = FIELD_GET(GENMASK(15, 8), reg1);
+ wl->nv_mac_address[2] = FIELD_GET(GENMASK(7, 0), reg1);
+ wl->nv_mac_address[3] = FIELD_GET(GENMASK(31, 24), reg2);
+ wl->nv_mac_address[4] = FIELD_GET(GENMASK(23, 16), reg2);
+ wl->nv_mac_address[5] = FIELD_GET(GENMASK(15, 8), reg2);
+
+ ret = 0;
+ break;
}
- return wilc->chipid;
+
+ rv = release_bus(wl, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return ret ? ret : rv;
}
+EXPORT_SYMBOL_GPL(wilc_load_mac_from_nv);
int wilc_wlan_init(struct net_device *dev)
{
- int ret = 0;
+ int ret = 0, rv;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc;
@@ -1484,11 +1748,26 @@ int wilc_wlan_init(struct net_device *dev)
wilc->quit = 0;
if (!wilc->hif_func->hif_is_init(wilc)) {
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ if (ret)
+ return ret;
+
ret = wilc->hif_func->hif_init(wilc, false);
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ if (!ret)
+ ret = wilc_get_chipid(wilc);
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ if (!ret && rv)
+ ret = rv;
if (ret)
goto fail;
+
+ if (!is_wilc1000(wilc->chipid) && !is_wilc3000(wilc->chipid)) {
+ netdev_err(dev, "Unsupported chipid: %x\n", wilc->chipid);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ netdev_dbg(dev, "chipid (%08x)\n", wilc->chipid);
}
if (!wilc->vmm_table)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h
index 54643d8fef04..b9e7f9222ead 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.h
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.h
@@ -56,7 +56,6 @@
#define WILC_HOST_RX_CTRL (WILC_PERIPH_REG_BASE + 0x80)
#define WILC_HOST_RX_EXTRA_SIZE (WILC_PERIPH_REG_BASE + 0x84)
#define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88)
-#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428)
#define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00)
#define WILC_INTR_ENABLE WILC_INTR_REG_BASE
#define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4)
@@ -97,8 +96,14 @@
#define WILC_SPI_WAKEUP_REG 0x1
#define WILC_SPI_WAKEUP_BIT BIT(1)
-#define WILC_SPI_CLK_STATUS_REG 0x0f
-#define WILC_SPI_CLK_STATUS_BIT BIT(2)
+/* WILC1000 specific */
+#define WILC1000_SPI_CLK_STATUS_REG 0x0f
+#define WILC1000_SPI_CLK_STATUS_BIT BIT(2)
+
+/* WILC3000 specific */
+#define WILC3000_SPI_CLK_STATUS_REG 0x13
+#define WILC3000_SPI_CLK_STATUS_BIT BIT(2)
+
#define WILC_SPI_HOST_TO_FW_REG 0x0b
#define WILC_SPI_HOST_TO_FW_BIT BIT(0)
@@ -124,14 +129,24 @@
#define WILC_SDIO_WAKEUP_REG 0xf0
#define WILC_SDIO_WAKEUP_BIT BIT(0)
-#define WILC_SDIO_CLK_STATUS_REG 0xf1
-#define WILC_SDIO_CLK_STATUS_BIT BIT(0)
+/* WILC1000 */
+#define WILC1000_SDIO_CLK_STATUS_REG 0xf1
+#define WILC1000_SDIO_CLK_STATUS_BIT BIT(0)
+
+#define WILC1000_SDIO_IRQ_FLAG_REG 0xf7
+#define WILC1000_SDIO_IRQ_CLEAR_FLAG_REG 0xf8
+
+/* WILC3000 specific */
+#define WILC3000_SDIO_CLK_STATUS_REG 0xf0 /* clk & wakeup are on same reg */
+#define WILC3000_SDIO_CLK_STATUS_BIT BIT(4)
+
+#define WILC3000_SDIO_VMM_TBL_CTRL_REG 0xf1
+#define WILC3000_SDIO_IRQ_FLAG_REG 0xfe
+/* Common vendor specific CCCR register */
#define WILC_SDIO_INTERRUPT_DATA_SZ_REG 0xf2 /* Read size (2 bytes) */
#define WILC_SDIO_VMM_TBL_CTRL_REG 0xf6
-#define WILC_SDIO_IRQ_FLAG_REG 0xf7
-#define WILC_SDIO_IRQ_CLEAR_FLAG_REG 0xf8
#define WILC_SDIO_HOST_TO_FW_REG 0xfa
#define WILC_SDIO_HOST_TO_FW_BIT BIT(0)
@@ -173,8 +188,11 @@
#define WILC_HAVE_USE_IRQ_AS_HOST_WAKE BIT(8)
#define WILC_CORTUS_INTERRUPT_BASE 0x10A8
-#define WILC_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4)
-#define WILC_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8)
+#define WILC1000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4)
+#define WILC3000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x14)
+
+#define WILC1000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8)
+#define WILC3000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x18)
/* tx control register 1 to 4 for RX */
#define WILC_REG_4_TO_1_RX 0x1e1c
@@ -184,6 +202,9 @@
#define WILC_CORTUS_RESET_MUX_SEL 0x1118
#define WILC_CORTUS_BOOT_REGISTER 0xc0000
+#define WILC3000_BOOTROM_STATUS 0x207ac
+#define WILC3000_CORTUS_BOOT_REGISTER_2 0x4f0000
+#define WILC3000_CHIP_ID 0x3b0000
#define WILC_CORTUS_BOOT_FROM_IRAM 0x71
@@ -196,6 +217,8 @@
#define WILC_1000_BASE_ID_2B_REV1 (WILC_1000_BASE_ID_2B + 1)
#define WILC_1000_BASE_ID_2B_REV2 (WILC_1000_BASE_ID_2B + 2)
+#define WILC_3000_BASE_ID 0x300000
+
#define WILC_CHIP_REV_FIELD GENMASK(11, 0)
/********************************************
@@ -414,6 +437,11 @@ static inline bool is_wilc1000(u32 id)
return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID;
}
+static inline bool is_wilc3000(u32 id)
+{
+ return (id & (~WILC_CHIP_REV_FIELD)) == WILC_3000_BASE_ID;
+}
+
int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
u32 buffer_size);
int wilc_wlan_start(struct wilc *wilc);
@@ -437,12 +465,11 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size);
bool wilc_wfi_mgmt_frame_rx(struct wilc_vif *vif, u8 *buff, u32 size);
-void host_wakeup_notify(struct wilc *wilc);
-void host_sleep_notify(struct wilc *wilc);
-void chip_allow_sleep(struct wilc *wilc);
-void chip_wakeup(struct wilc *wilc);
+int host_wakeup_notify(struct wilc *wilc);
+int host_sleep_notify(struct wilc *wilc);
int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
u32 count);
int wilc_wlan_init(struct net_device *dev);
-u32 wilc_get_chipid(struct wilc *wilc, bool update);
+int wilc_get_chipid(struct wilc *wilc);
+int wilc_load_mac_from_nv(struct wilc *wilc);
#endif