/* Copyright (c) 2014 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. */ #include "board.h" #include "common.h" #include "console.h" #include "hooks.h" #include "registers.h" #include "task.h" #include "timer.h" #include "util.h" #include "usb_pd.h" #define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) /* TODO(crossbug.com/p/28869): update source and sink tables to spec. */ const uint32_t pd_src_pdo[] = { PDO_FIXED(5000, 500, PDO_FIXED_EXTERNAL), PDO_FIXED(5000, 900, 0), }; const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo); /* TODO(crossbug.com/p/28869): update source and sink tables to spec. */ const uint32_t pd_snk_pdo[] = { PDO_BATT(4500, 5500, 15000), PDO_BATT(11500, 12500, 36000), }; const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo); /* Cap on the max voltage requested as a sink (in millivolts) */ static unsigned max_mv = -1; /* no cap */ int pd_choose_voltage(int cnt, uint32_t *src_caps, uint32_t *rdo) { int i; int sel_mv; int max_uw = 0; int max_i = -1; /* Get max power */ for (i = 0; i < cnt; i++) { int uw; int mv = ((src_caps[i] >> 10) & 0x3FF) * 50; if ((src_caps[i] & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) { uw = 250000 * (src_caps[i] & 0x3FF); } else { int ma = (src_caps[i] & 0x3FF) * 10; uw = ma * mv; } if ((uw > max_uw) && (mv <= max_mv)) { max_i = i; max_uw = uw; sel_mv = mv; } } if (max_i < 0) return -EC_ERROR_UNKNOWN; /* request all the power ... */ if ((src_caps[max_i] & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) { int uw = 250000 * (src_caps[i] & 0x3FF); *rdo = RDO_BATT(max_i + 1, uw/2, uw, 0); ccprintf("Request [%d] %dV %d/%d mW\n", max_i, sel_mv/1000, uw/1000, uw/1000); } else { int ma = 10 * (src_caps[max_i] & 0x3FF); *rdo = RDO_FIXED(max_i + 1, ma / 2, ma, 0); ccprintf("Request [%d] %dV %d/%d mA\n", max_i, sel_mv/1000, max_i, ma/2, ma); } return EC_SUCCESS; } void pd_set_max_voltage(unsigned mv) { max_mv = mv; } int pd_request_voltage(uint32_t rdo) { int op_ma = rdo & 0x3FF; int max_ma = (rdo >> 10) & 0x3FF; int idx = rdo >> 28; uint32_t pdo; uint32_t pdo_ma; if (!idx || idx > pd_src_pdo_cnt) return EC_ERROR_INVAL; /* Invalid index */ /* check current ... */ pdo = pd_src_pdo[idx - 1]; pdo_ma = (pdo & 0x3ff); if (op_ma > pdo_ma) return EC_ERROR_INVAL; /* too much op current */ if (max_ma > pdo_ma) return EC_ERROR_INVAL; /* too much max current */ ccprintf("Switch to %d V %d mA (for %d/%d mA)\n", ((pdo >> 10) & 0x3ff) * 50, (pdo & 0x3ff) * 10, ((rdo >> 10) & 0x3ff) * 10, (rdo & 0x3ff) * 10); return EC_SUCCESS; } int pd_set_power_supply_ready(void) { return EC_SUCCESS; /* we are ready */ } void pd_power_supply_reset(void) { } int pd_board_checks(void) { return EC_SUCCESS; }