Merge remote-tracking branch 'origin/cros-ec-typec-for-5.12' into ib-usb-typec-chrome-platform-cros-ec-typec-changes-for-5.12
This commit is contained in:
@@ -44,8 +44,13 @@ struct cros_typec_port {
|
|||||||
/* Initial capabilities for the port. */
|
/* Initial capabilities for the port. */
|
||||||
struct typec_capability caps;
|
struct typec_capability caps;
|
||||||
struct typec_partner *partner;
|
struct typec_partner *partner;
|
||||||
|
struct typec_cable *cable;
|
||||||
|
/* SOP' plug. */
|
||||||
|
struct typec_plug *plug;
|
||||||
/* Port partner PD identity info. */
|
/* Port partner PD identity info. */
|
||||||
struct usb_pd_identity p_identity;
|
struct usb_pd_identity p_identity;
|
||||||
|
/* Port cable PD identity info. */
|
||||||
|
struct usb_pd_identity c_identity;
|
||||||
struct typec_switch *ori_sw;
|
struct typec_switch *ori_sw;
|
||||||
struct typec_mux *mux;
|
struct typec_mux *mux;
|
||||||
struct usb_role_switch *role_sw;
|
struct usb_role_switch *role_sw;
|
||||||
@@ -57,10 +62,12 @@ struct cros_typec_port {
|
|||||||
/* Port alt modes. */
|
/* Port alt modes. */
|
||||||
struct typec_altmode p_altmode[CROS_EC_ALTMODE_MAX];
|
struct typec_altmode p_altmode[CROS_EC_ALTMODE_MAX];
|
||||||
|
|
||||||
/* Flag indicating that PD discovery data parsing is completed. */
|
/* Flag indicating that PD partner discovery data parsing is completed. */
|
||||||
bool disc_done;
|
bool sop_disc_done;
|
||||||
struct ec_response_typec_discovery *sop_disc;
|
bool sop_prime_disc_done;
|
||||||
|
struct ec_response_typec_discovery *disc_data;
|
||||||
struct list_head partner_mode_list;
|
struct list_head partner_mode_list;
|
||||||
|
struct list_head plug_mode_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Platform-specific data for the Chrome OS EC Type C controller. */
|
/* Platform-specific data for the Chrome OS EC Type C controller. */
|
||||||
@@ -74,6 +81,7 @@ struct cros_typec_data {
|
|||||||
struct notifier_block nb;
|
struct notifier_block nb;
|
||||||
struct work_struct port_work;
|
struct work_struct port_work;
|
||||||
bool typec_cmd_supported;
|
bool typec_cmd_supported;
|
||||||
|
bool needs_mux_ack;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cros_typec_parse_port_props(struct typec_capability *cap,
|
static int cros_typec_parse_port_props(struct typec_capability *cap,
|
||||||
@@ -180,12 +188,15 @@ static int cros_typec_add_partner(struct cros_typec_data *typec, int port_num,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cros_typec_unregister_altmodes(struct cros_typec_data *typec, int port_num)
|
static void cros_typec_unregister_altmodes(struct cros_typec_data *typec, int port_num,
|
||||||
|
bool is_partner)
|
||||||
{
|
{
|
||||||
struct cros_typec_port *port = typec->ports[port_num];
|
struct cros_typec_port *port = typec->ports[port_num];
|
||||||
struct cros_typec_altmode_node *node, *tmp;
|
struct cros_typec_altmode_node *node, *tmp;
|
||||||
|
struct list_head *head;
|
||||||
|
|
||||||
list_for_each_entry_safe(node, tmp, &port->partner_mode_list, list) {
|
head = is_partner ? &port->partner_mode_list : &port->plug_mode_list;
|
||||||
|
list_for_each_entry_safe(node, tmp, head, list) {
|
||||||
list_del(&node->list);
|
list_del(&node->list);
|
||||||
typec_unregister_altmode(node->amode);
|
typec_unregister_altmode(node->amode);
|
||||||
devm_kfree(typec->dev, node);
|
devm_kfree(typec->dev, node);
|
||||||
@@ -197,7 +208,7 @@ static void cros_typec_remove_partner(struct cros_typec_data *typec,
|
|||||||
{
|
{
|
||||||
struct cros_typec_port *port = typec->ports[port_num];
|
struct cros_typec_port *port = typec->ports[port_num];
|
||||||
|
|
||||||
cros_typec_unregister_altmodes(typec, port_num);
|
cros_typec_unregister_altmodes(typec, port_num, true);
|
||||||
|
|
||||||
port->state.alt = NULL;
|
port->state.alt = NULL;
|
||||||
port->state.mode = TYPEC_STATE_USB;
|
port->state.mode = TYPEC_STATE_USB;
|
||||||
@@ -210,7 +221,22 @@ static void cros_typec_remove_partner(struct cros_typec_data *typec,
|
|||||||
typec_unregister_partner(port->partner);
|
typec_unregister_partner(port->partner);
|
||||||
port->partner = NULL;
|
port->partner = NULL;
|
||||||
memset(&port->p_identity, 0, sizeof(port->p_identity));
|
memset(&port->p_identity, 0, sizeof(port->p_identity));
|
||||||
port->disc_done = false;
|
port->sop_disc_done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cros_typec_remove_cable(struct cros_typec_data *typec,
|
||||||
|
int port_num)
|
||||||
|
{
|
||||||
|
struct cros_typec_port *port = typec->ports[port_num];
|
||||||
|
|
||||||
|
cros_typec_unregister_altmodes(typec, port_num, false);
|
||||||
|
|
||||||
|
typec_unregister_plug(port->plug);
|
||||||
|
port->plug = NULL;
|
||||||
|
typec_unregister_cable(port->cable);
|
||||||
|
port->cable = NULL;
|
||||||
|
memset(&port->c_identity, 0, sizeof(port->c_identity));
|
||||||
|
port->sop_prime_disc_done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cros_unregister_ports(struct cros_typec_data *typec)
|
static void cros_unregister_ports(struct cros_typec_data *typec)
|
||||||
@@ -224,6 +250,9 @@ static void cros_unregister_ports(struct cros_typec_data *typec)
|
|||||||
if (typec->ports[i]->partner)
|
if (typec->ports[i]->partner)
|
||||||
cros_typec_remove_partner(typec, i);
|
cros_typec_remove_partner(typec, i);
|
||||||
|
|
||||||
|
if (typec->ports[i]->cable)
|
||||||
|
cros_typec_remove_cable(typec, i);
|
||||||
|
|
||||||
usb_role_switch_put(typec->ports[i]->role_sw);
|
usb_role_switch_put(typec->ports[i]->role_sw);
|
||||||
typec_switch_put(typec->ports[i]->ori_sw);
|
typec_switch_put(typec->ports[i]->ori_sw);
|
||||||
typec_mux_put(typec->ports[i]->mux);
|
typec_mux_put(typec->ports[i]->mux);
|
||||||
@@ -323,13 +352,14 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
|
|||||||
|
|
||||||
cros_typec_register_port_altmodes(typec, port_num);
|
cros_typec_register_port_altmodes(typec, port_num);
|
||||||
|
|
||||||
cros_port->sop_disc = devm_kzalloc(dev, EC_PROTO2_MAX_RESPONSE_SIZE, GFP_KERNEL);
|
cros_port->disc_data = devm_kzalloc(dev, EC_PROTO2_MAX_RESPONSE_SIZE, GFP_KERNEL);
|
||||||
if (!cros_port->sop_disc) {
|
if (!cros_port->disc_data) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto unregister_ports;
|
goto unregister_ports;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&cros_port->partner_mode_list);
|
INIT_LIST_HEAD(&cros_port->partner_mode_list);
|
||||||
|
INIT_LIST_HEAD(&cros_port->plug_mode_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -502,6 +532,7 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
|
|||||||
struct ec_response_usb_pd_control_v2 *pd_ctrl)
|
struct ec_response_usb_pd_control_v2 *pd_ctrl)
|
||||||
{
|
{
|
||||||
struct cros_typec_port *port = typec->ports[port_num];
|
struct cros_typec_port *port = typec->ports[port_num];
|
||||||
|
struct ec_params_usb_pd_mux_ack mux_ack;
|
||||||
enum typec_orientation orientation;
|
enum typec_orientation orientation;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -541,6 +572,18 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
|
|||||||
mux_flags);
|
mux_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!typec->needs_mux_ack)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Sending Acknowledgment to EC */
|
||||||
|
mux_ack.port = port_num;
|
||||||
|
|
||||||
|
if (cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack,
|
||||||
|
sizeof(mux_ack), NULL, 0) < 0)
|
||||||
|
dev_warn(typec->dev,
|
||||||
|
"Failed to send Mux ACK to EC for port: %d\n",
|
||||||
|
port_num);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,6 +641,9 @@ static void cros_typec_set_port_params_v1(struct cros_typec_data *typec,
|
|||||||
if (!typec->ports[port_num]->partner)
|
if (!typec->ports[port_num]->partner)
|
||||||
return;
|
return;
|
||||||
cros_typec_remove_partner(typec, port_num);
|
cros_typec_remove_partner(typec, port_num);
|
||||||
|
|
||||||
|
if (typec->ports[port_num]->cable)
|
||||||
|
cros_typec_remove_cable(typec, port_num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,13 +658,18 @@ static int cros_typec_get_mux_info(struct cros_typec_data *typec, int port_num,
|
|||||||
sizeof(req), resp, sizeof(*resp));
|
sizeof(req), resp, sizeof(*resp));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cros_typec_register_altmodes(struct cros_typec_data *typec, int port_num)
|
/*
|
||||||
|
* Helper function to register partner/plug altmodes.
|
||||||
|
*/
|
||||||
|
static int cros_typec_register_altmodes(struct cros_typec_data *typec, int port_num,
|
||||||
|
bool is_partner)
|
||||||
{
|
{
|
||||||
struct cros_typec_port *port = typec->ports[port_num];
|
struct cros_typec_port *port = typec->ports[port_num];
|
||||||
struct ec_response_typec_discovery *sop_disc = port->sop_disc;
|
struct ec_response_typec_discovery *sop_disc = port->disc_data;
|
||||||
struct cros_typec_altmode_node *node;
|
struct cros_typec_altmode_node *node;
|
||||||
struct typec_altmode_desc desc;
|
struct typec_altmode_desc desc;
|
||||||
struct typec_altmode *amode;
|
struct typec_altmode *amode;
|
||||||
|
int num_altmodes = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
@@ -629,7 +680,11 @@ static int cros_typec_register_altmodes(struct cros_typec_data *typec, int port_
|
|||||||
desc.mode = j;
|
desc.mode = j;
|
||||||
desc.vdo = sop_disc->svids[i].mode_vdo[j];
|
desc.vdo = sop_disc->svids[i].mode_vdo[j];
|
||||||
|
|
||||||
amode = typec_partner_register_altmode(port->partner, &desc);
|
if (is_partner)
|
||||||
|
amode = typec_partner_register_altmode(port->partner, &desc);
|
||||||
|
else
|
||||||
|
amode = typec_plug_register_altmode(port->plug, &desc);
|
||||||
|
|
||||||
if (IS_ERR(amode)) {
|
if (IS_ERR(amode)) {
|
||||||
ret = PTR_ERR(amode);
|
ret = PTR_ERR(amode);
|
||||||
goto err_cleanup;
|
goto err_cleanup;
|
||||||
@@ -644,27 +699,139 @@ static int cros_typec_register_altmodes(struct cros_typec_data *typec, int port_
|
|||||||
}
|
}
|
||||||
|
|
||||||
node->amode = amode;
|
node->amode = amode;
|
||||||
list_add_tail(&node->list, &port->partner_mode_list);
|
|
||||||
|
if (is_partner)
|
||||||
|
list_add_tail(&node->list, &port->partner_mode_list);
|
||||||
|
else
|
||||||
|
list_add_tail(&node->list, &port->plug_mode_list);
|
||||||
|
num_altmodes++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_partner)
|
||||||
|
ret = typec_partner_set_num_altmodes(port->partner, num_altmodes);
|
||||||
|
else
|
||||||
|
ret = typec_plug_set_num_altmodes(port->plug, num_altmodes);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(typec->dev, "Unable to set %s num_altmodes for port: %d\n",
|
||||||
|
is_partner ? "partner" : "plug", port_num);
|
||||||
|
goto err_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_cleanup:
|
err_cleanup:
|
||||||
cros_typec_unregister_altmodes(typec, port_num);
|
cros_typec_unregister_altmodes(typec, port_num, is_partner);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the PD identity data from the EC PD discovery responses and copy that to the supplied
|
||||||
|
* PD identity struct.
|
||||||
|
*/
|
||||||
|
static void cros_typec_parse_pd_identity(struct usb_pd_identity *id,
|
||||||
|
struct ec_response_typec_discovery *disc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* First, update the PD identity VDOs for the partner. */
|
||||||
|
if (disc->identity_count > 0)
|
||||||
|
id->id_header = disc->discovery_vdo[0];
|
||||||
|
if (disc->identity_count > 1)
|
||||||
|
id->cert_stat = disc->discovery_vdo[1];
|
||||||
|
if (disc->identity_count > 2)
|
||||||
|
id->product = disc->discovery_vdo[2];
|
||||||
|
|
||||||
|
/* Copy the remaining identity VDOs till a maximum of 6. */
|
||||||
|
for (i = 3; i < disc->identity_count && i < VDO_MAX_OBJECTS; i++)
|
||||||
|
id->vdo[i - 3] = disc->discovery_vdo[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cros_typec_handle_sop_prime_disc(struct cros_typec_data *typec, int port_num)
|
||||||
|
{
|
||||||
|
struct cros_typec_port *port = typec->ports[port_num];
|
||||||
|
struct ec_response_typec_discovery *disc = port->disc_data;
|
||||||
|
struct typec_cable_desc c_desc = {};
|
||||||
|
struct typec_plug_desc p_desc;
|
||||||
|
struct ec_params_typec_discovery req = {
|
||||||
|
.port = port_num,
|
||||||
|
.partner_type = TYPEC_PARTNER_SOP_PRIME,
|
||||||
|
};
|
||||||
|
u32 cable_plug_type;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
memset(disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE);
|
||||||
|
ret = cros_typec_ec_command(typec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
|
||||||
|
disc, EC_PROTO2_MAX_RESPONSE_SIZE);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(typec->dev, "Failed to get SOP' discovery data for port: %d\n", port_num);
|
||||||
|
goto sop_prime_disc_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the PD identity data, even if only 0s were returned. */
|
||||||
|
cros_typec_parse_pd_identity(&port->c_identity, disc);
|
||||||
|
|
||||||
|
if (disc->identity_count != 0) {
|
||||||
|
cable_plug_type = VDO_TYPEC_CABLE_TYPE(port->c_identity.vdo[0]);
|
||||||
|
switch (cable_plug_type) {
|
||||||
|
case CABLE_ATYPE:
|
||||||
|
c_desc.type = USB_PLUG_TYPE_A;
|
||||||
|
break;
|
||||||
|
case CABLE_BTYPE:
|
||||||
|
c_desc.type = USB_PLUG_TYPE_B;
|
||||||
|
break;
|
||||||
|
case CABLE_CTYPE:
|
||||||
|
c_desc.type = USB_PLUG_TYPE_C;
|
||||||
|
break;
|
||||||
|
case CABLE_CAPTIVE:
|
||||||
|
c_desc.type = USB_PLUG_CAPTIVE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
c_desc.type = USB_PLUG_NONE;
|
||||||
|
}
|
||||||
|
c_desc.active = PD_IDH_PTYPE(port->c_identity.id_header) == IDH_PTYPE_ACABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_desc.identity = &port->c_identity;
|
||||||
|
|
||||||
|
port->cable = typec_register_cable(port->port, &c_desc);
|
||||||
|
if (IS_ERR(port->cable)) {
|
||||||
|
ret = PTR_ERR(port->cable);
|
||||||
|
port->cable = NULL;
|
||||||
|
goto sop_prime_disc_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_desc.index = TYPEC_PLUG_SOP_P;
|
||||||
|
port->plug = typec_register_plug(port->cable, &p_desc);
|
||||||
|
if (IS_ERR(port->plug)) {
|
||||||
|
ret = PTR_ERR(port->plug);
|
||||||
|
port->plug = NULL;
|
||||||
|
goto sop_prime_disc_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cros_typec_register_altmodes(typec, port_num, false);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(typec->dev, "Failed to register plug altmodes, port: %d\n", port_num);
|
||||||
|
goto sop_prime_disc_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sop_prime_disc_exit:
|
||||||
|
cros_typec_remove_cable(typec, port_num);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_num)
|
static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_num)
|
||||||
{
|
{
|
||||||
struct cros_typec_port *port = typec->ports[port_num];
|
struct cros_typec_port *port = typec->ports[port_num];
|
||||||
struct ec_response_typec_discovery *sop_disc = port->sop_disc;
|
struct ec_response_typec_discovery *sop_disc = port->disc_data;
|
||||||
struct ec_params_typec_discovery req = {
|
struct ec_params_typec_discovery req = {
|
||||||
.port = port_num,
|
.port = port_num,
|
||||||
.partner_type = TYPEC_PARTNER_SOP,
|
.partner_type = TYPEC_PARTNER_SOP,
|
||||||
};
|
};
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!port->partner) {
|
if (!port->partner) {
|
||||||
dev_err(typec->dev,
|
dev_err(typec->dev,
|
||||||
@@ -682,17 +849,7 @@ static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_nu
|
|||||||
goto disc_exit;
|
goto disc_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First, update the PD identity VDOs for the partner. */
|
cros_typec_parse_pd_identity(&port->p_identity, sop_disc);
|
||||||
if (sop_disc->identity_count > 0)
|
|
||||||
port->p_identity.id_header = sop_disc->discovery_vdo[0];
|
|
||||||
if (sop_disc->identity_count > 1)
|
|
||||||
port->p_identity.cert_stat = sop_disc->discovery_vdo[1];
|
|
||||||
if (sop_disc->identity_count > 2)
|
|
||||||
port->p_identity.product = sop_disc->discovery_vdo[2];
|
|
||||||
|
|
||||||
/* Copy the remaining identity VDOs till a maximum of 6. */
|
|
||||||
for (i = 3; i < sop_disc->identity_count && i < VDO_MAX_OBJECTS; i++)
|
|
||||||
port->p_identity.vdo[i - 3] = sop_disc->discovery_vdo[i];
|
|
||||||
|
|
||||||
ret = typec_partner_set_identity(port->partner);
|
ret = typec_partner_set_identity(port->partner);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -700,7 +857,7 @@ static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_nu
|
|||||||
goto disc_exit;
|
goto disc_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cros_typec_register_altmodes(typec, port_num);
|
ret = cros_typec_register_altmodes(typec, port_num, true);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(typec->dev, "Failed to register partner altmodes, port: %d\n", port_num);
|
dev_err(typec->dev, "Failed to register partner altmodes, port: %d\n", port_num);
|
||||||
goto disc_exit;
|
goto disc_exit;
|
||||||
@@ -725,18 +882,22 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typec->ports[port_num]->disc_done)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Handle any events appropriately. */
|
/* Handle any events appropriately. */
|
||||||
if (resp.events & PD_STATUS_EVENT_SOP_DISC_DONE) {
|
if (resp.events & PD_STATUS_EVENT_SOP_DISC_DONE && !typec->ports[port_num]->sop_disc_done) {
|
||||||
ret = cros_typec_handle_sop_disc(typec, port_num);
|
ret = cros_typec_handle_sop_disc(typec, port_num);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
dev_err(typec->dev, "Couldn't parse SOP Disc data, port: %d\n", port_num);
|
dev_err(typec->dev, "Couldn't parse SOP Disc data, port: %d\n", port_num);
|
||||||
return;
|
else
|
||||||
}
|
typec->ports[port_num]->sop_disc_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
typec->ports[port_num]->disc_done = true;
|
if (resp.events & PD_STATUS_EVENT_SOP_PRIME_DISC_DONE &&
|
||||||
|
!typec->ports[port_num]->sop_prime_disc_done) {
|
||||||
|
ret = cros_typec_handle_sop_prime_disc(typec, port_num);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(typec->dev, "Couldn't parse SOP' Disc data, port: %d\n", port_num);
|
||||||
|
else
|
||||||
|
typec->ports[port_num]->sop_prime_disc_done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,8 +988,8 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the EC feature flags to see if TYPEC_* commands are supported. */
|
/* Check the EC feature flags to see if TYPEC_* features are supported. */
|
||||||
static int cros_typec_cmds_supported(struct cros_typec_data *typec)
|
static int cros_typec_feature_supported(struct cros_typec_data *typec, enum ec_feature_code feature)
|
||||||
{
|
{
|
||||||
struct ec_response_get_features resp = {};
|
struct ec_response_get_features resp = {};
|
||||||
int ret;
|
int ret;
|
||||||
@@ -837,11 +998,12 @@ static int cros_typec_cmds_supported(struct cros_typec_data *typec)
|
|||||||
&resp, sizeof(resp));
|
&resp, sizeof(resp));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_warn(typec->dev,
|
dev_warn(typec->dev,
|
||||||
"Failed to get features, assuming typec commands unsupported.\n");
|
"Failed to get features, assuming typec feature=%d unsupported.\n",
|
||||||
|
feature);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.flags[EC_FEATURE_TYPEC_CMD / 32] & EC_FEATURE_MASK_1(EC_FEATURE_TYPEC_CMD);
|
return resp.flags[feature / 32] & EC_FEATURE_MASK_1(feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cros_typec_port_work(struct work_struct *work)
|
static void cros_typec_port_work(struct work_struct *work)
|
||||||
@@ -903,7 +1065,10 @@ static int cros_typec_probe(struct platform_device *pdev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
typec->typec_cmd_supported = !!cros_typec_cmds_supported(typec);
|
typec->typec_cmd_supported = !!cros_typec_feature_supported(typec,
|
||||||
|
EC_FEATURE_TYPEC_CMD);
|
||||||
|
typec->needs_mux_ack = !!cros_typec_feature_supported(typec,
|
||||||
|
EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK);
|
||||||
|
|
||||||
ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
|
ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
|
||||||
&resp, sizeof(resp));
|
&resp, sizeof(resp));
|
||||||
|
|||||||
@@ -1286,6 +1286,16 @@ enum ec_feature_code {
|
|||||||
EC_FEATURE_ISH = 40,
|
EC_FEATURE_ISH = 40,
|
||||||
/* New TCPMv2 TYPEC_ prefaced commands supported */
|
/* New TCPMv2 TYPEC_ prefaced commands supported */
|
||||||
EC_FEATURE_TYPEC_CMD = 41,
|
EC_FEATURE_TYPEC_CMD = 41,
|
||||||
|
/*
|
||||||
|
* The EC will wait for direction from the AP to enter Type-C alternate
|
||||||
|
* modes or USB4.
|
||||||
|
*/
|
||||||
|
EC_FEATURE_TYPEC_REQUIRE_AP_MODE_ENTRY = 42,
|
||||||
|
/*
|
||||||
|
* The EC will wait for an acknowledge from the AP after setting the
|
||||||
|
* mux.
|
||||||
|
*/
|
||||||
|
EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK = 43,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32)
|
#define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32)
|
||||||
@@ -6054,6 +6064,13 @@ struct ec_params_charger_control {
|
|||||||
uint8_t allow_charging;
|
uint8_t allow_charging;
|
||||||
} __ec_align_size1;
|
} __ec_align_size1;
|
||||||
|
|
||||||
|
/* Get ACK from the USB-C SS muxes */
|
||||||
|
#define EC_CMD_USB_PD_MUX_ACK 0x0603
|
||||||
|
|
||||||
|
struct ec_params_usb_pd_mux_ack {
|
||||||
|
uint8_t port; /* USB-C port number */
|
||||||
|
} __ec_align1;
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*
|
/*
|
||||||
* Reserve a range of host commands for board-specific, experimental, or
|
* Reserve a range of host commands for board-specific, experimental, or
|
||||||
|
|||||||
Reference in New Issue
Block a user