Lines Matching +full:twl6030 +full:- +full:charger

1 // SPDX-License-Identifier: GPL-2.0-only
10 * Copyright (C) 2009-2010 Motorola, Inc.
23 #include <linux/nvmem-consumer.h>
28 #include <linux/mfd/motorola-cpcap.h>
32 * map to MC13783UG.pdf "Table 5-19. Register 13, Power Control 0"
48 * Register bit defines for CPCAP_REG_CCC1. These seem similar to the twl6030
49 * coulomb counter registers rather than the mc13892 registers. Both twl6030
51 * sets bit 0 to start the coulomb counter while twl6030 sets bit 0 to stop
52 * the coulomb counter like cpcap does. So for now, we use the twl6030 style
141 #define CPCAP_NO_BATTERY -400
153 return &ddata->state[state]; in cpcap_battery_get_state()
186 channel = ddata->channels[CPCAP_BATTERY_IIO_BATTDET]; in cpcap_charger_battery_temperature()
190 dev_warn(ddata->dev, "%s failed: %i\n", __func__, error); in cpcap_charger_battery_temperature()
206 channel = ddata->channels[CPCAP_BATTERY_IIO_VOLTAGE]; in cpcap_battery_get_voltage()
209 dev_warn(ddata->dev, "%s failed: %i\n", __func__, error); in cpcap_battery_get_voltage()
222 channel = ddata->channels[CPCAP_BATTERY_IIO_BATT_CURRENT]; in cpcap_battery_get_current()
225 dev_warn(ddata->dev, "%s failed: %i\n", __func__, error); in cpcap_battery_get_current()
234 * cpcap_battery_cc_raw_div - calculate and divide coulomb counter μAms values
249 * "TWL6030 Gas Gauging Basics (Rev. A)" swca095a.pdf in chapter
264 acc -= (s64)sample * offset; in cpcap_battery_cc_raw_div()
265 acc *= ddata->cc_lsb; in cpcap_battery_cc_raw_div()
266 acc *= -1; in cpcap_battery_cc_raw_div()
293 * cpcap_battery_read_accumulated - reads cpcap coulomb counter
299 * the coulomb counter in TWL6030. See "TWL6030 Gas Gauging Basics
314 ccd->sample = 0; in cpcap_battery_read_accumulated()
315 ccd->accumulator = 0; in cpcap_battery_read_accumulated()
316 ccd->offset = 0; in cpcap_battery_read_accumulated()
317 ccd->integrator = 0; in cpcap_battery_read_accumulated()
320 error = regmap_bulk_read(ddata->reg, CPCAP_REG_CCS1, in cpcap_battery_read_accumulated()
326 ccd->sample = (buf[1] & 0x0fff) << 16; in cpcap_battery_read_accumulated()
327 ccd->sample |= buf[0]; in cpcap_battery_read_accumulated()
328 if (ddata->vendor == CPCAP_VENDOR_TI) in cpcap_battery_read_accumulated()
329 ccd->sample = sign_extend32(24, ccd->sample); in cpcap_battery_read_accumulated()
332 ccd->accumulator = ((s16)buf[3]) << 16; in cpcap_battery_read_accumulated()
333 ccd->accumulator |= buf[2]; in cpcap_battery_read_accumulated()
339 ccd->offset = buf[4]; in cpcap_battery_read_accumulated()
340 ccd->offset = sign_extend32(ccd->offset, 9); in cpcap_battery_read_accumulated()
343 if (ddata->vendor == CPCAP_VENDOR_TI) in cpcap_battery_read_accumulated()
344 ccd->integrator = sign_extend32(buf[6], 13); in cpcap_battery_read_accumulated()
346 ccd->integrator = (s16)buf[6]; in cpcap_battery_read_accumulated()
349 ccd->sample, in cpcap_battery_read_accumulated()
350 ccd->accumulator, in cpcap_battery_read_accumulated()
351 ccd->offset); in cpcap_battery_read_accumulated()
401 if (strcmp(dev_name(dev), "89-500029ba0f73") == 0) in cpcap_battery_match_nvmem()
412 ddata->check_nvmem = false; in cpcap_battery_detect_battery_type()
416 ddata->check_nvmem = true; in cpcap_battery_detect_battery_type()
417 dev_info_once(ddata->dev, "Can not find battery nvmem device. Assuming generic lipo battery\n"); in cpcap_battery_detect_battery_type()
420 ddata->check_nvmem = true; in cpcap_battery_detect_battery_type()
421 dev_warn(ddata->dev, "Can not read battery nvmem device. Assuming generic lipo battery\n"); in cpcap_battery_detect_battery_type()
426 ddata->config = cpcap_battery_eb41_data; in cpcap_battery_detect_battery_type()
429 ddata->config = cpcap_battery_bw8x_data; in cpcap_battery_detect_battery_type()
432 ddata->config = cpcap_battery_unkown_data; in cpcap_battery_detect_battery_type()
437 * cpcap_battery_cc_get_avg_current - read cpcap coulumb counter
447 error = regmap_read(ddata->reg, CPCAP_REG_CCI, &value); in cpcap_battery_cc_get_avg_current()
451 if (ddata->vendor == CPCAP_VENDOR_TI) { in cpcap_battery_cc_get_avg_current()
460 error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value); in cpcap_battery_cc_get_avg_current()
473 struct power_supply *charger; in cpcap_battery_get_charger_status() local
476 charger = power_supply_get_by_name("usb"); in cpcap_battery_get_charger_status()
477 if (!charger) in cpcap_battery_get_charger_status()
478 return -ENODEV; in cpcap_battery_get_charger_status()
480 error = power_supply_get_property(charger, POWER_SUPPLY_PROP_STATUS, in cpcap_battery_get_charger_status()
487 power_supply_put(charger); in cpcap_battery_get_charger_status()
502 dev_dbg(ddata->dev, "charger disconnected\n"); in cpcap_battery_full()
503 ddata->is_full = 0; in cpcap_battery_full()
506 dev_dbg(ddata->dev, "charger full status\n"); in cpcap_battery_full()
507 ddata->is_full = 1; in cpcap_battery_full()
517 * on charger disconnect above anyways. in cpcap_battery_full()
519 vfull = ddata->config.bat.constant_charge_voltage_max_uv - 120000; in cpcap_battery_full()
521 if (ddata->is_full && state->voltage < vfull) in cpcap_battery_full()
522 ddata->is_full = 0; in cpcap_battery_full()
524 return ddata->is_full; in cpcap_battery_full()
532 if (state->current_ua > 0 && (state->voltage <= 3350000 || is_low)) in cpcap_battery_low()
552 s64 delta_ms = ktime_to_ms(ktime_sub(now, latest->time)); in cpcap_battery_update_status()
577 if (empty->voltage && empty->voltage != -1) { in cpcap_battery_update_status()
578 empty->voltage = -1; in cpcap_battery_update_status()
579 ddata->charge_full = in cpcap_battery_update_status()
580 empty->counter_uah - full->counter_uah; in cpcap_battery_update_status()
581 } else if (ddata->charge_full) { in cpcap_battery_update_status()
582 empty->voltage = -1; in cpcap_battery_update_status()
583 empty->counter_uah = in cpcap_battery_update_status()
584 full->counter_uah + ddata->charge_full; in cpcap_battery_update_status()
591 if (full->voltage) { in cpcap_battery_update_status()
592 full->voltage = 0; in cpcap_battery_update_status()
593 ddata->charge_full = in cpcap_battery_update_status()
594 empty->counter_uah - full->counter_uah; in cpcap_battery_update_status()
602 * Update battery status when cpcap-charger calls power_supply_changed().
603 * This allows us to detect battery full condition before the charger
653 if (ddata->check_nvmem) in cpcap_battery_get_property()
658 if (latest->temperature > CPCAP_NO_BATTERY || ignore_temperature_probe) in cpcap_battery_get_property()
659 val->intval = 1; in cpcap_battery_get_property()
661 val->intval = 0; in cpcap_battery_get_property()
665 val->intval = POWER_SUPPLY_STATUS_FULL; in cpcap_battery_get_property()
669 val->intval = POWER_SUPPLY_STATUS_CHARGING; in cpcap_battery_get_property()
671 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; in cpcap_battery_get_property()
674 val->intval = ddata->config.info.technology; in cpcap_battery_get_property()
677 val->intval = cpcap_battery_get_voltage(ddata); in cpcap_battery_get_property()
680 val->intval = ddata->config.info.voltage_max_design; in cpcap_battery_get_property()
683 val->intval = ddata->config.info.voltage_min_design; in cpcap_battery_get_property()
686 val->intval = ddata->config.bat.constant_charge_voltage_max_uv; in cpcap_battery_get_property()
689 sample = latest->cc.sample - previous->cc.sample; in cpcap_battery_get_property()
691 val->intval = cpcap_battery_cc_get_avg_current(ddata); in cpcap_battery_get_property()
694 accumulator = latest->cc.accumulator - previous->cc.accumulator; in cpcap_battery_get_property()
695 val->intval = cpcap_battery_cc_to_ua(ddata, sample, in cpcap_battery_get_property()
697 latest->cc.offset); in cpcap_battery_get_property()
700 val->intval = latest->current_ua; in cpcap_battery_get_property()
703 val->intval = latest->counter_uah; in cpcap_battery_get_property()
706 tmp = (latest->voltage / 10000) * latest->current_ua; in cpcap_battery_get_property()
707 val->intval = div64_s64(tmp, 100); in cpcap_battery_get_property()
710 sample = latest->cc.sample - previous->cc.sample; in cpcap_battery_get_property()
713 tmp *= (latest->voltage / 10000); in cpcap_battery_get_property()
714 val->intval = div64_s64(tmp, 100); in cpcap_battery_get_property()
717 accumulator = latest->cc.accumulator - previous->cc.accumulator; in cpcap_battery_get_property()
719 latest->cc.offset); in cpcap_battery_get_property()
720 tmp *= ((latest->voltage + previous->voltage) / 20000); in cpcap_battery_get_property()
721 val->intval = div64_s64(tmp, 100); in cpcap_battery_get_property()
725 if (!empty->voltage || !ddata->charge_full) in cpcap_battery_get_property()
726 return -ENODATA; in cpcap_battery_get_property()
727 /* (ddata->charge_full / 200) is needed for rounding */ in cpcap_battery_get_property()
728 val->intval = empty->counter_uah - latest->counter_uah + in cpcap_battery_get_property()
729 ddata->charge_full / 200; in cpcap_battery_get_property()
730 val->intval = clamp(val->intval, 0, ddata->charge_full); in cpcap_battery_get_property()
731 val->intval = val->intval * 100 / ddata->charge_full; in cpcap_battery_get_property()
735 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; in cpcap_battery_get_property()
736 else if (latest->voltage >= 3750000) in cpcap_battery_get_property()
737 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; in cpcap_battery_get_property()
738 else if (latest->voltage >= 3300000) in cpcap_battery_get_property()
739 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; in cpcap_battery_get_property()
740 else if (latest->voltage > 3100000) in cpcap_battery_get_property()
741 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; in cpcap_battery_get_property()
742 else if (latest->voltage <= 3100000) in cpcap_battery_get_property()
743 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; in cpcap_battery_get_property()
745 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; in cpcap_battery_get_property()
749 if (!empty->voltage) in cpcap_battery_get_property()
750 return -ENODATA; in cpcap_battery_get_property()
751 val->intval = empty->counter_uah - latest->counter_uah; in cpcap_battery_get_property()
752 if (val->intval < 0) { in cpcap_battery_get_property()
753 /* Assume invalid config if CHARGE_NOW is -20% */ in cpcap_battery_get_property()
754 if (ddata->charge_full && abs(val->intval) > ddata->charge_full/5) { in cpcap_battery_get_property()
755 empty->voltage = 0; in cpcap_battery_get_property()
756 ddata->charge_full = 0; in cpcap_battery_get_property()
757 return -ENODATA; in cpcap_battery_get_property()
759 val->intval = 0; in cpcap_battery_get_property()
760 } else if (ddata->charge_full && ddata->charge_full < val->intval) { in cpcap_battery_get_property()
762 if (val->intval > (6*ddata->charge_full)/5) { in cpcap_battery_get_property()
763 empty->voltage = 0; in cpcap_battery_get_property()
764 ddata->charge_full = 0; in cpcap_battery_get_property()
765 return -ENODATA; in cpcap_battery_get_property()
767 val->intval = ddata->charge_full; in cpcap_battery_get_property()
771 if (!ddata->charge_full) in cpcap_battery_get_property()
772 return -ENODATA; in cpcap_battery_get_property()
773 val->intval = ddata->charge_full; in cpcap_battery_get_property()
776 val->intval = ddata->config.info.charge_full_design; in cpcap_battery_get_property()
779 val->intval = POWER_SUPPLY_SCOPE_SYSTEM; in cpcap_battery_get_property()
783 return -ENODATA; in cpcap_battery_get_property()
784 val->intval = latest->temperature; in cpcap_battery_get_property()
787 return -EINVAL; in cpcap_battery_get_property()
798 struct power_supply *charger; in cpcap_battery_update_charger() local
801 charger = power_supply_get_by_name("usb"); in cpcap_battery_update_charger()
802 if (!charger) in cpcap_battery_update_charger()
803 return -ENODEV; in cpcap_battery_update_charger()
805 error = power_supply_get_property(charger, in cpcap_battery_update_charger()
811 /* Allow charger const voltage lower than battery const voltage */ in cpcap_battery_update_charger()
817 error = power_supply_set_property(charger, in cpcap_battery_update_charger()
821 power_supply_put(charger); in cpcap_battery_update_charger()
834 if (val->intval < ddata->config.info.voltage_min_design) in cpcap_battery_set_property()
835 return -EINVAL; in cpcap_battery_set_property()
836 if (val->intval > ddata->config.info.voltage_max_design) in cpcap_battery_set_property()
837 return -EINVAL; in cpcap_battery_set_property()
839 ddata->config.bat.constant_charge_voltage_max_uv = val->intval; in cpcap_battery_set_property()
841 return cpcap_battery_update_charger(ddata, val->intval); in cpcap_battery_set_property()
843 if (val->intval < 0) in cpcap_battery_set_property()
844 return -EINVAL; in cpcap_battery_set_property()
845 if (val->intval > (6*ddata->config.info.charge_full_design)/5) in cpcap_battery_set_property()
846 return -EINVAL; in cpcap_battery_set_property()
848 ddata->charge_full = val->intval; in cpcap_battery_set_property()
852 return -EINVAL; in cpcap_battery_set_property()
876 if (!atomic_read(&ddata->active)) in cpcap_battery_irq_thread()
879 list_for_each_entry(d, &ddata->irq_list, node) { in cpcap_battery_irq_thread()
880 if (irq == d->irq) in cpcap_battery_irq_thread()
884 if (list_entry_is_head(d, &ddata->irq_list, node)) in cpcap_battery_irq_thread()
889 switch (d->action) { in cpcap_battery_irq_thread()
891 dev_info(ddata->dev, "Coulomb counter calibration done\n"); in cpcap_battery_irq_thread()
894 if (latest->current_ua >= 0) in cpcap_battery_irq_thread()
895 dev_warn(ddata->dev, "Battery low at %imV!\n", in cpcap_battery_irq_thread()
896 latest->voltage / 1000); in cpcap_battery_irq_thread()
899 if (latest->current_ua >= 0 && latest->voltage <= 3200000) { in cpcap_battery_irq_thread()
900 dev_emerg(ddata->dev, in cpcap_battery_irq_thread()
902 latest->voltage / 1000); in cpcap_battery_irq_thread()
910 power_supply_changed(ddata->psy); in cpcap_battery_irq_thread()
926 error = devm_request_threaded_irq(ddata->dev, irq, NULL, in cpcap_battery_init_irq()
931 dev_err(ddata->dev, "could not get irq %s: %i\n", in cpcap_battery_init_irq()
937 d = devm_kzalloc(ddata->dev, sizeof(*d), GFP_KERNEL); in cpcap_battery_init_irq()
939 return -ENOMEM; in cpcap_battery_init_irq()
941 d->name = name; in cpcap_battery_init_irq()
942 d->irq = irq; in cpcap_battery_init_irq()
945 d->action = CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE; in cpcap_battery_init_irq()
947 d->action = CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW; in cpcap_battery_init_irq()
949 d->action = CPCAP_BATTERY_IRQ_ACTION_POWEROFF; in cpcap_battery_init_irq()
951 list_add(&d->node, &ddata->irq_list); in cpcap_battery_init_irq()
976 error = regmap_update_bits(ddata->reg, CPCAP_REG_BPEOL, in cpcap_battery_init_interrupts()
993 ddata->channels[i] = devm_iio_channel_get(ddata->dev, in cpcap_battery_init_iio()
995 if (IS_ERR(ddata->channels[i])) { in cpcap_battery_init_iio()
996 error = PTR_ERR(ddata->channels[i]); in cpcap_battery_init_iio()
1000 if (!ddata->channels[i]->indio_dev) { in cpcap_battery_init_iio()
1001 error = -ENXIO; in cpcap_battery_init_iio()
1009 return dev_err_probe(ddata->dev, error, in cpcap_battery_init_iio()
1019 error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &ccc1); in cpcap_battery_calibrate()
1026 error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1, in cpcap_battery_calibrate()
1033 error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &value); in cpcap_battery_calibrate()
1040 error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value); in cpcap_battery_calibrate()
1048 error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value); in cpcap_battery_calibrate()
1052 dev_info(ddata->dev, "calibration done: 0x%04x\n", value); in cpcap_battery_calibrate()
1056 dev_err(ddata->dev, "%s: error %i\n", __func__, error); in cpcap_battery_calibrate()
1058 error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1, in cpcap_battery_calibrate()
1061 dev_err(ddata->dev, "%s: restore error %i\n", in cpcap_battery_calibrate()
1070 .compatible = "motorola,cpcap-battery",
1094 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); in cpcap_battery_probe()
1096 return -ENOMEM; in cpcap_battery_probe()
1100 INIT_LIST_HEAD(&ddata->irq_list); in cpcap_battery_probe()
1101 ddata->dev = &pdev->dev; in cpcap_battery_probe()
1103 ddata->reg = dev_get_regmap(ddata->dev->parent, NULL); in cpcap_battery_probe()
1104 if (!ddata->reg) in cpcap_battery_probe()
1105 return -ENODEV; in cpcap_battery_probe()
1107 error = cpcap_get_vendor(ddata->dev, ddata->reg, &ddata->vendor); in cpcap_battery_probe()
1111 switch (ddata->vendor) { in cpcap_battery_probe()
1113 ddata->cc_lsb = 95374; /* μAms per LSB */ in cpcap_battery_probe()
1116 ddata->cc_lsb = 91501; /* μAms per LSB */ in cpcap_battery_probe()
1119 return -EINVAL; in cpcap_battery_probe()
1121 ddata->cc_lsb = (ddata->cc_lsb * ddata->config.cd_factor) / 1000; in cpcap_battery_probe()
1133 psy_cfg.of_node = pdev->dev.of_node; in cpcap_battery_probe()
1136 ddata->psy = devm_power_supply_register(ddata->dev, in cpcap_battery_probe()
1139 error = PTR_ERR_OR_ZERO(ddata->psy); in cpcap_battery_probe()
1141 dev_err(ddata->dev, "failed to register power supply\n"); in cpcap_battery_probe()
1145 atomic_set(&ddata->active, 1); in cpcap_battery_probe()
1159 atomic_set(&ddata->active, 0); in cpcap_battery_remove()
1160 error = regmap_update_bits(ddata->reg, CPCAP_REG_BPEOL, in cpcap_battery_remove()
1163 dev_err(&pdev->dev, "could not disable: %i\n", error); in cpcap_battery_remove()