summaryrefslogtreecommitdiff
path: root/common/inductive_charging.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/inductive_charging.c')
-rw-r--r--common/inductive_charging.c60
1 files changed, 56 insertions, 4 deletions
diff --git a/common/inductive_charging.c b/common/inductive_charging.c
index 0021cc3ac6..8b92394c8c 100644
--- a/common/inductive_charging.c
+++ b/common/inductive_charging.c
@@ -8,22 +8,74 @@
#include "common.h"
#include "gpio.h"
#include "hooks.h"
+#include "inductive_charging.h"
#include "lid_switch.h"
#include "timer.h"
+/*
+ * The inductive charger is controlled with two signals:
+ * - BASE_CHG_VDD_EN controls whether the charger is powered.
+ * - CHARGE_EN controls whether to enable charging.
+ * Charging status is reported via CHARGE_DONE, but in a tricky way:
+ * - It's 0 if:
+ * + The charger is unpowered. (i.e. BASE_CHG_VDD_EN = 0)
+ * + Or charging is disabled. (i.e. CHARGE_EN = 0)
+ * + Or the charging current is small enough.
+ * - Otherwise, it's 1.
+ */
+
+/* Whether we want to process interrupts on CHARGE_DONE or not. */
+static int monitor_charge_done;
+
+/*
+ * Start monitoring CHARGE_DONE and fires the interrupt once so that
+ * we react to the current value.
+ */
+static void inductive_charging_monitor_charge(void)
+{
+ monitor_charge_done = 1;
+ inductive_charging_interrupt(GPIO_CHARGE_DONE);
+}
+DECLARE_DEFERRED(inductive_charging_monitor_charge);
+
void inductive_charging_interrupt(enum gpio_signal signal)
{
int charger_enabled = gpio_get_level(GPIO_BASE_CHG_VDD_EN);
int charge_done = gpio_get_level(GPIO_CHARGE_DONE);
+ static int charge_already_done;
+
+ if (!monitor_charge_done && signal == GPIO_CHARGE_DONE)
+ return;
- /* Always try to charge if the lid is just closed */
- if (signal == GPIO_LID_OPEN)
+ if (signal == GPIO_LID_OPEN) {
+ /* The lid has been opened. Clear all states. */
charge_done = 0;
+ charge_already_done = 0;
+ monitor_charge_done = 0;
+ } else if (signal == GPIO_CHARGE_DONE) {
+ /*
+ * Once we see CHARGE_DONE=1, we ignore any change on
+ * CHARGE_DONE until the next time the lid is opened.
+ */
+ if (charge_done == 1)
+ charge_already_done = 1;
+ else if (charge_already_done)
+ return;
+ }
- if (!charger_enabled || charge_done)
+ if (!charger_enabled || charge_done) {
gpio_set_level(GPIO_CHARGE_EN, 0);
- else
+ } else {
gpio_set_level(GPIO_CHARGE_EN, 1);
+ /*
+ * When the charging is just enabled, there might be a
+ * blip on CHARGE_DONE. Wait for a second before we start
+ * looking at CHARGE_DONE.
+ */
+ if (!monitor_charge_done)
+ hook_call_deferred(inductive_charging_monitor_charge,
+ SECOND);
+ }
}
static void inductive_charging_deferred_update(void)