summaryrefslogtreecommitdiff
path: root/chip/stm32/usb_power.c
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2018-02-05 18:50:12 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-03-28 19:34:27 -0700
commit2da18f938d64462ac62f6a77f46d05237ed30096 (patch)
treec8382814f7bb025a8f708bf6455bd2517f74e1d3 /chip/stm32/usb_power.c
parentbb1a079a628cc2a53c4c282da41692f3f29b0a3d (diff)
downloadchrome-ec-2da18f938d64462ac62f6a77f46d05237ed30096.tar.gz
sweetberry: add current and voltage logging
This adds a config to specify whether sweetberry should measure power, current, voltage per powerlog entry. The json format is slightly revised to allow data type per channel. powerlog and sweetberry fw are updated to handle the new functionality. BUG=b:72973433 BRANCH=None TEST=./powerlog.py -b marlin.board -c marlin_a.scenario -s .5 Signed-off-by: Nick Sanders <nsanders@chromium.org> Change-Id: I231fc6600495146fad30583872bf14c660d5a50b Reviewed-on: https://chromium-review.googlesource.com/905427 Commit-Ready: Nick Sanders <nsanders@chromium.org> Tested-by: Nick Sanders <nsanders@chromium.org> Reviewed-by: Mengqi Guo <mqg@chromium.org>
Diffstat (limited to 'chip/stm32/usb_power.c')
-rw-r--r--chip/stm32/usb_power.c99
1 files changed, 80 insertions, 19 deletions
diff --git a/chip/stm32/usb_power.c b/chip/stm32/usb_power.c
index ad2b6d55d6..bf9e824f84 100644
--- a/chip/stm32/usb_power.c
+++ b/chip/stm32/usb_power.c
@@ -16,8 +16,6 @@
#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args)
-
-
static int usb_power_init_inas(struct usb_power_config const *config);
static int usb_power_read(struct usb_power_config const *config);
static int usb_power_write_line(struct usb_power_config const *config);
@@ -102,9 +100,6 @@ static int usb_power_write_line(struct usb_power_config const *config)
return bytes;
}
- CPRINTS("usb_power_write_line: no data rs: %d, rc: %d",
- USB_POWER_RECORD_SIZE(state->ina_count),
- USB_POWER_MAX_CACHED(state->ina_count));
return 0;
}
@@ -133,12 +128,12 @@ static int usb_power_state_stop(struct usb_power_config const *config)
return USB_POWER_ERROR_NOT_CAPTURING;
}
- state->state = USB_POWER_STATE_SETUP;
+ state->state = USB_POWER_STATE_OFF;
state->reports_head = 0;
state->reports_tail = 0;
state->reports_xmit_active = 0;
state->stride_bytes = 0;
- CPRINTS("[STOP] STATE: CAPTURING -> SETUP");
+ CPRINTS("[STOP] STATE: CAPTURING -> OFF");
return USB_POWER_SUCCESS;
}
@@ -149,14 +144,16 @@ static int usb_power_state_start(struct usb_power_config const *config,
{
struct usb_power_state *state = config->state;
int integration_us = cmd->start.integration_us;
+ int ret;
if (state->state != USB_POWER_STATE_SETUP) {
CPRINTS("[START] Error not setup.");
return USB_POWER_ERROR_NOT_SETUP;
}
- if (count != 6) {
- CPRINTS("[START] Error count %d is not 6", (int)count);
+ if (count != sizeof(struct usb_power_command_start)) {
+ CPRINTS("[START] Error count %d is not %d", (int)count,
+ sizeof(struct usb_power_command_start));
return USB_POWER_ERROR_READ_SIZE;
}
@@ -170,7 +167,10 @@ static int usb_power_state_start(struct usb_power_config const *config,
state->max_cached = USB_POWER_MAX_CACHED(state->ina_count);
state->integration_us = integration_us;
- usb_power_init_inas(config);
+ ret = usb_power_init_inas(config);
+
+ if (ret)
+ return USB_POWER_ERROR_INVAL;
state->state = USB_POWER_STATE_CAPTURING;
CPRINTS("[START] STATE: SETUP -> CAPTURING %dus", integration_us);
@@ -198,7 +198,7 @@ static int usb_power_state_settime(struct usb_power_config const *config,
else
config->state->wall_offset = 0;
- return EC_SUCCESS;
+ return USB_POWER_SUCCESS;
}
@@ -207,6 +207,7 @@ static int usb_power_state_addina(struct usb_power_config const *config,
{
struct usb_power_state *state = config->state;
struct usb_power_ina_cfg *ina;
+ int i;
/* Only valid from OFF or SETUP */
if ((state->state != USB_POWER_STATE_OFF) &&
@@ -232,12 +233,48 @@ static int usb_power_state_addina(struct usb_power_config const *config,
state->ina_count = 0;
}
+ if ((cmd->addina.type < USBP_INA231_POWER) ||
+ (cmd->addina.type > USBP_INA231_SHUNTV)) {
+ CPRINTS("[ADDINA] Error INA type 0x%x invalid",
+ (int)(cmd->addina.type));
+ return USB_POWER_ERROR_INVAL;
+ }
+
+ if (cmd->addina.rs == 0) {
+ CPRINTS("[ADDINA] Error INA resistance cannot be zero!");
+ return USB_POWER_ERROR_INVAL;
+ }
+
/* Select INA to configure */
ina = state->ina_cfg + state->ina_count;
ina->port = cmd->addina.port;
ina->addr = (cmd->addina.addr) << 1; /* 7 to 8 bit addr. */
ina->rs = cmd->addina.rs;
+ ina->type = cmd->addina.type;
+
+ /*
+ * INAs can be shared, in that they will have various values
+ * (and therefore registers) read from them each cycle, including
+ * power, voltage, current. If only a single value is read,
+ * we an use i2c_readagain for faster transactions as we don't
+ * have to respecify the address.
+ */
+ ina->shared = 0;
+#ifdef USB_POWER_VERBOSE
+ ina->shared = 1;
+#endif
+
+ /* Check if shared with previously configured INAs. */
+ for (i = 0; i < state->ina_count; i++) {
+ struct usb_power_ina_cfg *tmp = state->ina_cfg + i;
+
+ if ((tmp->port == ina->port) &&
+ (tmp->addr == ina->addr)) {
+ ina->shared = 1;
+ tmp->shared = 1;
+ }
+ }
state->ina_count += 1;
return USB_POWER_SUCCESS;
@@ -305,7 +342,6 @@ static int usb_power_read(struct usb_power_config const *config)
if (ret)
return EC_SUCCESS;
- CPRINTS("[CAP] busy");
result = USB_POWER_ERROR_BUSY;
} else {
CPRINTS("[STOP] Error not capturing.");
@@ -353,7 +389,22 @@ static int usb_power_read(struct usb_power_config const *config)
#define INA231_MODE_BUS 0x6
#define INA231_MODE_BOTH 0x7
+int reg_type_mapping(enum usb_power_ina_type ina_type)
+{
+ switch (ina_type) {
+ case USBP_INA231_POWER:
+ return INA231_REG_PWR;
+ case USBP_INA231_BUSV:
+ return INA231_REG_BUSV;
+ case USBP_INA231_CURRENT:
+ return INA231_REG_CURR;
+ case USBP_INA231_SHUNTV:
+ return INA231_REG_RSHV;
+ default:
+ return INA231_REG_CONF;
+ }
+}
uint16_t ina2xx_readagain(uint8_t port, uint8_t addr)
{
@@ -407,6 +458,7 @@ int ina2xx_write(uint8_t port, uint8_t addr, uint8_t reg, uint16_t val)
*/
/* INA231 integration and averaging time presets, indexed by register value */
+#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
static const int average_settings[] = {
1, 4, 16, 64, 128, 256, 512, 1024};
static const int conversion_time_us[] = {
@@ -426,14 +478,14 @@ static int usb_power_init_inas(struct usb_power_config const *config)
}
/* Find an INA preset integration time less than specified */
- while (shunt_time < 7) {
+ while (shunt_time < (NELEMS(conversion_time_us) - 1)) {
if (conversion_time_us[shunt_time + 1] > target_us)
break;
shunt_time++;
}
/* Find an averaging setting from the INA presets that fits. */
- while (avg < 7) {
+ while (avg < (NELEMS(average_settings) - 1)) {
if ((conversion_time_us[shunt_time] *
average_settings[avg + 1])
> target_us)
@@ -464,6 +516,7 @@ static int usb_power_init_inas(struct usb_power_config const *config)
* CurrentLSB = uA per div = 80mV / (Rsh * 2^15)
* CurrentLSB 100x uA = 100x 80000000nV / (Rsh mOhm * 0x8000)
*/
+ /* TODO: allow voltage readings if no sense resistor. */
if (ina->rs == 0)
return -1;
@@ -524,7 +577,10 @@ static int usb_power_init_inas(struct usb_power_config const *config)
* will be cached and all ina2xx_readagain() calls will read
* from the same address.
*/
- ina2xx_read(ina->port, ina->addr, INA231_REG_PWR);
+ ina2xx_read(ina->port, ina->addr, reg_type_mapping(ina->type));
+#ifdef USB_POWER_VERBOSE
+ CPRINTS("[CAP] %d (%d,0x%02x): type:%d", (int)(ina->type));
+#endif
}
return EC_SUCCESS;
@@ -570,7 +626,7 @@ static int usb_power_get_samples(struct usb_power_config const *config)
r->timestamp = time;
for (i = 0; i < state->ina_count; i++) {
- int power;
+ int regval;
struct usb_power_ina_cfg *ina = inas + i;
/* Read INA231.
@@ -578,11 +634,16 @@ static int usb_power_get_samples(struct usb_power_config const *config)
* Readagain cached this address so we'll save an I2C
* transaction.
*/
- power = ina2xx_readagain(ina->port, ina->addr);
- r->power[i] = power;
+ if (ina->shared)
+ regval = ina2xx_read(ina->port, ina->addr,
+ reg_type_mapping(ina->type));
+ else
+ regval = ina2xx_readagain(ina->port, ina->addr);
+ r->power[i] = regval;
#ifdef USB_POWER_VERBOSE
{
int current;
+ int power;
int voltage;
int bvoltage;
@@ -590,7 +651,6 @@ static int usb_power_get_samples(struct usb_power_config const *config)
bvoltage = ina2xx_read(ina->port, ina->addr, INA231_REG_BUSV);
current = ina2xx_read(ina->port, ina->addr, INA231_REG_CURR);
power = ina2xx_read(ina->port, ina->addr, INA231_REG_PWR);
- }
{
int uV = ((int)voltage * 25) / 10;
int mV = ((int)bvoltage * 125) / 100;
@@ -604,6 +664,7 @@ static int usb_power_get_samples(struct usb_power_config const *config)
"%duW v:%04x, b:%04x, p:%04x",
uV, mV, uA, CuA, uW, voltage, bvoltage, power);
}
+ }
#endif
}