Lines Matching +full:antenna +full:- +full:config +full:- +full:file

1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
6 * Copyright (c) 2010, ST-Ericsson
8 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
9 * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
11 * Copyright (c) 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
36 #define WFX_PDS_TLV_TYPE 0x4450 // "PD" (Platform Data) in ascii little-endian
135 .config = wfx_config,
171 if (wdev->hw_caps.api_version_major < major) in wfx_api_older_than()
173 if (wdev->hw_caps.api_version_major > major) in wfx_api_older_than()
175 if (wdev->hw_caps.api_version_minor < minor) in wfx_api_older_than()
180 /* The device needs data about the antenna configuration. This information in provided by PDS
183 * https://github.com/SiliconLabs/wfx-firmware/blob/master/PDS/README.md
185 * The PDS file is an array of Time-Length-Value structs.
192 dev_err(wdev->dev, "PDS: malformed file (legacy format?)\n"); in wfx_send_pds()
193 return -EINVAL; in wfx_send_pds()
199 dev_err(wdev->dev, "PDS:%d: corrupted file\n", chunk_num); in wfx_send_pds()
200 return -EINVAL; in wfx_send_pds()
203 dev_info(wdev->dev, "PDS:%d: skip unknown data\n", chunk_num); in wfx_send_pds()
207 dev_warn(wdev->dev, "PDS:%d: unexpectedly large chunk\n", chunk_num); in wfx_send_pds()
208 if (buf[4] != '{' || buf[chunk_len - 1] != '}') in wfx_send_pds()
209 dev_warn(wdev->dev, "PDS:%d: unexpected content\n", chunk_num); in wfx_send_pds()
211 ret = wfx_hif_configuration(wdev, buf + 4, chunk_len - 4); in wfx_send_pds()
213 dev_err(wdev->dev, "PDS:%d: invalid data (unsupported options?)\n", chunk_num); in wfx_send_pds()
214 return -EINVAL; in wfx_send_pds()
216 if (ret == -ETIMEDOUT) { in wfx_send_pds()
217 dev_err(wdev->dev, "PDS:%d: chip didn't reply (corrupted file?)\n", chunk_num); in wfx_send_pds()
221 dev_err(wdev->dev, "PDS:%d: chip returned an unknown error\n", chunk_num); in wfx_send_pds()
222 return -EIO; in wfx_send_pds()
226 len -= chunk_len; in wfx_send_pds()
238 ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev); in wfx_send_pdata_pds()
240 dev_err(wdev->dev, "can't load antenna parameters (PDS file %s). The device may be unstable.\n", in wfx_send_pdata_pds()
241 wdev->pdata.file_pds); in wfx_send_pdata_pds()
244 tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL); in wfx_send_pdata_pds()
246 ret = -ENOMEM; in wfx_send_pdata_pds()
249 ret = wfx_send_pds(wdev, tmp_buf, pds->size); in wfx_send_pdata_pds()
260 mutex_destroy(&wdev->tx_power_loop_info_lock); in wfx_free_common()
261 mutex_destroy(&wdev->rx_stats_lock); in wfx_free_common()
262 mutex_destroy(&wdev->scan_lock); in wfx_free_common()
263 mutex_destroy(&wdev->conf_mutex); in wfx_free_common()
264 ieee80211_free_hw(wdev->hw); in wfx_free_common()
288 hw->vif_data_size = sizeof(struct wfx_vif); in wfx_init_common()
289 hw->sta_data_size = sizeof(struct wfx_sta_priv); in wfx_init_common()
290 hw->queues = 4; in wfx_init_common()
291 hw->max_rates = 8; in wfx_init_common()
292 hw->max_rate_tries = 8; in wfx_init_common()
293 hw->extra_tx_headroom = sizeof(struct wfx_hif_msg) + sizeof(struct wfx_hif_req_tx) + in wfx_init_common()
295 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | in wfx_init_common()
298 hw->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | in wfx_init_common()
302 hw->wiphy->features |= NL80211_FEATURE_AP_SCAN; in wfx_init_common()
304 hw->wiphy->wowlan = &wfx_wowlan_support; in wfx_init_common()
306 hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; in wfx_init_common()
307 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; in wfx_init_common()
308 hw->wiphy->max_remain_on_channel_duration = 5000; in wfx_init_common()
309 hw->wiphy->max_ap_assoc_sta = HIF_LINK_ID_MAX; in wfx_init_common()
310 hw->wiphy->max_scan_ssids = 2; in wfx_init_common()
311 hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; in wfx_init_common()
312 hw->wiphy->n_iface_combinations = ARRAY_SIZE(wfx_iface_combinations); in wfx_init_common()
313 hw->wiphy->iface_combinations = wfx_iface_combinations; in wfx_init_common()
315 hw->wiphy->bands[NL80211_BAND_2GHZ] = devm_kmemdup(dev, &wfx_band_2ghz, in wfx_init_common()
317 if (!hw->wiphy->bands[NL80211_BAND_2GHZ]) in wfx_init_common()
320 wdev = hw->priv; in wfx_init_common()
321 wdev->hw = hw; in wfx_init_common()
322 wdev->dev = dev; in wfx_init_common()
323 wdev->hwbus_ops = hwbus_ops; in wfx_init_common()
324 wdev->hwbus_priv = hwbus_priv; in wfx_init_common()
325 memcpy(&wdev->pdata, pdata, sizeof(*pdata)); in wfx_init_common()
326 of_property_read_string(dev->of_node, "silabs,antenna-config-file", &wdev->pdata.file_pds); in wfx_init_common()
327 wdev->pdata.gpio_wakeup = devm_gpiod_get_optional(dev, "wakeup", GPIOD_OUT_LOW); in wfx_init_common()
328 if (IS_ERR(wdev->pdata.gpio_wakeup)) in wfx_init_common()
331 if (wdev->pdata.gpio_wakeup) in wfx_init_common()
332 gpiod_set_consumer_name(wdev->pdata.gpio_wakeup, "wfx wakeup"); in wfx_init_common()
334 mutex_init(&wdev->conf_mutex); in wfx_init_common()
335 mutex_init(&wdev->scan_lock); in wfx_init_common()
336 mutex_init(&wdev->rx_stats_lock); in wfx_init_common()
337 mutex_init(&wdev->tx_power_loop_info_lock); in wfx_init_common()
338 init_completion(&wdev->firmware_ready); in wfx_init_common()
339 INIT_DELAYED_WORK(&wdev->cooling_timeout_work, wfx_cooling_timeout_work); in wfx_init_common()
340 skb_queue_head_init(&wdev->tx_pending); in wfx_init_common()
341 init_waitqueue_head(&wdev->tx_dequeue); in wfx_init_common()
342 wfx_init_hif_cmd(&wdev->hif_cmd); in wfx_init_common()
363 gpio_saved = wdev->pdata.gpio_wakeup; in wfx_probe()
364 wdev->pdata.gpio_wakeup = NULL; in wfx_probe()
365 wdev->poll_irq = true; in wfx_probe()
367 wdev->bh_wq = alloc_workqueue("wfx_bh_wq", WQ_HIGHPRI, 0); in wfx_probe()
368 if (!wdev->bh_wq) in wfx_probe()
369 return -ENOMEM; in wfx_probe()
378 err = wait_for_completion_timeout(&wdev->firmware_ready, 1 * HZ); in wfx_probe()
380 dev_err(wdev->dev, "timeout while waiting for startup indication\n"); in wfx_probe()
381 err = -ETIMEDOUT; in wfx_probe()
386 dev_info(wdev->dev, "started firmware %d.%d.%d \"%s\" (API: %d.%d, keyset: %02X, caps: 0x%.8X)\n", in wfx_probe()
387 wdev->hw_caps.firmware_major, wdev->hw_caps.firmware_minor, in wfx_probe()
388 wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label, in wfx_probe()
389 wdev->hw_caps.api_version_major, wdev->hw_caps.api_version_minor, in wfx_probe()
390 wdev->keyset, wdev->hw_caps.link_mode); in wfx_probe()
391 snprintf(wdev->hw->wiphy->fw_version, in wfx_probe()
392 sizeof(wdev->hw->wiphy->fw_version), in wfx_probe()
394 wdev->hw_caps.firmware_major, in wfx_probe()
395 wdev->hw_caps.firmware_minor, in wfx_probe()
396 wdev->hw_caps.firmware_build); in wfx_probe()
399 dev_err(wdev->dev, "unsupported firmware API version (expect 1 while firmware returns %d)\n", in wfx_probe()
400 wdev->hw_caps.api_version_major); in wfx_probe()
401 err = -EOPNOTSUPP; in wfx_probe()
405 if (wdev->hw_caps.link_mode == SEC_LINK_ENFORCED) { in wfx_probe()
406 dev_err(wdev->dev, "chip require secure_link, but can't negotiate it\n"); in wfx_probe()
410 if (wdev->hw_caps.region_sel_mode) { in wfx_probe()
411 wdev->hw->wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS; in wfx_probe()
412 wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[11].flags |= in wfx_probe()
414 wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[12].flags |= in wfx_probe()
416 wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[13].flags |= in wfx_probe()
420 dev_dbg(wdev->dev, "sending configuration file %s\n", wdev->pdata.file_pds); in wfx_probe()
422 if (err < 0 && err != -ENOENT) in wfx_probe()
425 wdev->poll_irq = false; in wfx_probe()
426 err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv); in wfx_probe()
432 dev_err(wdev->dev, "misconfigured IRQ?\n"); in wfx_probe()
434 wdev->pdata.gpio_wakeup = gpio_saved; in wfx_probe()
435 if (wdev->pdata.gpio_wakeup) { in wfx_probe()
436 dev_dbg(wdev->dev, "enable 'quiescent' power mode with wakeup GPIO and PDS file %s\n", in wfx_probe()
437 wdev->pdata.file_pds); in wfx_probe()
438 gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); in wfx_probe()
445 for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) { in wfx_probe()
446 eth_zero_addr(wdev->addresses[i].addr); in wfx_probe()
447 err = of_get_mac_address(wdev->dev->of_node, wdev->addresses[i].addr); in wfx_probe()
449 wdev->addresses[i].addr[ETH_ALEN - 1] += i; in wfx_probe()
451 ether_addr_copy(wdev->addresses[i].addr, wdev->hw_caps.mac_addr[i]); in wfx_probe()
452 if (!is_valid_ether_addr(wdev->addresses[i].addr)) { in wfx_probe()
453 dev_warn(wdev->dev, "using random MAC address\n"); in wfx_probe()
454 eth_random_addr(wdev->addresses[i].addr); in wfx_probe()
456 dev_info(wdev->dev, "MAC address %d: %pM\n", i, wdev->addresses[i].addr); in wfx_probe()
458 wdev->hw->wiphy->n_addresses = ARRAY_SIZE(wdev->addresses); in wfx_probe()
459 wdev->hw->wiphy->addresses = wdev->addresses; in wfx_probe()
462 wdev->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; in wfx_probe()
464 err = ieee80211_register_hw(wdev->hw); in wfx_probe()
475 ieee80211_unregister_hw(wdev->hw); in wfx_probe()
477 wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); in wfx_probe()
480 destroy_workqueue(wdev->bh_wq); in wfx_probe()
486 ieee80211_unregister_hw(wdev->hw); in wfx_release()
488 wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); in wfx_release()
490 destroy_workqueue(wdev->bh_wq); in wfx_release()