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