Lines Matching +full:current +full:- +full:boost +full:- +full:limit
1 // SPDX-License-Identifier: GPL-2.0-only
3 * axp288_charger.c - X-power AXP288 PMIC Charger driver
5 * Copyright (C) 2016-2017 Hans de Goede <hdegoede@redhat.com>
150 else if (cc > info->max_cc) in axp288_charger_set_cc()
151 cc = info->max_cc; in axp288_charger_set_cc()
153 reg_val = (cc - CHRG_CCCV_CC_OFFSET) / CHRG_CCCV_CC_LSB_RES; in axp288_charger_set_cc()
157 ret = regmap_update_bits(info->regmap, in axp288_charger_set_cc()
161 info->cc = cc; in axp288_charger_set_cc()
187 ret = regmap_update_bits(info->regmap, in axp288_charger_set_cv()
192 info->cv = cv; in axp288_charger_set_cv()
202 ret = regmap_read(info->regmap, AXP20X_CHRG_BAK_CTRL, &val); in axp288_charger_get_vbus_inlmt()
255 ret = regmap_update_bits(info->regmap, AXP20X_CHRG_BAK_CTRL, in axp288_charger_set_vbus_inlmt()
258 dev_err(&info->pdev->dev, "charger BAK control %d\n", ret); in axp288_charger_set_vbus_inlmt()
269 ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT, in axp288_charger_vbus_path_select()
272 ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT, in axp288_charger_vbus_path_select()
276 dev_err(&info->pdev->dev, "axp288 vbus path select %d\n", ret); in axp288_charger_vbus_path_select()
287 ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1, in axp288_charger_enable_charger()
290 ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1, in axp288_charger_enable_charger()
293 dev_err(&info->pdev->dev, "axp288 enable charger %d\n", ret); in axp288_charger_enable_charger()
303 ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val); in axp288_charger_is_present()
317 ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val); in axp288_charger_is_online()
332 ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val); in axp288_get_charger_health()
338 ret = regmap_read(info->regmap, AXP20X_PWR_OP_MODE, &val); in axp288_get_charger_health()
367 scaled_val = min(val->intval, info->max_cc); in axp288_charger_usb_set_property()
371 dev_warn(&info->pdev->dev, "set charge current failed\n"); in axp288_charger_usb_set_property()
374 scaled_val = min(val->intval, info->max_cv); in axp288_charger_usb_set_property()
378 dev_warn(&info->pdev->dev, "set charge voltage failed\n"); in axp288_charger_usb_set_property()
381 ret = axp288_charger_set_vbus_inlmt(info, val->intval); in axp288_charger_usb_set_property()
383 dev_warn(&info->pdev->dev, "set input current limit failed\n"); in axp288_charger_usb_set_property()
386 ret = -EINVAL; in axp288_charger_usb_set_property()
402 if (info->otg.id_short) { in axp288_charger_usb_get_property()
403 val->intval = 0; in axp288_charger_usb_get_property()
409 val->intval = ret; in axp288_charger_usb_get_property()
413 if (info->otg.id_short) { in axp288_charger_usb_get_property()
414 val->intval = 0; in axp288_charger_usb_get_property()
420 val->intval = ret; in axp288_charger_usb_get_property()
423 val->intval = axp288_get_charger_health(info); in axp288_charger_usb_get_property()
426 val->intval = info->cc * 1000; in axp288_charger_usb_get_property()
429 val->intval = info->max_cc * 1000; in axp288_charger_usb_get_property()
432 val->intval = info->cv * 1000; in axp288_charger_usb_get_property()
435 val->intval = info->max_cv * 1000; in axp288_charger_usb_get_property()
441 val->intval = ret; in axp288_charger_usb_get_property()
444 return -EINVAL; in axp288_charger_usb_get_property()
496 if (info->irq[i] == irq) in axp288_charger_irq_thread_handler()
501 dev_warn(&info->pdev->dev, "spurious interrupt!!\n"); in axp288_charger_irq_thread_handler()
507 dev_dbg(&info->pdev->dev, "VBUS Over Voltage INTR\n"); in axp288_charger_irq_thread_handler()
510 dev_dbg(&info->pdev->dev, "Charging Done INTR\n"); in axp288_charger_irq_thread_handler()
513 dev_dbg(&info->pdev->dev, "Start Charging IRQ\n"); in axp288_charger_irq_thread_handler()
516 dev_dbg(&info->pdev->dev, in axp288_charger_irq_thread_handler()
520 dev_dbg(&info->pdev->dev, in axp288_charger_irq_thread_handler()
524 dev_dbg(&info->pdev->dev, in axp288_charger_irq_thread_handler()
528 dev_dbg(&info->pdev->dev, in axp288_charger_irq_thread_handler()
532 dev_dbg(&info->pdev->dev, in axp288_charger_irq_thread_handler()
536 dev_dbg(&info->pdev->dev, in axp288_charger_irq_thread_handler()
540 dev_warn(&info->pdev->dev, "Spurious Interrupt!!!\n"); in axp288_charger_irq_thread_handler()
544 power_supply_changed(info->psy_usb); in axp288_charger_irq_thread_handler()
557 * 1. All variants use a Type-C connector which the AXP288 does not support, so
558 * when using a Type-C charger it is not recognized. Unlike most AXP288 devices,
565 * 2. If no charger is connected the machine boots with the vbus-path disabled.
566 * Normally this is done when a 5V boost converter is active to avoid the PMIC
567 * trying to charge from the 5V boost converter's output. This is done when
568 * an OTG host cable is inserted and the ID pin on the micro-B receptacle is
570 * which re-enables the vbus-path when the ID pin is pulled high when the
571 * OTG host cable is removed. The Type-C connector has no ID pin, there is
572 * no ID pin handler and there appears to be no 5V boost converter, so we
573 * end up not charging because the vbus-path is disabled, until we unplug
574 * the charger which automatically clears the vbus-path disable bit and then
575 * on the second plug-in of the adapter we start charging. To solve the not
576 * charging on first charger plugin we unconditionally enable the vbus-path at
577 * probe on this model, which is safe since there is no 5V boost converter.
582 * Bay Trail model has "Hewlett-Packard" as sys_vendor, Cherry
597 struct extcon_dev *edev = info->cable.edev; in axp288_charger_extcon_evt_worker()
600 ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val); in axp288_charger_extcon_evt_worker()
602 dev_err(&info->pdev->dev, "Error reading status (%d)\n", ret); in axp288_charger_extcon_evt_worker()
608 dev_dbg(&info->pdev->dev, "USB charger disconnected\n"); in axp288_charger_extcon_evt_worker()
610 power_supply_changed(info->psy_usb); in axp288_charger_extcon_evt_worker()
617 dev_dbg(&info->pdev->dev, "HP X2 with Type-C, setting inlmt to 3A\n"); in axp288_charger_extcon_evt_worker()
620 dev_dbg(&info->pdev->dev, "USB SDP charger is connected\n"); in axp288_charger_extcon_evt_worker()
623 dev_dbg(&info->pdev->dev, "USB CDP charger is connected\n"); in axp288_charger_extcon_evt_worker()
626 dev_dbg(&info->pdev->dev, "USB DCP charger is connected\n"); in axp288_charger_extcon_evt_worker()
633 /* Set vbus current limit first, then enable charger */ in axp288_charger_extcon_evt_worker()
638 dev_err(&info->pdev->dev, in axp288_charger_extcon_evt_worker()
639 "error setting current limit (%d)\n", ret); in axp288_charger_extcon_evt_worker()
641 power_supply_changed(info->psy_usb); in axp288_charger_extcon_evt_worker()
649 schedule_work(&info->cable.work); in axp288_charger_handle_cable_evt()
657 struct extcon_dev *edev = info->otg.cable; in axp288_charger_otg_evt_worker()
660 dev_dbg(&info->pdev->dev, "external connector USB-Host is %s\n", in axp288_charger_otg_evt_worker()
667 info->otg.id_short = usb_host; in axp288_charger_otg_evt_worker()
669 /* Disable VBUS path before enabling the 5V boost */ in axp288_charger_otg_evt_worker()
670 ret = axp288_charger_vbus_path_select(info, !info->otg.id_short); in axp288_charger_otg_evt_worker()
672 dev_warn(&info->pdev->dev, "vbus path disable failed\n"); in axp288_charger_otg_evt_worker()
681 schedule_work(&info->otg.work); in axp288_charger_handle_otg_evt()
692 ret = regmap_write(info->regmap, AXP20X_V_LTF_CHRG, CHRG_VLTFC_0C); in charger_init_hw_regs()
694 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
699 ret = regmap_write(info->regmap, AXP20X_V_HTF_CHRG, CHRG_VHTFC_45C); in charger_init_hw_regs()
701 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
706 /* Do not turn-off charger o/p after charge cycle ends */ in charger_init_hw_regs()
707 ret = regmap_update_bits(info->regmap, in charger_init_hw_regs()
711 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
717 ret = regmap_update_bits(info->regmap, in charger_init_hw_regs()
721 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
726 /* Disable OCV-SOC curve calibration */ in charger_init_hw_regs()
727 ret = regmap_update_bits(info->regmap, in charger_init_hw_regs()
731 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
743 /* Read current charge voltage and current limit */ in charger_init_hw_regs()
744 ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val); in charger_init_hw_regs()
746 dev_err(&info->pdev->dev, "register(%x) read error(%d)\n", in charger_init_hw_regs()
755 info->cv = CV_4100MV; in charger_init_hw_regs()
758 info->cv = CV_4150MV; in charger_init_hw_regs()
761 info->cv = CV_4200MV; in charger_init_hw_regs()
764 info->cv = CV_4350MV; in charger_init_hw_regs()
768 /* Determine charge current limit */ in charger_init_hw_regs()
771 info->cc = cc; in charger_init_hw_regs()
777 info->max_cv = info->cv; in charger_init_hw_regs()
778 info->max_cc = info->cc; in charger_init_hw_regs()
787 cancel_work_sync(&info->otg.work); in axp288_charger_cancel_work()
788 cancel_work_sync(&info->cable.work); in axp288_charger_cancel_work()
795 struct device *dev = &pdev->dev; in axp288_charger_probe()
796 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); in axp288_charger_probe()
804 ret = regmap_read(axp20x->regmap, AXP20X_CC_CTRL, &val); in axp288_charger_probe()
808 return -ENODEV; in axp288_charger_probe()
810 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); in axp288_charger_probe()
812 return -ENOMEM; in axp288_charger_probe()
814 info->pdev = pdev; in axp288_charger_probe()
815 info->regmap = axp20x->regmap; in axp288_charger_probe()
816 info->regmap_irqc = axp20x->regmap_irqc; in axp288_charger_probe()
818 info->cable.edev = extcon_get_extcon_dev(AXP288_EXTCON_DEV_NAME); in axp288_charger_probe()
819 if (info->cable.edev == NULL) { in axp288_charger_probe()
820 dev_dbg(&pdev->dev, "%s is not ready, probe deferred\n", in axp288_charger_probe()
822 return -EPROBE_DEFER; in axp288_charger_probe()
825 if (acpi_dev_present(USB_HOST_EXTCON_HID, NULL, -1)) { in axp288_charger_probe()
826 info->otg.cable = extcon_get_extcon_dev(USB_HOST_EXTCON_NAME); in axp288_charger_probe()
827 if (info->otg.cable == NULL) { in axp288_charger_probe()
829 return -EPROBE_DEFER; in axp288_charger_probe()
831 dev_info(&pdev->dev, in axp288_charger_probe()
832 "Using " USB_HOST_EXTCON_HID " extcon for usb-id\n"); in axp288_charger_probe()
843 info->psy_usb = devm_power_supply_register(dev, &axp288_charger_desc, in axp288_charger_probe()
845 if (IS_ERR(info->psy_usb)) { in axp288_charger_probe()
846 ret = PTR_ERR(info->psy_usb); in axp288_charger_probe()
857 INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker); in axp288_charger_probe()
858 info->cable.nb.notifier_call = axp288_charger_handle_cable_evt; in axp288_charger_probe()
859 ret = devm_extcon_register_notifier_all(dev, info->cable.edev, in axp288_charger_probe()
860 &info->cable.nb); in axp288_charger_probe()
865 schedule_work(&info->cable.work); in axp288_charger_probe()
868 INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker); in axp288_charger_probe()
869 info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt; in axp288_charger_probe()
870 if (info->otg.cable) { in axp288_charger_probe()
871 ret = devm_extcon_register_notifier(&pdev->dev, info->otg.cable, in axp288_charger_probe()
872 EXTCON_USB_HOST, &info->otg.id_nb); in axp288_charger_probe()
877 schedule_work(&info->otg.work); in axp288_charger_probe()
882 pirq = platform_get_irq(info->pdev, i); in axp288_charger_probe()
886 info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); in axp288_charger_probe()
887 if (info->irq[i] < 0) { in axp288_charger_probe()
888 dev_warn(&info->pdev->dev, in axp288_charger_probe()
890 return info->irq[i]; in axp288_charger_probe()
892 ret = devm_request_threaded_irq(&info->pdev->dev, info->irq[i], in axp288_charger_probe()
894 IRQF_ONESHOT, info->pdev->name, info); in axp288_charger_probe()
896 dev_err(&pdev->dev, "failed to request interrupt=%d\n", in axp288_charger_probe()
897 info->irq[i]); in axp288_charger_probe()
922 MODULE_DESCRIPTION("X-power AXP288 Charger Driver");