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:
Sameer Nanda
2014-11-21 13:28:03 -08:00
committed by chrome-internal-fetch
parent 659e44c15a
commit 481800dfda

View File

@@ -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;
}