1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * AXP20x PMIC USB power supply status driver 4 * 5 * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com> 6 * Copyright (C) 2014 Bruno Prémont <bonbons@linux-vserver.org> 7 */ 8 9 #include <linux/bitops.h> 10 #include <linux/device.h> 11 #include <linux/devm-helpers.h> 12 #include <linux/init.h> 13 #include <linux/interrupt.h> 14 #include <linux/kernel.h> 15 #include <linux/mfd/axp20x.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/platform_device.h> 19 #include <linux/pm.h> 20 #include <linux/power_supply.h> 21 #include <linux/regmap.h> 22 #include <linux/slab.h> 23 #include <linux/iio/consumer.h> 24 #include <linux/workqueue.h> 25 26 #define DRVNAME "axp20x-usb-power-supply" 27 28 #define AXP192_USB_OTG_STATUS 0x04 29 30 #define AXP20X_PWR_STATUS_VBUS_PRESENT BIT(5) 31 #define AXP20X_PWR_STATUS_VBUS_USED BIT(4) 32 33 #define AXP20X_USB_STATUS_VBUS_VALID BIT(2) 34 35 #define AXP20X_VBUS_VHOLD_uV(b) (4000000 + (((b) >> 3) & 7) * 100000) 36 #define AXP20X_VBUS_VHOLD_MASK GENMASK(5, 3) 37 #define AXP20X_VBUS_VHOLD_OFFSET 3 38 39 #define AXP20X_ADC_EN1_VBUS_CURR BIT(2) 40 #define AXP20X_ADC_EN1_VBUS_VOLT BIT(3) 41 42 /* 43 * Note do not raise the debounce time, we must report Vusb high within 44 * 100ms otherwise we get Vbus errors in musb. 45 */ 46 #define DEBOUNCE_TIME msecs_to_jiffies(50) 47 48 struct axp_data { 49 const struct power_supply_desc *power_desc; 50 const char * const *irq_names; 51 unsigned int num_irq_names; 52 const int *curr_lim_table; 53 struct reg_field curr_lim_fld; 54 struct reg_field vbus_valid_bit; 55 struct reg_field vbus_mon_bit; 56 struct reg_field usb_bc_en_bit; 57 struct reg_field vbus_disable_bit; 58 bool vbus_needs_polling: 1; 59 }; 60 61 struct axp20x_usb_power { 62 struct regmap *regmap; 63 struct regmap_field *curr_lim_fld; 64 struct regmap_field *vbus_valid_bit; 65 struct regmap_field *vbus_mon_bit; 66 struct regmap_field *usb_bc_en_bit; 67 struct regmap_field *vbus_disable_bit; 68 struct power_supply *supply; 69 const struct axp_data *axp_data; 70 struct iio_channel *vbus_v; 71 struct iio_channel *vbus_i; 72 struct delayed_work vbus_detect; 73 unsigned int old_status; 74 unsigned int online; 75 unsigned int num_irqs; 76 unsigned int irqs[] __counted_by(num_irqs); 77 }; 78 79 static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power) 80 { 81 /* 82 * Polling is only necessary while VBUS is offline. While online, a 83 * present->absent transition implies an online->offline transition 84 * and will trigger the VBUS_REMOVAL IRQ. 85 */ 86 if (power->axp_data->vbus_needs_polling && !power->online) 87 return true; 88 89 return false; 90 } 91 92 static irqreturn_t axp20x_usb_power_irq(int irq, void *devid) 93 { 94 struct axp20x_usb_power *power = devid; 95 96 power_supply_changed(power->supply); 97 98 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); 99 100 return IRQ_HANDLED; 101 } 102 103 static void axp20x_usb_power_poll_vbus(struct work_struct *work) 104 { 105 struct axp20x_usb_power *power = 106 container_of(work, struct axp20x_usb_power, vbus_detect.work); 107 unsigned int val; 108 int ret; 109 110 ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val); 111 if (ret) 112 goto out; 113 114 val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED); 115 if (val != power->old_status) 116 power_supply_changed(power->supply); 117 118 power->old_status = val; 119 power->online = val & AXP20X_PWR_STATUS_VBUS_USED; 120 121 out: 122 if (axp20x_usb_vbus_needs_polling(power)) 123 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); 124 } 125 126 static int axp20x_usb_power_get_property(struct power_supply *psy, 127 enum power_supply_property psp, union power_supply_propval *val) 128 { 129 struct axp20x_usb_power *power = power_supply_get_drvdata(psy); 130 unsigned int input, v; 131 int ret; 132 133 switch (psp) { 134 case POWER_SUPPLY_PROP_VOLTAGE_MIN: 135 ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v); 136 if (ret) 137 return ret; 138 139 val->intval = AXP20X_VBUS_VHOLD_uV(v); 140 return 0; 141 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 142 if (IS_ENABLED(CONFIG_AXP20X_ADC)) { 143 ret = iio_read_channel_processed(power->vbus_v, 144 &val->intval); 145 if (ret) 146 return ret; 147 148 /* 149 * IIO framework gives mV but Power Supply framework 150 * gives uV. 151 */ 152 val->intval *= 1000; 153 return 0; 154 } 155 156 ret = axp20x_read_variable_width(power->regmap, 157 AXP20X_VBUS_V_ADC_H, 12); 158 if (ret < 0) 159 return ret; 160 161 val->intval = ret * 1700; /* 1 step = 1.7 mV */ 162 return 0; 163 case POWER_SUPPLY_PROP_CURRENT_MAX: 164 ret = regmap_field_read(power->curr_lim_fld, &v); 165 if (ret) 166 return ret; 167 168 val->intval = power->axp_data->curr_lim_table[v]; 169 return 0; 170 case POWER_SUPPLY_PROP_CURRENT_NOW: 171 if (IS_ENABLED(CONFIG_AXP20X_ADC)) { 172 ret = iio_read_channel_processed(power->vbus_i, 173 &val->intval); 174 if (ret) 175 return ret; 176 177 /* 178 * IIO framework gives mA but Power Supply framework 179 * gives uA. 180 */ 181 val->intval *= 1000; 182 return 0; 183 } 184 185 ret = axp20x_read_variable_width(power->regmap, 186 AXP20X_VBUS_I_ADC_H, 12); 187 if (ret < 0) 188 return ret; 189 190 val->intval = ret * 375; /* 1 step = 0.375 mA */ 191 return 0; 192 default: 193 break; 194 } 195 196 /* All the properties below need the input-status reg value */ 197 ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &input); 198 if (ret) 199 return ret; 200 201 switch (psp) { 202 case POWER_SUPPLY_PROP_HEALTH: 203 if (!(input & AXP20X_PWR_STATUS_VBUS_PRESENT)) { 204 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; 205 break; 206 } 207 208 val->intval = POWER_SUPPLY_HEALTH_GOOD; 209 210 if (power->vbus_valid_bit) { 211 ret = regmap_field_read(power->vbus_valid_bit, &v); 212 if (ret) 213 return ret; 214 215 if (v == 0) 216 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 217 } 218 219 break; 220 case POWER_SUPPLY_PROP_PRESENT: 221 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT); 222 break; 223 case POWER_SUPPLY_PROP_ONLINE: 224 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_USED); 225 break; 226 default: 227 return -EINVAL; 228 } 229 230 return 0; 231 } 232 233 static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, 234 int intval) 235 { 236 int val; 237 238 switch (intval) { 239 case 4000000: 240 case 4100000: 241 case 4200000: 242 case 4300000: 243 case 4400000: 244 case 4500000: 245 case 4600000: 246 case 4700000: 247 val = (intval - 4000000) / 100000; 248 return regmap_update_bits(power->regmap, 249 AXP20X_VBUS_IPSOUT_MGMT, 250 AXP20X_VBUS_VHOLD_MASK, 251 val << AXP20X_VBUS_VHOLD_OFFSET); 252 default: 253 return -EINVAL; 254 } 255 256 return -EINVAL; 257 } 258 259 static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power, int intval) 260 { 261 const unsigned int max = GENMASK(power->axp_data->curr_lim_fld.msb, 262 power->axp_data->curr_lim_fld.lsb); 263 264 if (intval == -1) 265 return -EINVAL; 266 267 for (unsigned int i = 0; i <= max; ++i) 268 if (power->axp_data->curr_lim_table[i] == intval) 269 return regmap_field_write(power->curr_lim_fld, i); 270 271 return -EINVAL; 272 } 273 274 static int axp20x_usb_power_set_property(struct power_supply *psy, 275 enum power_supply_property psp, 276 const union power_supply_propval *val) 277 { 278 struct axp20x_usb_power *power = power_supply_get_drvdata(psy); 279 280 switch (psp) { 281 case POWER_SUPPLY_PROP_ONLINE: 282 if (!power->vbus_disable_bit) 283 return -EINVAL; 284 285 return regmap_field_write(power->vbus_disable_bit, !val->intval); 286 287 case POWER_SUPPLY_PROP_VOLTAGE_MIN: 288 return axp20x_usb_power_set_voltage_min(power, val->intval); 289 290 case POWER_SUPPLY_PROP_CURRENT_MAX: 291 return axp20x_usb_power_set_current_max(power, val->intval); 292 293 default: 294 return -EINVAL; 295 } 296 297 return -EINVAL; 298 } 299 300 static int axp20x_usb_power_prop_writeable(struct power_supply *psy, 301 enum power_supply_property psp) 302 { 303 struct axp20x_usb_power *power = power_supply_get_drvdata(psy); 304 305 /* 306 * The VBUS path select flag works differently on AXP288 and newer: 307 * - On AXP20x and AXP22x, the flag enables VBUS (ignoring N_VBUSEN). 308 * - On AXP288 and AXP8xx, the flag disables VBUS (ignoring N_VBUSEN). 309 * We only expose the control on variants where it can be used to force 310 * the VBUS input offline. 311 */ 312 if (psp == POWER_SUPPLY_PROP_ONLINE) 313 return power->vbus_disable_bit != NULL; 314 315 return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN || 316 psp == POWER_SUPPLY_PROP_CURRENT_MAX; 317 } 318 319 static enum power_supply_property axp20x_usb_power_properties[] = { 320 POWER_SUPPLY_PROP_HEALTH, 321 POWER_SUPPLY_PROP_PRESENT, 322 POWER_SUPPLY_PROP_ONLINE, 323 POWER_SUPPLY_PROP_VOLTAGE_MIN, 324 POWER_SUPPLY_PROP_VOLTAGE_NOW, 325 POWER_SUPPLY_PROP_CURRENT_MAX, 326 POWER_SUPPLY_PROP_CURRENT_NOW, 327 }; 328 329 static enum power_supply_property axp22x_usb_power_properties[] = { 330 POWER_SUPPLY_PROP_HEALTH, 331 POWER_SUPPLY_PROP_PRESENT, 332 POWER_SUPPLY_PROP_ONLINE, 333 POWER_SUPPLY_PROP_VOLTAGE_MIN, 334 POWER_SUPPLY_PROP_CURRENT_MAX, 335 }; 336 337 static const struct power_supply_desc axp20x_usb_power_desc = { 338 .name = "axp20x-usb", 339 .type = POWER_SUPPLY_TYPE_USB, 340 .properties = axp20x_usb_power_properties, 341 .num_properties = ARRAY_SIZE(axp20x_usb_power_properties), 342 .property_is_writeable = axp20x_usb_power_prop_writeable, 343 .get_property = axp20x_usb_power_get_property, 344 .set_property = axp20x_usb_power_set_property, 345 }; 346 347 static const struct power_supply_desc axp22x_usb_power_desc = { 348 .name = "axp20x-usb", 349 .type = POWER_SUPPLY_TYPE_USB, 350 .properties = axp22x_usb_power_properties, 351 .num_properties = ARRAY_SIZE(axp22x_usb_power_properties), 352 .property_is_writeable = axp20x_usb_power_prop_writeable, 353 .get_property = axp20x_usb_power_get_property, 354 .set_property = axp20x_usb_power_set_property, 355 }; 356 357 static const char * const axp20x_irq_names[] = { 358 "VBUS_PLUGIN", 359 "VBUS_REMOVAL", 360 "VBUS_VALID", 361 "VBUS_NOT_VALID", 362 }; 363 364 static const char * const axp22x_irq_names[] = { 365 "VBUS_PLUGIN", 366 "VBUS_REMOVAL", 367 }; 368 369 static int axp192_usb_curr_lim_table[] = { 370 -1, 371 -1, 372 500000, 373 100000, 374 }; 375 376 static int axp20x_usb_curr_lim_table[] = { 377 900000, 378 500000, 379 100000, 380 -1, 381 }; 382 383 static int axp221_usb_curr_lim_table[] = { 384 900000, 385 500000, 386 -1, 387 -1, 388 }; 389 390 static int axp813_usb_curr_lim_table[] = { 391 900000, 392 1500000, 393 2000000, 394 2500000, 395 }; 396 397 static const struct axp_data axp192_data = { 398 .power_desc = &axp20x_usb_power_desc, 399 .irq_names = axp20x_irq_names, 400 .num_irq_names = ARRAY_SIZE(axp20x_irq_names), 401 .curr_lim_table = axp192_usb_curr_lim_table, 402 .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), 403 .vbus_valid_bit = REG_FIELD(AXP192_USB_OTG_STATUS, 2, 2), 404 .vbus_mon_bit = REG_FIELD(AXP20X_VBUS_MON, 3, 3), 405 }; 406 407 static const struct axp_data axp202_data = { 408 .power_desc = &axp20x_usb_power_desc, 409 .irq_names = axp20x_irq_names, 410 .num_irq_names = ARRAY_SIZE(axp20x_irq_names), 411 .curr_lim_table = axp20x_usb_curr_lim_table, 412 .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), 413 .vbus_valid_bit = REG_FIELD(AXP20X_USB_OTG_STATUS, 2, 2), 414 .vbus_mon_bit = REG_FIELD(AXP20X_VBUS_MON, 3, 3), 415 }; 416 417 static const struct axp_data axp221_data = { 418 .power_desc = &axp22x_usb_power_desc, 419 .irq_names = axp22x_irq_names, 420 .num_irq_names = ARRAY_SIZE(axp22x_irq_names), 421 .curr_lim_table = axp221_usb_curr_lim_table, 422 .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), 423 .vbus_needs_polling = true, 424 }; 425 426 static const struct axp_data axp223_data = { 427 .power_desc = &axp22x_usb_power_desc, 428 .irq_names = axp22x_irq_names, 429 .num_irq_names = ARRAY_SIZE(axp22x_irq_names), 430 .curr_lim_table = axp20x_usb_curr_lim_table, 431 .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), 432 .vbus_needs_polling = true, 433 }; 434 435 static const struct axp_data axp813_data = { 436 .power_desc = &axp22x_usb_power_desc, 437 .irq_names = axp22x_irq_names, 438 .num_irq_names = ARRAY_SIZE(axp22x_irq_names), 439 .curr_lim_table = axp813_usb_curr_lim_table, 440 .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), 441 .usb_bc_en_bit = REG_FIELD(AXP288_BC_GLOBAL, 0, 0), 442 .vbus_disable_bit = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 7, 7), 443 .vbus_needs_polling = true, 444 }; 445 446 #ifdef CONFIG_PM_SLEEP 447 static int axp20x_usb_power_suspend(struct device *dev) 448 { 449 struct axp20x_usb_power *power = dev_get_drvdata(dev); 450 int i = 0; 451 452 /* 453 * Allow wake via VBUS_PLUGIN only. 454 * 455 * As nested threaded IRQs are not automatically disabled during 456 * suspend, we must explicitly disable the remainder of the IRQs. 457 */ 458 if (device_may_wakeup(&power->supply->dev)) 459 enable_irq_wake(power->irqs[i++]); 460 while (i < power->num_irqs) 461 disable_irq(power->irqs[i++]); 462 463 return 0; 464 } 465 466 static int axp20x_usb_power_resume(struct device *dev) 467 { 468 struct axp20x_usb_power *power = dev_get_drvdata(dev); 469 int i = 0; 470 471 if (device_may_wakeup(&power->supply->dev)) 472 disable_irq_wake(power->irqs[i++]); 473 while (i < power->num_irqs) 474 enable_irq(power->irqs[i++]); 475 476 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); 477 478 return 0; 479 } 480 #endif 481 482 static SIMPLE_DEV_PM_OPS(axp20x_usb_power_pm_ops, axp20x_usb_power_suspend, 483 axp20x_usb_power_resume); 484 485 static int configure_iio_channels(struct platform_device *pdev, 486 struct axp20x_usb_power *power) 487 { 488 power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v"); 489 if (IS_ERR(power->vbus_v)) { 490 if (PTR_ERR(power->vbus_v) == -ENODEV) 491 return -EPROBE_DEFER; 492 return PTR_ERR(power->vbus_v); 493 } 494 495 power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i"); 496 if (IS_ERR(power->vbus_i)) { 497 if (PTR_ERR(power->vbus_i) == -ENODEV) 498 return -EPROBE_DEFER; 499 return PTR_ERR(power->vbus_i); 500 } 501 502 return 0; 503 } 504 505 static int configure_adc_registers(struct axp20x_usb_power *power) 506 { 507 /* Enable vbus voltage and current measurement */ 508 return regmap_update_bits(power->regmap, AXP20X_ADC_EN1, 509 AXP20X_ADC_EN1_VBUS_CURR | 510 AXP20X_ADC_EN1_VBUS_VOLT, 511 AXP20X_ADC_EN1_VBUS_CURR | 512 AXP20X_ADC_EN1_VBUS_VOLT); 513 } 514 515 static int axp20x_regmap_field_alloc_optional(struct device *dev, 516 struct regmap *regmap, 517 struct reg_field fdesc, 518 struct regmap_field **fieldp) 519 { 520 struct regmap_field *field; 521 522 if (fdesc.reg == 0) { 523 *fieldp = NULL; 524 return 0; 525 } 526 527 field = devm_regmap_field_alloc(dev, regmap, fdesc); 528 if (IS_ERR(field)) 529 return PTR_ERR(field); 530 531 *fieldp = field; 532 return 0; 533 } 534 535 static int axp20x_usb_power_probe(struct platform_device *pdev) 536 { 537 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); 538 struct power_supply_config psy_cfg = {}; 539 struct axp20x_usb_power *power; 540 const struct axp_data *axp_data; 541 int i, irq, ret; 542 543 if (!of_device_is_available(pdev->dev.of_node)) 544 return -ENODEV; 545 546 if (!axp20x) { 547 dev_err(&pdev->dev, "Parent drvdata not set\n"); 548 return -EINVAL; 549 } 550 551 axp_data = of_device_get_match_data(&pdev->dev); 552 553 power = devm_kzalloc(&pdev->dev, 554 struct_size(power, irqs, axp_data->num_irq_names), 555 GFP_KERNEL); 556 if (!power) 557 return -ENOMEM; 558 559 platform_set_drvdata(pdev, power); 560 561 power->axp_data = axp_data; 562 power->regmap = axp20x->regmap; 563 power->num_irqs = axp_data->num_irq_names; 564 565 power->curr_lim_fld = devm_regmap_field_alloc(&pdev->dev, power->regmap, 566 axp_data->curr_lim_fld); 567 if (IS_ERR(power->curr_lim_fld)) 568 return PTR_ERR(power->curr_lim_fld); 569 570 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, 571 axp_data->vbus_valid_bit, 572 &power->vbus_valid_bit); 573 if (ret) 574 return ret; 575 576 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, 577 axp_data->vbus_mon_bit, 578 &power->vbus_mon_bit); 579 if (ret) 580 return ret; 581 582 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, 583 axp_data->usb_bc_en_bit, 584 &power->usb_bc_en_bit); 585 if (ret) 586 return ret; 587 588 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, 589 axp_data->vbus_disable_bit, 590 &power->vbus_disable_bit); 591 if (ret) 592 return ret; 593 594 ret = devm_delayed_work_autocancel(&pdev->dev, &power->vbus_detect, 595 axp20x_usb_power_poll_vbus); 596 if (ret) 597 return ret; 598 599 if (power->vbus_mon_bit) { 600 /* Enable vbus valid checking */ 601 ret = regmap_field_write(power->vbus_mon_bit, 1); 602 if (ret) 603 return ret; 604 605 if (IS_ENABLED(CONFIG_AXP20X_ADC)) 606 ret = configure_iio_channels(pdev, power); 607 else 608 ret = configure_adc_registers(power); 609 610 if (ret) 611 return ret; 612 } 613 614 if (power->usb_bc_en_bit) { 615 /* Enable USB Battery Charging specification detection */ 616 ret = regmap_field_write(power->usb_bc_en_bit, 1); 617 if (ret) 618 return ret; 619 } 620 621 psy_cfg.of_node = pdev->dev.of_node; 622 psy_cfg.drv_data = power; 623 624 power->supply = devm_power_supply_register(&pdev->dev, 625 axp_data->power_desc, 626 &psy_cfg); 627 if (IS_ERR(power->supply)) 628 return PTR_ERR(power->supply); 629 630 /* Request irqs after registering, as irqs may trigger immediately */ 631 for (i = 0; i < axp_data->num_irq_names; i++) { 632 irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]); 633 if (irq < 0) 634 return irq; 635 636 power->irqs[i] = regmap_irq_get_virq(axp20x->regmap_irqc, irq); 637 ret = devm_request_any_context_irq(&pdev->dev, power->irqs[i], 638 axp20x_usb_power_irq, 0, 639 DRVNAME, power); 640 if (ret < 0) { 641 dev_err(&pdev->dev, "Error requesting %s IRQ: %d\n", 642 axp_data->irq_names[i], ret); 643 return ret; 644 } 645 } 646 647 if (axp20x_usb_vbus_needs_polling(power)) 648 queue_delayed_work(system_power_efficient_wq, &power->vbus_detect, 0); 649 650 return 0; 651 } 652 653 static const struct of_device_id axp20x_usb_power_match[] = { 654 { 655 .compatible = "x-powers,axp192-usb-power-supply", 656 .data = &axp192_data, 657 }, { 658 .compatible = "x-powers,axp202-usb-power-supply", 659 .data = &axp202_data, 660 }, { 661 .compatible = "x-powers,axp221-usb-power-supply", 662 .data = &axp221_data, 663 }, { 664 .compatible = "x-powers,axp223-usb-power-supply", 665 .data = &axp223_data, 666 }, { 667 .compatible = "x-powers,axp813-usb-power-supply", 668 .data = &axp813_data, 669 }, { /* sentinel */ } 670 }; 671 MODULE_DEVICE_TABLE(of, axp20x_usb_power_match); 672 673 static struct platform_driver axp20x_usb_power_driver = { 674 .probe = axp20x_usb_power_probe, 675 .driver = { 676 .name = DRVNAME, 677 .of_match_table = axp20x_usb_power_match, 678 .pm = &axp20x_usb_power_pm_ops, 679 }, 680 }; 681 682 module_platform_driver(axp20x_usb_power_driver); 683 684 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 685 MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver"); 686 MODULE_LICENSE("GPL"); 687