xref: /linux/drivers/power/sequencing/pwrseq-qcom-wcn.c (revision cbae17630954cb89f2bdf5bbadfd3aa81ea67283)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2024 Linaro Ltd.
4  */
5 
6 #include <linux/clk.h>
7 #include <linux/delay.h>
8 #include <linux/device.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/jiffies.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/platform_device.h>
14 #include <linux/property.h>
15 #include <linux/regulator/consumer.h>
16 #include <linux/pwrseq/provider.h>
17 #include <linux/string.h>
18 #include <linux/types.h>
19 
20 struct pwrseq_qcom_wcn_pdata {
21 	const char *const *vregs;
22 	size_t num_vregs;
23 	unsigned int pwup_delay_ms;
24 	unsigned int gpio_enable_delay_ms;
25 	const struct pwrseq_target_data **targets;
26 	bool has_vddio; /* separate VDD IO regulator */
27 	int (*match)(struct pwrseq_device *pwrseq, struct device *dev);
28 };
29 
30 struct pwrseq_qcom_wcn_ctx {
31 	struct pwrseq_device *pwrseq;
32 	struct device_node *of_node;
33 	const struct pwrseq_qcom_wcn_pdata *pdata;
34 	struct regulator_bulk_data *regs;
35 	struct regulator *vddio;
36 	struct gpio_desc *bt_gpio;
37 	struct gpio_desc *wlan_gpio;
38 	struct gpio_desc *xo_clk_gpio;
39 	struct clk *clk;
40 	unsigned long last_gpio_enable_jf;
41 };
42 
43 static void pwrseq_qcom_wcn_ensure_gpio_delay(struct pwrseq_qcom_wcn_ctx *ctx)
44 {
45 	unsigned long diff_jiffies;
46 	unsigned int diff_msecs;
47 
48 	if (!ctx->pdata->gpio_enable_delay_ms)
49 		return;
50 
51 	diff_jiffies = jiffies - ctx->last_gpio_enable_jf;
52 	diff_msecs = jiffies_to_msecs(diff_jiffies);
53 
54 	if (diff_msecs < ctx->pdata->gpio_enable_delay_ms)
55 		msleep(ctx->pdata->gpio_enable_delay_ms - diff_msecs);
56 }
57 
58 static int pwrseq_qcom_wcn_vddio_enable(struct pwrseq_device *pwrseq)
59 {
60 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
61 
62 	return regulator_enable(ctx->vddio);
63 }
64 
65 static int pwrseq_qcom_wcn_vddio_disable(struct pwrseq_device *pwrseq)
66 {
67 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
68 
69 	return regulator_disable(ctx->vddio);
70 }
71 
72 static const struct pwrseq_unit_data pwrseq_qcom_wcn_vddio_unit_data = {
73 	.name = "vddio-enable",
74 	.enable = pwrseq_qcom_wcn_vddio_enable,
75 	.disable = pwrseq_qcom_wcn_vddio_disable,
76 };
77 
78 static int pwrseq_qcom_wcn_vregs_enable(struct pwrseq_device *pwrseq)
79 {
80 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
81 
82 	return regulator_bulk_enable(ctx->pdata->num_vregs, ctx->regs);
83 }
84 
85 static int pwrseq_qcom_wcn_vregs_disable(struct pwrseq_device *pwrseq)
86 {
87 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
88 
89 	return regulator_bulk_disable(ctx->pdata->num_vregs, ctx->regs);
90 }
91 
92 static const struct pwrseq_unit_data pwrseq_qcom_wcn_vregs_unit_data = {
93 	.name = "regulators-enable",
94 	.enable = pwrseq_qcom_wcn_vregs_enable,
95 	.disable = pwrseq_qcom_wcn_vregs_disable,
96 };
97 
98 static int pwrseq_qcom_wcn_clk_enable(struct pwrseq_device *pwrseq)
99 {
100 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
101 
102 	return clk_prepare_enable(ctx->clk);
103 }
104 
105 static int pwrseq_qcom_wcn_clk_disable(struct pwrseq_device *pwrseq)
106 {
107 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
108 
109 	clk_disable_unprepare(ctx->clk);
110 
111 	return 0;
112 }
113 
114 static const struct pwrseq_unit_data pwrseq_qcom_wcn_clk_unit_data = {
115 	.name = "clock-enable",
116 	.enable = pwrseq_qcom_wcn_clk_enable,
117 	.disable = pwrseq_qcom_wcn_clk_disable,
118 };
119 
120 static const struct pwrseq_unit_data *pwrseq_qcom_wcn3990_unit_deps[] = {
121 	&pwrseq_qcom_wcn_vddio_unit_data,
122 	&pwrseq_qcom_wcn_vregs_unit_data,
123 	NULL,
124 };
125 
126 static const struct pwrseq_unit_data pwrseq_qcom_wcn3990_unit_data = {
127 	.name = "clock-enable",
128 	.deps = pwrseq_qcom_wcn3990_unit_deps,
129 	.enable = pwrseq_qcom_wcn_clk_enable,
130 	.disable = pwrseq_qcom_wcn_clk_disable,
131 };
132 
133 static const struct pwrseq_unit_data *pwrseq_qcom_wcn_unit_deps[] = {
134 	&pwrseq_qcom_wcn_vregs_unit_data,
135 	&pwrseq_qcom_wcn_clk_unit_data,
136 	NULL
137 };
138 
139 static int pwrseq_qcom_wcn6855_clk_assert(struct pwrseq_device *pwrseq)
140 {
141 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
142 
143 	if (!ctx->xo_clk_gpio)
144 		return 0;
145 
146 	msleep(1);
147 
148 	gpiod_set_value_cansleep(ctx->xo_clk_gpio, 1);
149 	usleep_range(100, 200);
150 
151 	return 0;
152 }
153 
154 static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_xo_clk_assert = {
155 	.name = "xo-clk-assert",
156 	.enable = pwrseq_qcom_wcn6855_clk_assert,
157 };
158 
159 static const struct pwrseq_unit_data *pwrseq_qcom_wcn6855_unit_deps[] = {
160 	&pwrseq_qcom_wcn_vregs_unit_data,
161 	&pwrseq_qcom_wcn_clk_unit_data,
162 	&pwrseq_qcom_wcn6855_xo_clk_assert,
163 	NULL
164 };
165 
166 static int pwrseq_qcom_wcn_bt_enable(struct pwrseq_device *pwrseq)
167 {
168 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
169 
170 	pwrseq_qcom_wcn_ensure_gpio_delay(ctx);
171 	gpiod_set_value_cansleep(ctx->bt_gpio, 1);
172 	ctx->last_gpio_enable_jf = jiffies;
173 
174 	return 0;
175 }
176 
177 static int pwrseq_qcom_wcn_bt_disable(struct pwrseq_device *pwrseq)
178 {
179 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
180 
181 	gpiod_set_value_cansleep(ctx->bt_gpio, 0);
182 
183 	return 0;
184 }
185 
186 static const struct pwrseq_unit_data pwrseq_qcom_wcn_bt_unit_data = {
187 	.name = "bluetooth-enable",
188 	.deps = pwrseq_qcom_wcn_unit_deps,
189 	.enable = pwrseq_qcom_wcn_bt_enable,
190 	.disable = pwrseq_qcom_wcn_bt_disable,
191 };
192 
193 static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_bt_unit_data = {
194 	.name = "bluetooth-enable",
195 	.deps = pwrseq_qcom_wcn6855_unit_deps,
196 	.enable = pwrseq_qcom_wcn_bt_enable,
197 	.disable = pwrseq_qcom_wcn_bt_disable,
198 };
199 
200 static int pwrseq_qcom_wcn_wlan_enable(struct pwrseq_device *pwrseq)
201 {
202 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
203 
204 	pwrseq_qcom_wcn_ensure_gpio_delay(ctx);
205 	gpiod_set_value_cansleep(ctx->wlan_gpio, 1);
206 	ctx->last_gpio_enable_jf = jiffies;
207 
208 	return 0;
209 }
210 
211 static int pwrseq_qcom_wcn_wlan_disable(struct pwrseq_device *pwrseq)
212 {
213 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
214 
215 	gpiod_set_value_cansleep(ctx->wlan_gpio, 0);
216 
217 	return 0;
218 }
219 
220 static const struct pwrseq_unit_data pwrseq_qcom_wcn_wlan_unit_data = {
221 	.name = "wlan-enable",
222 	.deps = pwrseq_qcom_wcn_unit_deps,
223 	.enable = pwrseq_qcom_wcn_wlan_enable,
224 	.disable = pwrseq_qcom_wcn_wlan_disable,
225 };
226 
227 static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_wlan_unit_data = {
228 	.name = "wlan-enable",
229 	.deps = pwrseq_qcom_wcn6855_unit_deps,
230 	.enable = pwrseq_qcom_wcn_wlan_enable,
231 	.disable = pwrseq_qcom_wcn_wlan_disable,
232 };
233 
234 static int pwrseq_qcom_wcn_pwup_delay(struct pwrseq_device *pwrseq)
235 {
236 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
237 
238 	if (ctx->pdata->pwup_delay_ms)
239 		msleep(ctx->pdata->pwup_delay_ms);
240 
241 	return 0;
242 }
243 
244 static int pwrseq_qcom_wcn6855_xo_clk_deassert(struct pwrseq_device *pwrseq)
245 {
246 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
247 
248 	if (ctx->xo_clk_gpio) {
249 		usleep_range(2000, 5000);
250 		gpiod_set_value_cansleep(ctx->xo_clk_gpio, 0);
251 	}
252 
253 	return pwrseq_qcom_wcn_pwup_delay(pwrseq);
254 }
255 
256 static const struct pwrseq_target_data pwrseq_qcom_wcn_bt_target_data = {
257 	.name = "bluetooth",
258 	.unit = &pwrseq_qcom_wcn_bt_unit_data,
259 	.post_enable = pwrseq_qcom_wcn_pwup_delay,
260 };
261 
262 static const struct pwrseq_target_data pwrseq_qcom_wcn_wlan_target_data = {
263 	.name = "wlan",
264 	.unit = &pwrseq_qcom_wcn_wlan_unit_data,
265 	.post_enable = pwrseq_qcom_wcn_pwup_delay,
266 };
267 
268 /* There are no separate BT and WLAN enablement pins */
269 static const struct pwrseq_target_data pwrseq_qcom_wcn3990_bt_target_data = {
270 	.name = "bluetooth",
271 	.unit = &pwrseq_qcom_wcn3990_unit_data,
272 };
273 
274 static const struct pwrseq_target_data pwrseq_qcom_wcn3990_wlan_target_data = {
275 	.name = "wlan",
276 	.unit = &pwrseq_qcom_wcn3990_unit_data,
277 };
278 
279 static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = {
280 	.name = "bluetooth",
281 	.unit = &pwrseq_qcom_wcn6855_bt_unit_data,
282 	.post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert,
283 };
284 
285 static const struct pwrseq_target_data pwrseq_qcom_wcn6855_wlan_target_data = {
286 	.name = "wlan",
287 	.unit = &pwrseq_qcom_wcn6855_wlan_unit_data,
288 	.post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert,
289 };
290 
291 static const struct pwrseq_target_data *pwrseq_qcom_wcn_targets[] = {
292 	&pwrseq_qcom_wcn_bt_target_data,
293 	&pwrseq_qcom_wcn_wlan_target_data,
294 	NULL
295 };
296 
297 static const struct pwrseq_target_data *pwrseq_qcom_wcn3990_targets[] = {
298 	&pwrseq_qcom_wcn3990_bt_target_data,
299 	&pwrseq_qcom_wcn3990_wlan_target_data,
300 	NULL
301 };
302 
303 static const struct pwrseq_target_data *pwrseq_qcom_wcn6855_targets[] = {
304 	&pwrseq_qcom_wcn6855_bt_target_data,
305 	&pwrseq_qcom_wcn6855_wlan_target_data,
306 	NULL
307 };
308 
309 static const char *const pwrseq_qca6390_vregs[] = {
310 	"vddio",
311 	"vddaon",
312 	"vddpmu",
313 	"vddrfa0p95",
314 	"vddrfa1p3",
315 	"vddrfa1p9",
316 	"vddpcie1p3",
317 	"vddpcie1p9",
318 };
319 
320 static const struct pwrseq_qcom_wcn_pdata pwrseq_qca6390_of_data = {
321 	.vregs = pwrseq_qca6390_vregs,
322 	.num_vregs = ARRAY_SIZE(pwrseq_qca6390_vregs),
323 	.pwup_delay_ms = 60,
324 	.gpio_enable_delay_ms = 100,
325 	.targets = pwrseq_qcom_wcn_targets,
326 };
327 
328 static const char *const pwrseq_wcn3990_vregs[] = {
329 	/* vddio is handled separately */
330 	"vddxo",
331 	"vddrf",
332 	"vddch0",
333 	"vddch1",
334 };
335 
336 static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq,
337 				     struct device *dev);
338 
339 static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn3990_of_data = {
340 	.vregs = pwrseq_wcn3990_vregs,
341 	.num_vregs = ARRAY_SIZE(pwrseq_wcn3990_vregs),
342 	.pwup_delay_ms = 50,
343 	.targets = pwrseq_qcom_wcn3990_targets,
344 	.has_vddio = true,
345 	.match = pwrseq_qcom_wcn3990_match,
346 };
347 
348 static const char *const pwrseq_wcn6750_vregs[] = {
349 	"vddaon",
350 	"vddasd",
351 	"vddpmu",
352 	"vddrfa0p8",
353 	"vddrfa1p2",
354 	"vddrfa1p7",
355 	"vddrfa2p2",
356 };
357 
358 static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn6750_of_data = {
359 	.vregs = pwrseq_wcn6750_vregs,
360 	.num_vregs = ARRAY_SIZE(pwrseq_wcn6750_vregs),
361 	.pwup_delay_ms = 50,
362 	.gpio_enable_delay_ms = 5,
363 	.targets = pwrseq_qcom_wcn_targets,
364 };
365 
366 static const char *const pwrseq_wcn6855_vregs[] = {
367 	"vddio",
368 	"vddaon",
369 	"vddpmu",
370 	"vddpmumx",
371 	"vddpmucx",
372 	"vddrfa0p95",
373 	"vddrfa1p3",
374 	"vddrfa1p9",
375 	"vddpcie1p3",
376 	"vddpcie1p9",
377 };
378 
379 static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn6855_of_data = {
380 	.vregs = pwrseq_wcn6855_vregs,
381 	.num_vregs = ARRAY_SIZE(pwrseq_wcn6855_vregs),
382 	.pwup_delay_ms = 50,
383 	.gpio_enable_delay_ms = 5,
384 	.targets = pwrseq_qcom_wcn6855_targets,
385 };
386 
387 static const char *const pwrseq_wcn7850_vregs[] = {
388 	"vdd",
389 	"vddio",
390 	"vddio1p2",
391 	"vddaon",
392 	"vdddig",
393 	"vddrfa1p2",
394 	"vddrfa1p8",
395 };
396 
397 static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn7850_of_data = {
398 	.vregs = pwrseq_wcn7850_vregs,
399 	.num_vregs = ARRAY_SIZE(pwrseq_wcn7850_vregs),
400 	.pwup_delay_ms = 50,
401 	.targets = pwrseq_qcom_wcn_targets,
402 };
403 
404 static int pwrseq_qcom_wcn_match_regulator(struct pwrseq_device *pwrseq,
405 					   struct device *dev,
406 					   const char *name)
407 {
408 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
409 	struct device_node *dev_node = dev->of_node;
410 
411 	/*
412 	 * The PMU supplies power to the Bluetooth and WLAN modules. both
413 	 * consume the PMU AON output so check the presence of the
414 	 * 'vddaon-supply' property and whether it leads us to the right
415 	 * device.
416 	 */
417 	if (!of_property_present(dev_node, name))
418 		return PWRSEQ_NO_MATCH;
419 
420 	struct device_node *reg_node __free(device_node) =
421 			of_parse_phandle(dev_node, name, 0);
422 	if (!reg_node)
423 		return PWRSEQ_NO_MATCH;
424 
425 	/*
426 	 * `reg_node` is the PMU AON regulator, its parent is the `regulators`
427 	 * node and finally its grandparent is the PMU device node that we're
428 	 * looking for.
429 	 */
430 	if (!reg_node->parent || !reg_node->parent->parent ||
431 	    reg_node->parent->parent != ctx->of_node)
432 		return PWRSEQ_NO_MATCH;
433 
434 	return PWRSEQ_MATCH_OK;
435 }
436 
437 static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq,
438 				 struct device *dev)
439 {
440 	return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddaon-supply");
441 }
442 
443 static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq,
444 				     struct device *dev)
445 {
446 	int ret;
447 
448 	/* BT device */
449 	ret = pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddio-supply");
450 	if (ret == PWRSEQ_MATCH_OK)
451 		return ret;
452 
453 	/* WiFi device match */
454 	return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vdd-1.8-xo-supply");
455 }
456 
457 static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
458 {
459 	struct device *dev = &pdev->dev;
460 	struct pwrseq_qcom_wcn_ctx *ctx;
461 	struct pwrseq_config config;
462 	int i, ret;
463 
464 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
465 	if (!ctx)
466 		return -ENOMEM;
467 
468 	ctx->of_node = dev->of_node;
469 
470 	ctx->pdata = device_get_match_data(dev);
471 	if (!ctx->pdata)
472 		return dev_err_probe(dev, -ENODEV,
473 				     "Failed to obtain platform data\n");
474 
475 	ctx->regs = devm_kcalloc(dev, ctx->pdata->num_vregs,
476 				 sizeof(*ctx->regs), GFP_KERNEL);
477 	if (!ctx->regs)
478 		return -ENOMEM;
479 
480 	for (i = 0; i < ctx->pdata->num_vregs; i++)
481 		ctx->regs[i].supply = ctx->pdata->vregs[i];
482 
483 	ret = devm_regulator_bulk_get(dev, ctx->pdata->num_vregs, ctx->regs);
484 	if (ret < 0)
485 		return dev_err_probe(dev, ret,
486 				     "Failed to get all regulators\n");
487 
488 	if (ctx->pdata->has_vddio) {
489 		ctx->vddio = devm_regulator_get(dev, "vddio");
490 		if (IS_ERR(ctx->vddio))
491 			return dev_err_probe(dev, PTR_ERR(ctx->vddio), "Failed to get VDDIO\n");
492 	}
493 
494 	ctx->bt_gpio = devm_gpiod_get_optional(dev, "bt-enable", GPIOD_OUT_LOW);
495 	if (IS_ERR(ctx->bt_gpio))
496 		return dev_err_probe(dev, PTR_ERR(ctx->bt_gpio),
497 				     "Failed to get the Bluetooth enable GPIO\n");
498 
499 	/*
500 	 * FIXME: This should actually be GPIOD_OUT_LOW, but doing so would
501 	 * cause the WLAN power to be toggled, resulting in PCIe link down.
502 	 * Since the PCIe controller driver is not handling link down currently,
503 	 * the device becomes unusable. So we need to keep this workaround until
504 	 * the link down handling is implemented in the controller driver.
505 	 */
506 	ctx->wlan_gpio = devm_gpiod_get_optional(dev, "wlan-enable",
507 						 GPIOD_ASIS);
508 	if (IS_ERR(ctx->wlan_gpio))
509 		return dev_err_probe(dev, PTR_ERR(ctx->wlan_gpio),
510 				     "Failed to get the WLAN enable GPIO\n");
511 
512 	ctx->xo_clk_gpio = devm_gpiod_get_optional(dev, "xo-clk",
513 						   GPIOD_OUT_LOW);
514 	if (IS_ERR(ctx->xo_clk_gpio))
515 		return dev_err_probe(dev, PTR_ERR(ctx->xo_clk_gpio),
516 				     "Failed to get the XO_CLK GPIO\n");
517 
518 	/*
519 	 * Set direction to output but keep the current value in order to not
520 	 * disable the WLAN module accidentally if it's already powered on.
521 	 */
522 	gpiod_direction_output(ctx->wlan_gpio,
523 			       gpiod_get_value_cansleep(ctx->wlan_gpio));
524 
525 	ctx->clk = devm_clk_get_optional(dev, NULL);
526 	if (IS_ERR(ctx->clk))
527 		return dev_err_probe(dev, PTR_ERR(ctx->clk),
528 				     "Failed to get the reference clock\n");
529 
530 	memset(&config, 0, sizeof(config));
531 
532 	config.parent = dev;
533 	config.owner = THIS_MODULE;
534 	config.drvdata = ctx;
535 	config.match = ctx->pdata->match ? : pwrseq_qcom_wcn_match;
536 	config.targets = ctx->pdata->targets;
537 
538 	ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
539 	if (IS_ERR(ctx->pwrseq))
540 		return dev_err_probe(dev, PTR_ERR(ctx->pwrseq),
541 				     "Failed to register the power sequencer\n");
542 
543 	return 0;
544 }
545 
546 static const struct of_device_id pwrseq_qcom_wcn_of_match[] = {
547 	{
548 		.compatible = "qcom,wcn3950-pmu",
549 		.data = &pwrseq_wcn3990_of_data,
550 	},
551 	{
552 		.compatible = "qcom,wcn3988-pmu",
553 		.data = &pwrseq_wcn3990_of_data,
554 	},
555 	{
556 		.compatible = "qcom,wcn3990-pmu",
557 		.data = &pwrseq_wcn3990_of_data,
558 	},
559 	{
560 		.compatible = "qcom,wcn3991-pmu",
561 		.data = &pwrseq_wcn3990_of_data,
562 	},
563 	{
564 		.compatible = "qcom,wcn3998-pmu",
565 		.data = &pwrseq_wcn3990_of_data,
566 	},
567 	{
568 		.compatible = "qcom,qca6390-pmu",
569 		.data = &pwrseq_qca6390_of_data,
570 	},
571 	{
572 		.compatible = "qcom,wcn6855-pmu",
573 		.data = &pwrseq_wcn6855_of_data,
574 	},
575 	{
576 		.compatible = "qcom,wcn7850-pmu",
577 		.data = &pwrseq_wcn7850_of_data,
578 	},
579 	{
580 		.compatible = "qcom,wcn6750-pmu",
581 		.data = &pwrseq_wcn6750_of_data,
582 	},
583 	{ }
584 };
585 MODULE_DEVICE_TABLE(of, pwrseq_qcom_wcn_of_match);
586 
587 static struct platform_driver pwrseq_qcom_wcn_driver = {
588 	.driver = {
589 		.name = "pwrseq-qcom_wcn",
590 		.of_match_table = pwrseq_qcom_wcn_of_match,
591 	},
592 	.probe = pwrseq_qcom_wcn_probe,
593 };
594 module_platform_driver(pwrseq_qcom_wcn_driver);
595 
596 MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>");
597 MODULE_DESCRIPTION("Qualcomm WCN PMU power sequencing driver");
598 MODULE_LICENSE("GPL");
599