Lines Matching +full:ac +full:- +full:charger

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * TWL4030/TPS65950 BCI (Battery Charger Interface) driver
72 #define TWL4030_ICHGEOC BIT(4) /* Battery current end-of-charge */
80 #define TWL4030_ACCHGOV BIT(3) /* Ac charger overvoltage */
91 * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11)
92 * then AC is available.
113 struct power_supply *ac; member
206 * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
207 * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7
209 * CGAIN == 0: val * 1.6618 - 0.85 * 1000
210 * CGAIN == 1: (val * 1.6618 - 0.85 * 1000) * 2
218 return (regval * 16618 - 8500 * 1000) / 5; in regval2ua()
220 return (regval * 16618 - 8500 * 1000) / 10; in regval2ua()
248 * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11) in twl4030_charger_update_current()
249 * and AC is enabled, set current for 'ac' in twl4030_charger_update_current()
251 if (ac_available(bci->channel_vac)) { in twl4030_charger_update_current()
252 cur = bci->ac_cur; in twl4030_charger_update_current()
253 bci->ac_is_active = true; in twl4030_charger_update_current()
255 cur = bci->usb_cur; in twl4030_charger_update_current()
256 bci->ac_is_active = false; in twl4030_charger_update_current()
257 if (cur > bci->usb_cur_target) { in twl4030_charger_update_current()
258 cur = bci->usb_cur_target; in twl4030_charger_update_current()
259 bci->usb_cur = cur; in twl4030_charger_update_current()
261 if (cur < bci->usb_cur_target) in twl4030_charger_update_current()
262 schedule_delayed_work(&bci->current_worker, USB_CUR_DELAY); in twl4030_charger_update_current()
266 if (bci->ichg_eoc >= 200000) in twl4030_charger_update_current()
268 if (bci->ichg_lo >= 400000) in twl4030_charger_update_current()
270 if (bci->ichg_hi >= 820000) in twl4030_charger_update_current()
295 reg = ua2regval(bci->ichg_eoc, cgain); in twl4030_charger_update_current()
307 reg = ua2regval(bci->ichg_lo, cgain); in twl4030_charger_update_current()
329 reg = ua2regval(bci->ichg_hi, cgain); in twl4030_charger_update_current()
388 /* Flip CGAIN and re-enable charging */ in twl4030_charger_update_current()
414 dev_dbg(bci->dev, "v=%d cur=%d limit=%d target=%d\n", v, curr, in twl4030_current_worker()
415 bci->usb_cur, bci->usb_cur_target); in twl4030_current_worker()
419 if (bci->usb_cur >= USB_CUR_STEP) in twl4030_current_worker()
420 bci->usb_cur -= USB_CUR_STEP; in twl4030_current_worker()
421 bci->usb_cur_target = bci->usb_cur; in twl4030_current_worker()
422 } else if (bci->usb_cur >= bci->usb_cur_target || in twl4030_current_worker()
423 bci->usb_cur + USB_CUR_STEP > USB_MAX_CURRENT) { in twl4030_current_worker()
424 /* Reached target and voltage is OK - stop */ in twl4030_current_worker()
427 bci->usb_cur += USB_CUR_STEP; in twl4030_current_worker()
428 schedule_delayed_work(&bci->current_worker, USB_CUR_DELAY); in twl4030_current_worker()
441 if (bci->usb_mode == CHARGE_OFF) in twl4030_charger_enable_usb()
443 if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { in twl4030_charger_enable_usb()
448 if (!bci->usb_enabled) { in twl4030_charger_enable_usb()
449 pm_runtime_get_sync(bci->transceiver->dev); in twl4030_charger_enable_usb()
450 bci->usb_enabled = 1; in twl4030_charger_enable_usb()
453 if (bci->usb_mode == CHARGE_AUTO) { in twl4030_charger_enable_usb()
461 dev_err(bci->dev, in twl4030_charger_enable_usb()
473 if (bci->usb_mode == CHARGE_LINEAR) { in twl4030_charger_enable_usb()
480 dev_err(bci->dev, in twl4030_charger_enable_usb()
501 /* ICHGEOCEN - end-of-charge monitor (current < 80mA) in twl4030_charger_enable_usb()
503 * ICHGLOWEN - current level monitor (charge continues) in twl4030_charger_enable_usb()
504 * don't monitor over-current or heat save in twl4030_charger_enable_usb()
513 if (bci->usb_enabled) { in twl4030_charger_enable_usb()
514 pm_runtime_mark_last_busy(bci->transceiver->dev); in twl4030_charger_enable_usb()
515 pm_runtime_put_autosuspend(bci->transceiver->dev); in twl4030_charger_enable_usb()
516 bci->usb_enabled = 0; in twl4030_charger_enable_usb()
518 bci->usb_cur = 0; in twl4030_charger_enable_usb()
525 * Enable/Disable AC Charge funtionality.
531 if (bci->ac_mode == CHARGE_OFF) in twl4030_charger_enable_ac()
586 * TWL4030 CHG_PRES (AC charger presence) events
592 dev_dbg(bci->dev, "CHG_PRES irq\n"); in twl4030_charger_interrupt()
594 bci->ac_cur = 500000; in twl4030_charger_interrupt()
596 power_supply_changed(bci->ac); in twl4030_charger_interrupt()
597 power_supply_changed(bci->usb); in twl4030_charger_interrupt()
621 dev_dbg(bci->dev, "BCI irq %02x %02x\n", irqs2, irqs1); in twl4030_bci_interrupt()
624 /* charger state change, inform the core */ in twl4030_bci_interrupt()
625 power_supply_changed(bci->ac); in twl4030_bci_interrupt()
626 power_supply_changed(bci->usb); in twl4030_bci_interrupt()
632 dev_warn(bci->dev, "battery temperature out of range\n"); in twl4030_bci_interrupt()
635 dev_crit(bci->dev, "battery disconnected\n"); in twl4030_bci_interrupt()
638 dev_crit(bci->dev, "VBAT overvoltage\n"); in twl4030_bci_interrupt()
641 dev_crit(bci->dev, "VBUS overvoltage\n"); in twl4030_bci_interrupt()
644 dev_crit(bci->dev, "Ac charger overvoltage\n"); in twl4030_bci_interrupt()
653 switch (bci->event) { in twl4030_bci_usb_work()
669 dev_dbg(bci->dev, "OTG notify %lu\n", val); in twl4030_bci_usb_ncb()
673 bci->usb_cur_target = 500000; in twl4030_bci_usb_ncb()
675 bci->usb_cur_target = 100000; in twl4030_bci_usb_ncb()
677 bci->event = val; in twl4030_bci_usb_ncb()
678 schedule_work(&bci->work); in twl4030_bci_usb_ncb()
684 * sysfs charger enabled store
690 struct twl4030_bci *bci = dev_get_drvdata(dev->parent); in twl4030_bci_mode_store()
698 if (dev == &bci->ac->dev) { in twl4030_bci_mode_store()
700 return -EINVAL; in twl4030_bci_mode_store()
702 bci->ac_mode = mode; in twl4030_bci_mode_store()
706 bci->usb_mode = mode; in twl4030_bci_mode_store()
713 * sysfs charger enabled show
719 struct twl4030_bci *bci = dev_get_drvdata(dev->parent); in twl4030_bci_mode_show()
722 int mode = bci->usb_mode; in twl4030_bci_mode_show()
724 if (dev == &bci->ac->dev) in twl4030_bci_mode_show()
725 mode = bci->ac_mode; in twl4030_bci_mode_show()
729 len += scnprintf(buf+len, PAGE_SIZE-len, in twl4030_bci_mode_show()
732 len += scnprintf(buf+len, PAGE_SIZE-len, in twl4030_bci_mode_show()
734 buf[len-1] = '\n'; in twl4030_bci_mode_show()
768 dev_err(bci->dev, "error reading BCIMSTATEC\n"); in twl4030bci_state()
772 dev_dbg(bci->dev, "state: %02x\n", state); in twl4030bci_state()
793 struct twl4030_bci *bci = dev_get_drvdata(psy->dev.parent); in twl4030_bci_get_property()
802 if (psy->desc->type == POWER_SUPPLY_TYPE_USB) in twl4030_bci_get_property()
811 if (psy->desc->type == POWER_SUPPLY_TYPE_USB) in twl4030_bci_get_property()
823 val->intval = twl4030_bci_state_to_status(state); in twl4030_bci_get_property()
825 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; in twl4030_bci_get_property()
830 return -ENODATA; in twl4030_bci_get_property()
831 if (psy->desc->type == POWER_SUPPLY_TYPE_USB) { in twl4030_bci_get_property()
836 val->intval = ret * 6843; in twl4030_bci_get_property()
842 val->intval = ret * 9775; in twl4030_bci_get_property()
847 return -ENODATA; in twl4030_bci_get_property()
848 /* current measurement is shared between AC and USB */ in twl4030_bci_get_property()
852 val->intval = ret; in twl4030_bci_get_property()
855 val->intval = is_charging && in twl4030_bci_get_property()
860 val->intval = -1; in twl4030_bci_get_property()
861 if (psy->desc->type != POWER_SUPPLY_TYPE_USB) { in twl4030_bci_get_property()
862 if (!bci->ac_is_active) in twl4030_bci_get_property()
863 val->intval = bci->ac_cur; in twl4030_bci_get_property()
865 if (bci->ac_is_active) in twl4030_bci_get_property()
866 val->intval = bci->usb_cur_target; in twl4030_bci_get_property()
868 if (val->intval < 0) { in twl4030_bci_get_property()
871 val->intval = twl4030bci_read_adc_val(TWL4030_BCIIREF1); in twl4030_bci_get_property()
872 if (val->intval < 0) in twl4030_bci_get_property()
873 return val->intval; in twl4030_bci_get_property()
877 val->intval = regval2ua(val->intval, bcictl1 & in twl4030_bci_get_property()
882 return -EINVAL; in twl4030_bci_get_property()
892 struct twl4030_bci *bci = dev_get_drvdata(psy->dev.parent); in twl4030_bci_set_property()
896 if (psy->desc->type == POWER_SUPPLY_TYPE_USB) in twl4030_bci_set_property()
897 bci->usb_cur_target = val->intval; in twl4030_bci_set_property()
899 bci->ac_cur = val->intval; in twl4030_bci_set_property()
903 return -EINVAL; in twl4030_bci_set_property()
932 struct device_node *np = dev->of_node; in twl4030_bci_parse_dt()
942 if (of_property_read_u32(np, "ti,bb-uvolt", &num) == 0) in twl4030_bci_parse_dt()
943 pdata->bb_uvolt = num; in twl4030_bci_parse_dt()
944 if (of_property_read_u32(np, "ti,bb-uamp", &num) == 0) in twl4030_bci_parse_dt()
945 pdata->bb_uamp = num; in twl4030_bci_parse_dt()
979 const struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data; in twl4030_bci_probe()
983 bci = devm_kzalloc(&pdev->dev, sizeof(*bci), GFP_KERNEL); in twl4030_bci_probe()
985 return -ENOMEM; in twl4030_bci_probe()
988 pdata = twl4030_bci_parse_dt(&pdev->dev); in twl4030_bci_probe()
990 bci->ichg_eoc = 80100; /* Stop charging when current drops to here */ in twl4030_bci_probe()
991 bci->ichg_lo = 241000; /* Low threshold */ in twl4030_bci_probe()
992 bci->ichg_hi = 500000; /* High threshold */ in twl4030_bci_probe()
993 bci->ac_cur = 500000; /* 500mA */ in twl4030_bci_probe()
995 bci->usb_cur_target = 500000; /* 500mA */ in twl4030_bci_probe()
997 bci->usb_cur_target = 100000; /* 100mA */ in twl4030_bci_probe()
998 bci->usb_mode = CHARGE_AUTO; in twl4030_bci_probe()
999 bci->ac_mode = CHARGE_AUTO; in twl4030_bci_probe()
1001 bci->dev = &pdev->dev; in twl4030_bci_probe()
1002 bci->irq_chg = platform_get_irq(pdev, 0); in twl4030_bci_probe()
1003 bci->irq_bci = platform_get_irq(pdev, 1); in twl4030_bci_probe()
1007 INIT_WORK(&bci->work, twl4030_bci_usb_work); in twl4030_bci_probe()
1008 INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker); in twl4030_bci_probe()
1010 bci->channel_vac = devm_iio_channel_get(&pdev->dev, "vac"); in twl4030_bci_probe()
1011 if (IS_ERR(bci->channel_vac)) { in twl4030_bci_probe()
1012 ret = PTR_ERR(bci->channel_vac); in twl4030_bci_probe()
1013 if (ret == -EPROBE_DEFER) in twl4030_bci_probe()
1015 dev_warn(&pdev->dev, "could not request vac iio channel (%d)", in twl4030_bci_probe()
1017 bci->channel_vac = NULL; in twl4030_bci_probe()
1020 if (bci->dev->of_node) { in twl4030_bci_probe()
1023 phynode = of_get_compatible_child(bci->dev->of_node->parent, in twl4030_bci_probe()
1024 "ti,twl4030-usb"); in twl4030_bci_probe()
1026 bci->usb_nb.notifier_call = twl4030_bci_usb_ncb; in twl4030_bci_probe()
1027 bci->transceiver = devm_usb_get_phy_by_node( in twl4030_bci_probe()
1028 bci->dev, phynode, &bci->usb_nb); in twl4030_bci_probe()
1030 if (IS_ERR(bci->transceiver)) { in twl4030_bci_probe()
1031 ret = PTR_ERR(bci->transceiver); in twl4030_bci_probe()
1032 if (ret == -EPROBE_DEFER) in twl4030_bci_probe()
1034 dev_warn(&pdev->dev, "could not request transceiver (%d)", in twl4030_bci_probe()
1036 bci->transceiver = NULL; in twl4030_bci_probe()
1041 bci->ac = devm_power_supply_register(&pdev->dev, &twl4030_bci_ac_desc, in twl4030_bci_probe()
1043 if (IS_ERR(bci->ac)) { in twl4030_bci_probe()
1044 ret = PTR_ERR(bci->ac); in twl4030_bci_probe()
1045 dev_err(&pdev->dev, "failed to register ac: %d\n", ret); in twl4030_bci_probe()
1049 bci->usb = devm_power_supply_register(&pdev->dev, &twl4030_bci_usb_desc, in twl4030_bci_probe()
1051 if (IS_ERR(bci->usb)) { in twl4030_bci_probe()
1052 ret = PTR_ERR(bci->usb); in twl4030_bci_probe()
1053 dev_err(&pdev->dev, "failed to register usb: %d\n", ret); in twl4030_bci_probe()
1057 ret = devm_request_threaded_irq(&pdev->dev, bci->irq_chg, NULL, in twl4030_bci_probe()
1058 twl4030_charger_interrupt, IRQF_ONESHOT, pdev->name, in twl4030_bci_probe()
1061 dev_err(&pdev->dev, "could not request irq %d, status %d\n", in twl4030_bci_probe()
1062 bci->irq_chg, ret); in twl4030_bci_probe()
1066 ret = devm_request_threaded_irq(&pdev->dev, bci->irq_bci, NULL, in twl4030_bci_probe()
1067 twl4030_bci_interrupt, IRQF_ONESHOT, pdev->name, bci); in twl4030_bci_probe()
1069 dev_err(&pdev->dev, "could not request irq %d, status %d\n", in twl4030_bci_probe()
1070 bci->irq_bci, ret); in twl4030_bci_probe()
1080 dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret); in twl4030_bci_probe()
1088 dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); in twl4030_bci_probe()
1091 if (device_create_file(&bci->usb->dev, &dev_attr_mode)) in twl4030_bci_probe()
1092 dev_warn(&pdev->dev, "could not create sysfs file\n"); in twl4030_bci_probe()
1093 if (device_create_file(&bci->ac->dev, &dev_attr_mode)) in twl4030_bci_probe()
1094 dev_warn(&pdev->dev, "could not create sysfs file\n"); in twl4030_bci_probe()
1097 if (!IS_ERR_OR_NULL(bci->transceiver)) in twl4030_bci_probe()
1098 twl4030_bci_usb_ncb(&bci->usb_nb, in twl4030_bci_probe()
1099 bci->transceiver->last_event, in twl4030_bci_probe()
1104 twl4030_charger_enable_backup(pdata->bb_uvolt, in twl4030_bci_probe()
1105 pdata->bb_uamp); in twl4030_bci_probe()
1120 device_remove_file(&bci->usb->dev, &dev_attr_mode); in twl4030_bci_remove()
1121 device_remove_file(&bci->ac->dev, &dev_attr_mode); in twl4030_bci_remove()
1132 {.compatible = "ti,twl4030-bci", },
1148 MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver");