aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/e300/rev_c/ltc4155.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/e300/rev_c/ltc4155.c')
-rw-r--r--firmware/e300/rev_c/ltc4155.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/firmware/e300/rev_c/ltc4155.c b/firmware/e300/rev_c/ltc4155.c
new file mode 100644
index 000000000..5f404e651
--- /dev/null
+++ b/firmware/e300/rev_c/ltc4155.c
@@ -0,0 +1,402 @@
+/*
+ * ltc4155.c
+ */
+
+#ifndef CHARGER_TI
+
+#include "config.h"
+#include "ltc4155.h"
+
+#include <util/delay.h>
+
+#include "io.h"
+#include "i2c.h"
+#include "power.h"
+#include "debug.h"
+#include "global.h"
+#include "error.h"
+
+static io_pin_t USBPM_IRQ = IO_PB(1);
+
+#ifdef ATTINY88_DIP
+
+static io_pin_t CHRG_SDA = IO_PC(2);
+static io_pin_t CHRG_SCL = IO_PC(3);
+
+#else
+
+#ifdef I2C_REWORK
+
+static io_pin_t CHRG_SDA = IO_PC(4);
+static io_pin_t CHRG_SCL = IO_PC(5);
+
+#else
+
+#define CHRG_SDA PWR_SDA
+#define CHRG_SCL PWR_SCL
+
+#endif // I2C_REWORK
+
+#endif // ATTINY88_DIP
+
+const bool _ltc4155_pull_up = false;
+
+#define LTC4155_BASE_ADDRESS 0x12
+#define LTC4155_WRITE_ADDRESS (LTC4155_BASE_ADDRESS + 0)
+#define LTC4155_READ_ADDRESS (LTC4155_BASE_ADDRESS + 1)
+/*
+#define LTC4155_RETRY_DELAY 1 // us MAGIC
+#define LTC4155_MAX_ACK_RETRIES 10 // * LTC4155_RETRY_DELAY us
+
+#define LTC4155_SCL_LOW_PERIOD 2 // 1.3 us
+#define LTC4155_SCL_HIGH_PERIOD 1 // 0.6 us
+#define LTC4155_BUS_FREE_TIME 2 // 1.3 us
+#define LTC4155_STOP_TIME 1 // 0.6 us
+*/
+enum LTC4155Registers
+{
+ LTC4155_REG_USB = 0x00, // W/R
+ LTC4155_REG_WALL = 0x01, // W/R
+ LTC4155_REG_CHARGE = 0x02, // W/R
+ LTC4155_REG_STATUS = 0x03, // R
+ LTC4155_REG_GOOD = 0x04, // R
+ LTC4155_REG_THERMISTOR = 0x05, // R
+ LTC4155_REG_ENABLE = 0x06, // W/R
+ LTC4155_REG_ARM_AND_SHIP= 0x07 // W
+};
+
+enum LTC4155InterruptMasks // LTC4155_REG_ENABLE
+{
+ LTC4155_ENABLE_USB_OTG = 1 << 1,
+
+ LTC4155_INT_UVCL = 1 << 2,
+ LTC4155_INT_ILIMIT = 1 << 3,
+ LTC4155_INT_USB_OTG = 1 << 4,
+ LTC4155_INT_EXT_PWR = 1 << 5,
+ LTC4155_INT_FAULT = 1 << 6,
+ LTC4155_INT_CHARGER = 1 << 7
+};
+
+enum LTC4155Options // LTC4155_REG_USB
+{
+ LTC4155_USB_OTG_LOCKOUT = 1 << 5,
+ LTC4155_ENABLE_BATTERY_CONDITIONER = 1 << 6,
+ LTC4155_DISABLE_INPUT_UVCL = 1 << 7
+};
+
+enum LTC4155Shifts
+{
+ LTC4155_SHIFTS_CHARGE_CURRENT_LIMIT = 4,
+ LTC4155_SHIFTS_CHARGE_FLOAT_VOLTAGE = 2,
+ LTC4155_SHIFTS_WALL_PRIORITY = 7,
+ LTC4155_SHIFTS_WALL_SAFETY_TIMER = 5
+};
+
+enum LTC4155Statuses // LTC4155_REG_STATUS
+{
+ LTC4155_LOW_BATTERY = 1 << 0,
+ LTC4155_BOOST_ENABLE = 1 << 3,
+ LTC4155_ID_PIN_DETECT = 1 << 4,
+};
+
+enum LTC4155Goods // LTC4155_REG_GOOD
+{
+ LTC4155_BAD_CELL_FAULT = 1 << 0,
+ LTC4155_OTG_FAULT = 1 << 1,
+ LTC4155_OVP_ACTIVE = 1 << 2,
+ LTC4155_INPUT_UVCL_ACTIVE = 1 << 3,
+ LTC4155_INPUT_CURRENT_LIMIT_ACTIVE = 1 << 4,
+ LTC4155_WALLSNS_GOOD = 1 << 5,
+ LTC4155_USBSNS_GOOD = 1 << 6,
+ LTC4155_EXTERNAL_POWER_GOOD = 1 << 7
+};
+
+enum LTC4155BatteryChargerStatues
+{
+ LTC4155_CHARGER_OFF,
+ LTC4155_CHARGER_LOW_BATTERY_VOLTAGE,
+ LTC4155_CHARGER_CONSTANT_CURRENT,
+ LTC4155_CHARGER_CONSTANT_VOLTAGE_VPROG_GT_VCX,
+ LTC4155_CHARGER_CONSTANT_VOLTAGE_VPROG_LT_VCX,
+ LTC4155_CHARGER_NTC_TOO_WARM,
+ LTC4155_CHARGER_NTC_TOO_COLD,
+ LTC4155_CHARGER_NTC_HOT
+};
+
+enum LTC4155ThermistorStatuses
+{
+ LTC4155_NTC_NORMAL,
+ LTC4155_NTC_TOO_COLD,
+ LTC4155_NTC_TOO_WARM,
+ LTC4155_NTC_FAULT
+};
+
+static const uint8_t _ltc4155_interrupt_mask =
+// LTC4155_ENABLE_USB_OTG |// Enable +5V on USB connector // Is this causing the chip to power off the output?!
+ LTC4155_INT_UVCL |
+ LTC4155_INT_ILIMIT |
+ LTC4155_INT_USB_OTG |
+ LTC4155_INT_EXT_PWR | // Turn up current limit
+ LTC4155_INT_FAULT | // Blink error
+ LTC4155_INT_CHARGER; // Illuminate charge LED
+
+static bool _ltc4155_clear_irq(void)
+{
+ return i2c_write_ex(CHRG_SDA, CHRG_SCL, LTC4155_WRITE_ADDRESS, LTC4155_REG_ENABLE, _ltc4155_interrupt_mask, _ltc4155_pull_up);
+}
+
+bool ltc4155_clear_irq(void)
+{
+ pmc_mask_irqs(true);
+
+ bool result = _ltc4155_clear_irq();
+
+ pmc_mask_irqs(false);
+
+ return result;
+}
+
+static uint8_t _ltc4155_last_good, _ltc4155_last_status;
+
+bool _ltc4155_handle_irq(void)
+{
+ _ltc4155_clear_irq(); // Clear frozen registers to get the real-time ones
+
+ _delay_ms(50); // Wait for registers to clear/update
+
+ //////////////////
+
+ uint8_t val = 0x00;
+ bool result = false;
+
+ if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_READ_ADDRESS, LTC4155_REG_GOOD, &val, _ltc4155_pull_up) == false)
+ goto _ltc4155_handle_fail;
+
+ //if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_READ_ADDRESS, LTC4155_REG_GOOD, &val, _ltc4155_pull_up) == false)
+ // goto _ltc4155_handle_fail;
+
+ debug_log_ex("4155GO ", false);
+ debug_log_hex(val);
+
+ if (val & LTC4155_WALLSNS_GOOD)
+ {
+ uint8_t wall_state = 0;
+ if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_READ_ADDRESS, LTC4155_REG_WALL, &wall_state, _ltc4155_pull_up) == false)
+ goto _ltc4155_handle_fail;
+
+ wall_state &= ~0x1E;
+ wall_state |= 0x0E;
+
+ if (i2c_write_ex(CHRG_SDA, CHRG_SCL, LTC4155_WRITE_ADDRESS, LTC4155_REG_WALL, wall_state, _ltc4155_pull_up) == false)
+ goto _ltc4155_handle_fail;
+
+ debug_log("I+");
+ }
+
+ _ltc4155_last_good = val;
+
+ if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_READ_ADDRESS, LTC4155_REG_STATUS, &val, _ltc4155_pull_up) == false)
+ goto _ltc4155_handle_fail;
+
+ //if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_READ_ADDRESS, LTC4155_REG_STATUS, &val, _ltc4155_pull_up) == false)
+ // goto _ltc4155_handle_fail;
+
+ debug_log_ex("4155ST ", false);
+ debug_log_hex(val);
+
+ _ltc4155_last_status = val;
+
+ val >>= 5;
+
+ if (_state.blink_error == BlinkError_None)
+ {
+ switch (val)
+ {
+ case LTC4155_CHARGER_CONSTANT_CURRENT:
+ case LTC4155_CHARGER_CONSTANT_VOLTAGE_VPROG_GT_VCX:
+ case LTC4155_CHARGER_LOW_BATTERY_VOLTAGE: // If this persists for more than 1/2hr, BAD_CELL_FAULT is enabled and FAULT interrupt is generated
+ {
+ if ((_state.battery_not_present == false) &&
+ (_ltc4155_last_good & (LTC4155_WALLSNS_GOOD | LTC4155_USBSNS_GOOD)))
+ {
+ //charge_set_led(true);
+ charge_notify(true);
+ break;
+ }
+ }
+ case LTC4155_CHARGER_CONSTANT_VOLTAGE_VPROG_LT_VCX: // Small amount of current still charging the battery but below Vc/x threshold
+ //case LTC4155_CHARGER_NTC_TOO_WARM:
+ //case LTC4155_CHARGER_NTC_TOO_COLD:
+ //case LTC4155_CHARGER_NTC_HOT:
+ // break;
+ //case LTC4155_CHARGER_OFF:
+ default:
+ //charge_set_led(false);
+ charge_notify(false);
+ }
+ }
+
+// ltc4155_dump();
+
+ result = true;
+_ltc4155_handle_fail:
+ _ltc4155_clear_irq(); // Even though it happens first above, this is necessary otherwise future IRQs won't be detected
+
+ return result;
+}
+
+#define LTC4155_CHARGE_CURRENT_LIMIT /*0xF*/0x7 // [100%] 50%
+
+bool ltc4155_set_charge_current_limit(uint8_t percentage)
+{
+ uint8_t val = 0;
+ uint8_t limit = 0;
+
+ if (percentage > 100)
+ return false;
+ else if (percentage == 100)
+ percentage = 0xF;
+ else if (percentage > 12) // 0..88 -> 0..8800
+ {
+ uint16_t l = (((uint16_t)percentage - 12) * 100) / 586;
+ limit = (uint8_t)l;
+ }
+
+ if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_WRITE_ADDRESS, LTC4155_REG_CHARGE, &val, _ltc4155_pull_up) == false)
+ return false;
+
+ val &= ((0x1 << LTC4155_SHIFTS_CHARGE_CURRENT_LIMIT) - 1);
+ //val |= (LTC4155_CHARGE_CURRENT_LIMIT << LTC4155_SHIFTS_CHARGE_CURRENT_LIMIT);
+ val |= (limit << LTC4155_SHIFTS_CHARGE_CURRENT_LIMIT);
+
+ if (i2c_write_ex(CHRG_SDA, CHRG_SCL, LTC4155_WRITE_ADDRESS, LTC4155_REG_CHARGE, val, _ltc4155_pull_up) == false)
+ return false;
+
+//ltc4155_dump();
+
+ return true;
+}
+
+bool ltc4155_init(bool disable_charger)
+{
+ io_input_pin(USBPM_IRQ);
+#if !defined(DEBUG) && !defined(ATTINY88_DIP)
+ io_set_pin(USBPM_IRQ); // Enable pull-up for Open Drain
+#endif // DEBUG
+#ifdef I2C_REWORK
+ i2c_init_ex(CHRG_SDA, CHRG_SCL, _ltc4155_pull_up);
+#endif // I2C_REWORK
+ if (/*_ltc4155_clear_irq()*/_ltc4155_handle_irq() == false) // Will set interrupt masks // FIXME: Why does this cause instability?!
+ return false;
+
+ const uint8_t charge_state =
+ (disable_charger ? 0x0 : LTC4155_CHARGE_CURRENT_LIMIT) << LTC4155_SHIFTS_CHARGE_CURRENT_LIMIT | // Battery charger I limit = 100%
+ 0x3 << LTC4155_SHIFTS_CHARGE_FLOAT_VOLTAGE | // FIXME: Vbatt float = 4.05V - 4.2V for LiPo (default 0x00)
+ 0x0; // Full capacity charge threshold = 10%
+ if (i2c_write_ex(CHRG_SDA, CHRG_SCL, LTC4155_WRITE_ADDRESS, LTC4155_REG_CHARGE, charge_state, _ltc4155_pull_up) == false)
+ return false;
+
+ const uint8_t wall_state =
+ 0x0 << LTC4155_SHIFTS_WALL_PRIORITY |
+ 0x0 << LTC4155_SHIFTS_WALL_SAFETY_TIMER | // Charge safety timer = 4hr // FIXME: 8hr or Vc/x
+ 0xE; // 3 amps, 0x1F - CLPROG1
+ if (i2c_write_ex(CHRG_SDA, CHRG_SCL, LTC4155_WRITE_ADDRESS, LTC4155_REG_WALL, wall_state, _ltc4155_pull_up) == false)
+ return false;
+
+ // FIXME:
+ // Disable ID pin detection & autonomous startup
+ // Enable OTG
+ //i2c_write_ex(CHRG_SDA, CHRG_SCL, LTC4155_WRITE_ADDRESS, LTC4155_REG_USB, LTC4155_USB_OTG_LOCKOUT, _ltc4155_pull_up); // Disable autonomous startup
+ //i2c_write_ex(CHRG_SDA, CHRG_SCL, LTC4155_WRITE_ADDRESS, LTC4155_REG_ENABLE, LTC4155_ENABLE_USB_OTG, _ltc4155_pull_up); // Enable OTG
+
+ if (_ltc4155_handle_irq() == false) // One more time (IRQ LED stays lit in dev setup)
+ return false;
+
+ return true;
+}
+
+bool ltc4155_has_interrupt(void)
+{
+ //bool state = io_test_pin(USBPM_IRQ);
+ //debug_log_ex("4155IRQ", false);
+ //debug_log_byte(state);
+ //return (state != 1);
+ return (io_test_pin(USBPM_IRQ) == false);
+}
+
+bool ltc4155_handle_irq(void)
+{
+ pmc_mask_irqs(true);
+
+ bool result = _ltc4155_handle_irq();
+
+ pmc_mask_irqs(false);
+
+ return result;
+}
+
+bool ltc4155_arm_ship_and_store(void)
+{
+ return true;
+}
+
+bool ltc4155_get_thermistor(uint8_t* val, bool* warning)
+{
+ bool result = false;
+ uint8_t _val = 0;
+
+ pmc_mask_irqs(true);
+
+ if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_READ_ADDRESS, LTC4155_REG_THERMISTOR, &_val, _ltc4155_pull_up) == false)
+ goto ltc4155_get_thermistor_fail;
+
+ if (val)
+ (*val) = _val >> 1;
+
+ if (warning)
+ (*warning) = ((_val & 0x01) != 0x00);
+
+ result = true;
+ltc4155_get_thermistor_fail:
+ pmc_mask_irqs(false);
+ return result;
+}
+
+void ltc4155_dump(void)
+{
+ pmc_mask_irqs(true);
+
+ uint8_t val = 0x00;
+ bool warning = false;
+
+ if (ltc4155_get_thermistor(&val, &warning) == false)
+ goto ltc4155_dump_fail;
+
+ debug_log_ex("\tTHRM", false);
+ if (warning)
+ debug_log_ex("!", false);
+ debug_log_byte(val);
+
+ if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_READ_ADDRESS, LTC4155_REG_WALL, &val, _ltc4155_pull_up) == false)
+ goto ltc4155_dump_fail;
+
+ debug_log_ex("\tWALL", false);
+ debug_log_hex(val);
+
+ if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_READ_ADDRESS, LTC4155_REG_GOOD, &val, _ltc4155_pull_up) == false)
+ goto ltc4155_dump_fail;
+
+ debug_log_ex("\t4155GO ", false);
+ debug_log_hex(val);
+
+ if (i2c_read2_ex(CHRG_SDA, CHRG_SCL, LTC4155_READ_ADDRESS, LTC4155_REG_STATUS, &val, _ltc4155_pull_up) == false)
+ goto ltc4155_dump_fail;
+
+ debug_log_ex("\t4155ST ", false);
+ debug_log_hex(val);
+
+ltc4155_dump_fail:
+ pmc_mask_irqs(false);
+}
+
+#endif // !CHARGER_TI