root/drivers/power/supply/axp20x_usb_power.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. axp20x_usb_power_irq
  2. axp20x_usb_power_poll_vbus
  3. axp20x_usb_vbus_needs_polling
  4. axp20x_get_current_max
  5. axp813_get_current_max
  6. axp20x_usb_power_get_property
  7. axp20x_usb_power_set_voltage_min
  8. axp813_usb_power_set_current_max
  9. axp20x_usb_power_set_current_max
  10. axp20x_usb_power_set_property
  11. axp20x_usb_power_prop_writeable
  12. configure_iio_channels
  13. configure_adc_registers
  14. axp20x_usb_power_probe
  15. axp20x_usb_power_remove

   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/init.h>
  12 #include <linux/interrupt.h>
  13 #include <linux/kernel.h>
  14 #include <linux/mfd/axp20x.h>
  15 #include <linux/module.h>
  16 #include <linux/of.h>
  17 #include <linux/of_device.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/power_supply.h>
  20 #include <linux/regmap.h>
  21 #include <linux/slab.h>
  22 #include <linux/iio/consumer.h>
  23 #include <linux/workqueue.h>
  24 
  25 #define DRVNAME "axp20x-usb-power-supply"
  26 
  27 #define AXP20X_PWR_STATUS_VBUS_PRESENT  BIT(5)
  28 #define AXP20X_PWR_STATUS_VBUS_USED     BIT(4)
  29 
  30 #define AXP20X_USB_STATUS_VBUS_VALID    BIT(2)
  31 
  32 #define AXP20X_VBUS_VHOLD_uV(b)         (4000000 + (((b) >> 3) & 7) * 100000)
  33 #define AXP20X_VBUS_VHOLD_MASK          GENMASK(5, 3)
  34 #define AXP20X_VBUS_VHOLD_OFFSET        3
  35 #define AXP20X_VBUS_CLIMIT_MASK         3
  36 #define AXP20X_VBUS_CLIMIT_900mA        0
  37 #define AXP20X_VBUS_CLIMIT_500mA        1
  38 #define AXP20X_VBUS_CLIMIT_100mA        2
  39 #define AXP20X_VBUS_CLIMIT_NONE         3
  40 
  41 #define AXP813_VBUS_CLIMIT_900mA        0
  42 #define AXP813_VBUS_CLIMIT_1500mA       1
  43 #define AXP813_VBUS_CLIMIT_2000mA       2
  44 #define AXP813_VBUS_CLIMIT_2500mA       3
  45 
  46 #define AXP20X_ADC_EN1_VBUS_CURR        BIT(2)
  47 #define AXP20X_ADC_EN1_VBUS_VOLT        BIT(3)
  48 
  49 #define AXP20X_VBUS_MON_VBUS_VALID      BIT(3)
  50 
  51 /*
  52  * Note do not raise the debounce time, we must report Vusb high within
  53  * 100ms otherwise we get Vbus errors in musb.
  54  */
  55 #define DEBOUNCE_TIME                   msecs_to_jiffies(50)
  56 
  57 struct axp20x_usb_power {
  58         struct device_node *np;
  59         struct regmap *regmap;
  60         struct power_supply *supply;
  61         enum axp20x_variants axp20x_id;
  62         struct iio_channel *vbus_v;
  63         struct iio_channel *vbus_i;
  64         struct delayed_work vbus_detect;
  65         unsigned int old_status;
  66 };
  67 
  68 static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
  69 {
  70         struct axp20x_usb_power *power = devid;
  71 
  72         power_supply_changed(power->supply);
  73 
  74         return IRQ_HANDLED;
  75 }
  76 
  77 static void axp20x_usb_power_poll_vbus(struct work_struct *work)
  78 {
  79         struct axp20x_usb_power *power =
  80                 container_of(work, struct axp20x_usb_power, vbus_detect.work);
  81         unsigned int val;
  82         int ret;
  83 
  84         ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val);
  85         if (ret)
  86                 goto out;
  87 
  88         val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED);
  89         if (val != power->old_status)
  90                 power_supply_changed(power->supply);
  91 
  92         power->old_status = val;
  93 
  94 out:
  95         mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
  96 }
  97 
  98 static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power)
  99 {
 100         if (power->axp20x_id >= AXP221_ID)
 101                 return true;
 102 
 103         return false;
 104 }
 105 
 106 static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val)
 107 {
 108         unsigned int v;
 109         int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
 110 
 111         if (ret)
 112                 return ret;
 113 
 114         switch (v & AXP20X_VBUS_CLIMIT_MASK) {
 115         case AXP20X_VBUS_CLIMIT_100mA:
 116                 if (power->axp20x_id == AXP221_ID)
 117                         *val = -1; /* No 100mA limit */
 118                 else
 119                         *val = 100000;
 120                 break;
 121         case AXP20X_VBUS_CLIMIT_500mA:
 122                 *val = 500000;
 123                 break;
 124         case AXP20X_VBUS_CLIMIT_900mA:
 125                 *val = 900000;
 126                 break;
 127         case AXP20X_VBUS_CLIMIT_NONE:
 128                 *val = -1;
 129                 break;
 130         }
 131 
 132         return 0;
 133 }
 134 
 135 static int axp813_get_current_max(struct axp20x_usb_power *power, int *val)
 136 {
 137         unsigned int v;
 138         int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
 139 
 140         if (ret)
 141                 return ret;
 142 
 143         switch (v & AXP20X_VBUS_CLIMIT_MASK) {
 144         case AXP813_VBUS_CLIMIT_900mA:
 145                 *val = 900000;
 146                 break;
 147         case AXP813_VBUS_CLIMIT_1500mA:
 148                 *val = 1500000;
 149                 break;
 150         case AXP813_VBUS_CLIMIT_2000mA:
 151                 *val = 2000000;
 152                 break;
 153         case AXP813_VBUS_CLIMIT_2500mA:
 154                 *val = 2500000;
 155                 break;
 156         }
 157         return 0;
 158 }
 159 
 160 static int axp20x_usb_power_get_property(struct power_supply *psy,
 161         enum power_supply_property psp, union power_supply_propval *val)
 162 {
 163         struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
 164         unsigned int input, v;
 165         int ret;
 166 
 167         switch (psp) {
 168         case POWER_SUPPLY_PROP_VOLTAGE_MIN:
 169                 ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
 170                 if (ret)
 171                         return ret;
 172 
 173                 val->intval = AXP20X_VBUS_VHOLD_uV(v);
 174                 return 0;
 175         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 176                 if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
 177                         ret = iio_read_channel_processed(power->vbus_v,
 178                                                          &val->intval);
 179                         if (ret)
 180                                 return ret;
 181 
 182                         /*
 183                          * IIO framework gives mV but Power Supply framework
 184                          * gives uV.
 185                          */
 186                         val->intval *= 1000;
 187                         return 0;
 188                 }
 189 
 190                 ret = axp20x_read_variable_width(power->regmap,
 191                                                  AXP20X_VBUS_V_ADC_H, 12);
 192                 if (ret < 0)
 193                         return ret;
 194 
 195                 val->intval = ret * 1700; /* 1 step = 1.7 mV */
 196                 return 0;
 197         case POWER_SUPPLY_PROP_CURRENT_MAX:
 198                 if (power->axp20x_id == AXP813_ID)
 199                         return axp813_get_current_max(power, &val->intval);
 200                 return axp20x_get_current_max(power, &val->intval);
 201         case POWER_SUPPLY_PROP_CURRENT_NOW:
 202                 if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
 203                         ret = iio_read_channel_processed(power->vbus_i,
 204                                                          &val->intval);
 205                         if (ret)
 206                                 return ret;
 207 
 208                         /*
 209                          * IIO framework gives mA but Power Supply framework
 210                          * gives uA.
 211                          */
 212                         val->intval *= 1000;
 213                         return 0;
 214                 }
 215 
 216                 ret = axp20x_read_variable_width(power->regmap,
 217                                                  AXP20X_VBUS_I_ADC_H, 12);
 218                 if (ret < 0)
 219                         return ret;
 220 
 221                 val->intval = ret * 375; /* 1 step = 0.375 mA */
 222                 return 0;
 223         default:
 224                 break;
 225         }
 226 
 227         /* All the properties below need the input-status reg value */
 228         ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &input);
 229         if (ret)
 230                 return ret;
 231 
 232         switch (psp) {
 233         case POWER_SUPPLY_PROP_HEALTH:
 234                 if (!(input & AXP20X_PWR_STATUS_VBUS_PRESENT)) {
 235                         val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
 236                         break;
 237                 }
 238 
 239                 val->intval = POWER_SUPPLY_HEALTH_GOOD;
 240 
 241                 if (power->axp20x_id == AXP202_ID) {
 242                         ret = regmap_read(power->regmap,
 243                                           AXP20X_USB_OTG_STATUS, &v);
 244                         if (ret)
 245                                 return ret;
 246 
 247                         if (!(v & AXP20X_USB_STATUS_VBUS_VALID))
 248                                 val->intval =
 249                                         POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
 250                 }
 251                 break;
 252         case POWER_SUPPLY_PROP_PRESENT:
 253                 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT);
 254                 break;
 255         case POWER_SUPPLY_PROP_ONLINE:
 256                 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_USED);
 257                 break;
 258         default:
 259                 return -EINVAL;
 260         }
 261 
 262         return 0;
 263 }
 264 
 265 static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power,
 266                                             int intval)
 267 {
 268         int val;
 269 
 270         switch (intval) {
 271         case 4000000:
 272         case 4100000:
 273         case 4200000:
 274         case 4300000:
 275         case 4400000:
 276         case 4500000:
 277         case 4600000:
 278         case 4700000:
 279                 val = (intval - 4000000) / 100000;
 280                 return regmap_update_bits(power->regmap,
 281                                           AXP20X_VBUS_IPSOUT_MGMT,
 282                                           AXP20X_VBUS_VHOLD_MASK,
 283                                           val << AXP20X_VBUS_VHOLD_OFFSET);
 284         default:
 285                 return -EINVAL;
 286         }
 287 
 288         return -EINVAL;
 289 }
 290 
 291 static int axp813_usb_power_set_current_max(struct axp20x_usb_power *power,
 292                                             int intval)
 293 {
 294         int val;
 295 
 296         switch (intval) {
 297         case 900000:
 298                 return regmap_update_bits(power->regmap,
 299                                           AXP20X_VBUS_IPSOUT_MGMT,
 300                                           AXP20X_VBUS_CLIMIT_MASK,
 301                                           AXP813_VBUS_CLIMIT_900mA);
 302         case 1500000:
 303         case 2000000:
 304         case 2500000:
 305                 val = (intval - 1000000) / 500000;
 306                 return regmap_update_bits(power->regmap,
 307                                           AXP20X_VBUS_IPSOUT_MGMT,
 308                                           AXP20X_VBUS_CLIMIT_MASK, val);
 309         default:
 310                 return -EINVAL;
 311         }
 312 
 313         return -EINVAL;
 314 }
 315 
 316 static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power,
 317                                             int intval)
 318 {
 319         int val;
 320 
 321         switch (intval) {
 322         case 100000:
 323                 if (power->axp20x_id == AXP221_ID)
 324                         return -EINVAL;
 325                 /* fall through */
 326         case 500000:
 327         case 900000:
 328                 val = (900000 - intval) / 400000;
 329                 return regmap_update_bits(power->regmap,
 330                                           AXP20X_VBUS_IPSOUT_MGMT,
 331                                           AXP20X_VBUS_CLIMIT_MASK, val);
 332         default:
 333                 return -EINVAL;
 334         }
 335 
 336         return -EINVAL;
 337 }
 338 
 339 static int axp20x_usb_power_set_property(struct power_supply *psy,
 340                                          enum power_supply_property psp,
 341                                          const union power_supply_propval *val)
 342 {
 343         struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
 344 
 345         switch (psp) {
 346         case POWER_SUPPLY_PROP_VOLTAGE_MIN:
 347                 return axp20x_usb_power_set_voltage_min(power, val->intval);
 348 
 349         case POWER_SUPPLY_PROP_CURRENT_MAX:
 350                 if (power->axp20x_id == AXP813_ID)
 351                         return axp813_usb_power_set_current_max(power,
 352                                                                 val->intval);
 353                 return axp20x_usb_power_set_current_max(power, val->intval);
 354 
 355         default:
 356                 return -EINVAL;
 357         }
 358 
 359         return -EINVAL;
 360 }
 361 
 362 static int axp20x_usb_power_prop_writeable(struct power_supply *psy,
 363                                            enum power_supply_property psp)
 364 {
 365         return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||
 366                psp == POWER_SUPPLY_PROP_CURRENT_MAX;
 367 }
 368 
 369 static enum power_supply_property axp20x_usb_power_properties[] = {
 370         POWER_SUPPLY_PROP_HEALTH,
 371         POWER_SUPPLY_PROP_PRESENT,
 372         POWER_SUPPLY_PROP_ONLINE,
 373         POWER_SUPPLY_PROP_VOLTAGE_MIN,
 374         POWER_SUPPLY_PROP_VOLTAGE_NOW,
 375         POWER_SUPPLY_PROP_CURRENT_MAX,
 376         POWER_SUPPLY_PROP_CURRENT_NOW,
 377 };
 378 
 379 static enum power_supply_property axp22x_usb_power_properties[] = {
 380         POWER_SUPPLY_PROP_HEALTH,
 381         POWER_SUPPLY_PROP_PRESENT,
 382         POWER_SUPPLY_PROP_ONLINE,
 383         POWER_SUPPLY_PROP_VOLTAGE_MIN,
 384         POWER_SUPPLY_PROP_CURRENT_MAX,
 385 };
 386 
 387 static const struct power_supply_desc axp20x_usb_power_desc = {
 388         .name = "axp20x-usb",
 389         .type = POWER_SUPPLY_TYPE_USB,
 390         .properties = axp20x_usb_power_properties,
 391         .num_properties = ARRAY_SIZE(axp20x_usb_power_properties),
 392         .property_is_writeable = axp20x_usb_power_prop_writeable,
 393         .get_property = axp20x_usb_power_get_property,
 394         .set_property = axp20x_usb_power_set_property,
 395 };
 396 
 397 static const struct power_supply_desc axp22x_usb_power_desc = {
 398         .name = "axp20x-usb",
 399         .type = POWER_SUPPLY_TYPE_USB,
 400         .properties = axp22x_usb_power_properties,
 401         .num_properties = ARRAY_SIZE(axp22x_usb_power_properties),
 402         .property_is_writeable = axp20x_usb_power_prop_writeable,
 403         .get_property = axp20x_usb_power_get_property,
 404         .set_property = axp20x_usb_power_set_property,
 405 };
 406 
 407 static int configure_iio_channels(struct platform_device *pdev,
 408                                   struct axp20x_usb_power *power)
 409 {
 410         power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");
 411         if (IS_ERR(power->vbus_v)) {
 412                 if (PTR_ERR(power->vbus_v) == -ENODEV)
 413                         return -EPROBE_DEFER;
 414                 return PTR_ERR(power->vbus_v);
 415         }
 416 
 417         power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i");
 418         if (IS_ERR(power->vbus_i)) {
 419                 if (PTR_ERR(power->vbus_i) == -ENODEV)
 420                         return -EPROBE_DEFER;
 421                 return PTR_ERR(power->vbus_i);
 422         }
 423 
 424         return 0;
 425 }
 426 
 427 static int configure_adc_registers(struct axp20x_usb_power *power)
 428 {
 429         /* Enable vbus voltage and current measurement */
 430         return regmap_update_bits(power->regmap, AXP20X_ADC_EN1,
 431                                   AXP20X_ADC_EN1_VBUS_CURR |
 432                                   AXP20X_ADC_EN1_VBUS_VOLT,
 433                                   AXP20X_ADC_EN1_VBUS_CURR |
 434                                   AXP20X_ADC_EN1_VBUS_VOLT);
 435 }
 436 
 437 static int axp20x_usb_power_probe(struct platform_device *pdev)
 438 {
 439         struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
 440         struct power_supply_config psy_cfg = {};
 441         struct axp20x_usb_power *power;
 442         static const char * const axp20x_irq_names[] = { "VBUS_PLUGIN",
 443                 "VBUS_REMOVAL", "VBUS_VALID", "VBUS_NOT_VALID", NULL };
 444         static const char * const axp22x_irq_names[] = {
 445                 "VBUS_PLUGIN", "VBUS_REMOVAL", NULL };
 446         const char * const *irq_names;
 447         const struct power_supply_desc *usb_power_desc;
 448         int i, irq, ret;
 449 
 450         if (!of_device_is_available(pdev->dev.of_node))
 451                 return -ENODEV;
 452 
 453         if (!axp20x) {
 454                 dev_err(&pdev->dev, "Parent drvdata not set\n");
 455                 return -EINVAL;
 456         }
 457 
 458         power = devm_kzalloc(&pdev->dev, sizeof(*power), GFP_KERNEL);
 459         if (!power)
 460                 return -ENOMEM;
 461 
 462         platform_set_drvdata(pdev, power);
 463         power->axp20x_id = (enum axp20x_variants)of_device_get_match_data(
 464                                                                 &pdev->dev);
 465 
 466         power->np = pdev->dev.of_node;
 467         power->regmap = axp20x->regmap;
 468 
 469         if (power->axp20x_id == AXP202_ID) {
 470                 /* Enable vbus valid checking */
 471                 ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON,
 472                                          AXP20X_VBUS_MON_VBUS_VALID,
 473                                          AXP20X_VBUS_MON_VBUS_VALID);
 474                 if (ret)
 475                         return ret;
 476 
 477                 if (IS_ENABLED(CONFIG_AXP20X_ADC))
 478                         ret = configure_iio_channels(pdev, power);
 479                 else
 480                         ret = configure_adc_registers(power);
 481 
 482                 if (ret)
 483                         return ret;
 484 
 485                 usb_power_desc = &axp20x_usb_power_desc;
 486                 irq_names = axp20x_irq_names;
 487         } else if (power->axp20x_id == AXP221_ID ||
 488                    power->axp20x_id == AXP223_ID ||
 489                    power->axp20x_id == AXP813_ID) {
 490                 usb_power_desc = &axp22x_usb_power_desc;
 491                 irq_names = axp22x_irq_names;
 492         } else {
 493                 dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n",
 494                         axp20x->variant);
 495                 return -EINVAL;
 496         }
 497 
 498         psy_cfg.of_node = pdev->dev.of_node;
 499         psy_cfg.drv_data = power;
 500 
 501         power->supply = devm_power_supply_register(&pdev->dev, usb_power_desc,
 502                                                    &psy_cfg);
 503         if (IS_ERR(power->supply))
 504                 return PTR_ERR(power->supply);
 505 
 506         /* Request irqs after registering, as irqs may trigger immediately */
 507         for (i = 0; irq_names[i]; i++) {
 508                 irq = platform_get_irq_byname(pdev, irq_names[i]);
 509                 if (irq < 0) {
 510                         dev_warn(&pdev->dev, "No IRQ for %s: %d\n",
 511                                  irq_names[i], irq);
 512                         continue;
 513                 }
 514                 irq = regmap_irq_get_virq(axp20x->regmap_irqc, irq);
 515                 ret = devm_request_any_context_irq(&pdev->dev, irq,
 516                                 axp20x_usb_power_irq, 0, DRVNAME, power);
 517                 if (ret < 0)
 518                         dev_warn(&pdev->dev, "Error requesting %s IRQ: %d\n",
 519                                  irq_names[i], ret);
 520         }
 521 
 522         INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus);
 523         if (axp20x_usb_vbus_needs_polling(power))
 524                 queue_delayed_work(system_wq, &power->vbus_detect, 0);
 525 
 526         return 0;
 527 }
 528 
 529 static int axp20x_usb_power_remove(struct platform_device *pdev)
 530 {
 531         struct axp20x_usb_power *power = platform_get_drvdata(pdev);
 532 
 533         cancel_delayed_work_sync(&power->vbus_detect);
 534 
 535         return 0;
 536 }
 537 
 538 static const struct of_device_id axp20x_usb_power_match[] = {
 539         {
 540                 .compatible = "x-powers,axp202-usb-power-supply",
 541                 .data = (void *)AXP202_ID,
 542         }, {
 543                 .compatible = "x-powers,axp221-usb-power-supply",
 544                 .data = (void *)AXP221_ID,
 545         }, {
 546                 .compatible = "x-powers,axp223-usb-power-supply",
 547                 .data = (void *)AXP223_ID,
 548         }, {
 549                 .compatible = "x-powers,axp813-usb-power-supply",
 550                 .data = (void *)AXP813_ID,
 551         }, { /* sentinel */ }
 552 };
 553 MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
 554 
 555 static struct platform_driver axp20x_usb_power_driver = {
 556         .probe = axp20x_usb_power_probe,
 557         .remove = axp20x_usb_power_remove,
 558         .driver = {
 559                 .name = DRVNAME,
 560                 .of_match_table = axp20x_usb_power_match,
 561         },
 562 };
 563 
 564 module_platform_driver(axp20x_usb_power_driver);
 565 
 566 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 567 MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver");
 568 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */