xref: /linux/drivers/power/sequencing/pwrseq-qcom-wcn.c (revision 74b1dbf6f236f4fe88bd1077ae4657ca4b2c339e)
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 bool pwrseq_qcom_wcn_bt_is_controllable(struct pwrseq_device *pwrseq)
187 {
188 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
189 
190 	/*
191 	 * The Bluetooth enable is driven through the BT_EN GPIO. When it is not
192 	 * wired up (e.g. hardwired to an always-on pull-up), the enable/disable
193 	 * callbacks are no-ops, so the host cannot gate the Bluetooth function
194 	 * on its own.
195 	 */
196 	return !!ctx->bt_gpio;
197 }
198 
199 static const struct pwrseq_unit_data pwrseq_qcom_wcn_bt_unit_data = {
200 	.name = "bluetooth-enable",
201 	.deps = pwrseq_qcom_wcn_unit_deps,
202 	.enable = pwrseq_qcom_wcn_bt_enable,
203 	.disable = pwrseq_qcom_wcn_bt_disable,
204 };
205 
206 static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_bt_unit_data = {
207 	.name = "bluetooth-enable",
208 	.deps = pwrseq_qcom_wcn6855_unit_deps,
209 	.enable = pwrseq_qcom_wcn_bt_enable,
210 	.disable = pwrseq_qcom_wcn_bt_disable,
211 };
212 
213 static int pwrseq_qcom_wcn_wlan_enable(struct pwrseq_device *pwrseq)
214 {
215 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
216 
217 	pwrseq_qcom_wcn_ensure_gpio_delay(ctx);
218 	gpiod_set_value_cansleep(ctx->wlan_gpio, 1);
219 	ctx->last_gpio_enable_jf = jiffies;
220 
221 	return 0;
222 }
223 
224 static int pwrseq_qcom_wcn_wlan_disable(struct pwrseq_device *pwrseq)
225 {
226 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
227 
228 	gpiod_set_value_cansleep(ctx->wlan_gpio, 0);
229 
230 	return 0;
231 }
232 
233 static bool pwrseq_qcom_wcn_wlan_is_controllable(struct pwrseq_device *pwrseq)
234 {
235 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
236 
237 	/*
238 	 * The WLAN enable is driven through the WLAN_EN GPIO. When it is not
239 	 * wired up (e.g. hardwired to an always-on pull-up), the enable/disable
240 	 * callbacks are no-ops, so the host cannot gate the WLAN function on
241 	 * its own.
242 	 */
243 	return !!ctx->wlan_gpio;
244 }
245 
246 static const struct pwrseq_unit_data pwrseq_qcom_wcn_wlan_unit_data = {
247 	.name = "wlan-enable",
248 	.deps = pwrseq_qcom_wcn_unit_deps,
249 	.enable = pwrseq_qcom_wcn_wlan_enable,
250 	.disable = pwrseq_qcom_wcn_wlan_disable,
251 };
252 
253 static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_wlan_unit_data = {
254 	.name = "wlan-enable",
255 	.deps = pwrseq_qcom_wcn6855_unit_deps,
256 	.enable = pwrseq_qcom_wcn_wlan_enable,
257 	.disable = pwrseq_qcom_wcn_wlan_disable,
258 };
259 
260 static int pwrseq_qcom_wcn_pwup_delay(struct pwrseq_device *pwrseq)
261 {
262 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
263 
264 	if (ctx->pdata->pwup_delay_ms)
265 		msleep(ctx->pdata->pwup_delay_ms);
266 
267 	return 0;
268 }
269 
270 static int pwrseq_qcom_wcn6855_xo_clk_deassert(struct pwrseq_device *pwrseq)
271 {
272 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
273 
274 	if (ctx->xo_clk_gpio) {
275 		usleep_range(2000, 5000);
276 		gpiod_set_value_cansleep(ctx->xo_clk_gpio, 0);
277 	}
278 
279 	return pwrseq_qcom_wcn_pwup_delay(pwrseq);
280 }
281 
282 static const struct pwrseq_target_data pwrseq_qcom_wcn_bt_target_data = {
283 	.name = "bluetooth",
284 	.unit = &pwrseq_qcom_wcn_bt_unit_data,
285 	.post_enable = pwrseq_qcom_wcn_pwup_delay,
286 	.is_controllable = pwrseq_qcom_wcn_bt_is_controllable,
287 };
288 
289 static const struct pwrseq_target_data pwrseq_qcom_wcn_wlan_target_data = {
290 	.name = "wlan",
291 	.unit = &pwrseq_qcom_wcn_wlan_unit_data,
292 	.post_enable = pwrseq_qcom_wcn_pwup_delay,
293 	.is_controllable = pwrseq_qcom_wcn_wlan_is_controllable,
294 };
295 
296 /* There are no separate BT and WLAN enablement pins */
297 static const struct pwrseq_target_data pwrseq_qcom_wcn3990_bt_target_data = {
298 	.name = "bluetooth",
299 	.unit = &pwrseq_qcom_wcn3990_unit_data,
300 };
301 
302 static const struct pwrseq_target_data pwrseq_qcom_wcn3990_wlan_target_data = {
303 	.name = "wlan",
304 	.unit = &pwrseq_qcom_wcn3990_unit_data,
305 };
306 
307 static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = {
308 	.name = "bluetooth",
309 	.unit = &pwrseq_qcom_wcn6855_bt_unit_data,
310 	.post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert,
311 	.is_controllable = pwrseq_qcom_wcn_bt_is_controllable,
312 };
313 
314 static const struct pwrseq_target_data pwrseq_qcom_wcn6855_wlan_target_data = {
315 	.name = "wlan",
316 	.unit = &pwrseq_qcom_wcn6855_wlan_unit_data,
317 	.post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert,
318 	.is_controllable = pwrseq_qcom_wcn_wlan_is_controllable,
319 };
320 
321 static const struct pwrseq_target_data *pwrseq_qcom_wcn_targets[] = {
322 	&pwrseq_qcom_wcn_bt_target_data,
323 	&pwrseq_qcom_wcn_wlan_target_data,
324 	NULL
325 };
326 
327 static const struct pwrseq_target_data *pwrseq_qcom_wcn3990_targets[] = {
328 	&pwrseq_qcom_wcn3990_bt_target_data,
329 	&pwrseq_qcom_wcn3990_wlan_target_data,
330 	NULL
331 };
332 
333 static const struct pwrseq_target_data *pwrseq_qcom_wcn6855_targets[] = {
334 	&pwrseq_qcom_wcn6855_bt_target_data,
335 	&pwrseq_qcom_wcn6855_wlan_target_data,
336 	NULL
337 };
338 
339 static const char *const pwrseq_qca6390_vregs[] = {
340 	"vddio",
341 	"vddaon",
342 	"vddpmu",
343 	"vddrfa0p95",
344 	"vddrfa1p3",
345 	"vddrfa1p9",
346 	"vddpcie1p3",
347 	"vddpcie1p9",
348 };
349 
350 static const struct pwrseq_qcom_wcn_pdata pwrseq_qca6390_of_data = {
351 	.vregs = pwrseq_qca6390_vregs,
352 	.num_vregs = ARRAY_SIZE(pwrseq_qca6390_vregs),
353 	.pwup_delay_ms = 60,
354 	.gpio_enable_delay_ms = 100,
355 	.targets = pwrseq_qcom_wcn_targets,
356 };
357 
358 static const char *const pwrseq_wcn3990_vregs[] = {
359 	/* vddio is handled separately */
360 	"vddxo",
361 	"vddrf",
362 	"vddch0",
363 	"vddch1",
364 };
365 
366 static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq,
367 				     struct device *dev);
368 
369 static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn3990_of_data = {
370 	.vregs = pwrseq_wcn3990_vregs,
371 	.num_vregs = ARRAY_SIZE(pwrseq_wcn3990_vregs),
372 	.pwup_delay_ms = 50,
373 	.targets = pwrseq_qcom_wcn3990_targets,
374 	.has_vddio = true,
375 	.match = pwrseq_qcom_wcn3990_match,
376 };
377 
378 static const char *const pwrseq_wcn6750_vregs[] = {
379 	"vddaon",
380 	"vddasd",
381 	"vddpmu",
382 	"vddrfa0p8",
383 	"vddrfa1p2",
384 	"vddrfa1p7",
385 	"vddrfa2p2",
386 };
387 
388 static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn6750_of_data = {
389 	.vregs = pwrseq_wcn6750_vregs,
390 	.num_vregs = ARRAY_SIZE(pwrseq_wcn6750_vregs),
391 	.pwup_delay_ms = 50,
392 	.gpio_enable_delay_ms = 5,
393 	.targets = pwrseq_qcom_wcn_targets,
394 };
395 
396 static const char *const pwrseq_wcn6855_vregs[] = {
397 	"vddio",
398 	"vddaon",
399 	"vddpmu",
400 	"vddpmumx",
401 	"vddpmucx",
402 	"vddrfa0p95",
403 	"vddrfa1p3",
404 	"vddrfa1p9",
405 	"vddpcie1p3",
406 	"vddpcie1p9",
407 };
408 
409 static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn6855_of_data = {
410 	.vregs = pwrseq_wcn6855_vregs,
411 	.num_vregs = ARRAY_SIZE(pwrseq_wcn6855_vregs),
412 	.pwup_delay_ms = 50,
413 	.gpio_enable_delay_ms = 5,
414 	.targets = pwrseq_qcom_wcn6855_targets,
415 };
416 
417 static const char *const pwrseq_wcn7850_vregs[] = {
418 	"vdd",
419 	"vddio",
420 	"vddio1p2",
421 	"vddaon",
422 	"vdddig",
423 	"vddrfa1p2",
424 	"vddrfa1p8",
425 };
426 
427 static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn7850_of_data = {
428 	.vregs = pwrseq_wcn7850_vregs,
429 	.num_vregs = ARRAY_SIZE(pwrseq_wcn7850_vregs),
430 	.pwup_delay_ms = 50,
431 	.targets = pwrseq_qcom_wcn_targets,
432 };
433 
434 static int pwrseq_qcom_wcn_match_regulator(struct pwrseq_device *pwrseq,
435 					   struct device *dev,
436 					   const char *name)
437 {
438 	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
439 	struct device_node *dev_node = dev->of_node;
440 
441 	/*
442 	 * The PMU supplies power to the Bluetooth and WLAN modules. both
443 	 * consume the PMU AON output so check the presence of the
444 	 * 'vddaon-supply' property and whether it leads us to the right
445 	 * device.
446 	 */
447 	if (!of_property_present(dev_node, name))
448 		return PWRSEQ_NO_MATCH;
449 
450 	struct device_node *reg_node __free(device_node) =
451 			of_parse_phandle(dev_node, name, 0);
452 	if (!reg_node)
453 		return PWRSEQ_NO_MATCH;
454 
455 	/*
456 	 * `reg_node` is the PMU AON regulator, its parent is the `regulators`
457 	 * node and finally its grandparent is the PMU device node that we're
458 	 * looking for.
459 	 */
460 	if (!reg_node->parent || !reg_node->parent->parent ||
461 	    reg_node->parent->parent != ctx->of_node)
462 		return PWRSEQ_NO_MATCH;
463 
464 	return PWRSEQ_MATCH_OK;
465 }
466 
467 static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq,
468 				 struct device *dev)
469 {
470 	return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddaon-supply");
471 }
472 
473 static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq,
474 				     struct device *dev)
475 {
476 	int ret;
477 
478 	/* BT device */
479 	ret = pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddio-supply");
480 	if (ret == PWRSEQ_MATCH_OK)
481 		return ret;
482 
483 	/* WiFi device match */
484 	return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vdd-1.8-xo-supply");
485 }
486 
487 static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
488 {
489 	struct device *dev = &pdev->dev;
490 	struct pwrseq_qcom_wcn_ctx *ctx;
491 	struct pwrseq_config config;
492 	int i, ret;
493 
494 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
495 	if (!ctx)
496 		return -ENOMEM;
497 
498 	ctx->of_node = dev->of_node;
499 
500 	ctx->pdata = device_get_match_data(dev);
501 	if (!ctx->pdata)
502 		return dev_err_probe(dev, -ENODEV,
503 				     "Failed to obtain platform data\n");
504 
505 	ctx->regs = devm_kcalloc(dev, ctx->pdata->num_vregs,
506 				 sizeof(*ctx->regs), GFP_KERNEL);
507 	if (!ctx->regs)
508 		return -ENOMEM;
509 
510 	for (i = 0; i < ctx->pdata->num_vregs; i++)
511 		ctx->regs[i].supply = ctx->pdata->vregs[i];
512 
513 	ret = devm_regulator_bulk_get(dev, ctx->pdata->num_vregs, ctx->regs);
514 	if (ret < 0)
515 		return dev_err_probe(dev, ret,
516 				     "Failed to get all regulators\n");
517 
518 	if (ctx->pdata->has_vddio) {
519 		ctx->vddio = devm_regulator_get(dev, "vddio");
520 		if (IS_ERR(ctx->vddio))
521 			return dev_err_probe(dev, PTR_ERR(ctx->vddio), "Failed to get VDDIO\n");
522 	}
523 
524 	ctx->bt_gpio = devm_gpiod_get_optional(dev, "bt-enable", GPIOD_OUT_LOW);
525 	if (IS_ERR(ctx->bt_gpio))
526 		return dev_err_probe(dev, PTR_ERR(ctx->bt_gpio),
527 				     "Failed to get the Bluetooth enable GPIO\n");
528 
529 	ctx->wlan_gpio = devm_gpiod_get_optional(dev, "wlan-enable",
530 						 GPIOD_OUT_LOW);
531 	if (IS_ERR(ctx->wlan_gpio))
532 		return dev_err_probe(dev, PTR_ERR(ctx->wlan_gpio),
533 				     "Failed to get the WLAN enable GPIO\n");
534 
535 	ctx->xo_clk_gpio = devm_gpiod_get_optional(dev, "xo-clk",
536 						   GPIOD_OUT_LOW);
537 	if (IS_ERR(ctx->xo_clk_gpio))
538 		return dev_err_probe(dev, PTR_ERR(ctx->xo_clk_gpio),
539 				     "Failed to get the XO_CLK GPIO\n");
540 
541 	ctx->clk = devm_clk_get_optional(dev, NULL);
542 	if (IS_ERR(ctx->clk))
543 		return dev_err_probe(dev, PTR_ERR(ctx->clk),
544 				     "Failed to get the reference clock\n");
545 
546 	memset(&config, 0, sizeof(config));
547 
548 	config.parent = dev;
549 	config.owner = THIS_MODULE;
550 	config.drvdata = ctx;
551 	config.match = ctx->pdata->match ? : pwrseq_qcom_wcn_match;
552 	config.targets = ctx->pdata->targets;
553 
554 	ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
555 	if (IS_ERR(ctx->pwrseq))
556 		return dev_err_probe(dev, PTR_ERR(ctx->pwrseq),
557 				     "Failed to register the power sequencer\n");
558 
559 	return 0;
560 }
561 
562 static const struct of_device_id pwrseq_qcom_wcn_of_match[] = {
563 	{
564 		.compatible = "qcom,wcn3950-pmu",
565 		.data = &pwrseq_wcn3990_of_data,
566 	},
567 	{
568 		.compatible = "qcom,wcn3988-pmu",
569 		.data = &pwrseq_wcn3990_of_data,
570 	},
571 	{
572 		.compatible = "qcom,wcn3990-pmu",
573 		.data = &pwrseq_wcn3990_of_data,
574 	},
575 	{
576 		.compatible = "qcom,wcn3991-pmu",
577 		.data = &pwrseq_wcn3990_of_data,
578 	},
579 	{
580 		.compatible = "qcom,wcn3998-pmu",
581 		.data = &pwrseq_wcn3990_of_data,
582 	},
583 	{
584 		.compatible = "qcom,qca6390-pmu",
585 		.data = &pwrseq_qca6390_of_data,
586 	},
587 	{
588 		.compatible = "qcom,wcn6855-pmu",
589 		.data = &pwrseq_wcn6855_of_data,
590 	},
591 	{
592 		.compatible = "qcom,wcn7850-pmu",
593 		.data = &pwrseq_wcn7850_of_data,
594 	},
595 	{
596 		.compatible = "qcom,wcn6750-pmu",
597 		.data = &pwrseq_wcn6750_of_data,
598 	},
599 	{ }
600 };
601 MODULE_DEVICE_TABLE(of, pwrseq_qcom_wcn_of_match);
602 
603 static struct platform_driver pwrseq_qcom_wcn_driver = {
604 	.driver = {
605 		.name = "pwrseq-qcom_wcn",
606 		.of_match_table = pwrseq_qcom_wcn_of_match,
607 	},
608 	.probe = pwrseq_qcom_wcn_probe,
609 };
610 module_platform_driver(pwrseq_qcom_wcn_driver);
611 
612 MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>");
613 MODULE_DESCRIPTION("Qualcomm WCN PMU power sequencing driver");
614 MODULE_LICENSE("GPL");
615