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