CHROMIUM: usb_pd_charger: support discovery & override commands
Added support for EC_CMD_USB_PD_DISCOVERY command. With this, the VID/PID of the attached device can be read. Added suport for EC_CMD_PD_CHARGE_PORT_OVERRIDE command. With this default charger manager policy can be overridden. BUG=chrome-os-partner:32650 TEST=cd /sys/class/power_supply and ensure the directories for the USB PD charger ports show up. Signed-off-by: Sameer Nanda <snanda@chromium.org> Change-Id: Ibb6af7896109034ec5fe7477ea9a8b9a20270479 Reviewed-on: https://chromium-review.googlesource.com/231402 Reviewed-by: Todd Broch <tbroch@chromium.org> Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
659e44c15a
commit
481800dfda
@@ -30,14 +30,18 @@
|
||||
*/
|
||||
#include "../mfd/cros_ec_dev.h"
|
||||
|
||||
#define CROS_USB_PD_MAX_PORTS 8
|
||||
|
||||
#define CHARGER_DIR_NAME "CROS_USB_PD_CHARGER%d"
|
||||
#define CHARGER_DIR_NAME_LENGTH sizeof(CHARGER_DIR_NAME)
|
||||
|
||||
#define CROS_USB_PD_MAX_PORTS 8
|
||||
#define MANUFACTURER_MODEL_LENGTH 32
|
||||
|
||||
struct port_data {
|
||||
int port_number;
|
||||
char name[CHARGER_DIR_NAME_LENGTH];
|
||||
char manufacturer[MANUFACTURER_MODEL_LENGTH];
|
||||
char model_name[MANUFACTURER_MODEL_LENGTH];
|
||||
struct power_supply psy;
|
||||
int psy_type;
|
||||
int psy_online;
|
||||
@@ -89,6 +93,26 @@ int ec_command(struct charger_data *charger, int command,
|
||||
return cros_ec_cmd_xfer(ec_device, &msg);
|
||||
}
|
||||
|
||||
static int set_ec_usb_pd_override_ports(struct charger_data *charger,
|
||||
int port_num)
|
||||
{
|
||||
struct device *dev = charger->dev;
|
||||
struct ec_params_charge_port_override req;
|
||||
int ret;
|
||||
|
||||
req.override_port = port_num;
|
||||
|
||||
ret = ec_command(charger, EC_CMD_PD_CHARGE_PORT_OVERRIDE,
|
||||
(uint8_t *)&req, sizeof(req),
|
||||
NULL, 0);
|
||||
if (ret < 0) {
|
||||
dev_info(dev, "Port Override command returned 0x%x\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ec_num_ports(struct charger_data *charger, int *num_ports)
|
||||
{
|
||||
struct device *dev = charger->dev;
|
||||
@@ -109,7 +133,35 @@ static int get_ec_num_ports(struct charger_data *charger, int *num_ports)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ec_port_status(struct port_data *port)
|
||||
static int get_ec_usb_pd_discovery_info(struct port_data *port)
|
||||
{
|
||||
struct charger_data *charger = port->charger;
|
||||
struct device *dev = charger->dev;
|
||||
struct ec_params_usb_pd_info_request req;
|
||||
struct ec_params_usb_pd_discovery_entry resp;
|
||||
int ret;
|
||||
|
||||
req.port = port->port_number;
|
||||
|
||||
ret = ec_command(charger, EC_CMD_USB_PD_DISCOVERY,
|
||||
(uint8_t *)&req, sizeof(req),
|
||||
(uint8_t *)&resp, sizeof(resp));
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Unable to query Discovery info (err:0x%x)\n",
|
||||
ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Port %d: VID = 0x%x, PID=0x%x, PTYPE=0x%x\n",
|
||||
port->port_number, resp.vid, resp.pid, resp.ptype);
|
||||
|
||||
snprintf(port->manufacturer, MANUFACTURER_MODEL_LENGTH, "%x", resp.vid);
|
||||
snprintf(port->model_name, MANUFACTURER_MODEL_LENGTH, "%x", resp.pid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ec_usb_pd_power_info(struct port_data *port)
|
||||
{
|
||||
struct charger_data *charger = port->charger;
|
||||
struct device *dev = charger->dev;
|
||||
@@ -121,9 +173,8 @@ static int get_ec_port_status(struct port_data *port)
|
||||
ret = ec_command(charger, EC_CMD_USB_PD_POWER_INFO,
|
||||
(uint8_t *)&req, sizeof(req),
|
||||
(uint8_t *)&resp, sizeof(resp));
|
||||
if (!ret) {
|
||||
WARN(1, "%s: Unable to query PD power info (err:0x%x)\n",
|
||||
dev_name(dev), ret);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Unable to query PD power info (err:0x%x)\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -150,6 +201,7 @@ static int get_ec_port_status(struct port_data *port)
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Unknown role %d\n", resp.role);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (resp.type) {
|
||||
@@ -192,10 +244,20 @@ static int get_ec_port_status(struct port_data *port)
|
||||
port->port_number, resp.max_power);
|
||||
port->psy_power_max = resp.max_power;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ec_port_status(struct port_data *port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = get_ec_usb_pd_power_info(port);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return get_ec_usb_pd_discovery_info(port);
|
||||
}
|
||||
|
||||
static void cros_usb_pd_charger_power_changed(struct power_supply *psy)
|
||||
{
|
||||
struct port_data *port = container_of(psy, struct port_data, psy);
|
||||
@@ -219,7 +281,7 @@ static int cros_usb_pd_charger_get_prop(struct power_supply *psy,
|
||||
|
||||
/* TODO: use cached values instead? */
|
||||
ret = get_ec_port_status(port);
|
||||
if (ret) {
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to get port status (err:0x%x)\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -246,10 +308,10 @@ static int cros_usb_pd_charger_get_prop(struct power_supply *psy,
|
||||
val->intval = 0;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||
val->strval = NULL;
|
||||
val->strval = port->model_name;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MANUFACTURER:
|
||||
val->strval = NULL;
|
||||
val->strval = port->manufacturer;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -262,18 +324,21 @@ static int cros_usb_pd_charger_set_prop(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct port_data *port = container_of(psy, struct port_data, psy);
|
||||
struct charger_data *charger = port->charger;
|
||||
int port_number;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
/*
|
||||
* TODO: Send a TBD host command to the EC to change the
|
||||
* charging role of the port associated with this psy.
|
||||
*/
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
|
||||
/*
|
||||
* TODO: Send a TBD host command to the EC with port number
|
||||
* set to -1.
|
||||
* A value of -1 implies switching to battery as the power
|
||||
* source. Any other value implies using this port as the
|
||||
* power source.
|
||||
*/
|
||||
port_number = val->intval;
|
||||
if (port_number != -1)
|
||||
port_number = port->port_number;
|
||||
return set_ec_usb_pd_override_ports(charger, port_number);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -287,7 +352,6 @@ static int cros_usb_pd_charger_is_writeable(struct power_supply *psy,
|
||||
int ret;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
|
||||
ret = 1;
|
||||
break;
|
||||
@@ -326,7 +390,7 @@ static int cros_usb_pd_charger_probe(struct platform_device *pd)
|
||||
charger = devm_kzalloc(dev, sizeof(struct charger_data),
|
||||
GFP_KERNEL);
|
||||
if (!charger) {
|
||||
WARN(1, "%s: Failed to alloc charger\n", dev_name(dev));
|
||||
dev_err(dev, "Failed to alloc charger. Failing probe.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -336,9 +400,10 @@ static int cros_usb_pd_charger_probe(struct platform_device *pd)
|
||||
|
||||
platform_set_drvdata(pd, charger);
|
||||
|
||||
if (get_ec_num_ports(charger, &charger->num_charger_ports)) {
|
||||
if ((get_ec_num_ports(charger, &charger->num_charger_ports) < 0) ||
|
||||
!charger->num_charger_ports) {
|
||||
/*
|
||||
* This can happen on a system that doesn't supprt USB PD.
|
||||
* This can happen on a system that doesn't support USB PD.
|
||||
* Log a message, but no need to warn.
|
||||
*/
|
||||
dev_info(dev, "No charging ports found\n");
|
||||
@@ -382,7 +447,7 @@ static int cros_usb_pd_charger_probe(struct platform_device *pd)
|
||||
|
||||
if (!charger->num_registered_psy) {
|
||||
ret = -ENODEV;
|
||||
WARN(1, "%s: No power supplies registered\n", dev_name(dev));
|
||||
dev_err(dev, "No power supplies registered\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -403,6 +468,7 @@ fail_nowarn:
|
||||
devm_kfree(dev, charger);
|
||||
}
|
||||
|
||||
dev_info(dev, "Failing probe (err:0x%x)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user