Lines Matching +full:full +full:- +full:bit
9 * Copyright (C) 2009-2010 Motorola, Inc.
35 #include <linux/mfd/motorola-cpcap.h>
38 * Register bit defines for CPCAP_REG_BPEOL. Some of these seem to
39 * map to MC13783UG.pdf "Table 5-19. Register 13, Power Control 0"
43 #define CPCAP_REG_BPEOL_BIT_EOL9 BIT(9) /* Set for EOL irq */
44 #define CPCAP_REG_BPEOL_BIT_EOL8 BIT(8) /* Set for EOL irq */
45 #define CPCAP_REG_BPEOL_BIT_UNKNOWN7 BIT(7)
46 #define CPCAP_REG_BPEOL_BIT_UNKNOWN6 BIT(6)
47 #define CPCAP_REG_BPEOL_BIT_UNKNOWN5 BIT(5)
48 #define CPCAP_REG_BPEOL_BIT_EOL_MULTI BIT(4) /* Set for multiple EOL irqs */
49 #define CPCAP_REG_BPEOL_BIT_UNKNOWN3 BIT(3)
50 #define CPCAP_REG_BPEOL_BIT_UNKNOWN2 BIT(2)
51 #define CPCAP_REG_BPEOL_BIT_BATTDETEN BIT(1) /* Enable battery detect */
52 #define CPCAP_REG_BPEOL_BIT_EOLSEL BIT(0) /* BPDET = 0, EOL = 1 */
55 * Register bit defines for CPCAP_REG_CCC1. These seem similar to the twl6030
58 * sets bit 0 to start the coulomb counter while twl6030 sets bit 0 to stop
62 #define CPCAP_REG_CCC1_ACTIVE_MODE1 BIT(4) /* Update rate */
63 #define CPCAP_REG_CCC1_ACTIVE_MODE0 BIT(3) /* Update rate */
64 #define CPCAP_REG_CCC1_AUTOCLEAR BIT(2) /* Resets sample registers */
65 #define CPCAP_REG_CCC1_CAL_EN BIT(1) /* Clears after write in 1s */
66 #define CPCAP_REG_CCC1_PAUSE BIT(0) /* Stop counters, allow write */
70 #define CPCAP_REG_CCCC2_RATE1 BIT(5)
71 #define CPCAP_REG_CCCC2_RATE0 BIT(4)
72 #define CPCAP_REG_CCCC2_ENABLE BIT(3)
144 #define CPCAP_NO_BATTERY -400
156 return &ddata->state[state]; in cpcap_battery_get_state()
189 channel = ddata->channels[CPCAP_BATTERY_IIO_BATTDET]; in cpcap_charger_battery_temperature()
193 dev_warn(ddata->dev, "%s failed: %i\n", __func__, error); in cpcap_charger_battery_temperature()
209 channel = ddata->channels[CPCAP_BATTERY_IIO_VOLTAGE]; in cpcap_battery_get_voltage()
212 dev_warn(ddata->dev, "%s failed: %i\n", __func__, error); in cpcap_battery_get_voltage()
225 channel = ddata->channels[CPCAP_BATTERY_IIO_BATT_CURRENT]; in cpcap_battery_get_current()
228 dev_warn(ddata->dev, "%s failed: %i\n", __func__, error); in cpcap_battery_get_current()
237 * cpcap_battery_cc_raw_div - calculate and divide coulomb counter μAms values
267 acc -= (s64)sample * offset; in cpcap_battery_cc_raw_div()
268 acc *= ddata->cc_lsb; in cpcap_battery_cc_raw_div()
269 acc *= -1; in cpcap_battery_cc_raw_div()
296 * cpcap_battery_read_accumulated - reads cpcap coulomb counter
317 ccd->sample = 0; in cpcap_battery_read_accumulated()
318 ccd->accumulator = 0; in cpcap_battery_read_accumulated()
319 ccd->offset = 0; in cpcap_battery_read_accumulated()
320 ccd->integrator = 0; in cpcap_battery_read_accumulated()
323 error = regmap_bulk_read(ddata->reg, CPCAP_REG_CCS1, in cpcap_battery_read_accumulated()
329 ccd->sample = (buf[1] & 0x0fff) << 16; in cpcap_battery_read_accumulated()
330 ccd->sample |= buf[0]; in cpcap_battery_read_accumulated()
331 if (ddata->vendor == CPCAP_VENDOR_TI) in cpcap_battery_read_accumulated()
332 ccd->sample = sign_extend32(24, ccd->sample); in cpcap_battery_read_accumulated()
335 ccd->accumulator = ((s16)buf[3]) << 16; in cpcap_battery_read_accumulated()
336 ccd->accumulator |= buf[2]; in cpcap_battery_read_accumulated()
342 ccd->offset = buf[4]; in cpcap_battery_read_accumulated()
343 ccd->offset = sign_extend32(ccd->offset, 9); in cpcap_battery_read_accumulated()
346 if (ddata->vendor == CPCAP_VENDOR_TI) in cpcap_battery_read_accumulated()
347 ccd->integrator = sign_extend32(buf[6], 13); in cpcap_battery_read_accumulated()
349 ccd->integrator = (s16)buf[6]; in cpcap_battery_read_accumulated()
352 ccd->sample, in cpcap_battery_read_accumulated()
353 ccd->accumulator, in cpcap_battery_read_accumulated()
354 ccd->offset); in cpcap_battery_read_accumulated()
358 * cpcap_battery_cc_get_avg_current - read cpcap coulumb counter
368 error = regmap_read(ddata->reg, CPCAP_REG_CCI, &value); in cpcap_battery_cc_get_avg_current()
372 if (ddata->vendor == CPCAP_VENDOR_TI) { in cpcap_battery_cc_get_avg_current()
381 error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value); in cpcap_battery_cc_get_avg_current()
399 return -ENODEV; in cpcap_battery_get_charger_status()
423 dev_dbg(ddata->dev, "charger disconnected\n"); in cpcap_battery_full()
424 ddata->is_full = 0; in cpcap_battery_full()
427 dev_dbg(ddata->dev, "charger full status\n"); in cpcap_battery_full()
428 ddata->is_full = 1; in cpcap_battery_full()
436 * The full battery voltage here can be inaccurate, it's used just to in cpcap_battery_full()
440 vfull = ddata->config.bat.constant_charge_voltage_max_uv - 120000; in cpcap_battery_full()
442 if (ddata->is_full && state->voltage < vfull) in cpcap_battery_full()
443 ddata->is_full = 0; in cpcap_battery_full()
445 return ddata->is_full; in cpcap_battery_full()
453 if (state->current_ua > 0 && (state->voltage <= 3350000 || is_low)) in cpcap_battery_low()
464 *empty, *full; in cpcap_battery_update_status() local
473 s64 delta_ms = ktime_to_ms(ktime_sub(now, latest->time)); in cpcap_battery_update_status()
494 full = cpcap_battery_get_full(ddata); in cpcap_battery_update_status()
495 memcpy(full, latest, sizeof(*full)); in cpcap_battery_update_status()
498 if (empty->voltage && empty->voltage != -1) { in cpcap_battery_update_status()
499 empty->voltage = -1; in cpcap_battery_update_status()
500 ddata->charge_full = in cpcap_battery_update_status()
501 empty->counter_uah - full->counter_uah; in cpcap_battery_update_status()
502 } else if (ddata->charge_full) { in cpcap_battery_update_status()
503 empty->voltage = -1; in cpcap_battery_update_status()
504 empty->counter_uah = in cpcap_battery_update_status()
505 full->counter_uah + ddata->charge_full; in cpcap_battery_update_status()
511 full = cpcap_battery_get_full(ddata); in cpcap_battery_update_status()
512 if (full->voltage) { in cpcap_battery_update_status()
513 full->voltage = 0; in cpcap_battery_update_status()
514 ddata->charge_full = in cpcap_battery_update_status()
515 empty->counter_uah - full->counter_uah; in cpcap_battery_update_status()
523 * Update battery status when cpcap-charger calls power_supply_changed().
524 * This allows us to detect battery full condition before the charger
576 if (latest->temperature > CPCAP_NO_BATTERY || ignore_temperature_probe) in cpcap_battery_get_property()
577 val->intval = 1; in cpcap_battery_get_property()
579 val->intval = 0; in cpcap_battery_get_property()
583 val->intval = POWER_SUPPLY_STATUS_FULL; in cpcap_battery_get_property()
587 val->intval = POWER_SUPPLY_STATUS_CHARGING; in cpcap_battery_get_property()
589 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; in cpcap_battery_get_property()
592 val->intval = ddata->config.info.technology; in cpcap_battery_get_property()
595 val->intval = cpcap_battery_get_voltage(ddata); in cpcap_battery_get_property()
598 val->intval = ddata->config.info.voltage_max_design; in cpcap_battery_get_property()
601 val->intval = ddata->config.info.voltage_min_design; in cpcap_battery_get_property()
604 val->intval = ddata->config.bat.constant_charge_voltage_max_uv; in cpcap_battery_get_property()
607 sample = latest->cc.sample - previous->cc.sample; in cpcap_battery_get_property()
609 val->intval = cpcap_battery_cc_get_avg_current(ddata); in cpcap_battery_get_property()
612 accumulator = latest->cc.accumulator - previous->cc.accumulator; in cpcap_battery_get_property()
613 val->intval = cpcap_battery_cc_to_ua(ddata, sample, in cpcap_battery_get_property()
615 latest->cc.offset); in cpcap_battery_get_property()
618 val->intval = latest->current_ua; in cpcap_battery_get_property()
621 val->intval = latest->counter_uah; in cpcap_battery_get_property()
624 tmp = (latest->voltage / 10000) * latest->current_ua; in cpcap_battery_get_property()
625 val->intval = div64_s64(tmp, 100); in cpcap_battery_get_property()
628 sample = latest->cc.sample - previous->cc.sample; in cpcap_battery_get_property()
631 tmp *= (latest->voltage / 10000); in cpcap_battery_get_property()
632 val->intval = div64_s64(tmp, 100); in cpcap_battery_get_property()
635 accumulator = latest->cc.accumulator - previous->cc.accumulator; in cpcap_battery_get_property()
637 latest->cc.offset); in cpcap_battery_get_property()
638 tmp *= ((latest->voltage + previous->voltage) / 20000); in cpcap_battery_get_property()
639 val->intval = div64_s64(tmp, 100); in cpcap_battery_get_property()
643 if (!empty->voltage || !ddata->charge_full) in cpcap_battery_get_property()
644 return -ENODATA; in cpcap_battery_get_property()
645 /* (ddata->charge_full / 200) is needed for rounding */ in cpcap_battery_get_property()
646 val->intval = empty->counter_uah - latest->counter_uah + in cpcap_battery_get_property()
647 ddata->charge_full / 200; in cpcap_battery_get_property()
648 val->intval = clamp(val->intval, 0, ddata->charge_full); in cpcap_battery_get_property()
649 val->intval = val->intval * 100 / ddata->charge_full; in cpcap_battery_get_property()
653 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; in cpcap_battery_get_property()
654 else if (latest->voltage >= 3750000) in cpcap_battery_get_property()
655 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; in cpcap_battery_get_property()
656 else if (latest->voltage >= 3300000) in cpcap_battery_get_property()
657 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; in cpcap_battery_get_property()
658 else if (latest->voltage > 3100000) in cpcap_battery_get_property()
659 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; in cpcap_battery_get_property()
660 else if (latest->voltage <= 3100000) in cpcap_battery_get_property()
661 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; in cpcap_battery_get_property()
663 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; in cpcap_battery_get_property()
667 if (!empty->voltage) in cpcap_battery_get_property()
668 return -ENODATA; in cpcap_battery_get_property()
669 val->intval = empty->counter_uah - latest->counter_uah; in cpcap_battery_get_property()
670 if (val->intval < 0) { in cpcap_battery_get_property()
671 /* Assume invalid config if CHARGE_NOW is -20% */ in cpcap_battery_get_property()
672 if (ddata->charge_full && abs(val->intval) > ddata->charge_full/5) { in cpcap_battery_get_property()
673 empty->voltage = 0; in cpcap_battery_get_property()
674 ddata->charge_full = 0; in cpcap_battery_get_property()
675 return -ENODATA; in cpcap_battery_get_property()
677 val->intval = 0; in cpcap_battery_get_property()
678 } else if (ddata->charge_full && ddata->charge_full < val->intval) { in cpcap_battery_get_property()
680 if (val->intval > (6*ddata->charge_full)/5) { in cpcap_battery_get_property()
681 empty->voltage = 0; in cpcap_battery_get_property()
682 ddata->charge_full = 0; in cpcap_battery_get_property()
683 return -ENODATA; in cpcap_battery_get_property()
685 val->intval = ddata->charge_full; in cpcap_battery_get_property()
689 if (!ddata->charge_full) in cpcap_battery_get_property()
690 return -ENODATA; in cpcap_battery_get_property()
691 val->intval = ddata->charge_full; in cpcap_battery_get_property()
694 val->intval = ddata->config.info.charge_full_design; in cpcap_battery_get_property()
697 val->intval = POWER_SUPPLY_SCOPE_SYSTEM; in cpcap_battery_get_property()
701 return -ENODATA; in cpcap_battery_get_property()
702 val->intval = latest->temperature; in cpcap_battery_get_property()
705 return -EINVAL; in cpcap_battery_get_property()
721 return -ENODEV; in cpcap_battery_update_charger()
752 if (val->intval < ddata->config.info.voltage_min_design) in cpcap_battery_set_property()
753 return -EINVAL; in cpcap_battery_set_property()
754 if (val->intval > ddata->config.info.voltage_max_design) in cpcap_battery_set_property()
755 return -EINVAL; in cpcap_battery_set_property()
757 ddata->config.bat.constant_charge_voltage_max_uv = val->intval; in cpcap_battery_set_property()
759 return cpcap_battery_update_charger(ddata, val->intval); in cpcap_battery_set_property()
761 if (val->intval < 0) in cpcap_battery_set_property()
762 return -EINVAL; in cpcap_battery_set_property()
763 if (val->intval > (6*ddata->config.info.charge_full_design)/5) in cpcap_battery_set_property()
764 return -EINVAL; in cpcap_battery_set_property()
766 ddata->charge_full = val->intval; in cpcap_battery_set_property()
770 return -EINVAL; in cpcap_battery_set_property()
794 if (!atomic_read(&ddata->active)) in cpcap_battery_irq_thread()
797 list_for_each_entry(d, &ddata->irq_list, node) { in cpcap_battery_irq_thread()
798 if (irq == d->irq) in cpcap_battery_irq_thread()
802 if (list_entry_is_head(d, &ddata->irq_list, node)) in cpcap_battery_irq_thread()
807 switch (d->action) { in cpcap_battery_irq_thread()
809 dev_info(ddata->dev, "Coulomb counter calibration done\n"); in cpcap_battery_irq_thread()
812 if (latest->current_ua >= 0) in cpcap_battery_irq_thread()
813 dev_warn(ddata->dev, "Battery low at %imV!\n", in cpcap_battery_irq_thread()
814 latest->voltage / 1000); in cpcap_battery_irq_thread()
817 if (latest->current_ua >= 0 && latest->voltage <= 3200000) { in cpcap_battery_irq_thread()
818 dev_emerg(ddata->dev, in cpcap_battery_irq_thread()
820 latest->voltage / 1000); in cpcap_battery_irq_thread()
828 power_supply_changed(ddata->psy); in cpcap_battery_irq_thread()
844 error = devm_request_threaded_irq(ddata->dev, irq, NULL, in cpcap_battery_init_irq()
849 dev_err(ddata->dev, "could not get irq %s: %i\n", in cpcap_battery_init_irq()
855 d = devm_kzalloc(ddata->dev, sizeof(*d), GFP_KERNEL); in cpcap_battery_init_irq()
857 return -ENOMEM; in cpcap_battery_init_irq()
859 d->name = name; in cpcap_battery_init_irq()
860 d->irq = irq; in cpcap_battery_init_irq()
863 d->action = CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE; in cpcap_battery_init_irq()
865 d->action = CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW; in cpcap_battery_init_irq()
867 d->action = CPCAP_BATTERY_IRQ_ACTION_POWEROFF; in cpcap_battery_init_irq()
869 list_add(&d->node, &ddata->irq_list); in cpcap_battery_init_irq()
894 error = regmap_update_bits(ddata->reg, CPCAP_REG_BPEOL, in cpcap_battery_init_interrupts()
911 ddata->channels[i] = devm_iio_channel_get(ddata->dev, in cpcap_battery_init_iio()
913 if (IS_ERR(ddata->channels[i])) { in cpcap_battery_init_iio()
914 error = PTR_ERR(ddata->channels[i]); in cpcap_battery_init_iio()
918 if (!ddata->channels[i]->indio_dev) { in cpcap_battery_init_iio()
919 error = -ENXIO; in cpcap_battery_init_iio()
927 return dev_err_probe(ddata->dev, error, in cpcap_battery_init_iio()
937 error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &ccc1); in cpcap_battery_calibrate()
944 error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1, in cpcap_battery_calibrate()
951 error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &value); in cpcap_battery_calibrate()
958 error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value); in cpcap_battery_calibrate()
966 error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value); in cpcap_battery_calibrate()
970 dev_info(ddata->dev, "calibration done: 0x%04x\n", value); in cpcap_battery_calibrate()
974 dev_err(ddata->dev, "%s: error %i\n", __func__, error); in cpcap_battery_calibrate()
976 error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1, in cpcap_battery_calibrate()
979 dev_err(ddata->dev, "%s: restore error %i\n", in cpcap_battery_calibrate()
991 * And looking at the battery full and shutdown values for the stock
992 * kernel on droid 4, full is 4351000 and software initiates shutdown
1007 .compatible = "motorola,cpcap-battery",
1034 &pdev->dev); in cpcap_battery_probe()
1036 return -EINVAL; in cpcap_battery_probe()
1038 if (!match->data) { in cpcap_battery_probe()
1039 dev_err(&pdev->dev, "no configuration data found\n"); in cpcap_battery_probe()
1041 return -ENODEV; in cpcap_battery_probe()
1044 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); in cpcap_battery_probe()
1046 return -ENOMEM; in cpcap_battery_probe()
1048 INIT_LIST_HEAD(&ddata->irq_list); in cpcap_battery_probe()
1049 ddata->dev = &pdev->dev; in cpcap_battery_probe()
1050 memcpy(&ddata->config, match->data, sizeof(ddata->config)); in cpcap_battery_probe()
1052 ddata->reg = dev_get_regmap(ddata->dev->parent, NULL); in cpcap_battery_probe()
1053 if (!ddata->reg) in cpcap_battery_probe()
1054 return -ENODEV; in cpcap_battery_probe()
1056 error = cpcap_get_vendor(ddata->dev, ddata->reg, &ddata->vendor); in cpcap_battery_probe()
1060 switch (ddata->vendor) { in cpcap_battery_probe()
1062 ddata->cc_lsb = 95374; /* μAms per LSB */ in cpcap_battery_probe()
1065 ddata->cc_lsb = 91501; /* μAms per LSB */ in cpcap_battery_probe()
1068 return -EINVAL; in cpcap_battery_probe()
1070 ddata->cc_lsb = (ddata->cc_lsb * ddata->config.cd_factor) / 1000; in cpcap_battery_probe()
1082 psy_cfg.of_node = pdev->dev.of_node; in cpcap_battery_probe()
1085 ddata->psy = devm_power_supply_register(ddata->dev, in cpcap_battery_probe()
1088 error = PTR_ERR_OR_ZERO(ddata->psy); in cpcap_battery_probe()
1090 dev_err(ddata->dev, "failed to register power supply\n"); in cpcap_battery_probe()
1094 atomic_set(&ddata->active, 1); in cpcap_battery_probe()
1108 atomic_set(&ddata->active, 0); in cpcap_battery_remove()
1109 error = regmap_update_bits(ddata->reg, CPCAP_REG_BPEOL, in cpcap_battery_remove()
1112 dev_err(&pdev->dev, "could not disable: %i\n", error); in cpcap_battery_remove()