0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk.h>
0011 #include <linux/delay.h>
0012 #include <linux/firmware.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/io.h>
0017 #include <linux/of_address.h>
0018 #include <linux/of_device.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/pm_domain.h>
0021 #include <linux/pm_runtime.h>
0022 #include <linux/qcom_scm.h>
0023 #include <linux/regulator/consumer.h>
0024 #include <linux/remoteproc.h>
0025 #include <linux/soc/qcom/mdt_loader.h>
0026 #include <linux/soc/qcom/smem.h>
0027 #include <linux/soc/qcom/smem_state.h>
0028
0029 #include "qcom_common.h"
0030 #include "remoteproc_internal.h"
0031 #include "qcom_pil_info.h"
0032 #include "qcom_wcnss.h"
0033
0034 #define WCNSS_CRASH_REASON_SMEM 422
0035 #define WCNSS_FIRMWARE_NAME "wcnss.mdt"
0036 #define WCNSS_PAS_ID 6
0037 #define WCNSS_SSCTL_ID 0x13
0038
0039 #define WCNSS_SPARE_NVBIN_DLND BIT(25)
0040
0041 #define WCNSS_PMU_IRIS_XO_CFG BIT(3)
0042 #define WCNSS_PMU_IRIS_XO_EN BIT(4)
0043 #define WCNSS_PMU_GC_BUS_MUX_SEL_TOP BIT(5)
0044 #define WCNSS_PMU_IRIS_XO_CFG_STS BIT(6)
0045
0046 #define WCNSS_PMU_IRIS_RESET BIT(7)
0047 #define WCNSS_PMU_IRIS_RESET_STS BIT(8)
0048 #define WCNSS_PMU_IRIS_XO_READ BIT(9)
0049 #define WCNSS_PMU_IRIS_XO_READ_STS BIT(10)
0050
0051 #define WCNSS_PMU_XO_MODE_MASK GENMASK(2, 1)
0052 #define WCNSS_PMU_XO_MODE_19p2 0
0053 #define WCNSS_PMU_XO_MODE_48 3
0054
0055 #define WCNSS_MAX_PDS 2
0056
0057 struct wcnss_data {
0058 size_t pmu_offset;
0059 size_t spare_offset;
0060
0061 const char *pd_names[WCNSS_MAX_PDS];
0062 const struct wcnss_vreg_info *vregs;
0063 size_t num_vregs, num_pd_vregs;
0064 };
0065
0066 struct qcom_wcnss {
0067 struct device *dev;
0068 struct rproc *rproc;
0069
0070 void __iomem *pmu_cfg;
0071 void __iomem *spare_out;
0072
0073 bool use_48mhz_xo;
0074
0075 int wdog_irq;
0076 int fatal_irq;
0077 int ready_irq;
0078 int handover_irq;
0079 int stop_ack_irq;
0080
0081 struct qcom_smem_state *state;
0082 unsigned stop_bit;
0083
0084 struct mutex iris_lock;
0085 struct qcom_iris *iris;
0086
0087 struct device *pds[WCNSS_MAX_PDS];
0088 size_t num_pds;
0089 struct regulator_bulk_data *vregs;
0090 size_t num_vregs;
0091
0092 struct completion start_done;
0093 struct completion stop_done;
0094
0095 phys_addr_t mem_phys;
0096 phys_addr_t mem_reloc;
0097 void *mem_region;
0098 size_t mem_size;
0099
0100 struct qcom_rproc_subdev smd_subdev;
0101 struct qcom_sysmon *sysmon;
0102 };
0103
0104 static const struct wcnss_data riva_data = {
0105 .pmu_offset = 0x28,
0106 .spare_offset = 0xb4,
0107
0108 .vregs = (struct wcnss_vreg_info[]) {
0109 { "vddmx", 1050000, 1150000, 0 },
0110 { "vddcx", 1050000, 1150000, 0 },
0111 { "vddpx", 1800000, 1800000, 0 },
0112 },
0113 .num_vregs = 3,
0114 };
0115
0116 static const struct wcnss_data pronto_v1_data = {
0117 .pmu_offset = 0x1004,
0118 .spare_offset = 0x1088,
0119
0120 .pd_names = { "mx", "cx" },
0121 .vregs = (struct wcnss_vreg_info[]) {
0122 { "vddmx", 950000, 1150000, 0 },
0123 { "vddcx", .super_turbo = true},
0124 { "vddpx", 1800000, 1800000, 0 },
0125 },
0126 .num_pd_vregs = 2,
0127 .num_vregs = 1,
0128 };
0129
0130 static const struct wcnss_data pronto_v2_data = {
0131 .pmu_offset = 0x1004,
0132 .spare_offset = 0x1088,
0133
0134 .pd_names = { "mx", "cx" },
0135 .vregs = (struct wcnss_vreg_info[]) {
0136 { "vddmx", 1287500, 1287500, 0 },
0137 { "vddcx", .super_turbo = true },
0138 { "vddpx", 1800000, 1800000, 0 },
0139 },
0140 .num_pd_vregs = 2,
0141 .num_vregs = 1,
0142 };
0143
0144 static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
0145 {
0146 struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
0147 int ret;
0148
0149 ret = qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
0150 wcnss->mem_region, wcnss->mem_phys,
0151 wcnss->mem_size, &wcnss->mem_reloc);
0152 if (ret)
0153 return ret;
0154
0155 qcom_pil_info_store("wcnss", wcnss->mem_phys, wcnss->mem_size);
0156
0157 return 0;
0158 }
0159
0160 static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)
0161 {
0162 u32 val;
0163
0164
0165 val = readl(wcnss->spare_out);
0166 val |= WCNSS_SPARE_NVBIN_DLND;
0167 writel(val, wcnss->spare_out);
0168 }
0169
0170 static void wcnss_configure_iris(struct qcom_wcnss *wcnss)
0171 {
0172 u32 val;
0173
0174
0175 writel(0, wcnss->pmu_cfg);
0176
0177 val = WCNSS_PMU_GC_BUS_MUX_SEL_TOP | WCNSS_PMU_IRIS_XO_EN;
0178 writel(val, wcnss->pmu_cfg);
0179
0180
0181 val &= ~WCNSS_PMU_XO_MODE_MASK;
0182 if (wcnss->use_48mhz_xo)
0183 val |= WCNSS_PMU_XO_MODE_48 << 1;
0184 else
0185 val |= WCNSS_PMU_XO_MODE_19p2 << 1;
0186 writel(val, wcnss->pmu_cfg);
0187
0188
0189 val |= WCNSS_PMU_IRIS_RESET;
0190 writel(val, wcnss->pmu_cfg);
0191
0192
0193 while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_RESET_STS)
0194 cpu_relax();
0195
0196
0197 val &= ~WCNSS_PMU_IRIS_RESET;
0198 writel(val, wcnss->pmu_cfg);
0199
0200
0201 val |= WCNSS_PMU_IRIS_XO_CFG;
0202 writel(val, wcnss->pmu_cfg);
0203
0204
0205 while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_XO_CFG_STS)
0206 cpu_relax();
0207
0208
0209 val &= ~WCNSS_PMU_GC_BUS_MUX_SEL_TOP;
0210 val &= ~WCNSS_PMU_IRIS_XO_CFG;
0211 writel(val, wcnss->pmu_cfg);
0212
0213
0214 msleep(20);
0215 }
0216
0217 static int wcnss_start(struct rproc *rproc)
0218 {
0219 struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
0220 int ret, i;
0221
0222 mutex_lock(&wcnss->iris_lock);
0223 if (!wcnss->iris) {
0224 dev_err(wcnss->dev, "no iris registered\n");
0225 ret = -EINVAL;
0226 goto release_iris_lock;
0227 }
0228
0229 for (i = 0; i < wcnss->num_pds; i++) {
0230 dev_pm_genpd_set_performance_state(wcnss->pds[i], INT_MAX);
0231 ret = pm_runtime_get_sync(wcnss->pds[i]);
0232 if (ret < 0) {
0233 pm_runtime_put_noidle(wcnss->pds[i]);
0234 goto disable_pds;
0235 }
0236 }
0237
0238 ret = regulator_bulk_enable(wcnss->num_vregs, wcnss->vregs);
0239 if (ret)
0240 goto disable_pds;
0241
0242 ret = qcom_iris_enable(wcnss->iris);
0243 if (ret)
0244 goto disable_regulators;
0245
0246 wcnss_indicate_nv_download(wcnss);
0247 wcnss_configure_iris(wcnss);
0248
0249 ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
0250 if (ret) {
0251 dev_err(wcnss->dev,
0252 "failed to authenticate image and release reset\n");
0253 goto disable_iris;
0254 }
0255
0256 ret = wait_for_completion_timeout(&wcnss->start_done,
0257 msecs_to_jiffies(5000));
0258 if (wcnss->ready_irq > 0 && ret == 0) {
0259
0260 dev_err(wcnss->dev, "start timed out\n");
0261 qcom_scm_pas_shutdown(WCNSS_PAS_ID);
0262 ret = -ETIMEDOUT;
0263 goto disable_iris;
0264 }
0265
0266 ret = 0;
0267
0268 disable_iris:
0269 qcom_iris_disable(wcnss->iris);
0270 disable_regulators:
0271 regulator_bulk_disable(wcnss->num_vregs, wcnss->vregs);
0272 disable_pds:
0273 for (i--; i >= 0; i--) {
0274 pm_runtime_put(wcnss->pds[i]);
0275 dev_pm_genpd_set_performance_state(wcnss->pds[i], 0);
0276 }
0277 release_iris_lock:
0278 mutex_unlock(&wcnss->iris_lock);
0279
0280 return ret;
0281 }
0282
0283 static int wcnss_stop(struct rproc *rproc)
0284 {
0285 struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
0286 int ret;
0287
0288 if (wcnss->state) {
0289 qcom_smem_state_update_bits(wcnss->state,
0290 BIT(wcnss->stop_bit),
0291 BIT(wcnss->stop_bit));
0292
0293 ret = wait_for_completion_timeout(&wcnss->stop_done,
0294 msecs_to_jiffies(5000));
0295 if (ret == 0)
0296 dev_err(wcnss->dev, "timed out on wait\n");
0297
0298 qcom_smem_state_update_bits(wcnss->state,
0299 BIT(wcnss->stop_bit),
0300 0);
0301 }
0302
0303 ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
0304 if (ret)
0305 dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);
0306
0307 return ret;
0308 }
0309
0310 static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
0311 {
0312 struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
0313 int offset;
0314
0315 offset = da - wcnss->mem_reloc;
0316 if (offset < 0 || offset + len > wcnss->mem_size)
0317 return NULL;
0318
0319 return wcnss->mem_region + offset;
0320 }
0321
0322 static const struct rproc_ops wcnss_ops = {
0323 .start = wcnss_start,
0324 .stop = wcnss_stop,
0325 .da_to_va = wcnss_da_to_va,
0326 .parse_fw = qcom_register_dump_segments,
0327 .load = wcnss_load,
0328 };
0329
0330 static irqreturn_t wcnss_wdog_interrupt(int irq, void *dev)
0331 {
0332 struct qcom_wcnss *wcnss = dev;
0333
0334 rproc_report_crash(wcnss->rproc, RPROC_WATCHDOG);
0335
0336 return IRQ_HANDLED;
0337 }
0338
0339 static irqreturn_t wcnss_fatal_interrupt(int irq, void *dev)
0340 {
0341 struct qcom_wcnss *wcnss = dev;
0342 size_t len;
0343 char *msg;
0344
0345 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, WCNSS_CRASH_REASON_SMEM, &len);
0346 if (!IS_ERR(msg) && len > 0 && msg[0])
0347 dev_err(wcnss->dev, "fatal error received: %s\n", msg);
0348
0349 rproc_report_crash(wcnss->rproc, RPROC_FATAL_ERROR);
0350
0351 return IRQ_HANDLED;
0352 }
0353
0354 static irqreturn_t wcnss_ready_interrupt(int irq, void *dev)
0355 {
0356 struct qcom_wcnss *wcnss = dev;
0357
0358 complete(&wcnss->start_done);
0359
0360 return IRQ_HANDLED;
0361 }
0362
0363 static irqreturn_t wcnss_handover_interrupt(int irq, void *dev)
0364 {
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374 return IRQ_HANDLED;
0375 }
0376
0377 static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev)
0378 {
0379 struct qcom_wcnss *wcnss = dev;
0380
0381 complete(&wcnss->stop_done);
0382
0383 return IRQ_HANDLED;
0384 }
0385
0386 static int wcnss_init_pds(struct qcom_wcnss *wcnss,
0387 const char * const pd_names[WCNSS_MAX_PDS])
0388 {
0389 int i, ret;
0390
0391 for (i = 0; i < WCNSS_MAX_PDS; i++) {
0392 if (!pd_names[i])
0393 break;
0394
0395 wcnss->pds[i] = dev_pm_domain_attach_by_name(wcnss->dev, pd_names[i]);
0396 if (IS_ERR_OR_NULL(wcnss->pds[i])) {
0397 ret = PTR_ERR(wcnss->pds[i]) ? : -ENODATA;
0398 for (i--; i >= 0; i--)
0399 dev_pm_domain_detach(wcnss->pds[i], false);
0400 return ret;
0401 }
0402 }
0403 wcnss->num_pds = i;
0404
0405 return 0;
0406 }
0407
0408 static void wcnss_release_pds(struct qcom_wcnss *wcnss)
0409 {
0410 int i;
0411
0412 for (i = 0; i < wcnss->num_pds; i++)
0413 dev_pm_domain_detach(wcnss->pds[i], false);
0414 }
0415
0416 static int wcnss_init_regulators(struct qcom_wcnss *wcnss,
0417 const struct wcnss_vreg_info *info,
0418 int num_vregs, int num_pd_vregs)
0419 {
0420 struct regulator_bulk_data *bulk;
0421 int ret;
0422 int i;
0423
0424
0425
0426
0427
0428
0429 if (wcnss->num_pds)
0430 info += num_pd_vregs;
0431 else
0432 num_vregs += num_pd_vregs;
0433
0434 bulk = devm_kcalloc(wcnss->dev,
0435 num_vregs, sizeof(struct regulator_bulk_data),
0436 GFP_KERNEL);
0437 if (!bulk)
0438 return -ENOMEM;
0439
0440 for (i = 0; i < num_vregs; i++)
0441 bulk[i].supply = info[i].name;
0442
0443 ret = devm_regulator_bulk_get(wcnss->dev, num_vregs, bulk);
0444 if (ret)
0445 return ret;
0446
0447 for (i = 0; i < num_vregs; i++) {
0448 if (info[i].max_voltage)
0449 regulator_set_voltage(bulk[i].consumer,
0450 info[i].min_voltage,
0451 info[i].max_voltage);
0452
0453 if (info[i].load_uA)
0454 regulator_set_load(bulk[i].consumer, info[i].load_uA);
0455 }
0456
0457 wcnss->vregs = bulk;
0458 wcnss->num_vregs = num_vregs;
0459
0460 return 0;
0461 }
0462
0463 static int wcnss_request_irq(struct qcom_wcnss *wcnss,
0464 struct platform_device *pdev,
0465 const char *name,
0466 bool optional,
0467 irq_handler_t thread_fn)
0468 {
0469 int ret;
0470 int irq_number;
0471
0472 ret = platform_get_irq_byname(pdev, name);
0473 if (ret < 0 && optional) {
0474 dev_dbg(&pdev->dev, "no %s IRQ defined, ignoring\n", name);
0475 return 0;
0476 } else if (ret < 0) {
0477 dev_err(&pdev->dev, "no %s IRQ defined\n", name);
0478 return ret;
0479 }
0480
0481 irq_number = ret;
0482
0483 ret = devm_request_threaded_irq(&pdev->dev, ret,
0484 NULL, thread_fn,
0485 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
0486 "wcnss", wcnss);
0487 if (ret) {
0488 dev_err(&pdev->dev, "request %s IRQ failed\n", name);
0489 return ret;
0490 }
0491
0492
0493 return irq_number;
0494 }
0495
0496 static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
0497 {
0498 struct device_node *node;
0499 struct resource r;
0500 int ret;
0501
0502 node = of_parse_phandle(wcnss->dev->of_node, "memory-region", 0);
0503 if (!node) {
0504 dev_err(wcnss->dev, "no memory-region specified\n");
0505 return -EINVAL;
0506 }
0507
0508 ret = of_address_to_resource(node, 0, &r);
0509 of_node_put(node);
0510 if (ret)
0511 return ret;
0512
0513 wcnss->mem_phys = wcnss->mem_reloc = r.start;
0514 wcnss->mem_size = resource_size(&r);
0515 wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);
0516 if (!wcnss->mem_region) {
0517 dev_err(wcnss->dev, "unable to map memory region: %pa+%zx\n",
0518 &r.start, wcnss->mem_size);
0519 return -EBUSY;
0520 }
0521
0522 return 0;
0523 }
0524
0525 static int wcnss_probe(struct platform_device *pdev)
0526 {
0527 const char *fw_name = WCNSS_FIRMWARE_NAME;
0528 const struct wcnss_data *data;
0529 struct qcom_wcnss *wcnss;
0530 struct resource *res;
0531 struct rproc *rproc;
0532 void __iomem *mmio;
0533 int ret;
0534
0535 data = of_device_get_match_data(&pdev->dev);
0536
0537 if (!qcom_scm_is_available())
0538 return -EPROBE_DEFER;
0539
0540 if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
0541 dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
0542 return -ENXIO;
0543 }
0544
0545 ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
0546 &fw_name);
0547 if (ret < 0 && ret != -EINVAL)
0548 return ret;
0549
0550 rproc = rproc_alloc(&pdev->dev, pdev->name, &wcnss_ops,
0551 fw_name, sizeof(*wcnss));
0552 if (!rproc) {
0553 dev_err(&pdev->dev, "unable to allocate remoteproc\n");
0554 return -ENOMEM;
0555 }
0556 rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
0557
0558 wcnss = (struct qcom_wcnss *)rproc->priv;
0559 wcnss->dev = &pdev->dev;
0560 wcnss->rproc = rproc;
0561 platform_set_drvdata(pdev, wcnss);
0562
0563 init_completion(&wcnss->start_done);
0564 init_completion(&wcnss->stop_done);
0565
0566 mutex_init(&wcnss->iris_lock);
0567
0568 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu");
0569 mmio = devm_ioremap_resource(&pdev->dev, res);
0570 if (IS_ERR(mmio)) {
0571 ret = PTR_ERR(mmio);
0572 goto free_rproc;
0573 }
0574
0575 ret = wcnss_alloc_memory_region(wcnss);
0576 if (ret)
0577 goto free_rproc;
0578
0579 wcnss->pmu_cfg = mmio + data->pmu_offset;
0580 wcnss->spare_out = mmio + data->spare_offset;
0581
0582
0583
0584
0585
0586 ret = wcnss_init_pds(wcnss, data->pd_names);
0587 if (ret && (ret != -ENODATA || !data->num_pd_vregs))
0588 goto free_rproc;
0589
0590 ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs,
0591 data->num_pd_vregs);
0592 if (ret)
0593 goto detach_pds;
0594
0595 ret = wcnss_request_irq(wcnss, pdev, "wdog", false, wcnss_wdog_interrupt);
0596 if (ret < 0)
0597 goto detach_pds;
0598 wcnss->wdog_irq = ret;
0599
0600 ret = wcnss_request_irq(wcnss, pdev, "fatal", false, wcnss_fatal_interrupt);
0601 if (ret < 0)
0602 goto detach_pds;
0603 wcnss->fatal_irq = ret;
0604
0605 ret = wcnss_request_irq(wcnss, pdev, "ready", true, wcnss_ready_interrupt);
0606 if (ret < 0)
0607 goto detach_pds;
0608 wcnss->ready_irq = ret;
0609
0610 ret = wcnss_request_irq(wcnss, pdev, "handover", true, wcnss_handover_interrupt);
0611 if (ret < 0)
0612 goto detach_pds;
0613 wcnss->handover_irq = ret;
0614
0615 ret = wcnss_request_irq(wcnss, pdev, "stop-ack", true, wcnss_stop_ack_interrupt);
0616 if (ret < 0)
0617 goto detach_pds;
0618 wcnss->stop_ack_irq = ret;
0619
0620 if (wcnss->stop_ack_irq) {
0621 wcnss->state = devm_qcom_smem_state_get(&pdev->dev, "stop",
0622 &wcnss->stop_bit);
0623 if (IS_ERR(wcnss->state)) {
0624 ret = PTR_ERR(wcnss->state);
0625 goto detach_pds;
0626 }
0627 }
0628
0629 qcom_add_smd_subdev(rproc, &wcnss->smd_subdev);
0630 wcnss->sysmon = qcom_add_sysmon_subdev(rproc, "wcnss", WCNSS_SSCTL_ID);
0631 if (IS_ERR(wcnss->sysmon)) {
0632 ret = PTR_ERR(wcnss->sysmon);
0633 goto detach_pds;
0634 }
0635
0636 wcnss->iris = qcom_iris_probe(&pdev->dev, &wcnss->use_48mhz_xo);
0637 if (IS_ERR(wcnss->iris)) {
0638 ret = PTR_ERR(wcnss->iris);
0639 goto detach_pds;
0640 }
0641
0642 ret = rproc_add(rproc);
0643 if (ret)
0644 goto remove_iris;
0645
0646 return 0;
0647
0648 remove_iris:
0649 qcom_iris_remove(wcnss->iris);
0650 detach_pds:
0651 wcnss_release_pds(wcnss);
0652 free_rproc:
0653 rproc_free(rproc);
0654
0655 return ret;
0656 }
0657
0658 static int wcnss_remove(struct platform_device *pdev)
0659 {
0660 struct qcom_wcnss *wcnss = platform_get_drvdata(pdev);
0661
0662 qcom_iris_remove(wcnss->iris);
0663
0664 rproc_del(wcnss->rproc);
0665
0666 qcom_remove_sysmon_subdev(wcnss->sysmon);
0667 qcom_remove_smd_subdev(wcnss->rproc, &wcnss->smd_subdev);
0668 wcnss_release_pds(wcnss);
0669 rproc_free(wcnss->rproc);
0670
0671 return 0;
0672 }
0673
0674 static const struct of_device_id wcnss_of_match[] = {
0675 { .compatible = "qcom,riva-pil", &riva_data },
0676 { .compatible = "qcom,pronto-v1-pil", &pronto_v1_data },
0677 { .compatible = "qcom,pronto-v2-pil", &pronto_v2_data },
0678 { },
0679 };
0680 MODULE_DEVICE_TABLE(of, wcnss_of_match);
0681
0682 static struct platform_driver wcnss_driver = {
0683 .probe = wcnss_probe,
0684 .remove = wcnss_remove,
0685 .driver = {
0686 .name = "qcom-wcnss-pil",
0687 .of_match_table = wcnss_of_match,
0688 },
0689 };
0690
0691 module_platform_driver(wcnss_driver);
0692
0693 MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Wireless Subsystem");
0694 MODULE_LICENSE("GPL v2");