1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2016-2018 Linaro Ltd.
4  * Copyright (C) 2014 Sony Mobile Communications AB
5  * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
6  */
7 #include <linux/iopoll.h>
8 #include <linux/kernel.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/module.h>
11 #include <linux/of_reserved_mem.h>
12 #include <linux/platform_device.h>
13 #include <linux/regmap.h>
14 #include <linux/reset.h>
15 #include <linux/soc/qcom/mdt_loader.h>
16 #include "qcom_common.h"
17 #include "qcom_q6v5.h"
18 
19 #define WCSS_CRASH_REASON		421
20 
21 /* Q6SS Register Offsets */
22 #define Q6SS_RESET_REG		0x014
23 #define Q6SS_GFMUX_CTL_REG		0x020
24 #define Q6SS_PWR_CTL_REG		0x030
25 #define Q6SS_MEM_PWR_CTL		0x0B0
26 
27 /* AXI Halt Register Offsets */
28 #define AXI_HALTREQ_REG			0x0
29 #define AXI_HALTACK_REG			0x4
30 #define AXI_IDLE_REG			0x8
31 
32 #define HALT_ACK_TIMEOUT_MS		100
33 
34 /* Q6SS_RESET */
35 #define Q6SS_STOP_CORE			BIT(0)
36 #define Q6SS_CORE_ARES			BIT(1)
37 #define Q6SS_BUS_ARES_ENABLE		BIT(2)
38 
39 /* Q6SS_GFMUX_CTL */
40 #define Q6SS_CLK_ENABLE			BIT(1)
41 
42 /* Q6SS_PWR_CTL */
43 #define Q6SS_L2DATA_STBY_N		BIT(18)
44 #define Q6SS_SLP_RET_N			BIT(19)
45 #define Q6SS_CLAMP_IO			BIT(20)
46 #define QDSS_BHS_ON			BIT(21)
47 
48 /* Q6SS parameters */
49 #define Q6SS_LDO_BYP		BIT(25)
50 #define Q6SS_BHS_ON		BIT(24)
51 #define Q6SS_CLAMP_WL		BIT(21)
52 #define Q6SS_CLAMP_QMC_MEM		BIT(22)
53 #define HALT_CHECK_MAX_LOOPS		200
54 #define Q6SS_XO_CBCR		GENMASK(5, 3)
55 
56 /* Q6SS config/status registers */
57 #define TCSR_GLOBAL_CFG0	0x0
58 #define TCSR_GLOBAL_CFG1	0x4
59 #define SSCAON_CONFIG		0x8
60 #define SSCAON_STATUS		0xc
61 #define Q6SS_BHS_STATUS		0x78
62 #define Q6SS_RST_EVB		0x10
63 
64 #define BHS_EN_REST_ACK		BIT(0)
65 #define SSCAON_ENABLE		BIT(13)
66 #define SSCAON_BUS_EN		BIT(15)
67 #define SSCAON_BUS_MUX_MASK	GENMASK(18, 16)
68 
69 #define MEM_BANKS		19
70 #define TCSR_WCSS_CLK_MASK	0x1F
71 #define TCSR_WCSS_CLK_ENABLE	0x14
72 
73 struct q6v5_wcss {
74 	struct device *dev;
75 
76 	void __iomem *reg_base;
77 	void __iomem *rmb_base;
78 
79 	struct regmap *halt_map;
80 	u32 halt_q6;
81 	u32 halt_wcss;
82 	u32 halt_nc;
83 
84 	struct reset_control *wcss_aon_reset;
85 	struct reset_control *wcss_reset;
86 	struct reset_control *wcss_q6_reset;
87 
88 	struct qcom_q6v5 q6v5;
89 
90 	phys_addr_t mem_phys;
91 	phys_addr_t mem_reloc;
92 	void *mem_region;
93 	size_t mem_size;
94 
95 	struct qcom_rproc_glink glink_subdev;
96 	struct qcom_rproc_ssr ssr_subdev;
97 };
98 
99 static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
100 {
101 	int ret;
102 	u32 val;
103 	int i;
104 
105 	/* Assert resets, stop core */
106 	val = readl(wcss->reg_base + Q6SS_RESET_REG);
107 	val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
108 	writel(val, wcss->reg_base + Q6SS_RESET_REG);
109 
110 	/* BHS require xo cbcr to be enabled */
111 	val = readl(wcss->reg_base + Q6SS_XO_CBCR);
112 	val |= 0x1;
113 	writel(val, wcss->reg_base + Q6SS_XO_CBCR);
114 
115 	/* Read CLKOFF bit to go low indicating CLK is enabled */
116 	ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
117 				 val, !(val & BIT(31)), 1,
118 				 HALT_CHECK_MAX_LOOPS);
119 	if (ret) {
120 		dev_err(wcss->dev,
121 			"xo cbcr enabling timed out (rc:%d)\n", ret);
122 		return ret;
123 	}
124 	/* Enable power block headswitch and wait for it to stabilize */
125 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
126 	val |= Q6SS_BHS_ON;
127 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
128 	udelay(1);
129 
130 	/* Put LDO in bypass mode */
131 	val |= Q6SS_LDO_BYP;
132 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
133 
134 	/* Deassert Q6 compiler memory clamp */
135 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
136 	val &= ~Q6SS_CLAMP_QMC_MEM;
137 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
138 
139 	/* Deassert memory peripheral sleep and L2 memory standby */
140 	val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
141 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
142 
143 	/* Turn on L1, L2, ETB and JU memories 1 at a time */
144 	val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
145 	for (i = MEM_BANKS; i >= 0; i--) {
146 		val |= BIT(i);
147 		writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
148 		/*
149 		 * Read back value to ensure the write is done then
150 		 * wait for 1us for both memory peripheral and data
151 		 * array to turn on.
152 		 */
153 		val |= readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
154 		udelay(1);
155 	}
156 	/* Remove word line clamp */
157 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
158 	val &= ~Q6SS_CLAMP_WL;
159 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
160 
161 	/* Remove IO clamp */
162 	val &= ~Q6SS_CLAMP_IO;
163 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
164 
165 	/* Bring core out of reset */
166 	val = readl(wcss->reg_base + Q6SS_RESET_REG);
167 	val &= ~Q6SS_CORE_ARES;
168 	writel(val, wcss->reg_base + Q6SS_RESET_REG);
169 
170 	/* Turn on core clock */
171 	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
172 	val |= Q6SS_CLK_ENABLE;
173 	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
174 
175 	/* Start core execution */
176 	val = readl(wcss->reg_base + Q6SS_RESET_REG);
177 	val &= ~Q6SS_STOP_CORE;
178 	writel(val, wcss->reg_base + Q6SS_RESET_REG);
179 
180 	return 0;
181 }
182 
183 static int q6v5_wcss_start(struct rproc *rproc)
184 {
185 	struct q6v5_wcss *wcss = rproc->priv;
186 	int ret;
187 
188 	qcom_q6v5_prepare(&wcss->q6v5);
189 
190 	/* Release Q6 and WCSS reset */
191 	ret = reset_control_deassert(wcss->wcss_reset);
192 	if (ret) {
193 		dev_err(wcss->dev, "wcss_reset failed\n");
194 		return ret;
195 	}
196 
197 	ret = reset_control_deassert(wcss->wcss_q6_reset);
198 	if (ret) {
199 		dev_err(wcss->dev, "wcss_q6_reset failed\n");
200 		goto wcss_reset;
201 	}
202 
203 	/* Lithium configuration - clock gating and bus arbitration */
204 	ret = regmap_update_bits(wcss->halt_map,
205 				 wcss->halt_nc + TCSR_GLOBAL_CFG0,
206 				 TCSR_WCSS_CLK_MASK,
207 				 TCSR_WCSS_CLK_ENABLE);
208 	if (ret)
209 		goto wcss_q6_reset;
210 
211 	ret = regmap_update_bits(wcss->halt_map,
212 				 wcss->halt_nc + TCSR_GLOBAL_CFG1,
213 				 1, 0);
214 	if (ret)
215 		goto wcss_q6_reset;
216 
217 	/* Write bootaddr to EVB so that Q6WCSS will jump there after reset */
218 	writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);
219 
220 	ret = q6v5_wcss_reset(wcss);
221 	if (ret)
222 		goto wcss_q6_reset;
223 
224 	ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
225 	if (ret == -ETIMEDOUT)
226 		dev_err(wcss->dev, "start timed out\n");
227 
228 	return ret;
229 
230 wcss_q6_reset:
231 	reset_control_assert(wcss->wcss_q6_reset);
232 
233 wcss_reset:
234 	reset_control_assert(wcss->wcss_reset);
235 
236 	return ret;
237 }
238 
239 static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss,
240 				    struct regmap *halt_map,
241 				    u32 offset)
242 {
243 	unsigned long timeout;
244 	unsigned int val;
245 	int ret;
246 
247 	/* Check if we're already idle */
248 	ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
249 	if (!ret && val)
250 		return;
251 
252 	/* Assert halt request */
253 	regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
254 
255 	/* Wait for halt */
256 	timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
257 	for (;;) {
258 		ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
259 		if (ret || val || time_after(jiffies, timeout))
260 			break;
261 
262 		msleep(1);
263 	}
264 
265 	ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
266 	if (ret || !val)
267 		dev_err(wcss->dev, "port failed halt\n");
268 
269 	/* Clear halt request (port will remain halted until reset) */
270 	regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
271 }
272 
273 static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss)
274 {
275 	int ret;
276 	u32 val;
277 
278 	/* 1 - Assert WCSS/Q6 HALTREQ */
279 	q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss);
280 
281 	/* 2 - Enable WCSSAON_CONFIG */
282 	val = readl(wcss->rmb_base + SSCAON_CONFIG);
283 	val |= SSCAON_ENABLE;
284 	writel(val, wcss->rmb_base + SSCAON_CONFIG);
285 
286 	/* 3 - Set SSCAON_CONFIG */
287 	val |= SSCAON_BUS_EN;
288 	val &= ~SSCAON_BUS_MUX_MASK;
289 	writel(val, wcss->rmb_base + SSCAON_CONFIG);
290 
291 	/* 4 - SSCAON_CONFIG 1 */
292 	val |= BIT(1);
293 	writel(val, wcss->rmb_base + SSCAON_CONFIG);
294 
295 	/* 5 - wait for SSCAON_STATUS */
296 	ret = readl_poll_timeout(wcss->rmb_base + SSCAON_STATUS,
297 				 val, (val & 0xffff) == 0x400, 1000,
298 				 HALT_CHECK_MAX_LOOPS);
299 	if (ret) {
300 		dev_err(wcss->dev,
301 			"can't get SSCAON_STATUS rc:%d)\n", ret);
302 		return ret;
303 	}
304 
305 	/* 6 - De-assert WCSS_AON reset */
306 	reset_control_assert(wcss->wcss_aon_reset);
307 
308 	/* 7 - Disable WCSSAON_CONFIG 13 */
309 	val = readl(wcss->rmb_base + SSCAON_CONFIG);
310 	val &= ~SSCAON_ENABLE;
311 	writel(val, wcss->rmb_base + SSCAON_CONFIG);
312 
313 	/* 8 - De-assert WCSS/Q6 HALTREQ */
314 	reset_control_assert(wcss->wcss_reset);
315 
316 	return 0;
317 }
318 
319 static int q6v5_q6_powerdown(struct q6v5_wcss *wcss)
320 {
321 	int ret;
322 	u32 val;
323 	int i;
324 
325 	/* 1 - Halt Q6 bus interface */
326 	q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_q6);
327 
328 	/* 2 - Disable Q6 Core clock */
329 	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
330 	val &= ~Q6SS_CLK_ENABLE;
331 	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
332 
333 	/* 3 - Clamp I/O */
334 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
335 	val |= Q6SS_CLAMP_IO;
336 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
337 
338 	/* 4 - Clamp WL */
339 	val |= QDSS_BHS_ON;
340 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
341 
342 	/* 5 - Clear Erase standby */
343 	val &= ~Q6SS_L2DATA_STBY_N;
344 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
345 
346 	/* 6 - Clear Sleep RTN */
347 	val &= ~Q6SS_SLP_RET_N;
348 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
349 
350 	/* 7 - turn off Q6 memory foot/head switch one bank at a time */
351 	for (i = 0; i < 20; i++) {
352 		val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
353 		val &= ~BIT(i);
354 		writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
355 		mdelay(1);
356 	}
357 
358 	/* 8 - Assert QMC memory RTN */
359 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
360 	val |= Q6SS_CLAMP_QMC_MEM;
361 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
362 
363 	/* 9 - Turn off BHS */
364 	val &= ~Q6SS_BHS_ON;
365 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
366 	udelay(1);
367 
368 	/* 10 - Wait till BHS Reset is done */
369 	ret = readl_poll_timeout(wcss->reg_base + Q6SS_BHS_STATUS,
370 				 val, !(val & BHS_EN_REST_ACK), 1000,
371 				 HALT_CHECK_MAX_LOOPS);
372 	if (ret) {
373 		dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret);
374 		return ret;
375 	}
376 
377 	/* 11 -  Assert WCSS reset */
378 	reset_control_assert(wcss->wcss_reset);
379 
380 	/* 12 - Assert Q6 reset */
381 	reset_control_assert(wcss->wcss_q6_reset);
382 
383 	return 0;
384 }
385 
386 static int q6v5_wcss_stop(struct rproc *rproc)
387 {
388 	struct q6v5_wcss *wcss = rproc->priv;
389 	int ret;
390 
391 	/* WCSS powerdown */
392 	ret = qcom_q6v5_request_stop(&wcss->q6v5);
393 	if (ret == -ETIMEDOUT) {
394 		dev_err(wcss->dev, "timed out on wait\n");
395 		return ret;
396 	}
397 
398 	ret = q6v5_wcss_powerdown(wcss);
399 	if (ret)
400 		return ret;
401 
402 	/* Q6 Power down */
403 	ret = q6v5_q6_powerdown(wcss);
404 	if (ret)
405 		return ret;
406 
407 	qcom_q6v5_unprepare(&wcss->q6v5);
408 
409 	return 0;
410 }
411 
412 static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len)
413 {
414 	struct q6v5_wcss *wcss = rproc->priv;
415 	int offset;
416 
417 	offset = da - wcss->mem_reloc;
418 	if (offset < 0 || offset + len > wcss->mem_size)
419 		return NULL;
420 
421 	return wcss->mem_region + offset;
422 }
423 
424 static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
425 {
426 	struct q6v5_wcss *wcss = rproc->priv;
427 
428 	return qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware,
429 				     0, wcss->mem_region, wcss->mem_phys,
430 				     wcss->mem_size, &wcss->mem_reloc);
431 }
432 
433 static const struct rproc_ops q6v5_wcss_ops = {
434 	.start = q6v5_wcss_start,
435 	.stop = q6v5_wcss_stop,
436 	.da_to_va = q6v5_wcss_da_to_va,
437 	.load = q6v5_wcss_load,
438 	.get_boot_addr = rproc_elf_get_boot_addr,
439 };
440 
441 static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss)
442 {
443 	struct device *dev = wcss->dev;
444 
445 	wcss->wcss_aon_reset = devm_reset_control_get(dev, "wcss_aon_reset");
446 	if (IS_ERR(wcss->wcss_aon_reset)) {
447 		dev_err(wcss->dev, "unable to acquire wcss_aon_reset\n");
448 		return PTR_ERR(wcss->wcss_aon_reset);
449 	}
450 
451 	wcss->wcss_reset = devm_reset_control_get(dev, "wcss_reset");
452 	if (IS_ERR(wcss->wcss_reset)) {
453 		dev_err(wcss->dev, "unable to acquire wcss_reset\n");
454 		return PTR_ERR(wcss->wcss_reset);
455 	}
456 
457 	wcss->wcss_q6_reset = devm_reset_control_get(dev, "wcss_q6_reset");
458 	if (IS_ERR(wcss->wcss_q6_reset)) {
459 		dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
460 		return PTR_ERR(wcss->wcss_q6_reset);
461 	}
462 
463 	return 0;
464 }
465 
466 static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss,
467 			       struct platform_device *pdev)
468 {
469 	struct of_phandle_args args;
470 	struct resource *res;
471 	int ret;
472 
473 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
474 	wcss->reg_base = devm_ioremap_resource(&pdev->dev, res);
475 	if (IS_ERR(wcss->reg_base))
476 		return PTR_ERR(wcss->reg_base);
477 
478 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
479 	wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res);
480 	if (IS_ERR(wcss->rmb_base))
481 		return PTR_ERR(wcss->rmb_base);
482 
483 	ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
484 					       "qcom,halt-regs", 3, 0, &args);
485 	if (ret < 0) {
486 		dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
487 		return -EINVAL;
488 	}
489 
490 	wcss->halt_map = syscon_node_to_regmap(args.np);
491 	of_node_put(args.np);
492 	if (IS_ERR(wcss->halt_map))
493 		return PTR_ERR(wcss->halt_map);
494 
495 	wcss->halt_q6 = args.args[0];
496 	wcss->halt_wcss = args.args[1];
497 	wcss->halt_nc = args.args[2];
498 
499 	return 0;
500 }
501 
502 static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss)
503 {
504 	struct reserved_mem *rmem = NULL;
505 	struct device_node *node;
506 	struct device *dev = wcss->dev;
507 
508 	node = of_parse_phandle(dev->of_node, "memory-region", 0);
509 	if (node)
510 		rmem = of_reserved_mem_lookup(node);
511 	of_node_put(node);
512 
513 	if (!rmem) {
514 		dev_err(dev, "unable to acquire memory-region\n");
515 		return -EINVAL;
516 	}
517 
518 	wcss->mem_phys = rmem->base;
519 	wcss->mem_reloc = rmem->base;
520 	wcss->mem_size = rmem->size;
521 	wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
522 	if (!wcss->mem_region) {
523 		dev_err(dev, "unable to map memory region: %pa+%pa\n",
524 			&rmem->base, &rmem->size);
525 		return -EBUSY;
526 	}
527 
528 	return 0;
529 }
530 
531 static int q6v5_wcss_probe(struct platform_device *pdev)
532 {
533 	struct q6v5_wcss *wcss;
534 	struct rproc *rproc;
535 	int ret;
536 
537 	rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_wcss_ops,
538 			    "IPQ8074/q6_fw.mdt", sizeof(*wcss));
539 	if (!rproc) {
540 		dev_err(&pdev->dev, "failed to allocate rproc\n");
541 		return -ENOMEM;
542 	}
543 
544 	wcss = rproc->priv;
545 	wcss->dev = &pdev->dev;
546 
547 	ret = q6v5_wcss_init_mmio(wcss, pdev);
548 	if (ret)
549 		goto free_rproc;
550 
551 	ret = q6v5_alloc_memory_region(wcss);
552 	if (ret)
553 		goto free_rproc;
554 
555 	ret = q6v5_wcss_init_reset(wcss);
556 	if (ret)
557 		goto free_rproc;
558 
559 	ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, WCSS_CRASH_REASON, NULL);
560 	if (ret)
561 		goto free_rproc;
562 
563 	qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
564 	qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
565 
566 	ret = rproc_add(rproc);
567 	if (ret)
568 		goto free_rproc;
569 
570 	platform_set_drvdata(pdev, rproc);
571 
572 	return 0;
573 
574 free_rproc:
575 	rproc_free(rproc);
576 
577 	return ret;
578 }
579 
580 static int q6v5_wcss_remove(struct platform_device *pdev)
581 {
582 	struct rproc *rproc = platform_get_drvdata(pdev);
583 
584 	rproc_del(rproc);
585 	rproc_free(rproc);
586 
587 	return 0;
588 }
589 
590 static const struct of_device_id q6v5_wcss_of_match[] = {
591 	{ .compatible = "qcom,ipq8074-wcss-pil" },
592 	{ },
593 };
594 MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);
595 
596 static struct platform_driver q6v5_wcss_driver = {
597 	.probe = q6v5_wcss_probe,
598 	.remove = q6v5_wcss_remove,
599 	.driver = {
600 		.name = "qcom-q6v5-wcss-pil",
601 		.of_match_table = q6v5_wcss_of_match,
602 	},
603 };
604 module_platform_driver(q6v5_wcss_driver);
605 
606 MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader");
607 MODULE_LICENSE("GPL v2");
608