Lines Matching +full:usb +full:- +full:sdp

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>
18 #include <linux/usb/otg.h>
130 /* SDP/CDP/DCP USB charging cable notifications */
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()
551 * Bay Trail SoC + AXP288 PMIC, Micro-USB, DMI_BOARD_NAME: "8021"
552 * Bay Trail SoC + AXP288 PMIC, Type-C, DMI_BOARD_NAME: "815D"
553 * Cherry Trail SoC + AXP288 PMIC, Type-C, DMI_BOARD_NAME: "813E"
554 * Cherry Trail SoC + TI PMIC, Type-C, DMI_BOARD_NAME: "827C" or "82F4"
556 * The variants with the AXP288 + Type-C connector are all kinds of special:
558 * 1. They use a Type-C connector which the AXP288 does not support, so when
559 * using a Type-C charger it is not recognized. Unlike most AXP288 devices,
566 * 2. If no charger is connected the machine boots with the vbus-path disabled.
569 * an OTG host cable is inserted and the ID pin on the micro-B receptacle is
571 * which re-enables the vbus-path when the ID pin is pulled high when the
572 * OTG host cable is removed. The Type-C connector has no ID pin, there is
574 * end up not charging because the vbus-path is disabled, until we unplug
575 * the charger which automatically clears the vbus-path disable bit and then
576 * on the second plug-in of the adapter we start charging. To solve the not
577 * charging on first charger plugin we unconditionally enable the vbus-path at
583 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
603 struct extcon_dev *edev = info->cable.edev; in axp288_charger_extcon_evt_worker()
606 ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val); in axp288_charger_extcon_evt_worker()
608 dev_err(&info->pdev->dev, "Error reading status (%d)\n", ret); in axp288_charger_extcon_evt_worker()
614 dev_dbg(&info->pdev->dev, "USB charger disconnected\n"); in axp288_charger_extcon_evt_worker()
616 power_supply_changed(info->psy_usb); in axp288_charger_extcon_evt_worker()
623 dev_dbg(&info->pdev->dev, "HP X2 with Type-C, setting inlmt to 3A\n"); in axp288_charger_extcon_evt_worker()
626 dev_dbg(&info->pdev->dev, "USB SDP charger is connected\n"); in axp288_charger_extcon_evt_worker()
629 dev_dbg(&info->pdev->dev, "USB CDP charger is connected\n"); in axp288_charger_extcon_evt_worker()
632 dev_dbg(&info->pdev->dev, "USB DCP charger is connected\n"); in axp288_charger_extcon_evt_worker()
644 dev_err(&info->pdev->dev, in axp288_charger_extcon_evt_worker()
647 power_supply_changed(info->psy_usb); in axp288_charger_extcon_evt_worker()
655 schedule_work(&info->cable.work); in axp288_charger_handle_cable_evt()
663 struct extcon_dev *edev = info->otg.cable; in axp288_charger_otg_evt_worker()
666 dev_dbg(&info->pdev->dev, "external connector USB-Host is %s\n", in axp288_charger_otg_evt_worker()
671 * in case usb host. in axp288_charger_otg_evt_worker()
673 info->otg.id_short = usb_host; in axp288_charger_otg_evt_worker()
676 ret = axp288_charger_vbus_path_select(info, !info->otg.id_short); in axp288_charger_otg_evt_worker()
678 dev_warn(&info->pdev->dev, "vbus path disable failed\n"); in axp288_charger_otg_evt_worker()
687 schedule_work(&info->otg.work); in axp288_charger_handle_otg_evt()
698 ret = regmap_write(info->regmap, AXP20X_V_LTF_CHRG, CHRG_VLTFC_0C); in charger_init_hw_regs()
700 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
705 ret = regmap_write(info->regmap, AXP20X_V_HTF_CHRG, CHRG_VHTFC_45C); in charger_init_hw_regs()
707 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
712 /* Do not turn-off charger o/p after charge cycle ends */ in charger_init_hw_regs()
713 ret = regmap_update_bits(info->regmap, in charger_init_hw_regs()
717 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
723 ret = regmap_update_bits(info->regmap, in charger_init_hw_regs()
727 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
732 /* Disable OCV-SOC curve calibration */ in charger_init_hw_regs()
733 ret = regmap_update_bits(info->regmap, in charger_init_hw_regs()
737 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
750 ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT, in charger_init_hw_regs()
753 dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", in charger_init_hw_regs()
760 ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val); in charger_init_hw_regs()
762 dev_err(&info->pdev->dev, "register(%x) read error(%d)\n", in charger_init_hw_regs()
771 info->cv = CV_4100MV; in charger_init_hw_regs()
774 info->cv = CV_4150MV; in charger_init_hw_regs()
777 info->cv = CV_4200MV; in charger_init_hw_regs()
780 info->cv = CV_4350MV; in charger_init_hw_regs()
787 info->cc = cc; in charger_init_hw_regs()
793 info->max_cv = info->cv; in charger_init_hw_regs()
794 info->max_cc = info->cc; in charger_init_hw_regs()
803 cancel_work_sync(&info->otg.work); in axp288_charger_cancel_work()
804 cancel_work_sync(&info->cable.work); in axp288_charger_cancel_work()
811 struct device *dev = &pdev->dev; in axp288_charger_probe()
812 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); in axp288_charger_probe()
820 ret = regmap_read(axp20x->regmap, AXP20X_CC_CTRL, &val); in axp288_charger_probe()
824 return -ENODEV; in axp288_charger_probe()
826 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); in axp288_charger_probe()
828 return -ENOMEM; in axp288_charger_probe()
830 info->pdev = pdev; in axp288_charger_probe()
831 info->regmap = axp20x->regmap; in axp288_charger_probe()
832 info->regmap_irqc = axp20x->regmap_irqc; in axp288_charger_probe()
834 info->cable.edev = extcon_get_extcon_dev(AXP288_EXTCON_DEV_NAME); in axp288_charger_probe()
835 if (info->cable.edev == NULL) { in axp288_charger_probe()
836 dev_dbg(&pdev->dev, "%s is not ready, probe deferred\n", in axp288_charger_probe()
838 return -EPROBE_DEFER; in axp288_charger_probe()
841 if (acpi_dev_present(USB_HOST_EXTCON_HID, NULL, -1)) { in axp288_charger_probe()
842 info->otg.cable = extcon_get_extcon_dev(USB_HOST_EXTCON_NAME); in axp288_charger_probe()
843 if (info->otg.cable == NULL) { in axp288_charger_probe()
845 return -EPROBE_DEFER; in axp288_charger_probe()
847 dev_info(&pdev->dev, in axp288_charger_probe()
848 "Using " USB_HOST_EXTCON_HID " extcon for usb-id\n"); in axp288_charger_probe()
859 info->psy_usb = devm_power_supply_register(dev, &axp288_charger_desc, in axp288_charger_probe()
861 if (IS_ERR(info->psy_usb)) { in axp288_charger_probe()
862 ret = PTR_ERR(info->psy_usb); in axp288_charger_probe()
873 INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker); in axp288_charger_probe()
874 info->cable.nb.notifier_call = axp288_charger_handle_cable_evt; in axp288_charger_probe()
875 ret = devm_extcon_register_notifier_all(dev, info->cable.edev, in axp288_charger_probe()
876 &info->cable.nb); in axp288_charger_probe()
881 schedule_work(&info->cable.work); in axp288_charger_probe()
884 INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker); in axp288_charger_probe()
885 info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt; in axp288_charger_probe()
886 if (info->otg.cable) { in axp288_charger_probe()
887 ret = devm_extcon_register_notifier(&pdev->dev, info->otg.cable, in axp288_charger_probe()
888 EXTCON_USB_HOST, &info->otg.id_nb); in axp288_charger_probe()
893 schedule_work(&info->otg.work); in axp288_charger_probe()
898 pirq = platform_get_irq(info->pdev, i); in axp288_charger_probe()
902 info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); in axp288_charger_probe()
903 if (info->irq[i] < 0) { in axp288_charger_probe()
904 dev_warn(&info->pdev->dev, in axp288_charger_probe()
906 return info->irq[i]; in axp288_charger_probe()
908 ret = devm_request_threaded_irq(&info->pdev->dev, info->irq[i], in axp288_charger_probe()
910 IRQF_ONESHOT, info->pdev->name, info); in axp288_charger_probe()
912 dev_err(&pdev->dev, "failed to request interrupt=%d\n", in axp288_charger_probe()
913 info->irq[i]); in axp288_charger_probe()
938 MODULE_DESCRIPTION("X-power AXP288 Charger Driver");