|
@@ -32,6 +32,21 @@
|
32
|
32
|
#define DPM_MIN_CURRENT PD_MA2PDI(100)
|
33
|
33
|
|
34
|
34
|
|
|
35
|
+/*
|
|
36
|
+ * Return the current specified by the given PDBS configuration object at the
|
|
37
|
+ * given voltage (in millivolts), in centiamperes.
|
|
38
|
+ */
|
|
39
|
+static uint16_t dpm_get_current(struct pdbs_config *scfg, uint16_t mv)
|
|
40
|
+{
|
|
41
|
+ switch (scfg->flags & PDBS_CONFIG_FLAGS_CURRENT_DEFN) {
|
|
42
|
+ case PDBS_CONFIG_FLAGS_CURRENT_DEFN_I:
|
|
43
|
+ return scfg->i;
|
|
44
|
+ case PDBS_CONFIG_FLAGS_CURRENT_DEFN_P:
|
|
45
|
+ return (scfg->p * 1000 + mv - 1) / mv;
|
|
46
|
+ }
|
|
47
|
+}
|
|
48
|
+
|
|
49
|
+
|
35
|
50
|
/*
|
36
|
51
|
* Find the index of the first PDO from capabilities in the voltage range,
|
37
|
52
|
* using the desired order.
|
|
@@ -59,10 +74,11 @@ static int8_t dpm_get_range_fixed_pdo_index(const union pd_msg *caps,
|
59
|
74
|
while (0 <= i && i < numobj) {
|
60
|
75
|
/* If we have a fixed PDO, its V is within our range, and its I is at
|
61
|
76
|
* least our desired I */
|
|
77
|
+ uint16_t v = PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]);
|
62
|
78
|
if ((caps->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED
|
63
|
|
- && PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= scfg->i
|
64
|
|
- && PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]) >= PD_MV2PDV(scfg->vmin)
|
65
|
|
- && PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]) <= PD_MV2PDV(scfg->vmax)) {
|
|
79
|
+ && PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= dpm_get_current(scfg, PD_PDV2MV(v))
|
|
80
|
+ && v >= PD_MV2PDV(scfg->vmin)
|
|
81
|
+ && v <= PD_MV2PDV(scfg->vmax)) {
|
66
|
82
|
return i;
|
67
|
83
|
}
|
68
|
84
|
i += step;
|
|
@@ -100,6 +116,9 @@ bool pdbs_dpm_evaluate_capability(struct pdb_config *cfg,
|
100
|
116
|
/* Get whether or not the power supply is constrained */
|
101
|
117
|
dpm_data->_unconstrained_power = caps->obj[0] & PD_PDO_SRC_FIXED_UNCONSTRAINED;
|
102
|
118
|
|
|
119
|
+ /* Get the current we want */
|
|
120
|
+ uint16_t current = dpm_get_current(scfg, scfg->v);
|
|
121
|
+
|
103
|
122
|
/* Make sure we have configuration */
|
104
|
123
|
if (scfg != NULL && dpm_data->output_enabled) {
|
105
|
124
|
/* Look at the PDOs to see if one matches our desires */
|
|
@@ -108,20 +127,20 @@ bool pdbs_dpm_evaluate_capability(struct pdb_config *cfg,
|
108
|
127
|
* at least our desired I */
|
109
|
128
|
if ((caps->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED
|
110
|
129
|
&& PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i]) == PD_MV2PDV(scfg->v)
|
111
|
|
- && PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= scfg->i) {
|
|
130
|
+ && PD_PDO_SRC_FIXED_CURRENT_GET(caps->obj[i]) >= current) {
|
112
|
131
|
/* We got what we wanted, so build a request for that */
|
113
|
132
|
request->hdr = cfg->pe.hdr_template | PD_MSGTYPE_REQUEST
|
114
|
133
|
| PD_NUMOBJ(1);
|
115
|
134
|
if (scfg->flags & PDBS_CONFIG_FLAGS_GIVEBACK) {
|
116
|
135
|
/* GiveBack enabled */
|
117
|
136
|
request->obj[0] = PD_RDO_FV_MIN_CURRENT_SET(DPM_MIN_CURRENT)
|
118
|
|
- | PD_RDO_FV_CURRENT_SET(scfg->i)
|
|
137
|
+ | PD_RDO_FV_CURRENT_SET(current)
|
119
|
138
|
| PD_RDO_NO_USB_SUSPEND | PD_RDO_GIVEBACK
|
120
|
139
|
| PD_RDO_OBJPOS_SET(i + 1);
|
121
|
140
|
} else {
|
122
|
141
|
/* GiveBack disabled */
|
123
|
|
- request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(scfg->i)
|
124
|
|
- | PD_RDO_FV_CURRENT_SET(scfg->i)
|
|
142
|
+ request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(current)
|
|
143
|
+ | PD_RDO_FV_CURRENT_SET(current)
|
125
|
144
|
| PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
|
126
|
145
|
}
|
127
|
146
|
if (dpm_data->usb_comms) {
|
|
@@ -140,13 +159,13 @@ bool pdbs_dpm_evaluate_capability(struct pdb_config *cfg,
|
140
|
159
|
&& (caps->obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS
|
141
|
160
|
&& PD_APDO_PPS_MAX_VOLTAGE_GET(caps->obj[i]) >= PD_MV2PAV(scfg->v)
|
142
|
161
|
&& PD_APDO_PPS_MIN_VOLTAGE_GET(caps->obj[i]) <= PD_MV2PAV(scfg->v)
|
143
|
|
- && PD_APDO_PPS_CURRENT_GET(caps->obj[i]) >= PD_CA2PAI(scfg->i)) {
|
|
162
|
+ && PD_APDO_PPS_CURRENT_GET(caps->obj[i]) >= PD_CA2PAI(current)) {
|
144
|
163
|
/* We got what we wanted, so build a request for that */
|
145
|
164
|
request->hdr = cfg->pe.hdr_template | PD_MSGTYPE_REQUEST
|
146
|
165
|
| PD_NUMOBJ(1);
|
147
|
166
|
|
148
|
167
|
/* Build a request */
|
149
|
|
- request->obj[0] = PD_RDO_PROG_CURRENT_SET(PD_CA2PAI(scfg->i))
|
|
168
|
+ request->obj[0] = PD_RDO_PROG_CURRENT_SET(PD_CA2PAI(current))
|
150
|
169
|
| PD_RDO_PROG_VOLTAGE_SET(PD_MV2PRV(scfg->v))
|
151
|
170
|
| PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
|
152
|
171
|
if (dpm_data->usb_comms) {
|
|
@@ -166,16 +185,18 @@ bool pdbs_dpm_evaluate_capability(struct pdb_config *cfg,
|
166
|
185
|
/* We got what we wanted, so build a request for that */
|
167
|
186
|
request->hdr = cfg->pe.hdr_template | PD_MSGTYPE_REQUEST
|
168
|
187
|
| PD_NUMOBJ(1);
|
|
188
|
+ /* Get the current we need at this voltage */
|
|
189
|
+ current = dpm_get_current(scfg, PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(caps->obj[i])));
|
169
|
190
|
if (scfg->flags & PDBS_CONFIG_FLAGS_GIVEBACK) {
|
170
|
191
|
/* GiveBack enabled */
|
171
|
192
|
request->obj[0] = PD_RDO_FV_MIN_CURRENT_SET(DPM_MIN_CURRENT)
|
172
|
|
- | PD_RDO_FV_CURRENT_SET(scfg->i)
|
|
193
|
+ | PD_RDO_FV_CURRENT_SET(current)
|
173
|
194
|
| PD_RDO_NO_USB_SUSPEND | PD_RDO_GIVEBACK
|
174
|
195
|
| PD_RDO_OBJPOS_SET(i + 1);
|
175
|
196
|
} else {
|
176
|
197
|
/* GiveBack disabled */
|
177
|
|
- request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(scfg->i)
|
178
|
|
- | PD_RDO_FV_CURRENT_SET(scfg->i)
|
|
198
|
+ request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(current)
|
|
199
|
+ | PD_RDO_FV_CURRENT_SET(current)
|
179
|
200
|
| PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
|
180
|
201
|
}
|
181
|
202
|
if (dpm_data->usb_comms) {
|
|
@@ -232,10 +253,12 @@ void pdbs_dpm_get_sink_capability(struct pdb_config *cfg, union pd_msg *cap)
|
232
|
253
|
}
|
233
|
254
|
|
234
|
255
|
if (scfg != NULL) {
|
|
256
|
+ /* Get the current we want */
|
|
257
|
+ uint16_t current = dpm_get_current(scfg, scfg->v);
|
235
|
258
|
/* Add a PDO for the desired power. */
|
236
|
259
|
cap->obj[numobj++] = PD_PDO_TYPE_FIXED
|
237
|
260
|
| PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(scfg->v))
|
238
|
|
- | PD_PDO_SNK_FIXED_CURRENT_SET(scfg->i);
|
|
261
|
+ | PD_PDO_SNK_FIXED_CURRENT_SET(current);
|
239
|
262
|
|
240
|
263
|
/* Get the PDO from the voltage range */
|
241
|
264
|
int8_t i = dpm_get_range_fixed_pdo_index(dpm_data->capabilities, scfg);
|
|
@@ -243,7 +266,7 @@ void pdbs_dpm_get_sink_capability(struct pdb_config *cfg, union pd_msg *cap)
|
243
|
266
|
/* If it's vSafe5V, set our vSafe5V's current to what we want */
|
244
|
267
|
if (i == 0) {
|
245
|
268
|
cap->obj[0] &= ~PD_PDO_SNK_FIXED_CURRENT;
|
246
|
|
- cap->obj[0] |= PD_PDO_SNK_FIXED_CURRENT_SET(scfg->i);
|
|
269
|
+ cap->obj[0] |= PD_PDO_SNK_FIXED_CURRENT_SET(current);
|
247
|
270
|
} else {
|
248
|
271
|
/* If we want more than 5 V, set the Higher Capability flag */
|
249
|
272
|
if (PD_MV2PDV(scfg->v) != PD_MV2PDV(5000)) {
|
|
@@ -274,7 +297,7 @@ void pdbs_dpm_get_sink_capability(struct pdb_config *cfg, union pd_msg *cap)
|
274
|
297
|
cap->obj[numobj++] = PD_PDO_TYPE_AUGMENTED | PD_APDO_TYPE_PPS
|
275
|
298
|
| PD_APDO_PPS_MAX_VOLTAGE_SET(PD_MV2PAV(scfg->v))
|
276
|
299
|
| PD_APDO_PPS_MIN_VOLTAGE_SET(PD_MV2PAV(scfg->v))
|
277
|
|
- | PD_APDO_PPS_CURRENT_SET(PD_CA2PAI(scfg->i));
|
|
300
|
+ | PD_APDO_PPS_CURRENT_SET(PD_CA2PAI(current));
|
278
|
301
|
}
|
279
|
302
|
}
|
280
|
303
|
|
|
@@ -317,18 +340,22 @@ bool pdbs_dpm_evaluate_typec_current(struct pdb_config *cfg,
|
317
|
340
|
|
318
|
341
|
/* If we have no configuration or don't want 5 V, Type-C Current can't
|
319
|
342
|
* possibly satisfy our needs */
|
|
343
|
+ /* TODO Check if 5 V is inside the voltage range */
|
320
|
344
|
if (scfg == NULL || PD_MV2PDV(scfg->v) != PD_MV2PDV(5000)) {
|
321
|
345
|
dpm_data->_capability_match = false;
|
322
|
346
|
return false;
|
323
|
347
|
}
|
324
|
348
|
|
|
349
|
+ /* Get the current we want */
|
|
350
|
+ uint16_t current = dpm_get_current(scfg, scfg->v);
|
|
351
|
+
|
325
|
352
|
/* If 1.5 A is available and we want no more than that, great. */
|
326
|
|
- if (tcc == fusb_tcc_1_5 && scfg->i <= 150) {
|
|
353
|
+ if (tcc == fusb_tcc_1_5 && current <= 150) {
|
327
|
354
|
dpm_data->_capability_match = true;
|
328
|
355
|
return true;
|
329
|
356
|
}
|
330
|
357
|
/* If 3 A is available and we want no more than that, that's great too. */
|
331
|
|
- if (tcc == fusb_tcc_3_0 && scfg->i <= 300) {
|
|
358
|
+ if (tcc == fusb_tcc_3_0 && current <= 300) {
|
332
|
359
|
dpm_data->_capability_match = true;
|
333
|
360
|
return true;
|
334
|
361
|
}
|