1086 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * AXP20x PMIC USB power supply status driver4 *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 0x0429 30#define AXP20X_PWR_STATUS_VBUS_PRESENT BIT(5)31#define AXP20X_PWR_STATUS_VBUS_USED BIT(4)32 33#define AXP717_PWR_STATUS_VBUS_GOOD BIT(5)34 35#define AXP20X_USB_STATUS_VBUS_VALID BIT(2)36 37#define AXP717_PMU_FAULT_VBUS BIT(5)38#define AXP717_PMU_FAULT_VSYS BIT(3)39 40#define AXP20X_VBUS_VHOLD_uV(b) (4000000 + (((b) >> 3) & 7) * 100000)41#define AXP20X_VBUS_VHOLD_MASK GENMASK(5, 3)42#define AXP20X_VBUS_VHOLD_OFFSET 343 44#define AXP20X_ADC_EN1_VBUS_CURR BIT(2)45#define AXP20X_ADC_EN1_VBUS_VOLT BIT(3)46 47#define AXP717_INPUT_VOL_LIMIT_MASK GENMASK(3, 0)48#define AXP717_INPUT_CUR_LIMIT_MASK GENMASK(5, 0)49#define AXP717_ADC_DATA_MASK GENMASK(14, 0)50 51#define AXP717_ADC_EN_VBUS_VOLT BIT(2)52 53/*54 * Note do not raise the debounce time, we must report Vusb high within55 * 100ms otherwise we get Vbus errors in musb.56 */57#define DEBOUNCE_TIME msecs_to_jiffies(50)58 59struct axp20x_usb_power;60 61struct axp_data {62 const struct power_supply_desc *power_desc;63 const char * const *irq_names;64 unsigned int num_irq_names;65 const int *curr_lim_table;66 int curr_lim_table_size;67 struct reg_field curr_lim_fld;68 struct reg_field vbus_valid_bit;69 struct reg_field vbus_mon_bit;70 struct reg_field usb_bc_en_bit;71 struct reg_field usb_bc_det_fld;72 struct reg_field vbus_disable_bit;73 bool vbus_needs_polling: 1;74 void (*axp20x_read_vbus)(struct work_struct *work);75 int (*axp20x_cfg_iio_chan)(struct platform_device *pdev,76 struct axp20x_usb_power *power);77 int (*axp20x_cfg_adc_reg)(struct axp20x_usb_power *power);78};79 80struct axp20x_usb_power {81 struct device *dev;82 struct regmap *regmap;83 struct regmap_field *curr_lim_fld;84 struct regmap_field *vbus_valid_bit;85 struct regmap_field *vbus_mon_bit;86 struct regmap_field *usb_bc_en_bit;87 struct regmap_field *usb_bc_det_fld;88 struct regmap_field *vbus_disable_bit;89 struct power_supply *supply;90 const struct axp_data *axp_data;91 struct iio_channel *vbus_v;92 struct iio_channel *vbus_i;93 struct delayed_work vbus_detect;94 int max_input_cur;95 unsigned int old_status;96 unsigned int online;97 unsigned int num_irqs;98 unsigned int irqs[] __counted_by(num_irqs);99};100 101static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power)102{103 /*104 * Polling is only necessary while VBUS is offline. While online, a105 * present->absent transition implies an online->offline transition106 * and will trigger the VBUS_REMOVAL IRQ.107 */108 if (power->axp_data->vbus_needs_polling && !power->online)109 return true;110 111 return false;112}113 114static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)115{116 struct axp20x_usb_power *power = devid;117 118 power_supply_changed(power->supply);119 120 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);121 122 return IRQ_HANDLED;123}124 125static void axp20x_usb_power_poll_vbus(struct work_struct *work)126{127 struct axp20x_usb_power *power =128 container_of(work, struct axp20x_usb_power, vbus_detect.work);129 unsigned int val;130 int ret;131 132 ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val);133 if (ret)134 goto out;135 136 val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED);137 if (val != power->old_status)138 power_supply_changed(power->supply);139 140 if (power->usb_bc_en_bit && (val & AXP20X_PWR_STATUS_VBUS_PRESENT) !=141 (power->old_status & AXP20X_PWR_STATUS_VBUS_PRESENT)) {142 dev_dbg(power->dev, "Cable status changed, re-enabling USB BC");143 ret = regmap_field_write(power->usb_bc_en_bit, 1);144 if (ret)145 dev_err(power->dev, "failed to enable USB BC: errno %d",146 ret);147 }148 149 power->old_status = val;150 power->online = val & AXP20X_PWR_STATUS_VBUS_USED;151 152out:153 if (axp20x_usb_vbus_needs_polling(power))154 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);155}156 157static void axp717_usb_power_poll_vbus(struct work_struct *work)158{159 struct axp20x_usb_power *power =160 container_of(work, struct axp20x_usb_power, vbus_detect.work);161 unsigned int val;162 int ret;163 164 ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &val);165 if (ret)166 return;167 168 val &= AXP717_PWR_STATUS_VBUS_GOOD;169 if (val != power->old_status)170 power_supply_changed(power->supply);171 172 power->old_status = val;173}174 175static int axp20x_get_usb_type(struct axp20x_usb_power *power,176 union power_supply_propval *val)177{178 unsigned int reg;179 int ret;180 181 if (!power->usb_bc_det_fld)182 return -EINVAL;183 184 ret = regmap_field_read(power->usb_bc_det_fld, ®);185 if (ret)186 return ret;187 188 switch (reg) {189 case 1:190 val->intval = POWER_SUPPLY_USB_TYPE_SDP;191 break;192 case 2:193 val->intval = POWER_SUPPLY_USB_TYPE_CDP;194 break;195 case 3:196 val->intval = POWER_SUPPLY_USB_TYPE_DCP;197 break;198 default:199 val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;200 break;201 }202 203 return 0;204}205 206static int axp20x_usb_power_get_property(struct power_supply *psy,207 enum power_supply_property psp, union power_supply_propval *val)208{209 struct axp20x_usb_power *power = power_supply_get_drvdata(psy);210 unsigned int input, v;211 int ret;212 213 switch (psp) {214 case POWER_SUPPLY_PROP_VOLTAGE_MIN:215 ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);216 if (ret)217 return ret;218 219 val->intval = AXP20X_VBUS_VHOLD_uV(v);220 return 0;221 case POWER_SUPPLY_PROP_VOLTAGE_NOW:222 if (IS_ENABLED(CONFIG_AXP20X_ADC)) {223 ret = iio_read_channel_processed(power->vbus_v,224 &val->intval);225 if (ret)226 return ret;227 228 /*229 * IIO framework gives mV but Power Supply framework230 * gives uV.231 */232 val->intval *= 1000;233 return 0;234 }235 236 ret = axp20x_read_variable_width(power->regmap,237 AXP20X_VBUS_V_ADC_H, 12);238 if (ret < 0)239 return ret;240 241 val->intval = ret * 1700; /* 1 step = 1.7 mV */242 return 0;243 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:244 ret = regmap_field_read(power->curr_lim_fld, &v);245 if (ret)246 return ret;247 248 if (v < power->axp_data->curr_lim_table_size)249 val->intval = power->axp_data->curr_lim_table[v];250 else251 val->intval = power->axp_data->curr_lim_table[252 power->axp_data->curr_lim_table_size - 1];253 return 0;254 case POWER_SUPPLY_PROP_CURRENT_NOW:255 if (IS_ENABLED(CONFIG_AXP20X_ADC)) {256 ret = iio_read_channel_processed(power->vbus_i,257 &val->intval);258 if (ret)259 return ret;260 261 /*262 * IIO framework gives mA but Power Supply framework263 * gives uA.264 */265 val->intval *= 1000;266 return 0;267 }268 269 ret = axp20x_read_variable_width(power->regmap,270 AXP20X_VBUS_I_ADC_H, 12);271 if (ret < 0)272 return ret;273 274 val->intval = ret * 375; /* 1 step = 0.375 mA */275 return 0;276 277 case POWER_SUPPLY_PROP_USB_TYPE:278 return axp20x_get_usb_type(power, val);279 default:280 break;281 }282 283 /* All the properties below need the input-status reg value */284 ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &input);285 if (ret)286 return ret;287 288 switch (psp) {289 case POWER_SUPPLY_PROP_HEALTH:290 if (!(input & AXP20X_PWR_STATUS_VBUS_PRESENT)) {291 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;292 break;293 }294 295 val->intval = POWER_SUPPLY_HEALTH_GOOD;296 297 if (power->vbus_valid_bit) {298 ret = regmap_field_read(power->vbus_valid_bit, &v);299 if (ret)300 return ret;301 302 if (v == 0)303 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;304 }305 306 break;307 case POWER_SUPPLY_PROP_PRESENT:308 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT);309 break;310 case POWER_SUPPLY_PROP_ONLINE:311 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_USED);312 break;313 default:314 return -EINVAL;315 }316 317 return 0;318}319 320static int axp717_usb_power_get_property(struct power_supply *psy,321 enum power_supply_property psp, union power_supply_propval *val)322{323 struct axp20x_usb_power *power = power_supply_get_drvdata(psy);324 unsigned int v;325 int ret;326 327 switch (psp) {328 case POWER_SUPPLY_PROP_HEALTH:329 val->intval = POWER_SUPPLY_HEALTH_GOOD;330 ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &v);331 if (ret)332 return ret;333 334 if (!(v & AXP717_PWR_STATUS_VBUS_GOOD))335 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;336 337 ret = regmap_read(power->regmap, AXP717_PMU_FAULT_VBUS, &v);338 if (ret)339 return ret;340 341 v &= (AXP717_PMU_FAULT_VBUS | AXP717_PMU_FAULT_VSYS);342 if (v) {343 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;344 regmap_write(power->regmap, AXP717_PMU_FAULT_VBUS, v);345 }346 347 break;348 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:349 ret = regmap_read(power->regmap, AXP717_INPUT_CUR_LIMIT_CTRL, &v);350 if (ret)351 return ret;352 353 /* 50ma step size with 100ma offset. */354 v &= AXP717_INPUT_CUR_LIMIT_MASK;355 val->intval = (v * 50000) + 100000;356 break;357 case POWER_SUPPLY_PROP_ONLINE:358 case POWER_SUPPLY_PROP_PRESENT:359 ret = regmap_read(power->regmap, AXP717_ON_INDICATE, &v);360 if (ret)361 return ret;362 val->intval = !!(v & AXP717_PWR_STATUS_VBUS_GOOD);363 break;364 case POWER_SUPPLY_PROP_USB_TYPE:365 return axp20x_get_usb_type(power, val);366 case POWER_SUPPLY_PROP_VOLTAGE_MIN:367 ret = regmap_read(power->regmap, AXP717_INPUT_VOL_LIMIT_CTRL, &v);368 if (ret)369 return ret;370 371 /* 80mv step size with 3.88v offset. */372 v &= AXP717_INPUT_VOL_LIMIT_MASK;373 val->intval = (v * 80000) + 3880000;374 break;375 case POWER_SUPPLY_PROP_VOLTAGE_NOW:376 if (IS_ENABLED(CONFIG_AXP20X_ADC)) {377 ret = iio_read_channel_processed(power->vbus_v,378 &val->intval);379 if (ret)380 return ret;381 382 /*383 * IIO framework gives mV but Power Supply framework384 * gives uV.385 */386 val->intval *= 1000;387 return 0;388 }389 390 ret = axp20x_read_variable_width(power->regmap,391 AXP717_VBUS_V_H, 16);392 if (ret < 0)393 return ret;394 395 val->intval = (ret % AXP717_ADC_DATA_MASK) * 1000;396 break;397 default:398 return -EINVAL;399 }400 401 return 0;402 403}404 405static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power,406 int intval)407{408 int val;409 410 switch (intval) {411 case 4000000:412 case 4100000:413 case 4200000:414 case 4300000:415 case 4400000:416 case 4500000:417 case 4600000:418 case 4700000:419 val = (intval - 4000000) / 100000;420 return regmap_update_bits(power->regmap,421 AXP20X_VBUS_IPSOUT_MGMT,422 AXP20X_VBUS_VHOLD_MASK,423 val << AXP20X_VBUS_VHOLD_OFFSET);424 default:425 return -EINVAL;426 }427 428 return -EINVAL;429}430 431static int axp717_usb_power_set_voltage_min(struct axp20x_usb_power *power,432 int intval)433{434 int val;435 436 /* Minimum value of 3.88v and maximum of 5.08v. */437 if (intval < 3880000 || intval > 5080000)438 return -EINVAL;439 440 /* step size of 80ma with 3.88v offset. */441 val = (intval - 3880000) / 80000;442 return regmap_update_bits(power->regmap,443 AXP717_INPUT_VOL_LIMIT_CTRL,444 AXP717_INPUT_VOL_LIMIT_MASK, val);445}446 447static int axp20x_usb_power_set_input_current_limit(struct axp20x_usb_power *power,448 int intval)449{450 int ret;451 unsigned int reg;452 const unsigned int max = power->axp_data->curr_lim_table_size;453 454 if (intval == -1)455 return -EINVAL;456 457 if (power->max_input_cur && (intval > power->max_input_cur)) {458 dev_warn(power->dev,459 "requested current %d clamped to max current %d\n",460 intval, power->max_input_cur);461 intval = power->max_input_cur;462 }463 464 /*465 * BC1.2 detection can cause a race condition if we try to set a current466 * limit while it's in progress. When it finishes it will overwrite the467 * current limit we just set.468 */469 if (power->usb_bc_en_bit) {470 dev_dbg(power->dev,471 "disabling BC1.2 detection because current limit was set");472 ret = regmap_field_write(power->usb_bc_en_bit, 0);473 if (ret)474 return ret;475 }476 477 for (reg = max - 1; reg > 0; reg--)478 if (power->axp_data->curr_lim_table[reg] <= intval)479 break;480 481 dev_dbg(power->dev, "setting input current limit reg to %d (%d uA), requested %d uA",482 reg, power->axp_data->curr_lim_table[reg], intval);483 484 return regmap_field_write(power->curr_lim_fld, reg);485}486 487static int axp717_usb_power_set_input_current_limit(struct axp20x_usb_power *power,488 int intval)489{490 int tmp;491 492 /* Minimum value of 100mA and maximum value of 3.25A*/493 if (intval < 100000 || intval > 3250000)494 return -EINVAL;495 496 if (power->max_input_cur && (intval > power->max_input_cur)) {497 dev_warn(power->dev,498 "reqested current %d clamped to max current %d\n",499 intval, power->max_input_cur);500 intval = power->max_input_cur;501 }502 503 /* Minimum value of 100mA with step size of 50mA. */504 tmp = (intval - 100000) / 50000;505 return regmap_update_bits(power->regmap,506 AXP717_INPUT_CUR_LIMIT_CTRL,507 AXP717_INPUT_CUR_LIMIT_MASK, tmp);508}509 510static int axp20x_usb_power_set_property(struct power_supply *psy,511 enum power_supply_property psp,512 const union power_supply_propval *val)513{514 struct axp20x_usb_power *power = power_supply_get_drvdata(psy);515 516 switch (psp) {517 case POWER_SUPPLY_PROP_ONLINE:518 if (!power->vbus_disable_bit)519 return -EINVAL;520 521 return regmap_field_write(power->vbus_disable_bit, !val->intval);522 523 case POWER_SUPPLY_PROP_VOLTAGE_MIN:524 return axp20x_usb_power_set_voltage_min(power, val->intval);525 526 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:527 return axp20x_usb_power_set_input_current_limit(power, val->intval);528 529 default:530 return -EINVAL;531 }532}533 534static int axp717_usb_power_set_property(struct power_supply *psy,535 enum power_supply_property psp,536 const union power_supply_propval *val)537{538 struct axp20x_usb_power *power = power_supply_get_drvdata(psy);539 540 switch (psp) {541 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:542 return axp717_usb_power_set_input_current_limit(power, val->intval);543 544 case POWER_SUPPLY_PROP_VOLTAGE_MIN:545 return axp717_usb_power_set_voltage_min(power, val->intval);546 547 default:548 return -EINVAL;549 }550 551 return -EINVAL;552}553 554static int axp20x_usb_power_prop_writeable(struct power_supply *psy,555 enum power_supply_property psp)556{557 struct axp20x_usb_power *power = power_supply_get_drvdata(psy);558 559 /*560 * The VBUS path select flag works differently on AXP288 and newer:561 * - On AXP20x and AXP22x, the flag enables VBUS (ignoring N_VBUSEN).562 * - On AXP288 and AXP8xx, the flag disables VBUS (ignoring N_VBUSEN).563 * We only expose the control on variants where it can be used to force564 * the VBUS input offline.565 */566 if (psp == POWER_SUPPLY_PROP_ONLINE)567 return power->vbus_disable_bit != NULL;568 569 return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||570 psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;571}572 573static int axp717_usb_power_prop_writeable(struct power_supply *psy,574 enum power_supply_property psp)575{576 return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||577 psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;578}579 580static int axp20x_configure_iio_channels(struct platform_device *pdev,581 struct axp20x_usb_power *power)582{583 power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");584 if (IS_ERR(power->vbus_v)) {585 if (PTR_ERR(power->vbus_v) == -ENODEV)586 return -EPROBE_DEFER;587 return PTR_ERR(power->vbus_v);588 }589 590 power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i");591 if (IS_ERR(power->vbus_i)) {592 if (PTR_ERR(power->vbus_i) == -ENODEV)593 return -EPROBE_DEFER;594 return PTR_ERR(power->vbus_i);595 }596 597 return 0;598}599 600static int axp717_configure_iio_channels(struct platform_device *pdev,601 struct axp20x_usb_power *power)602{603 power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");604 if (IS_ERR(power->vbus_v)) {605 if (PTR_ERR(power->vbus_v) == -ENODEV)606 return -EPROBE_DEFER;607 return PTR_ERR(power->vbus_v);608 }609 610 return 0;611}612 613static int axp20x_configure_adc_registers(struct axp20x_usb_power *power)614{615 /* Enable vbus voltage and current measurement */616 return regmap_update_bits(power->regmap, AXP20X_ADC_EN1,617 AXP20X_ADC_EN1_VBUS_CURR |618 AXP20X_ADC_EN1_VBUS_VOLT,619 AXP20X_ADC_EN1_VBUS_CURR |620 AXP20X_ADC_EN1_VBUS_VOLT);621}622 623static int axp717_configure_adc_registers(struct axp20x_usb_power *power)624{625 /* Enable vbus voltage measurement */626 return regmap_update_bits(power->regmap, AXP717_ADC_CH_EN_CONTROL,627 AXP717_ADC_EN_VBUS_VOLT,628 AXP717_ADC_EN_VBUS_VOLT);629}630 631static enum power_supply_property axp20x_usb_power_properties[] = {632 POWER_SUPPLY_PROP_HEALTH,633 POWER_SUPPLY_PROP_PRESENT,634 POWER_SUPPLY_PROP_ONLINE,635 POWER_SUPPLY_PROP_VOLTAGE_MIN,636 POWER_SUPPLY_PROP_VOLTAGE_NOW,637 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,638 POWER_SUPPLY_PROP_CURRENT_NOW,639};640 641static enum power_supply_property axp22x_usb_power_properties[] = {642 POWER_SUPPLY_PROP_HEALTH,643 POWER_SUPPLY_PROP_PRESENT,644 POWER_SUPPLY_PROP_ONLINE,645 POWER_SUPPLY_PROP_VOLTAGE_MIN,646 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,647};648 649static enum power_supply_property axp717_usb_power_properties[] = {650 POWER_SUPPLY_PROP_HEALTH,651 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,652 POWER_SUPPLY_PROP_ONLINE,653 POWER_SUPPLY_PROP_PRESENT,654 POWER_SUPPLY_PROP_USB_TYPE,655 POWER_SUPPLY_PROP_VOLTAGE_MIN,656 POWER_SUPPLY_PROP_VOLTAGE_NOW,657};658 659static enum power_supply_property axp813_usb_power_properties[] = {660 POWER_SUPPLY_PROP_HEALTH,661 POWER_SUPPLY_PROP_PRESENT,662 POWER_SUPPLY_PROP_ONLINE,663 POWER_SUPPLY_PROP_VOLTAGE_MIN,664 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,665 POWER_SUPPLY_PROP_USB_TYPE,666};667 668static const struct power_supply_desc axp20x_usb_power_desc = {669 .name = "axp20x-usb",670 .type = POWER_SUPPLY_TYPE_USB,671 .properties = axp20x_usb_power_properties,672 .num_properties = ARRAY_SIZE(axp20x_usb_power_properties),673 .property_is_writeable = axp20x_usb_power_prop_writeable,674 .get_property = axp20x_usb_power_get_property,675 .set_property = axp20x_usb_power_set_property,676};677 678static const struct power_supply_desc axp22x_usb_power_desc = {679 .name = "axp20x-usb",680 .type = POWER_SUPPLY_TYPE_USB,681 .properties = axp22x_usb_power_properties,682 .num_properties = ARRAY_SIZE(axp22x_usb_power_properties),683 .property_is_writeable = axp20x_usb_power_prop_writeable,684 .get_property = axp20x_usb_power_get_property,685 .set_property = axp20x_usb_power_set_property,686};687 688static const struct power_supply_desc axp717_usb_power_desc = {689 .name = "axp20x-usb",690 .type = POWER_SUPPLY_TYPE_USB,691 .properties = axp717_usb_power_properties,692 .num_properties = ARRAY_SIZE(axp717_usb_power_properties),693 .property_is_writeable = axp717_usb_power_prop_writeable,694 .get_property = axp717_usb_power_get_property,695 .set_property = axp717_usb_power_set_property,696 .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) |697 BIT(POWER_SUPPLY_USB_TYPE_CDP) |698 BIT(POWER_SUPPLY_USB_TYPE_DCP) |699 BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),700};701 702static const struct power_supply_desc axp813_usb_power_desc = {703 .name = "axp20x-usb",704 .type = POWER_SUPPLY_TYPE_USB,705 .properties = axp813_usb_power_properties,706 .num_properties = ARRAY_SIZE(axp813_usb_power_properties),707 .property_is_writeable = axp20x_usb_power_prop_writeable,708 .get_property = axp20x_usb_power_get_property,709 .set_property = axp20x_usb_power_set_property,710 .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) |711 BIT(POWER_SUPPLY_USB_TYPE_CDP) |712 BIT(POWER_SUPPLY_USB_TYPE_DCP) |713 BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),714};715 716static const char * const axp20x_irq_names[] = {717 "VBUS_PLUGIN",718 "VBUS_REMOVAL",719 "VBUS_VALID",720 "VBUS_NOT_VALID",721};722 723static const char * const axp22x_irq_names[] = {724 "VBUS_PLUGIN",725 "VBUS_REMOVAL",726};727 728static const char * const axp717_irq_names[] = {729 "VBUS_PLUGIN",730 "VBUS_REMOVAL",731 "VBUS_OVER_V",732};733 734static int axp192_usb_curr_lim_table[] = {735 -1,736 -1,737 500000,738 100000,739};740 741static int axp20x_usb_curr_lim_table[] = {742 900000,743 500000,744 100000,745 -1,746};747 748static int axp221_usb_curr_lim_table[] = {749 900000,750 500000,751 -1,752 -1,753};754 755static int axp813_usb_curr_lim_table[] = {756 100000,757 500000,758 900000,759 1500000,760 2000000,761 2500000,762 3000000,763 3500000,764 4000000,765};766 767static const struct axp_data axp192_data = {768 .power_desc = &axp20x_usb_power_desc,769 .irq_names = axp20x_irq_names,770 .num_irq_names = ARRAY_SIZE(axp20x_irq_names),771 .curr_lim_table = axp192_usb_curr_lim_table,772 .curr_lim_table_size = ARRAY_SIZE(axp192_usb_curr_lim_table),773 .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1),774 .vbus_valid_bit = REG_FIELD(AXP192_USB_OTG_STATUS, 2, 2),775 .vbus_mon_bit = REG_FIELD(AXP20X_VBUS_MON, 3, 3),776 .axp20x_read_vbus = &axp20x_usb_power_poll_vbus,777 .axp20x_cfg_iio_chan = axp20x_configure_iio_channels,778 .axp20x_cfg_adc_reg = axp20x_configure_adc_registers,779};780 781static const struct axp_data axp202_data = {782 .power_desc = &axp20x_usb_power_desc,783 .irq_names = axp20x_irq_names,784 .num_irq_names = ARRAY_SIZE(axp20x_irq_names),785 .curr_lim_table = axp20x_usb_curr_lim_table,786 .curr_lim_table_size = ARRAY_SIZE(axp20x_usb_curr_lim_table),787 .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1),788 .vbus_valid_bit = REG_FIELD(AXP20X_USB_OTG_STATUS, 2, 2),789 .vbus_mon_bit = REG_FIELD(AXP20X_VBUS_MON, 3, 3),790 .axp20x_read_vbus = &axp20x_usb_power_poll_vbus,791 .axp20x_cfg_iio_chan = axp20x_configure_iio_channels,792 .axp20x_cfg_adc_reg = axp20x_configure_adc_registers,793};794 795static const struct axp_data axp221_data = {796 .power_desc = &axp22x_usb_power_desc,797 .irq_names = axp22x_irq_names,798 .num_irq_names = ARRAY_SIZE(axp22x_irq_names),799 .curr_lim_table = axp221_usb_curr_lim_table,800 .curr_lim_table_size = ARRAY_SIZE(axp221_usb_curr_lim_table),801 .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1),802 .vbus_needs_polling = true,803 .axp20x_read_vbus = &axp20x_usb_power_poll_vbus,804 .axp20x_cfg_iio_chan = axp20x_configure_iio_channels,805 .axp20x_cfg_adc_reg = axp20x_configure_adc_registers,806};807 808static const struct axp_data axp223_data = {809 .power_desc = &axp22x_usb_power_desc,810 .irq_names = axp22x_irq_names,811 .num_irq_names = ARRAY_SIZE(axp22x_irq_names),812 .curr_lim_table = axp20x_usb_curr_lim_table,813 .curr_lim_table_size = ARRAY_SIZE(axp20x_usb_curr_lim_table),814 .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1),815 .vbus_needs_polling = true,816 .axp20x_read_vbus = &axp20x_usb_power_poll_vbus,817 .axp20x_cfg_iio_chan = axp20x_configure_iio_channels,818 .axp20x_cfg_adc_reg = axp20x_configure_adc_registers,819};820 821static const struct axp_data axp717_data = {822 .power_desc = &axp717_usb_power_desc,823 .irq_names = axp717_irq_names,824 .num_irq_names = ARRAY_SIZE(axp717_irq_names),825 .curr_lim_fld = REG_FIELD(AXP717_INPUT_CUR_LIMIT_CTRL, 0, 5),826 .usb_bc_en_bit = REG_FIELD(AXP717_MODULE_EN_CONTROL_1, 4, 4),827 .usb_bc_det_fld = REG_FIELD(AXP717_BC_DETECT, 5, 7),828 .vbus_mon_bit = REG_FIELD(AXP717_ADC_CH_EN_CONTROL, 2, 2),829 .vbus_needs_polling = false,830 .axp20x_read_vbus = &axp717_usb_power_poll_vbus,831 .axp20x_cfg_iio_chan = axp717_configure_iio_channels,832 .axp20x_cfg_adc_reg = axp717_configure_adc_registers,833};834 835static const struct axp_data axp813_data = {836 .power_desc = &axp813_usb_power_desc,837 .irq_names = axp22x_irq_names,838 .num_irq_names = ARRAY_SIZE(axp22x_irq_names),839 .curr_lim_table = axp813_usb_curr_lim_table,840 .curr_lim_table_size = ARRAY_SIZE(axp813_usb_curr_lim_table),841 .curr_lim_fld = REG_FIELD(AXP22X_CHRG_CTRL3, 4, 7),842 .usb_bc_en_bit = REG_FIELD(AXP288_BC_GLOBAL, 0, 0),843 .usb_bc_det_fld = REG_FIELD(AXP288_BC_DET_STAT, 5, 7),844 .vbus_disable_bit = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 7, 7),845 .vbus_needs_polling = true,846 .axp20x_read_vbus = &axp20x_usb_power_poll_vbus,847 .axp20x_cfg_iio_chan = axp20x_configure_iio_channels,848 .axp20x_cfg_adc_reg = axp20x_configure_adc_registers,849};850 851#ifdef CONFIG_PM_SLEEP852static int axp20x_usb_power_suspend(struct device *dev)853{854 struct axp20x_usb_power *power = dev_get_drvdata(dev);855 int i = 0;856 857 /*858 * Allow wake via VBUS_PLUGIN only.859 *860 * As nested threaded IRQs are not automatically disabled during861 * suspend, we must explicitly disable the remainder of the IRQs.862 */863 if (device_may_wakeup(&power->supply->dev))864 enable_irq_wake(power->irqs[i++]);865 while (i < power->num_irqs)866 disable_irq(power->irqs[i++]);867 868 return 0;869}870 871static int axp20x_usb_power_resume(struct device *dev)872{873 struct axp20x_usb_power *power = dev_get_drvdata(dev);874 int i = 0;875 876 if (device_may_wakeup(&power->supply->dev))877 disable_irq_wake(power->irqs[i++]);878 while (i < power->num_irqs)879 enable_irq(power->irqs[i++]);880 881 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);882 883 return 0;884}885#endif886 887static SIMPLE_DEV_PM_OPS(axp20x_usb_power_pm_ops, axp20x_usb_power_suspend,888 axp20x_usb_power_resume);889 890static int axp20x_regmap_field_alloc_optional(struct device *dev,891 struct regmap *regmap,892 struct reg_field fdesc,893 struct regmap_field **fieldp)894{895 struct regmap_field *field;896 897 if (fdesc.reg == 0) {898 *fieldp = NULL;899 return 0;900 }901 902 field = devm_regmap_field_alloc(dev, regmap, fdesc);903 if (IS_ERR(field))904 return PTR_ERR(field);905 906 *fieldp = field;907 return 0;908}909 910/* Optionally allow users to specify a maximum charging current. */911static void axp20x_usb_power_parse_dt(struct device *dev,912 struct axp20x_usb_power *power)913{914 int ret;915 916 ret = device_property_read_u32(dev, "input-current-limit-microamp",917 &power->max_input_cur);918 if (ret)919 dev_dbg(dev, "%s() no input-current-limit specified\n", __func__);920}921 922static int axp20x_usb_power_probe(struct platform_device *pdev)923{924 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);925 struct power_supply_config psy_cfg = {};926 struct axp20x_usb_power *power;927 const struct axp_data *axp_data;928 int i, irq, ret;929 930 if (!of_device_is_available(pdev->dev.of_node))931 return -ENODEV;932 933 if (!axp20x) {934 dev_err(&pdev->dev, "Parent drvdata not set\n");935 return -EINVAL;936 }937 938 axp_data = of_device_get_match_data(&pdev->dev);939 940 power = devm_kzalloc(&pdev->dev,941 struct_size(power, irqs, axp_data->num_irq_names),942 GFP_KERNEL);943 if (!power)944 return -ENOMEM;945 946 platform_set_drvdata(pdev, power);947 948 power->dev = &pdev->dev;949 power->axp_data = axp_data;950 power->regmap = axp20x->regmap;951 power->num_irqs = axp_data->num_irq_names;952 953 power->curr_lim_fld = devm_regmap_field_alloc(&pdev->dev, power->regmap,954 axp_data->curr_lim_fld);955 if (IS_ERR(power->curr_lim_fld))956 return PTR_ERR(power->curr_lim_fld);957 958 axp20x_usb_power_parse_dt(&pdev->dev, power);959 960 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,961 axp_data->vbus_valid_bit,962 &power->vbus_valid_bit);963 if (ret)964 return ret;965 966 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,967 axp_data->vbus_mon_bit,968 &power->vbus_mon_bit);969 if (ret)970 return ret;971 972 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,973 axp_data->usb_bc_en_bit,974 &power->usb_bc_en_bit);975 if (ret)976 return ret;977 978 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,979 axp_data->usb_bc_det_fld,980 &power->usb_bc_det_fld);981 if (ret)982 return ret;983 984 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap,985 axp_data->vbus_disable_bit,986 &power->vbus_disable_bit);987 if (ret)988 return ret;989 990 ret = devm_delayed_work_autocancel(&pdev->dev, &power->vbus_detect,991 axp_data->axp20x_read_vbus);992 if (ret)993 return ret;994 995 if (power->vbus_mon_bit) {996 /* Enable vbus valid checking */997 ret = regmap_field_write(power->vbus_mon_bit, 1);998 if (ret)999 return ret;1000 1001 if (IS_ENABLED(CONFIG_AXP20X_ADC))1002 ret = axp_data->axp20x_cfg_iio_chan(pdev, power);1003 else1004 ret = axp_data->axp20x_cfg_adc_reg(power);1005 1006 if (ret)1007 return ret;1008 }1009 1010 if (power->usb_bc_en_bit) {1011 /* Enable USB Battery Charging specification detection */1012 ret = regmap_field_write(power->usb_bc_en_bit, 1);1013 if (ret)1014 return ret;1015 }1016 1017 psy_cfg.of_node = pdev->dev.of_node;1018 psy_cfg.drv_data = power;1019 1020 power->supply = devm_power_supply_register(&pdev->dev,1021 axp_data->power_desc,1022 &psy_cfg);1023 if (IS_ERR(power->supply))1024 return PTR_ERR(power->supply);1025 1026 /* Request irqs after registering, as irqs may trigger immediately */1027 for (i = 0; i < axp_data->num_irq_names; i++) {1028 irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]);1029 if (irq < 0)1030 return irq;1031 1032 power->irqs[i] = regmap_irq_get_virq(axp20x->regmap_irqc, irq);1033 ret = devm_request_any_context_irq(&pdev->dev, power->irqs[i],1034 axp20x_usb_power_irq, 0,1035 DRVNAME, power);1036 if (ret < 0) {1037 dev_err(&pdev->dev, "Error requesting %s IRQ: %d\n",1038 axp_data->irq_names[i], ret);1039 return ret;1040 }1041 }1042 1043 if (axp20x_usb_vbus_needs_polling(power))1044 queue_delayed_work(system_power_efficient_wq, &power->vbus_detect, 0);1045 1046 return 0;1047}1048 1049static const struct of_device_id axp20x_usb_power_match[] = {1050 {1051 .compatible = "x-powers,axp192-usb-power-supply",1052 .data = &axp192_data,1053 }, {1054 .compatible = "x-powers,axp202-usb-power-supply",1055 .data = &axp202_data,1056 }, {1057 .compatible = "x-powers,axp221-usb-power-supply",1058 .data = &axp221_data,1059 }, {1060 .compatible = "x-powers,axp223-usb-power-supply",1061 .data = &axp223_data,1062 }, {1063 .compatible = "x-powers,axp717-usb-power-supply",1064 .data = &axp717_data,1065 }, {1066 .compatible = "x-powers,axp813-usb-power-supply",1067 .data = &axp813_data,1068 }, { /* sentinel */ }1069};1070MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);1071 1072static struct platform_driver axp20x_usb_power_driver = {1073 .probe = axp20x_usb_power_probe,1074 .driver = {1075 .name = DRVNAME,1076 .of_match_table = axp20x_usb_power_match,1077 .pm = &axp20x_usb_power_pm_ops,1078 },1079};1080 1081module_platform_driver(axp20x_usb_power_driver);1082 1083MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");1084MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver");1085MODULE_LICENSE("GPL");1086