Merge tag 'samsung-dt-5.5-2' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk...
[linux-2.6-microblaze.git] / drivers / net / wireless / ath / wil6210 / pcie_bus.c
1 // SPDX-License-Identifier: ISC
2 /*
3  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
4  * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
5  */
6
7 #include <linux/module.h>
8 #include <linux/pci.h>
9 #include <linux/moduleparam.h>
10 #include <linux/interrupt.h>
11 #include <linux/suspend.h>
12 #include "wil6210.h"
13 #include <linux/rtnetlink.h>
14 #include <linux/pm_runtime.h>
15
16 static int n_msi = 3;
17 module_param(n_msi, int, 0444);
18 MODULE_PARM_DESC(n_msi, " Use MSI interrupt: 0 - use INTx, 1 - single, or 3 - (default) ");
19
20 bool ftm_mode;
21 module_param(ftm_mode, bool, 0444);
22 MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false");
23
24 static int wil6210_pm_notify(struct notifier_block *notify_block,
25                              unsigned long mode, void *unused);
26
27 static
28 int wil_set_capabilities(struct wil6210_priv *wil)
29 {
30         const char *wil_fw_name;
31         u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
32         u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) &
33                             RGF_USER_REVISION_ID_MASK);
34         int platform_capa;
35         struct fw_map *iccm_section, *sct;
36
37         bitmap_zero(wil->hw_capa, hw_capa_last);
38         bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
39         bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX);
40         wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT :
41                            WIL_FW_NAME_DEFAULT;
42         wil->chip_revision = chip_revision;
43
44         switch (jtag_id) {
45         case JTAG_DEV_ID_SPARROW:
46                 memcpy(fw_mapping, sparrow_fw_mapping,
47                        sizeof(sparrow_fw_mapping));
48                 switch (chip_revision) {
49                 case REVISION_ID_SPARROW_D0:
50                         wil->hw_name = "Sparrow D0";
51                         wil->hw_version = HW_VER_SPARROW_D0;
52                         wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_SPARROW_PLUS :
53                                       WIL_FW_NAME_SPARROW_PLUS;
54
55                         if (wil_fw_verify_file_exists(wil, wil_fw_name))
56                                 wil->wil_fw_name = wil_fw_name;
57                         sct = wil_find_fw_mapping("mac_rgf_ext");
58                         if (!sct) {
59                                 wil_err(wil, "mac_rgf_ext section not found in fw_mapping\n");
60                                 return -EINVAL;
61                         }
62                         memcpy(sct, &sparrow_d0_mac_rgf_ext, sizeof(*sct));
63                         break;
64                 case REVISION_ID_SPARROW_B0:
65                         wil->hw_name = "Sparrow B0";
66                         wil->hw_version = HW_VER_SPARROW_B0;
67                         break;
68                 default:
69                         wil->hw_name = "Unknown";
70                         wil->hw_version = HW_VER_UNKNOWN;
71                         break;
72                 }
73                 wil->rgf_fw_assert_code_addr = SPARROW_RGF_FW_ASSERT_CODE;
74                 wil->rgf_ucode_assert_code_addr = SPARROW_RGF_UCODE_ASSERT_CODE;
75                 break;
76         case JTAG_DEV_ID_TALYN:
77                 wil->hw_name = "Talyn-MA";
78                 wil->hw_version = HW_VER_TALYN;
79                 memcpy(fw_mapping, talyn_fw_mapping, sizeof(talyn_fw_mapping));
80                 wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE;
81                 wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE;
82                 if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) &
83                     BIT_NO_FLASH_INDICATION)
84                         set_bit(hw_capa_no_flash, wil->hw_capa);
85                 wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN :
86                               WIL_FW_NAME_TALYN;
87                 if (wil_fw_verify_file_exists(wil, wil_fw_name))
88                         wil->wil_fw_name = wil_fw_name;
89                 break;
90         case JTAG_DEV_ID_TALYN_MB:
91                 wil->hw_name = "Talyn-MB";
92                 wil->hw_version = HW_VER_TALYN_MB;
93                 memcpy(fw_mapping, talyn_mb_fw_mapping,
94                        sizeof(talyn_mb_fw_mapping));
95                 wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE;
96                 wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE;
97                 set_bit(hw_capa_no_flash, wil->hw_capa);
98                 wil->use_enhanced_dma_hw = true;
99                 wil->use_rx_hw_reordering = true;
100                 wil->use_compressed_rx_status = true;
101                 wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN :
102                               WIL_FW_NAME_TALYN;
103                 if (wil_fw_verify_file_exists(wil, wil_fw_name))
104                         wil->wil_fw_name = wil_fw_name;
105                 break;
106         default:
107                 wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
108                         jtag_id, chip_revision);
109                 wil->hw_name = "Unknown";
110                 wil->hw_version = HW_VER_UNKNOWN;
111                 return -EINVAL;
112         }
113
114         wil_init_txrx_ops(wil);
115
116         iccm_section = wil_find_fw_mapping("fw_code");
117         if (!iccm_section) {
118                 wil_err(wil, "fw_code section not found in fw_mapping\n");
119                 return -EINVAL;
120         }
121         wil->iccm_base = iccm_section->host;
122
123         wil_info(wil, "Board hardware is %s, flash %sexist\n", wil->hw_name,
124                  test_bit(hw_capa_no_flash, wil->hw_capa) ? "doesn't " : "");
125
126         /* Get platform capabilities */
127         if (wil->platform_ops.get_capa) {
128                 platform_capa =
129                         wil->platform_ops.get_capa(wil->platform_handle);
130                 memcpy(wil->platform_capa, &platform_capa,
131                        min(sizeof(wil->platform_capa), sizeof(platform_capa)));
132         }
133
134         wil_info(wil, "platform_capa 0x%lx\n", *wil->platform_capa);
135
136         /* extract FW capabilities from file without loading the FW */
137         wil_request_firmware(wil, wil->wil_fw_name, false);
138         wil_refresh_fw_capabilities(wil);
139
140         return 0;
141 }
142
143 void wil_disable_irq(struct wil6210_priv *wil)
144 {
145         int irq = wil->pdev->irq;
146
147         disable_irq(irq);
148         if (wil->n_msi == 3) {
149                 disable_irq(irq + 1);
150                 disable_irq(irq + 2);
151         }
152 }
153
154 void wil_enable_irq(struct wil6210_priv *wil)
155 {
156         int irq = wil->pdev->irq;
157
158         enable_irq(irq);
159         if (wil->n_msi == 3) {
160                 enable_irq(irq + 1);
161                 enable_irq(irq + 2);
162         }
163 }
164
165 static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
166 {
167         struct wil6210_vif *vif;
168         int i;
169
170         for (i = 1; i < GET_MAX_VIFS(wil); i++) {
171                 vif = wil->vifs[i];
172                 if (vif) {
173                         wil_vif_prepare_stop(vif);
174                         wil_vif_remove(wil, vif->mid);
175                 }
176         }
177 }
178
179 /* Bus ops */
180 static int wil_if_pcie_enable(struct wil6210_priv *wil)
181 {
182         struct pci_dev *pdev = wil->pdev;
183         int rc;
184         /* on platforms with buggy ACPI, pdev->msi_enabled may be set to
185          * allow pci_enable_device to work. This indicates INTx was not routed
186          * and only MSI should be used
187          */
188         int msi_only = pdev->msi_enabled;
189
190         wil_dbg_misc(wil, "if_pcie_enable\n");
191
192         pci_set_master(pdev);
193
194         /* how many MSI interrupts to request? */
195         switch (n_msi) {
196         case 3:
197         case 1:
198                 wil_dbg_misc(wil, "Setup %d MSI interrupts\n", n_msi);
199                 break;
200         case 0:
201                 wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
202                 break;
203         default:
204                 wil_err(wil, "Invalid n_msi=%d, default to 1\n", n_msi);
205                 n_msi = 1;
206         }
207
208         if (n_msi == 3 &&
209             pci_alloc_irq_vectors(pdev, n_msi, n_msi, PCI_IRQ_MSI) < n_msi) {
210                 wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
211                 n_msi = 1;
212         }
213
214         if (n_msi == 1 && pci_enable_msi(pdev)) {
215                 wil_err(wil, "pci_enable_msi failed, use INTx\n");
216                 n_msi = 0;
217         }
218
219         wil->n_msi = n_msi;
220
221         if (wil->n_msi == 0 && msi_only) {
222                 wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");
223                 rc = -ENODEV;
224                 goto stop_master;
225         }
226
227         rc = wil6210_init_irq(wil, pdev->irq);
228         if (rc)
229                 goto release_vectors;
230
231         /* need reset here to obtain MAC */
232         mutex_lock(&wil->mutex);
233         rc = wil_reset(wil, false);
234         mutex_unlock(&wil->mutex);
235         if (rc)
236                 goto release_irq;
237
238         return 0;
239
240  release_irq:
241         wil6210_fini_irq(wil, pdev->irq);
242  release_vectors:
243         /* safe to call if no allocation */
244         pci_free_irq_vectors(pdev);
245  stop_master:
246         pci_clear_master(pdev);
247         return rc;
248 }
249
250 static int wil_if_pcie_disable(struct wil6210_priv *wil)
251 {
252         struct pci_dev *pdev = wil->pdev;
253
254         wil_dbg_misc(wil, "if_pcie_disable\n");
255
256         pci_clear_master(pdev);
257         /* disable and release IRQ */
258         wil6210_fini_irq(wil, pdev->irq);
259         /* safe to call if no MSI */
260         pci_disable_msi(pdev);
261         /* TODO: disable HW */
262
263         return 0;
264 }
265
266 static int wil_platform_rop_ramdump(void *wil_handle, void *buf, uint32_t size)
267 {
268         struct wil6210_priv *wil = wil_handle;
269
270         if (!wil)
271                 return -EINVAL;
272
273         return wil_fw_copy_crash_dump(wil, buf, size);
274 }
275
276 static int wil_platform_rop_fw_recovery(void *wil_handle)
277 {
278         struct wil6210_priv *wil = wil_handle;
279
280         if (!wil)
281                 return -EINVAL;
282
283         wil_fw_error_recovery(wil);
284
285         return 0;
286 }
287
288 static void wil_platform_ops_uninit(struct wil6210_priv *wil)
289 {
290         if (wil->platform_ops.uninit)
291                 wil->platform_ops.uninit(wil->platform_handle);
292         memset(&wil->platform_ops, 0, sizeof(wil->platform_ops));
293 }
294
295 static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
296 {
297         struct wil6210_priv *wil;
298         struct device *dev = &pdev->dev;
299         int rc;
300         const struct wil_platform_rops rops = {
301                 .ramdump = wil_platform_rop_ramdump,
302                 .fw_recovery = wil_platform_rop_fw_recovery,
303         };
304         u32 bar_size = pci_resource_len(pdev, 0);
305         int dma_addr_size[] = {64, 48, 40, 32}; /* keep descending order */
306         int i, start_idx;
307
308         /* check HW */
309         dev_info(&pdev->dev, WIL_NAME
310                  " device found [%04x:%04x] (rev %x) bar size 0x%x\n",
311                  (int)pdev->vendor, (int)pdev->device, (int)pdev->revision,
312                  bar_size);
313
314         if ((bar_size < WIL6210_MIN_MEM_SIZE) ||
315             (bar_size > WIL6210_MAX_MEM_SIZE)) {
316                 dev_err(&pdev->dev, "Unexpected BAR0 size 0x%x\n",
317                         bar_size);
318                 return -ENODEV;
319         }
320
321         wil = wil_if_alloc(dev);
322         if (IS_ERR(wil)) {
323                 rc = (int)PTR_ERR(wil);
324                 dev_err(dev, "wil_if_alloc failed: %d\n", rc);
325                 return rc;
326         }
327
328         wil->pdev = pdev;
329         pci_set_drvdata(pdev, wil);
330         wil->bar_size = bar_size;
331         /* rollback to if_free */
332
333         wil->platform_handle =
334                 wil_platform_init(&pdev->dev, &wil->platform_ops, &rops, wil);
335         if (!wil->platform_handle) {
336                 rc = -ENODEV;
337                 wil_err(wil, "wil_platform_init failed\n");
338                 goto if_free;
339         }
340         /* rollback to err_plat */
341         rc = pci_enable_device(pdev);
342         if (rc && pdev->msi_enabled == 0) {
343                 wil_err(wil,
344                         "pci_enable_device failed, retry with MSI only\n");
345                 /* Work around for platforms that can't allocate IRQ:
346                  * retry with MSI only
347                  */
348                 pdev->msi_enabled = 1;
349                 rc = pci_enable_device(pdev);
350         }
351         if (rc) {
352                 wil_err(wil,
353                         "pci_enable_device failed, even with MSI only\n");
354                 goto err_plat;
355         }
356         /* rollback to err_disable_pdev */
357         pci_set_power_state(pdev, PCI_D0);
358
359         rc = pci_request_region(pdev, 0, WIL_NAME);
360         if (rc) {
361                 wil_err(wil, "pci_request_region failed\n");
362                 goto err_disable_pdev;
363         }
364         /* rollback to err_release_reg */
365
366         wil->csr = pci_ioremap_bar(pdev, 0);
367         if (!wil->csr) {
368                 wil_err(wil, "pci_ioremap_bar failed\n");
369                 rc = -ENODEV;
370                 goto err_release_reg;
371         }
372         /* rollback to err_iounmap */
373         wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr);
374
375         rc = wil_set_capabilities(wil);
376         if (rc) {
377                 wil_err(wil, "wil_set_capabilities failed, rc %d\n", rc);
378                 goto err_iounmap;
379         }
380
381         /* device supports >32bit addresses.
382          * for legacy DMA start from 48 bit.
383          */
384         start_idx = wil->use_enhanced_dma_hw ? 0 : 1;
385
386         for (i = start_idx; i < ARRAY_SIZE(dma_addr_size); i++) {
387                 rc = dma_set_mask_and_coherent(dev,
388                                                DMA_BIT_MASK(dma_addr_size[i]));
389                 if (rc) {
390                         dev_err(dev, "dma_set_mask_and_coherent(%d) failed: %d\n",
391                                 dma_addr_size[i], rc);
392                         continue;
393                 }
394                 dev_info(dev, "using dma mask %d", dma_addr_size[i]);
395                 wil->dma_addr_size = dma_addr_size[i];
396                 break;
397         }
398
399         if (wil->dma_addr_size == 0)
400                 goto err_iounmap;
401
402         wil6210_clear_irq(wil);
403
404         /* FW should raise IRQ when ready */
405         rc = wil_if_pcie_enable(wil);
406         if (rc) {
407                 wil_err(wil, "Enable device failed\n");
408                 goto err_iounmap;
409         }
410         /* rollback to bus_disable */
411
412         wil_clear_fw_log_addr(wil);
413         rc = wil_if_add(wil);
414         if (rc) {
415                 wil_err(wil, "wil_if_add failed: %d\n", rc);
416                 goto bus_disable;
417         }
418
419         /* in case of WMI-only FW, perform full reset and FW loading */
420         if (test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) {
421                 wil_dbg_misc(wil, "Loading WMI only FW\n");
422                 mutex_lock(&wil->mutex);
423                 rc = wil_reset(wil, true);
424                 mutex_unlock(&wil->mutex);
425                 if (rc) {
426                         wil_err(wil, "failed to load WMI only FW\n");
427                         /* ignore the error to allow debugging */
428                 }
429         }
430
431         if (IS_ENABLED(CONFIG_PM))
432                 wil->pm_notify.notifier_call = wil6210_pm_notify;
433
434         rc = register_pm_notifier(&wil->pm_notify);
435         if (rc)
436                 /* Do not fail the driver initialization, as suspend can
437                  * be prevented in a later phase if needed
438                  */
439                 wil_err(wil, "register_pm_notifier failed: %d\n", rc);
440
441         wil6210_debugfs_init(wil);
442
443         wil_pm_runtime_allow(wil);
444
445         return 0;
446
447 bus_disable:
448         wil_if_pcie_disable(wil);
449 err_iounmap:
450         pci_iounmap(pdev, wil->csr);
451 err_release_reg:
452         pci_release_region(pdev, 0);
453 err_disable_pdev:
454         pci_disable_device(pdev);
455 err_plat:
456         wil_platform_ops_uninit(wil);
457 if_free:
458         wil_if_free(wil);
459
460         return rc;
461 }
462
463 static void wil_pcie_remove(struct pci_dev *pdev)
464 {
465         struct wil6210_priv *wil = pci_get_drvdata(pdev);
466         void __iomem *csr = wil->csr;
467
468         wil_dbg_misc(wil, "pcie_remove\n");
469
470         unregister_pm_notifier(&wil->pm_notify);
471
472         wil_pm_runtime_forbid(wil);
473
474         wil6210_debugfs_remove(wil);
475         rtnl_lock();
476         wil_p2p_wdev_free(wil);
477         wil_remove_all_additional_vifs(wil);
478         rtnl_unlock();
479         wil_if_remove(wil);
480         wil_if_pcie_disable(wil);
481         pci_iounmap(pdev, csr);
482         pci_release_region(pdev, 0);
483         pci_disable_device(pdev);
484         wil_platform_ops_uninit(wil);
485         wil_if_free(wil);
486 }
487
488 static const struct pci_device_id wil6210_pcie_ids[] = {
489         { PCI_DEVICE(0x1ae9, 0x0310) },
490         { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */
491         { PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */
492         { /* end: all zeroes */ },
493 };
494 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
495
496 static int wil6210_suspend(struct device *dev, bool is_runtime)
497 {
498         int rc = 0;
499         struct pci_dev *pdev = to_pci_dev(dev);
500         struct wil6210_priv *wil = pci_get_drvdata(pdev);
501         bool keep_radio_on, active_ifaces;
502
503         wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
504
505         mutex_lock(&wil->vif_mutex);
506         active_ifaces = wil_has_active_ifaces(wil, true, false);
507         mutex_unlock(&wil->vif_mutex);
508         keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
509
510         rc = wil_can_suspend(wil, is_runtime);
511         if (rc)
512                 goto out;
513
514         rc = wil_suspend(wil, is_runtime, keep_radio_on);
515         if (!rc) {
516                 /* In case radio stays on, platform device will control
517                  * PCIe master
518                  */
519                 if (!keep_radio_on) {
520                         /* disable bus mastering */
521                         pci_clear_master(pdev);
522                         wil->suspend_stats.r_off.successful_suspends++;
523                 } else {
524                         wil->suspend_stats.r_on.successful_suspends++;
525                 }
526         }
527 out:
528         return rc;
529 }
530
531 static int wil6210_resume(struct device *dev, bool is_runtime)
532 {
533         int rc = 0;
534         struct pci_dev *pdev = to_pci_dev(dev);
535         struct wil6210_priv *wil = pci_get_drvdata(pdev);
536         bool keep_radio_on, active_ifaces;
537
538         wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
539
540         mutex_lock(&wil->vif_mutex);
541         active_ifaces = wil_has_active_ifaces(wil, true, false);
542         mutex_unlock(&wil->vif_mutex);
543         keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
544
545         /* In case radio stays on, platform device will control
546          * PCIe master
547          */
548         if (!keep_radio_on)
549                 /* allow master */
550                 pci_set_master(pdev);
551         rc = wil_resume(wil, is_runtime, keep_radio_on);
552         if (rc) {
553                 wil_err(wil, "device failed to resume (%d)\n", rc);
554                 if (!keep_radio_on) {
555                         pci_clear_master(pdev);
556                         wil->suspend_stats.r_off.failed_resumes++;
557                 } else {
558                         wil->suspend_stats.r_on.failed_resumes++;
559                 }
560         } else {
561                 if (keep_radio_on)
562                         wil->suspend_stats.r_on.successful_resumes++;
563                 else
564                         wil->suspend_stats.r_off.successful_resumes++;
565         }
566
567         return rc;
568 }
569
570 static int wil6210_pm_notify(struct notifier_block *notify_block,
571                              unsigned long mode, void *unused)
572 {
573         struct wil6210_priv *wil = container_of(
574                 notify_block, struct wil6210_priv, pm_notify);
575         int rc = 0;
576         enum wil_platform_event evt;
577
578         wil_dbg_pm(wil, "pm_notify: mode (%ld)\n", mode);
579
580         switch (mode) {
581         case PM_HIBERNATION_PREPARE:
582         case PM_SUSPEND_PREPARE:
583         case PM_RESTORE_PREPARE:
584                 rc = wil_can_suspend(wil, false);
585                 if (rc)
586                         break;
587                 evt = WIL_PLATFORM_EVT_PRE_SUSPEND;
588                 if (wil->platform_ops.notify)
589                         rc = wil->platform_ops.notify(wil->platform_handle,
590                                                       evt);
591                 break;
592         case PM_POST_SUSPEND:
593         case PM_POST_HIBERNATION:
594         case PM_POST_RESTORE:
595                 evt = WIL_PLATFORM_EVT_POST_SUSPEND;
596                 if (wil->platform_ops.notify)
597                         rc = wil->platform_ops.notify(wil->platform_handle,
598                                                       evt);
599                 break;
600         default:
601                 wil_dbg_pm(wil, "unhandled notify mode %ld\n", mode);
602                 break;
603         }
604
605         wil_dbg_pm(wil, "notification mode %ld: rc (%d)\n", mode, rc);
606         return rc;
607 }
608
609 static int __maybe_unused wil6210_pm_suspend(struct device *dev)
610 {
611         return wil6210_suspend(dev, false);
612 }
613
614 static int __maybe_unused wil6210_pm_resume(struct device *dev)
615 {
616         return wil6210_resume(dev, false);
617 }
618
619 static int __maybe_unused wil6210_pm_runtime_idle(struct device *dev)
620 {
621         struct wil6210_priv *wil = dev_get_drvdata(dev);
622
623         wil_dbg_pm(wil, "Runtime idle\n");
624
625         return wil_can_suspend(wil, true);
626 }
627
628 static int __maybe_unused wil6210_pm_runtime_resume(struct device *dev)
629 {
630         return wil6210_resume(dev, true);
631 }
632
633 static int __maybe_unused wil6210_pm_runtime_suspend(struct device *dev)
634 {
635         struct wil6210_priv *wil = dev_get_drvdata(dev);
636
637         if (test_bit(wil_status_suspended, wil->status)) {
638                 wil_dbg_pm(wil, "trying to suspend while suspended\n");
639                 return 1;
640         }
641
642         return wil6210_suspend(dev, true);
643 }
644
645 static const struct dev_pm_ops wil6210_pm_ops = {
646         SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume)
647         SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend,
648                            wil6210_pm_runtime_resume,
649                            wil6210_pm_runtime_idle)
650 };
651
652 static struct pci_driver wil6210_driver = {
653         .probe          = wil_pcie_probe,
654         .remove         = wil_pcie_remove,
655         .id_table       = wil6210_pcie_ids,
656         .name           = WIL_NAME,
657         .driver         = {
658                 .pm = &wil6210_pm_ops,
659         },
660 };
661
662 static int __init wil6210_driver_init(void)
663 {
664         int rc;
665
666         rc = wil_platform_modinit();
667         if (rc)
668                 return rc;
669
670         rc = pci_register_driver(&wil6210_driver);
671         if (rc)
672                 wil_platform_modexit();
673         return rc;
674 }
675 module_init(wil6210_driver_init);
676
677 static void __exit wil6210_driver_exit(void)
678 {
679         pci_unregister_driver(&wil6210_driver);
680         wil_platform_modexit();
681 }
682 module_exit(wil6210_driver_exit);
683
684 MODULE_LICENSE("Dual BSD/GPL");
685 MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>");
686 MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card");