xref: /linux/drivers/power/sequencing/pwrseq-pcie-m2.c (revision df34ecc52526480a1a4bb78bc75bfb009c6076a4)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4  * Author: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
5  */
6 
7 #include <linux/device.h>
8 #include <linux/delay.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/list.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/of_graph.h>
14 #include <linux/of_platform.h>
15 #include <linux/pci.h>
16 #include <linux/platform_device.h>
17 #include <linux/pwrseq/provider.h>
18 #include <linux/regulator/consumer.h>
19 #include <linux/serdev.h>
20 #include <linux/slab.h>
21 
22 struct pwrseq_pci_dev {
23 	struct serdev_device *serdev;
24 	struct of_changeset *ocs;
25 	struct pci_dev *pdev;
26 	struct list_head list;
27 };
28 
29 struct pwrseq_pcie_m2_pdata {
30 	const struct pwrseq_target_data **targets;
31 };
32 
33 struct pwrseq_pcie_m2_ctx {
34 	struct pwrseq_device *pwrseq;
35 	struct device_node *of_node;
36 	const struct pwrseq_pcie_m2_pdata *pdata;
37 	struct regulator_bulk_data *regs;
38 	size_t num_vregs;
39 	struct notifier_block nb;
40 	struct gpio_desc *w_disable1_gpio;
41 	struct gpio_desc *w_disable2_gpio;
42 	struct device *dev;
43 	struct list_head pci_devices;
44 	struct mutex list_lock;
45 };
46 
47 static int pwrseq_pcie_m2_vregs_enable(struct pwrseq_device *pwrseq)
48 {
49 	struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
50 
51 	return regulator_bulk_enable(ctx->num_vregs, ctx->regs);
52 }
53 
54 static int pwrseq_pcie_m2_vregs_disable(struct pwrseq_device *pwrseq)
55 {
56 	struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
57 
58 	return regulator_bulk_disable(ctx->num_vregs, ctx->regs);
59 }
60 
61 static const struct pwrseq_unit_data pwrseq_pcie_m2_vregs_unit_data = {
62 	.name = "regulators-enable",
63 	.enable = pwrseq_pcie_m2_vregs_enable,
64 	.disable = pwrseq_pcie_m2_vregs_disable,
65 };
66 
67 static const struct pwrseq_unit_data *pwrseq_pcie_m2_unit_deps[] = {
68 	&pwrseq_pcie_m2_vregs_unit_data,
69 	NULL
70 };
71 
72 static int pwrseq_pci_m2_e_uart_enable(struct pwrseq_device *pwrseq)
73 {
74 	struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
75 
76 	return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 0);
77 }
78 
79 static int pwrseq_pci_m2_e_uart_disable(struct pwrseq_device *pwrseq)
80 {
81 	struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
82 
83 	return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 1);
84 }
85 
86 static const struct pwrseq_unit_data pwrseq_pcie_m2_e_uart_unit_data = {
87 	.name = "uart-enable",
88 	.deps = pwrseq_pcie_m2_unit_deps,
89 	.enable = pwrseq_pci_m2_e_uart_enable,
90 	.disable = pwrseq_pci_m2_e_uart_disable,
91 };
92 
93 static int pwrseq_pci_m2_e_pcie_enable(struct pwrseq_device *pwrseq)
94 {
95 	struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
96 
97 	return gpiod_set_value_cansleep(ctx->w_disable1_gpio, 0);
98 }
99 
100 static int pwrseq_pci_m2_e_pcie_disable(struct pwrseq_device *pwrseq)
101 {
102 	struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
103 
104 	return gpiod_set_value_cansleep(ctx->w_disable1_gpio, 1);
105 }
106 
107 static const struct pwrseq_unit_data pwrseq_pcie_m2_e_pcie_unit_data = {
108 	.name = "pcie-enable",
109 	.deps = pwrseq_pcie_m2_unit_deps,
110 	.enable = pwrseq_pci_m2_e_pcie_enable,
111 	.disable = pwrseq_pci_m2_e_pcie_disable,
112 };
113 
114 static const struct pwrseq_unit_data pwrseq_pcie_m2_m_pcie_unit_data = {
115 	.name = "pcie-enable",
116 	.deps = pwrseq_pcie_m2_unit_deps,
117 };
118 
119 static int pwrseq_pcie_m2_e_pwup_delay(struct pwrseq_device *pwrseq)
120 {
121 	/*
122 	 * FIXME: This delay is only required for some Qcom WLAN/BT cards like
123 	 * WCN7850 and not for all devices. But currently, there is no way to
124 	 * identify the device model before enumeration.
125 	 */
126 	msleep(50);
127 
128 	return 0;
129 }
130 
131 static const struct pwrseq_target_data pwrseq_pcie_m2_e_uart_target_data = {
132 	.name = "uart",
133 	.unit = &pwrseq_pcie_m2_e_uart_unit_data,
134 	.post_enable = pwrseq_pcie_m2_e_pwup_delay,
135 };
136 
137 static const struct pwrseq_target_data pwrseq_pcie_m2_e_pcie_target_data = {
138 	.name = "pcie",
139 	.unit = &pwrseq_pcie_m2_e_pcie_unit_data,
140 	.post_enable = pwrseq_pcie_m2_e_pwup_delay,
141 };
142 
143 static const struct pwrseq_target_data pwrseq_pcie_m2_m_pcie_target_data = {
144 	.name = "pcie",
145 	.unit = &pwrseq_pcie_m2_m_pcie_unit_data,
146 };
147 
148 static const struct pwrseq_target_data *pwrseq_pcie_m2_e_targets[] = {
149 	&pwrseq_pcie_m2_e_pcie_target_data,
150 	&pwrseq_pcie_m2_e_uart_target_data,
151 	NULL
152 };
153 
154 static const struct pwrseq_target_data *pwrseq_pcie_m2_m_targets[] = {
155 	&pwrseq_pcie_m2_m_pcie_target_data,
156 	NULL
157 };
158 
159 static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_e_of_data = {
160 	.targets = pwrseq_pcie_m2_e_targets,
161 };
162 
163 static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_m_of_data = {
164 	.targets = pwrseq_pcie_m2_m_targets,
165 };
166 
167 static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
168 				 struct device *dev)
169 {
170 	struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
171 	struct device_node *endpoint __free(device_node) = NULL;
172 
173 	/*
174 	 * Traverse the 'remote-endpoint' nodes and check if the remote node's
175 	 * parent matches the OF node of 'dev'.
176 	 */
177 	for_each_endpoint_of_node(ctx->of_node, endpoint) {
178 		struct device_node *remote __free(device_node) =
179 				of_graph_get_remote_port_parent(endpoint);
180 		if (remote && (remote == dev_of_node(dev)))
181 			return PWRSEQ_MATCH_OK;
182 	}
183 
184 	return PWRSEQ_NO_MATCH;
185 }
186 
187 static const struct pci_device_id pwrseq_m2_pci_ids[] = {
188 	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1103),
189 	  .driver_data = (kernel_ulong_t)"qcom,wcn6855-bt" },
190 	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107),
191 	  .driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" },
192 	{ } /* Sentinel */
193 };
194 
195 static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
196 					struct pwrseq_pci_dev *pci_dev,
197 					struct device_node *parent,
198 					struct pci_dev *pdev)
199 {
200 	const struct pci_device_id *id;
201 	struct device *dev = ctx->dev;
202 	const char *compatible;
203 	struct device_node *np;
204 	int ret;
205 
206 	id = pci_match_id(pwrseq_m2_pci_ids, pdev);
207 	if (WARN_ON_ONCE(!id)) /* Shouldn't happen */
208 		return -ENODEV;
209 
210 	compatible = (const char *)id->driver_data;
211 
212 	pci_dev->ocs = kzalloc_obj(*pci_dev->ocs);
213 	if (!pci_dev->ocs)
214 		return -ENOMEM;
215 
216 	of_changeset_init(pci_dev->ocs);
217 
218 	np = of_changeset_create_node(pci_dev->ocs, parent, "bluetooth");
219 	if (!np) {
220 		dev_err(dev, "Failed to create bluetooth node\n");
221 		ret = -ENODEV;
222 		goto err_destroy_changeset;
223 	}
224 
225 	ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", compatible);
226 	if (ret) {
227 		dev_err(dev, "Failed to add bluetooth compatible: %d\n", ret);
228 		goto err_destroy_changeset;
229 	}
230 
231 	ret = of_changeset_apply(pci_dev->ocs);
232 	if (ret) {
233 		dev_err(dev, "Failed to apply changeset: %d\n", ret);
234 		goto err_destroy_changeset;
235 	}
236 
237 	ret = device_add_of_node(&pci_dev->serdev->dev, np);
238 	if (ret) {
239 		dev_err(dev, "Failed to add OF node: %d\n", ret);
240 		goto err_revert_changeset;
241 	}
242 
243 	return 0;
244 
245 err_revert_changeset:
246 	of_changeset_revert(pci_dev->ocs);
247 err_destroy_changeset:
248 	of_changeset_destroy(pci_dev->ocs);
249 	kfree(pci_dev->ocs);
250 	pci_dev->ocs = NULL;
251 
252 	return ret;
253 }
254 
255 static int pwrseq_pcie_m2_create_serdev_one(struct pwrseq_pcie_m2_ctx *ctx,
256 					struct pci_dev *pdev)
257 {
258 	struct serdev_controller *serdev_ctrl;
259 	struct device *dev = ctx->dev;
260 	struct pwrseq_pci_dev *pci_dev;
261 	int ret;
262 
263 	struct device_node *serdev_parent __free(device_node) =
264 		of_graph_get_remote_node(dev_of_node(ctx->dev), 3, 0);
265 	if (!serdev_parent)
266 		return 0;
267 
268 	serdev_ctrl = of_find_serdev_controller_by_node(serdev_parent);
269 	if (!serdev_ctrl)
270 		return 0;
271 
272 	/* Bail out if the device was already attached to this controller */
273 	if (serdev_ctrl->serdev) {
274 		serdev_controller_put(serdev_ctrl);
275 		return 0;
276 	}
277 
278 	/* Bail out if the serdev device was already created for the PCI dev */
279 	scoped_guard(mutex, &ctx->list_lock) {
280 		list_for_each_entry(pci_dev, &ctx->pci_devices, list) {
281 			if (pci_dev->pdev == pdev)
282 				return 0;
283 		}
284 	}
285 
286 	pci_dev = kzalloc(sizeof(*pci_dev), GFP_KERNEL);
287 	if (!pci_dev) {
288 		ret = -ENOMEM;
289 		goto err_put_ctrl;
290 	}
291 
292 	pci_dev->serdev = serdev_device_alloc(serdev_ctrl);
293 	if (!pci_dev->serdev) {
294 		ret = -ENOMEM;
295 		goto err_free_pci_dev;
296 	}
297 
298 	ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent, pdev);
299 	if (ret)
300 		goto err_free_serdev;
301 
302 	ret = serdev_device_add(pci_dev->serdev);
303 	if (ret) {
304 		dev_err(dev, "Failed to add serdev for PCI device (%s): %d\n",
305 			pci_name(pdev), ret);
306 		goto err_free_dt_node;
307 	}
308 
309 	serdev_controller_put(serdev_ctrl);
310 
311 	pci_dev->pdev = pci_dev_get(pdev);
312 
313 	mutex_lock(&ctx->list_lock);
314 	list_add_tail(&pci_dev->list, &ctx->pci_devices);
315 	mutex_unlock(&ctx->list_lock);
316 
317 	return 0;
318 
319 err_free_dt_node:
320 	device_remove_of_node(&pci_dev->serdev->dev);
321 	of_changeset_revert(pci_dev->ocs);
322 	of_changeset_destroy(pci_dev->ocs);
323 	kfree(pci_dev->ocs);
324 	pci_dev->ocs = NULL;
325 err_free_serdev:
326 	serdev_device_put(pci_dev->serdev);
327 	pci_dev->serdev = NULL;
328 err_free_pci_dev:
329 	kfree(pci_dev);
330 err_put_ctrl:
331 	serdev_controller_put(serdev_ctrl);
332 
333 	return ret;
334 }
335 
336 static void __pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
337 					   struct pwrseq_pci_dev *pci_dev)
338 {
339 	if (pci_dev->serdev) {
340 		device_remove_of_node(&pci_dev->serdev->dev);
341 		serdev_device_remove(pci_dev->serdev);
342 	}
343 
344 	if (pci_dev->ocs) {
345 		of_changeset_revert(pci_dev->ocs);
346 		of_changeset_destroy(pci_dev->ocs);
347 		kfree(pci_dev->ocs);
348 	}
349 
350 	pci_dev_put(pci_dev->pdev);
351 	list_del(&pci_dev->list);
352 	kfree(pci_dev);
353 }
354 
355 static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
356 					 struct pci_dev *pdev)
357 {
358 	struct pwrseq_pci_dev *pci_dev, *tmp;
359 
360 	mutex_lock(&ctx->list_lock);
361 	list_for_each_entry_safe(pci_dev, tmp, &ctx->pci_devices, list) {
362 		if (!pdev || pci_dev->pdev == pdev) {
363 			__pwrseq_pcie_m2_remove_serdev(ctx, pci_dev);
364 			if (pdev)
365 				break;
366 		}
367 	}
368 	mutex_unlock(&ctx->list_lock);
369 }
370 
371 static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
372 			      void *data)
373 {
374 	struct pwrseq_pcie_m2_ctx *ctx = container_of(nb, struct pwrseq_pcie_m2_ctx, nb);
375 	struct pci_dev *pdev = to_pci_dev(data);
376 	int ret;
377 
378 	/*
379 	 * Check whether the PCI device is associated with this M.2 connector or
380 	 * not, by comparing the OF node of the PCI device parent and the Port 0
381 	 * (PCIe) remote node parent OF node.
382 	 */
383 	struct device_node *pci_parent __free(device_node) =
384 			of_graph_get_remote_node(dev_of_node(ctx->dev), 0, 0);
385 	if (!pci_parent || (pci_parent != pdev->dev.parent->of_node))
386 		return NOTIFY_DONE;
387 
388 	switch (action) {
389 	case BUS_NOTIFY_ADD_DEVICE:
390 		if (pci_match_id(pwrseq_m2_pci_ids, pdev)) {
391 			ret = pwrseq_pcie_m2_create_serdev_one(ctx, pdev);
392 			if (ret)
393 				return notifier_from_errno(ret);
394 		}
395 		break;
396 	case BUS_NOTIFY_REMOVED_DEVICE:
397 		if (pci_match_id(pwrseq_m2_pci_ids, pdev))
398 			pwrseq_pcie_m2_remove_serdev(ctx, pdev);
399 
400 		break;
401 	}
402 
403 	return NOTIFY_OK;
404 }
405 
406 static bool pwrseq_pcie_m2_check_remote_node(struct device *dev, u8 port, u8 endpoint,
407 					     const char *node)
408 {
409 	struct device_node *remote __free(device_node) =
410 			of_graph_get_remote_node(dev_of_node(dev), port, endpoint);
411 
412 	if (remote && of_node_name_eq(remote, node))
413 		return true;
414 
415 	return false;
416 }
417 
418 /*
419  * If the connector exposes a non-discoverable bus like UART, the respective
420  * protocol device needs to be created manually with the help of the notifier
421  * of the discoverable bus like PCIe.
422  */
423 static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx)
424 {
425 	int ret;
426 
427 	/*
428 	 * Register a PCI notifier for Key E connector that has PCIe as Port
429 	 * 0/Endpoint 0 interface and Serial as Port 3/Endpoint 0 interface.
430 	 */
431 	if (!pwrseq_pcie_m2_check_remote_node(ctx->dev, 3, 0, "serial") ||
432 	    !pwrseq_pcie_m2_check_remote_node(ctx->dev, 0, 0, "pcie"))
433 		return 0;
434 
435 	ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
436 	ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
437 	if (ret)
438 		return dev_err_probe(ctx->dev, ret,
439 				     "Failed to register notifier for serdev\n");
440 	return 0;
441 }
442 
443 static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
444 {
445 	struct pci_dev *pdev = NULL;
446 	int ret;
447 
448 	if (!pwrseq_pcie_m2_check_remote_node(ctx->dev, 3, 0, "serial") ||
449 	    !pwrseq_pcie_m2_check_remote_node(ctx->dev, 0, 0, "pcie"))
450 		return 0;
451 
452 	struct device_node *pci_parent __free(device_node) =
453 				of_graph_get_remote_node(dev_of_node(ctx->dev), 0, 0);
454 	if (!pci_parent)
455 		return 0;
456 
457 	/* Create serdev for existing PCI devices if required */
458 	for_each_pci_dev(pdev) {
459 		if (!pdev->dev.parent || pci_parent != pdev->dev.parent->of_node)
460 			continue;
461 
462 		if (!pci_match_id(pwrseq_m2_pci_ids, pdev))
463 			continue;
464 
465 		ret = pwrseq_pcie_m2_create_serdev_one(ctx, pdev);
466 		if (ret) {
467 			dev_err_probe(ctx->dev, ret,
468 				      "Failed to create serdev for PCI device (%s)\n",
469 				      pci_name(pdev));
470 			pci_dev_put(pdev);
471 			goto err_remove_serdev;
472 		}
473 	}
474 
475 	return 0;
476 
477 err_remove_serdev:
478 	pwrseq_pcie_m2_remove_serdev(ctx, NULL);
479 
480 	return ret;
481 }
482 
483 static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
484 {
485 	struct device *dev = &pdev->dev;
486 	struct pwrseq_pcie_m2_ctx *ctx;
487 	struct pwrseq_config config = {};
488 	int ret;
489 
490 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
491 	if (!ctx)
492 		return -ENOMEM;
493 
494 	platform_set_drvdata(pdev, ctx);
495 	ctx->of_node = dev_of_node(dev);
496 	ctx->pdata = device_get_match_data(dev);
497 	if (!ctx->pdata)
498 		return dev_err_probe(dev, -ENODEV,
499 				     "Failed to obtain platform data\n");
500 
501 	/*
502 	 * Currently, of_regulator_bulk_get_all() is the only regulator API that
503 	 * allows to get all supplies in the devicetree node without manually
504 	 * specifying them.
505 	 */
506 	ret = of_regulator_bulk_get_all(dev, dev_of_node(dev), &ctx->regs);
507 	if (ret < 0)
508 		return dev_err_probe(dev, ret,
509 				     "Failed to get all regulators\n");
510 
511 	ctx->num_vregs = ret;
512 
513 	ctx->w_disable1_gpio = devm_gpiod_get_optional(dev, "w-disable1", GPIOD_OUT_HIGH);
514 	if (IS_ERR(ctx->w_disable1_gpio)) {
515 		ret = dev_err_probe(dev, PTR_ERR(ctx->w_disable1_gpio),
516 				     "Failed to get the W_DISABLE_1# GPIO\n");
517 		goto err_free_regulators;
518 	}
519 
520 	ctx->w_disable2_gpio = devm_gpiod_get_optional(dev, "w-disable2", GPIOD_OUT_HIGH);
521 	if (IS_ERR(ctx->w_disable2_gpio)) {
522 		ret = dev_err_probe(dev, PTR_ERR(ctx->w_disable2_gpio),
523 				     "Failed to get the W_DISABLE_2# GPIO\n");
524 		goto err_free_regulators;
525 	}
526 
527 	config.parent = dev;
528 	config.owner = THIS_MODULE;
529 	config.drvdata = ctx;
530 	config.match = pwrseq_pcie_m2_match;
531 	config.targets = ctx->pdata->targets;
532 
533 	ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
534 	if (IS_ERR(ctx->pwrseq)) {
535 		ret = dev_err_probe(dev, PTR_ERR(ctx->pwrseq),
536 				     "Failed to register the power sequencer\n");
537 		goto err_free_regulators;
538 	}
539 
540 	mutex_init(&ctx->list_lock);
541 	INIT_LIST_HEAD(&ctx->pci_devices);
542 	ctx->dev = dev;
543 
544 	/* Create serdev for available PCI devices (if required) */
545 	ret = pwrseq_pcie_m2_create_serdev(ctx);
546 	if (ret)
547 		goto err_destroy_mutex;
548 
549 	/*
550 	 * Register a notifier for creating protocol devices for
551 	 * non-discoverable busses like UART.
552 	 */
553 	ret = pwrseq_pcie_m2_register_notifier(ctx);
554 	if (ret)
555 		goto err_remove_serdev;
556 
557 	return 0;
558 
559 err_remove_serdev:
560 	pwrseq_pcie_m2_remove_serdev(ctx, NULL);
561 err_destroy_mutex:
562 	mutex_destroy(&ctx->list_lock);
563 err_free_regulators:
564 	regulator_bulk_free(ctx->num_vregs, ctx->regs);
565 
566 	return ret;
567 }
568 
569 static void pwrseq_pcie_m2_remove(struct platform_device *pdev)
570 {
571 	struct pwrseq_pcie_m2_ctx *ctx = platform_get_drvdata(pdev);
572 
573 	bus_unregister_notifier(&pci_bus_type, &ctx->nb);
574 	pwrseq_pcie_m2_remove_serdev(ctx, NULL);
575 	mutex_destroy(&ctx->list_lock);
576 
577 	regulator_bulk_free(ctx->num_vregs, ctx->regs);
578 }
579 
580 static const struct of_device_id pwrseq_pcie_m2_of_match[] = {
581 	{
582 		.compatible = "pcie-m2-m-connector",
583 		.data = &pwrseq_pcie_m2_m_of_data,
584 	},
585 	{
586 		.compatible = "pcie-m2-e-connector",
587 		.data = &pwrseq_pcie_m2_e_of_data,
588 	},
589 	{ }
590 };
591 MODULE_DEVICE_TABLE(of, pwrseq_pcie_m2_of_match);
592 
593 static struct platform_driver pwrseq_pcie_m2_driver = {
594 	.driver = {
595 		.name = "pwrseq-pcie-m2",
596 		.of_match_table = pwrseq_pcie_m2_of_match,
597 	},
598 	.probe = pwrseq_pcie_m2_probe,
599 	.remove = pwrseq_pcie_m2_remove,
600 };
601 module_platform_driver(pwrseq_pcie_m2_driver);
602 
603 MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>");
604 MODULE_DESCRIPTION("Power Sequencing driver for PCIe M.2 connector");
605 MODULE_LICENSE("GPL");
606