summaryrefslogtreecommitdiff
path: root/include/peripheral_charger.h
blob: 7944efd1090d5a8f72ccef42c1465a5383ae6bb3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/* Copyright 2020 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef __CROS_EC_PERIPHERAL_CHARGER_H
#define __CROS_EC_PERIPHERAL_CHARGER_H

#include "common.h"
#include "gpio.h"
#include "queue.h"
#include "stdbool.h"
#include "task.h"

/*
 * Peripheral charge manager
 *
 * Peripheral charge manager (PCHG) is a state machine (SM), which manages
 * charge ports to charge peripheral devices. Events can be generated
 * externally (by a charger chip) or internally (by a host command or the SM
 * itself). Events are queued and handled first-come-first-serve basis.
 *
 * Peripheral charger drivers should implement struct pchg_drv. Each operation
 * can be synchronous or asynchronous depending on the chip. If a function
 * works synchronously, it should return EC_SUCCESS. That'll make the SM
 * immediately queue the next event (if applicable) and transition to the next
 * state. If a function works asynchronously, it should return
 * EC_SUCCESS_IN_PROGRESS. That'll make the SM stay in the same state. The SM
 * is expected to receive IRQ for further information about the operation,
 * which may or may not make the SM transition to the next state.
 *
 * Roughly speaking the SM looks as follows:
 *
 *                  +---------------+
 *                  |     RESET     |
 *                  +-------+-------+
 *                          |
 *                          | INITIALIZED
 *                          v
 *                  +-------+-------+
 *                  |  INITIALIZED  |<--------------+
 *                  +------+-+------+               |
 *                         | ^                      |
 *                 ENABLED | | DISABLED             |
 *                         v |                      |
 *                  +------+--------+               |
 *   +------------->+    ENABLED    |               |
 *   |              +-------+-------+               |
 *   |                      |                       |
 *   |                      | DEVICE_DETECTED       |
 *   |                      v                       |
 *   |              +-------+-------+               |
 *   +--------------+   DETECTED    +---------------+
 *   | DEVICE_LOST  +------+-+------+  ERROR        |
 *   |                     | ^                      |
 *   |      CHARGE_STARTED | | CHARGE_ENDED         |
 *   |                     | | CHARGE_STOPPED       |
 *   |                     v |                      |
 *   |              +------+-+------+               |
 *   +--------------+   CHARGING    +---------------+
 *     DEVICE_LOST  +---------------+  ERROR
 *
 */

/* Size of event queue. Use it to initialize struct pchg.events. */
#define PCHG_EVENT_QUEUE_SIZE	8

enum pchg_event {
	/* No event */
	PCHG_EVENT_NONE = 0,

	/* IRQ is pending. */
	PCHG_EVENT_IRQ,

	/* External Events */
	PCHG_EVENT_RESET,
	PCHG_EVENT_INITIALIZED,
	PCHG_EVENT_ENABLED,
	PCHG_EVENT_DISABLED,
	PCHG_EVENT_DEVICE_DETECTED,
	PCHG_EVENT_DEVICE_LOST,
	PCHG_EVENT_CHARGE_STARTED,
	PCHG_EVENT_CHARGE_UPDATE,
	PCHG_EVENT_CHARGE_ENDED,
	PCHG_EVENT_CHARGE_STOPPED,
	PCHG_EVENT_IN_NORMAL,

	/* Errors */
	PCHG_EVENT_CHARGE_ERROR,
	PCHG_EVENT_OTHER_ERROR,

	/* Internal (a.k.a. Host) Events */
	PCHG_EVENT_INITIALIZE,
	PCHG_EVENT_ENABLE,
	PCHG_EVENT_DISABLE,

	/* Counter. Add new entry above. */
	PCHG_EVENT_COUNT,
};

enum pchg_error {
	PCHG_ERROR_NONE = 0,
	/* Error initiated by host. */
	PCHG_ERROR_HOST = BIT(0),
	PCHG_ERROR_OVER_TEMPERATURE = BIT(1),
	PCHG_ERROR_OVER_CURRENT = BIT(2),
	PCHG_ERROR_FOREIGN_OBJECT = BIT(3),
};

enum pchg_mode {
	PCHG_MODE_NORMAL = 0,
	PCHG_MODE_DOWNLOAD,
};

/**
 * Data struct describing the configuration of a peripheral charging port.
 */
struct pchg_config {
	/* Charger driver */
	const struct pchg_drv *drv;
	/* I2C port number */
	const int i2c_port;
	/* GPIO pin used for IRQ */
	const enum gpio_signal irq_pin;
	/* Full battery percentage */
	const uint8_t full_percent;
};

/**
 * Data struct describing the status of a peripheral charging port. It provides
 * the state machine and a charger driver with a context to work on.
 */
struct pchg {
	/* Static configuration */
	const struct pchg_config * const cfg;
	/* Current state of the port */
	enum pchg_state state;
	/* Event queue */
	struct queue const events;
	/* Event queue mutex */
	struct mutex mtx;
	/* 1:Pending IRQ 0:No pending IRQ */
	uint32_t irq;
	/* Event currently being handled */
	enum pchg_event event;
	/* Error (enum pchg_error). Port is disabled until it's cleared. */
	uint32_t error;
	/* Battery percentage (0% ~ 100%) of the connected peripheral device */
	uint8_t battery_percent;
	/* Number of dropped events (due to queue overflow) */
	uint32_t dropped_event_count;
	/* enum pchg_mode */
	uint8_t mode;
	/* FW version */
	uint32_t fw_version;
};

/**
 * Peripheral charger driver
 */
struct pchg_drv {
	/* Reset charger chip. */
	int (*reset)(struct pchg *ctx);
	/* Initialize the charger. */
	int (*init)(struct pchg *ctx);
	/* Enable/disable the charger. */
	int (*enable)(struct pchg *ctx, bool enable);
	/* Get event info. */
	int (*get_event)(struct pchg *ctx);
	/* Get battery level. */
	int (*get_soc)(struct pchg *ctx);
};

/**
 * Array storing configs and states of all the peripheral charging ports.
 * Should be defined in board.c.
 */
extern struct pchg pchgs[];
extern const int pchg_count;

/* Utility macro converting port config to port number. */
#define PCHG_CTX_TO_PORT(ctx)	((ctx) - &pchgs[0])

/**
 * Interrupt handler for a peripheral charger.
 *
 * @param signal
 */
void pchg_irq(enum gpio_signal signal);

/**
 * Task running a state machine for charging peripheral devices.
 */
void pchg_task(void *u);

#endif /* __CROS_EC_PERIPHERAL_CHARGER_H */