Lines Matching +full:power +full:- +full:supply
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * AXP20x PMIC USB power supply status driver
6 * Copyright (C) 2014 Bruno Prémont <bonbons@linux-vserver.org>
11 #include <linux/devm-helpers.h>
26 #define DRVNAME "axp20x-usb-power-supply"
68 struct power_supply *supply; member
79 static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power) in axp20x_usb_vbus_needs_polling() argument
83 * present->absent transition implies an online->offline transition in axp20x_usb_vbus_needs_polling()
86 if (power->axp_data->vbus_needs_polling && !power->online) in axp20x_usb_vbus_needs_polling()
94 struct axp20x_usb_power *power = devid; in axp20x_usb_power_irq() local
96 power_supply_changed(power->supply); in axp20x_usb_power_irq()
98 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); in axp20x_usb_power_irq()
105 struct axp20x_usb_power *power = in axp20x_usb_power_poll_vbus() local
110 ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val); in axp20x_usb_power_poll_vbus()
115 if (val != power->old_status) in axp20x_usb_power_poll_vbus()
116 power_supply_changed(power->supply); in axp20x_usb_power_poll_vbus()
118 power->old_status = val; in axp20x_usb_power_poll_vbus()
119 power->online = val & AXP20X_PWR_STATUS_VBUS_USED; in axp20x_usb_power_poll_vbus()
122 if (axp20x_usb_vbus_needs_polling(power)) in axp20x_usb_power_poll_vbus()
123 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); in axp20x_usb_power_poll_vbus()
129 struct axp20x_usb_power *power = power_supply_get_drvdata(psy); in axp20x_usb_power_get_property() local
135 ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v); in axp20x_usb_power_get_property()
139 val->intval = AXP20X_VBUS_VHOLD_uV(v); in axp20x_usb_power_get_property()
143 ret = iio_read_channel_processed(power->vbus_v, in axp20x_usb_power_get_property()
144 &val->intval); in axp20x_usb_power_get_property()
149 * IIO framework gives mV but Power Supply framework in axp20x_usb_power_get_property()
152 val->intval *= 1000; in axp20x_usb_power_get_property()
156 ret = axp20x_read_variable_width(power->regmap, in axp20x_usb_power_get_property()
161 val->intval = ret * 1700; /* 1 step = 1.7 mV */ in axp20x_usb_power_get_property()
164 ret = regmap_field_read(power->curr_lim_fld, &v); in axp20x_usb_power_get_property()
168 val->intval = power->axp_data->curr_lim_table[v]; in axp20x_usb_power_get_property()
172 ret = iio_read_channel_processed(power->vbus_i, in axp20x_usb_power_get_property()
173 &val->intval); in axp20x_usb_power_get_property()
178 * IIO framework gives mA but Power Supply framework in axp20x_usb_power_get_property()
181 val->intval *= 1000; in axp20x_usb_power_get_property()
185 ret = axp20x_read_variable_width(power->regmap, in axp20x_usb_power_get_property()
190 val->intval = ret * 375; /* 1 step = 0.375 mA */ in axp20x_usb_power_get_property()
196 /* All the properties below need the input-status reg value */ in axp20x_usb_power_get_property()
197 ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &input); in axp20x_usb_power_get_property()
204 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; in axp20x_usb_power_get_property()
208 val->intval = POWER_SUPPLY_HEALTH_GOOD; in axp20x_usb_power_get_property()
210 if (power->vbus_valid_bit) { in axp20x_usb_power_get_property()
211 ret = regmap_field_read(power->vbus_valid_bit, &v); in axp20x_usb_power_get_property()
216 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; in axp20x_usb_power_get_property()
221 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT); in axp20x_usb_power_get_property()
224 val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_USED); in axp20x_usb_power_get_property()
227 return -EINVAL; in axp20x_usb_power_get_property()
233 static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, in axp20x_usb_power_set_voltage_min() argument
247 val = (intval - 4000000) / 100000; in axp20x_usb_power_set_voltage_min()
248 return regmap_update_bits(power->regmap, in axp20x_usb_power_set_voltage_min()
253 return -EINVAL; in axp20x_usb_power_set_voltage_min()
256 return -EINVAL; in axp20x_usb_power_set_voltage_min()
259 static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power, int intval) in axp20x_usb_power_set_current_max() argument
261 const unsigned int max = GENMASK(power->axp_data->curr_lim_fld.msb, in axp20x_usb_power_set_current_max()
262 power->axp_data->curr_lim_fld.lsb); in axp20x_usb_power_set_current_max()
264 if (intval == -1) in axp20x_usb_power_set_current_max()
265 return -EINVAL; in axp20x_usb_power_set_current_max()
268 if (power->axp_data->curr_lim_table[i] == intval) in axp20x_usb_power_set_current_max()
269 return regmap_field_write(power->curr_lim_fld, i); in axp20x_usb_power_set_current_max()
271 return -EINVAL; in axp20x_usb_power_set_current_max()
278 struct axp20x_usb_power *power = power_supply_get_drvdata(psy); in axp20x_usb_power_set_property() local
282 if (!power->vbus_disable_bit) in axp20x_usb_power_set_property()
283 return -EINVAL; in axp20x_usb_power_set_property()
285 return regmap_field_write(power->vbus_disable_bit, !val->intval); in axp20x_usb_power_set_property()
288 return axp20x_usb_power_set_voltage_min(power, val->intval); in axp20x_usb_power_set_property()
291 return axp20x_usb_power_set_current_max(power, val->intval); in axp20x_usb_power_set_property()
294 return -EINVAL; in axp20x_usb_power_set_property()
297 return -EINVAL; in axp20x_usb_power_set_property()
303 struct axp20x_usb_power *power = power_supply_get_drvdata(psy); in axp20x_usb_power_prop_writeable() local
307 * - On AXP20x and AXP22x, the flag enables VBUS (ignoring N_VBUSEN). in axp20x_usb_power_prop_writeable()
308 * - On AXP288 and AXP8xx, the flag disables VBUS (ignoring N_VBUSEN). in axp20x_usb_power_prop_writeable()
313 return power->vbus_disable_bit != NULL; in axp20x_usb_power_prop_writeable()
338 .name = "axp20x-usb",
348 .name = "axp20x-usb",
370 -1,
371 -1,
380 -1,
386 -1,
387 -1,
449 struct axp20x_usb_power *power = dev_get_drvdata(dev); in axp20x_usb_power_suspend() local
458 if (device_may_wakeup(&power->supply->dev)) in axp20x_usb_power_suspend()
459 enable_irq_wake(power->irqs[i++]); in axp20x_usb_power_suspend()
460 while (i < power->num_irqs) in axp20x_usb_power_suspend()
461 disable_irq(power->irqs[i++]); in axp20x_usb_power_suspend()
468 struct axp20x_usb_power *power = dev_get_drvdata(dev); in axp20x_usb_power_resume() local
471 if (device_may_wakeup(&power->supply->dev)) in axp20x_usb_power_resume()
472 disable_irq_wake(power->irqs[i++]); in axp20x_usb_power_resume()
473 while (i < power->num_irqs) in axp20x_usb_power_resume()
474 enable_irq(power->irqs[i++]); in axp20x_usb_power_resume()
476 mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); in axp20x_usb_power_resume()
486 struct axp20x_usb_power *power) in configure_iio_channels() argument
488 power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v"); in configure_iio_channels()
489 if (IS_ERR(power->vbus_v)) { in configure_iio_channels()
490 if (PTR_ERR(power->vbus_v) == -ENODEV) in configure_iio_channels()
491 return -EPROBE_DEFER; in configure_iio_channels()
492 return PTR_ERR(power->vbus_v); in configure_iio_channels()
495 power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i"); in configure_iio_channels()
496 if (IS_ERR(power->vbus_i)) { in configure_iio_channels()
497 if (PTR_ERR(power->vbus_i) == -ENODEV) in configure_iio_channels()
498 return -EPROBE_DEFER; in configure_iio_channels()
499 return PTR_ERR(power->vbus_i); in configure_iio_channels()
505 static int configure_adc_registers(struct axp20x_usb_power *power) in configure_adc_registers() argument
508 return regmap_update_bits(power->regmap, AXP20X_ADC_EN1, in configure_adc_registers()
537 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); in axp20x_usb_power_probe()
539 struct axp20x_usb_power *power; in axp20x_usb_power_probe() local
543 if (!of_device_is_available(pdev->dev.of_node)) in axp20x_usb_power_probe()
544 return -ENODEV; in axp20x_usb_power_probe()
547 dev_err(&pdev->dev, "Parent drvdata not set\n"); in axp20x_usb_power_probe()
548 return -EINVAL; in axp20x_usb_power_probe()
551 axp_data = of_device_get_match_data(&pdev->dev); in axp20x_usb_power_probe()
553 power = devm_kzalloc(&pdev->dev, in axp20x_usb_power_probe()
554 struct_size(power, irqs, axp_data->num_irq_names), in axp20x_usb_power_probe()
556 if (!power) in axp20x_usb_power_probe()
557 return -ENOMEM; in axp20x_usb_power_probe()
559 platform_set_drvdata(pdev, power); in axp20x_usb_power_probe()
561 power->axp_data = axp_data; in axp20x_usb_power_probe()
562 power->regmap = axp20x->regmap; in axp20x_usb_power_probe()
563 power->num_irqs = axp_data->num_irq_names; in axp20x_usb_power_probe()
565 power->curr_lim_fld = devm_regmap_field_alloc(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
566 axp_data->curr_lim_fld); in axp20x_usb_power_probe()
567 if (IS_ERR(power->curr_lim_fld)) in axp20x_usb_power_probe()
568 return PTR_ERR(power->curr_lim_fld); in axp20x_usb_power_probe()
570 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
571 axp_data->vbus_valid_bit, in axp20x_usb_power_probe()
572 &power->vbus_valid_bit); in axp20x_usb_power_probe()
576 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
577 axp_data->vbus_mon_bit, in axp20x_usb_power_probe()
578 &power->vbus_mon_bit); in axp20x_usb_power_probe()
582 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
583 axp_data->usb_bc_en_bit, in axp20x_usb_power_probe()
584 &power->usb_bc_en_bit); in axp20x_usb_power_probe()
588 ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, in axp20x_usb_power_probe()
589 axp_data->vbus_disable_bit, in axp20x_usb_power_probe()
590 &power->vbus_disable_bit); in axp20x_usb_power_probe()
594 ret = devm_delayed_work_autocancel(&pdev->dev, &power->vbus_detect, in axp20x_usb_power_probe()
599 if (power->vbus_mon_bit) { in axp20x_usb_power_probe()
601 ret = regmap_field_write(power->vbus_mon_bit, 1); in axp20x_usb_power_probe()
606 ret = configure_iio_channels(pdev, power); in axp20x_usb_power_probe()
608 ret = configure_adc_registers(power); in axp20x_usb_power_probe()
614 if (power->usb_bc_en_bit) { in axp20x_usb_power_probe()
616 ret = regmap_field_write(power->usb_bc_en_bit, 1); in axp20x_usb_power_probe()
621 psy_cfg.of_node = pdev->dev.of_node; in axp20x_usb_power_probe()
622 psy_cfg.drv_data = power; in axp20x_usb_power_probe()
624 power->supply = devm_power_supply_register(&pdev->dev, in axp20x_usb_power_probe()
625 axp_data->power_desc, in axp20x_usb_power_probe()
627 if (IS_ERR(power->supply)) in axp20x_usb_power_probe()
628 return PTR_ERR(power->supply); in axp20x_usb_power_probe()
631 for (i = 0; i < axp_data->num_irq_names; i++) { in axp20x_usb_power_probe()
632 irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]); in axp20x_usb_power_probe()
636 power->irqs[i] = regmap_irq_get_virq(axp20x->regmap_irqc, irq); in axp20x_usb_power_probe()
637 ret = devm_request_any_context_irq(&pdev->dev, power->irqs[i], in axp20x_usb_power_probe()
639 DRVNAME, power); in axp20x_usb_power_probe()
641 dev_err(&pdev->dev, "Error requesting %s IRQ: %d\n", in axp20x_usb_power_probe()
642 axp_data->irq_names[i], ret); in axp20x_usb_power_probe()
647 if (axp20x_usb_vbus_needs_polling(power)) in axp20x_usb_power_probe()
648 queue_delayed_work(system_power_efficient_wq, &power->vbus_detect, 0); in axp20x_usb_power_probe()
655 .compatible = "x-powers,axp192-usb-power-supply",
658 .compatible = "x-powers,axp202-usb-power-supply",
661 .compatible = "x-powers,axp221-usb-power-supply",
664 .compatible = "x-powers,axp223-usb-power-supply",
667 .compatible = "x-powers,axp813-usb-power-supply",
685 MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver");