linux/drivers/power/supply/axp20x_usb_power.c
<<
>>
Prefs
   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
  57struct 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
  68static 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
  77static 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
  94out:
  95        mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
  96}
  97
  98static 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
 106static 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
 135static 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
 160static 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
 265static 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
 291static 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
 316static 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
 339static 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
 362static 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
 369static 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
 379static 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
 387static 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
 397static 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
 407static 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
 427static 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
 437static 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
 529static 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
 538static 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};
 553MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
 554
 555static 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
 564module_platform_driver(axp20x_usb_power_driver);
 565
 566MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 567MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver");
 568MODULE_LICENSE("GPL");
 569