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