Merge "power_supply: Add additional USB PD properties"

This commit is contained in:
Linux Build Service Account 2016-10-15 01:19:58 -07:00 committed by Gerrit - the friendly Code Review server
commit cb74f5d749
4 changed files with 300 additions and 107 deletions

View file

@ -40,6 +40,9 @@ Optional properties:
- vconn-supply: Regulator that enables VCONN source output. This will - vconn-supply: Regulator that enables VCONN source output. This will
be supplied on the USB CC line that is not used for be supplied on the USB CC line that is not used for
communication when Ra resistance is detected. communication when Ra resistance is detected.
- qcom,vconn-uses-external-source: Indicates whether VCONN supply is sourced
from an external regulator. If omitted, then it is
assumed it is connected to VBUS.
Example: Example:
qcom,qpnp-pdphy@1700 { qcom,qpnp-pdphy@1700 {

View file

@ -267,6 +267,9 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(typec_power_role), POWER_SUPPLY_ATTR(typec_power_role),
POWER_SUPPLY_ATTR(pd_allowed), POWER_SUPPLY_ATTR(pd_allowed),
POWER_SUPPLY_ATTR(pd_active), POWER_SUPPLY_ATTR(pd_active),
POWER_SUPPLY_ATTR(pd_in_hard_reset),
POWER_SUPPLY_ATTR(pd_current_max),
POWER_SUPPLY_ATTR(pd_usb_suspend_supported),
POWER_SUPPLY_ATTR(charger_temp), POWER_SUPPLY_ATTR(charger_temp),
POWER_SUPPLY_ATTR(charger_temp_max), POWER_SUPPLY_ATTR(charger_temp_max),
POWER_SUPPLY_ATTR(parallel_disable), POWER_SUPPLY_ATTR(parallel_disable),

View file

@ -59,6 +59,7 @@ enum usbpd_state {
PE_PRS_SRC_SNK_SEND_SWAP, PE_PRS_SRC_SNK_SEND_SWAP,
PE_PRS_SRC_SNK_TRANSITION_TO_OFF, PE_PRS_SRC_SNK_TRANSITION_TO_OFF,
PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_PRS_SRC_SNK_WAIT_SOURCE_ON,
PE_VCS_WAIT_FOR_VCONN,
}; };
static const char * const usbpd_state_strings[] = { static const char * const usbpd_state_strings[] = {
@ -94,6 +95,7 @@ static const char * const usbpd_state_strings[] = {
"PRS_SRC_SNK_Send_Swap", "PRS_SRC_SNK_Send_Swap",
"PRS_SRC_SNK_Transition_to_off", "PRS_SRC_SNK_Transition_to_off",
"PRS_SRC_SNK_Wait_Source_on", "PRS_SRC_SNK_Wait_Source_on",
"VCS_Wait_for_VCONN",
}; };
enum usbpd_control_msg_type { enum usbpd_control_msg_type {
@ -170,6 +172,7 @@ static void *usbpd_ipc_log;
#define PS_SOURCE_OFF 750 #define PS_SOURCE_OFF 750
#define SWAP_SOURCE_START_TIME 20 #define SWAP_SOURCE_START_TIME 20
#define VDM_BUSY_TIME 50 #define VDM_BUSY_TIME 50
#define VCONN_ON_TIME 100
/* tPSHardReset + tSafe0V + tSrcRecover + tSrcTurnOn */ /* tPSHardReset + tSafe0V + tSrcRecover + tSrcTurnOn */
#define SNK_HARD_RESET_RECOVER_TIME (35 + 650 + 1000 + 275) #define SNK_HARD_RESET_RECOVER_TIME (35 + 650 + 1000 + 275)
@ -195,7 +198,7 @@ static void *usbpd_ipc_log;
#define PD_RDO_MISMATCH(rdo) ((rdo) >> 26 & 1) #define PD_RDO_MISMATCH(rdo) ((rdo) >> 26 & 1)
#define PD_RDO_USB_COMM(rdo) ((rdo) >> 25 & 1) #define PD_RDO_USB_COMM(rdo) ((rdo) >> 25 & 1)
#define PD_RDO_NO_USB_SUSP(rdo) ((rdo) >> 24 & 1) #define PD_RDO_NO_USB_SUSP(rdo) ((rdo) >> 24 & 1)
#define PD_RDO_FIXED_CURR(rdo) ((rdo) >> 19 & 0x3FF) #define PD_RDO_FIXED_CURR(rdo) ((rdo) >> 10 & 0x3FF)
#define PD_RDO_FIXED_CURR_MINMAX(rdo) ((rdo) & 0x3FF) #define PD_RDO_FIXED_CURR_MINMAX(rdo) ((rdo) & 0x3FF)
#define PD_SRC_PDO_TYPE(pdo) (((pdo) >> 30) & 3) #define PD_SRC_PDO_TYPE(pdo) (((pdo) >> 30) & 3)
@ -223,9 +226,10 @@ static void *usbpd_ipc_log;
/* VDM header is the first 32-bit object following the 16-bit PD header */ /* VDM header is the first 32-bit object following the 16-bit PD header */
#define VDM_HDR_SVID(hdr) ((hdr) >> 16) #define VDM_HDR_SVID(hdr) ((hdr) >> 16)
#define VDM_HDR_TYPE(hdr) ((hdr) & 0x8000) #define VDM_IS_SVDM(hdr) ((hdr) & 0x8000)
#define VDM_HDR_CMD_TYPE(hdr) (((hdr) >> 6) & 0x3) #define SVDM_HDR_OBJ_POS(hdr) (((hdr) >> 8) & 0x7)
#define VDM_HDR_CMD(hdr) ((hdr) & 0x1f) #define SVDM_HDR_CMD_TYPE(hdr) (((hdr) >> 6) & 0x3)
#define SVDM_HDR_CMD(hdr) ((hdr) & 0x1f)
#define SVDM_HDR(svid, ver, obj, cmd_type, cmd) \ #define SVDM_HDR(svid, ver, obj, cmd_type, cmd) \
(((svid) << 16) | (1 << 15) | ((ver) << 13) \ (((svid) << 16) | (1 << 15) | ((ver) << 13) \
@ -253,15 +257,11 @@ static bool ss_dev = true;
module_param(ss_dev, bool, S_IRUSR | S_IWUSR); module_param(ss_dev, bool, S_IRUSR | S_IWUSR);
static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */ static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */
static const u32 default_snk_caps[] = { 0x2601905A }; /* 5V @ 900mA */
static const u32 default_snk_caps[] = { 0x2601905A, /* 5V @ 900mA */
0x0002D096, /* 9V @ 1.5A */
0x0003C064 }; /* 12V @ 1A */
struct vdm_tx { struct vdm_tx {
u32 data[7]; u32 data[7];
int size; int size;
struct list_head entry;
}; };
struct usbpd { struct usbpd {
@ -269,6 +269,7 @@ struct usbpd {
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct work_struct sm_work; struct work_struct sm_work;
struct hrtimer timer; struct hrtimer timer;
bool sm_queued;
struct extcon_dev *extcon; struct extcon_dev *extcon;
@ -307,6 +308,7 @@ struct usbpd {
struct regulator *vbus; struct regulator *vbus;
struct regulator *vconn; struct regulator *vconn;
bool vconn_enabled; bool vconn_enabled;
bool vconn_is_external;
u8 tx_msgid; u8 tx_msgid;
u8 rx_msgid; u8 rx_msgid;
@ -315,8 +317,9 @@ struct usbpd {
enum vdm_state vdm_state; enum vdm_state vdm_state;
u16 *discovered_svids; u16 *discovered_svids;
int num_svids;
struct vdm_tx *vdm_tx;
struct vdm_tx *vdm_tx_retry; struct vdm_tx *vdm_tx_retry;
struct list_head vdm_tx_queue;
struct list_head svid_handlers; struct list_head svid_handlers;
struct list_head instance; struct list_head instance;
@ -440,6 +443,12 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos)
} }
pd->requested_voltage = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000; pd->requested_voltage = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000;
/* Can't sink more than 5V if VCONN is sourced from the VBUS input */
if (pd->vconn_enabled && !pd->vconn_is_external &&
pd->requested_voltage > 5000000)
return -ENOTSUPP;
pd->requested_current = curr; pd->requested_current = curr;
pd->requested_pdo = pdo_pos; pd->requested_pdo = pdo_pos;
pd->rdo = PD_RDO_FIXED(pdo_pos, 0, mismatch, 1, 1, curr / 10, pd->rdo = PD_RDO_FIXED(pdo_pos, 0, mismatch, 1, 1, curr / 10,
@ -485,6 +494,17 @@ static void pd_send_hard_reset(struct usbpd *pd)
pd->hard_reset = true; pd->hard_reset = true;
} }
static void kick_sm(struct usbpd *pd, int ms)
{
pm_stay_awake(&pd->dev);
pd->sm_queued = true;
if (ms)
hrtimer_start(&pd->timer, ms_to_ktime(ms), HRTIMER_MODE_REL);
else
queue_work(pd->wq, &pd->sm_work);
}
static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
{ {
if (type != HARD_RESET_SIG) { if (type != HARD_RESET_SIG) {
@ -497,7 +517,7 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
/* Force CC logic to source/sink to keep Rp/Rd unchanged */ /* Force CC logic to source/sink to keep Rp/Rd unchanged */
set_power_role(pd, pd->current_pr); set_power_role(pd, pd->current_pr);
pd->hard_reset = true; pd->hard_reset = true;
queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0);
} }
static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
@ -534,6 +554,10 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
pd->rx_msgid = PD_MSG_HDR_ID(header); pd->rx_msgid = PD_MSG_HDR_ID(header);
/* discard Pings */
if (PD_MSG_HDR_TYPE(header) == MSG_PING && !len)
return;
/* check header's count field to see if it matches len */ /* check header's count field to see if it matches len */
if (PD_MSG_HDR_COUNT(header) != (len / 4)) { if (PD_MSG_HDR_COUNT(header) != (len / 4)) {
usbpd_err(&pd->dev, "header count (%d) mismatch, len=%ld\n", usbpd_err(&pd->dev, "header count (%d) mismatch, len=%ld\n",
@ -541,11 +565,18 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
return; return;
} }
/* block until previous message has been consumed by usbpd_sm */
if (pd->rx_msg_type)
flush_work(&pd->sm_work);
pd->rx_msg_type = PD_MSG_HDR_TYPE(header); pd->rx_msg_type = PD_MSG_HDR_TYPE(header);
pd->rx_msg_len = PD_MSG_HDR_COUNT(header); pd->rx_msg_len = PD_MSG_HDR_COUNT(header);
memcpy(&pd->rx_payload, buf, len); memcpy(&pd->rx_payload, buf, len);
queue_work(pd->wq, &pd->sm_work); usbpd_dbg(&pd->dev, "received message: type(%d) len(%d)\n",
pd->rx_msg_type, pd->rx_msg_len);
kick_sm(pd, 0);
} }
static void phy_shutdown(struct usbpd *pd) static void phy_shutdown(struct usbpd *pd)
@ -587,7 +618,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->in_pr_swap = false; pd->in_pr_swap = false;
set_power_role(pd, PR_NONE); set_power_role(pd, PR_NONE);
pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; pd->typec_mode = POWER_SUPPLY_TYPEC_NONE;
queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0);
break; break;
/* Source states */ /* Source states */
@ -634,20 +665,22 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->current_state = PE_SRC_SEND_CAPABILITIES; pd->current_state = PE_SRC_SEND_CAPABILITIES;
if (pd->in_pr_swap) { if (pd->in_pr_swap) {
pd->in_pr_swap = false; pd->in_pr_swap = false;
hrtimer_start(&pd->timer, kick_sm(pd, SWAP_SOURCE_START_TIME);
ms_to_ktime(SWAP_SOURCE_START_TIME),
HRTIMER_MODE_REL);
break; break;
} }
/* fall-through */ /* fall-through */
case PE_SRC_SEND_CAPABILITIES: case PE_SRC_SEND_CAPABILITIES:
queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0);
break; break;
case PE_SRC_NEGOTIATE_CAPABILITY: case PE_SRC_NEGOTIATE_CAPABILITY:
if (PD_RDO_OBJ_POS(pd->rdo) != 1) { if (PD_RDO_OBJ_POS(pd->rdo) != 1 ||
PD_RDO_FIXED_CURR(pd->rdo) >
PD_SRC_PDO_FIXED_MAX_CURR(*default_src_caps) ||
PD_RDO_FIXED_CURR_MINMAX(pd->rdo) >
PD_SRC_PDO_FIXED_MAX_CURR(*default_src_caps)) {
/* send Reject */ /* send Reject */
ret = pd_send_msg(pd, MSG_REJECT, NULL, 0, SOP_MSG); ret = pd_send_msg(pd, MSG_REJECT, NULL, 0, SOP_MSG);
if (ret) { if (ret) {
@ -717,6 +750,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
break; break;
case PE_SRC_TRANSITION_TO_DEFAULT: case PE_SRC_TRANSITION_TO_DEFAULT:
pd->hard_reset = false;
if (pd->vconn_enabled) if (pd->vconn_enabled)
regulator_disable(pd->vconn); regulator_disable(pd->vconn);
regulator_disable(pd->vbus); regulator_disable(pd->vbus);
@ -747,7 +782,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SRC_HARD_RESET: case PE_SRC_HARD_RESET:
case PE_SNK_HARD_RESET: case PE_SNK_HARD_RESET:
/* hard reset may sleep; handle it in the workqueue */ /* hard reset may sleep; handle it in the workqueue */
queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0);
break; break;
case PE_SRC_SEND_SOFT_RESET: case PE_SRC_SEND_SOFT_RESET:
@ -765,8 +800,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
} }
/* wait for ACCEPT */ /* wait for ACCEPT */
hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME), kick_sm(pd, SENDER_RESPONSE_TIME);
HRTIMER_MODE_REL);
break; break;
/* Sink states */ /* Sink states */
@ -786,9 +820,11 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
} }
} }
/* Reset protocol layer */
pd->tx_msgid = 0;
pd->rx_msgid = -1;
pd->rx_msg_len = 0; pd->rx_msg_len = 0;
pd->rx_msg_type = 0; pd->rx_msg_type = 0;
pd->rx_msgid = -1;
if (!pd->in_pr_swap) { if (!pd->in_pr_swap) {
if (pd->pd_phy_opened) { if (pd->pd_phy_opened) {
@ -819,11 +855,9 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SNK_WAIT_FOR_CAPABILITIES: case PE_SNK_WAIT_FOR_CAPABILITIES:
if (pd->rx_msg_len && pd->rx_msg_type) if (pd->rx_msg_len && pd->rx_msg_type)
queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0);
else else
hrtimer_start(&pd->timer, kick_sm(pd, SINK_WAIT_CAP_TIME);
ms_to_ktime(SINK_WAIT_CAP_TIME),
HRTIMER_MODE_REL);
break; break;
case PE_SNK_EVALUATE_CAPABILITY: case PE_SNK_EVALUATE_CAPABILITY:
@ -841,18 +875,19 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SNK_SELECT_CAPABILITY: case PE_SNK_SELECT_CAPABILITY:
ret = pd_send_msg(pd, MSG_REQUEST, &pd->rdo, 1, SOP_MSG); ret = pd_send_msg(pd, MSG_REQUEST, &pd->rdo, 1, SOP_MSG);
if (ret) if (ret) {
usbpd_err(&pd->dev, "Error sending Request\n"); usbpd_err(&pd->dev, "Error sending Request\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
/* wait for ACCEPT */ /* wait for ACCEPT */
hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME), kick_sm(pd, SENDER_RESPONSE_TIME);
HRTIMER_MODE_REL);
break; break;
case PE_SNK_TRANSITION_SINK: case PE_SNK_TRANSITION_SINK:
/* wait for PS_RDY */ /* wait for PS_RDY */
hrtimer_start(&pd->timer, ms_to_ktime(PS_TRANSITION_TIME), kick_sm(pd, PS_TRANSITION_TIME);
HRTIMER_MODE_REL);
break; break;
case PE_SNK_READY: case PE_SNK_READY:
@ -861,6 +896,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
break; break;
case PE_SNK_TRANSITION_TO_DEFAULT: case PE_SNK_TRANSITION_TO_DEFAULT:
pd->hard_reset = false;
if (pd->current_dr != DR_UFP) { if (pd->current_dr != DR_UFP) {
extcon_set_cable_state_(pd->extcon, EXTCON_USB_HOST, 0); extcon_set_cable_state_(pd->extcon, EXTCON_USB_HOST, 0);
@ -877,17 +914,13 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->vconn_enabled = false; pd->vconn_enabled = false;
} }
pd->tx_msgid = 0;
val.intval = pd->requested_voltage; /* set range back to 5V */ val.intval = pd->requested_voltage; /* set range back to 5V */
power_supply_set_property(pd->usb_psy, power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &val); POWER_SUPPLY_PROP_VOLTAGE_MAX, &val);
pd->current_voltage = pd->requested_voltage; pd->current_voltage = pd->requested_voltage;
/* max time for hard reset to toggle vbus off/on */ /* max time for hard reset to toggle vbus off/on */
hrtimer_start(&pd->timer, kick_sm(pd, SNK_HARD_RESET_RECOVER_TIME);
ms_to_ktime(SNK_HARD_RESET_RECOVER_TIME),
HRTIMER_MODE_REL);
break; break;
case PE_PRS_SNK_SRC_TRANSITION_TO_OFF: case PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
@ -904,8 +937,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd_phy_update_roles(pd->current_dr, PR_SRC); pd_phy_update_roles(pd->current_dr, PR_SRC);
/* wait for PS_RDY */ /* wait for PS_RDY */
hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_OFF), kick_sm(pd, PS_SOURCE_OFF);
HRTIMER_MODE_REL);
break; break;
default: default:
@ -929,10 +961,10 @@ int usbpd_register_svid(struct usbpd *pd, struct usbpd_svid_handler *hdlr)
/* already connected with this SVID discovered? */ /* already connected with this SVID discovered? */
if (pd->vdm_state >= DISCOVERED_SVIDS) { if (pd->vdm_state >= DISCOVERED_SVIDS) {
u16 *psvid; int i;
for (psvid = pd->discovered_svids; *psvid; psvid++) { for (i = 0; i < pd->num_svids; i++) {
if (*psvid == hdlr->svid) { if (pd->discovered_svids[i] == hdlr->svid) {
if (hdlr->connect) if (hdlr->connect)
hdlr->connect(hdlr); hdlr->connect(hdlr);
break; break;
@ -954,7 +986,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos)
{ {
struct vdm_tx *vdm_tx; struct vdm_tx *vdm_tx;
if (!pd->in_explicit_contract) if (!pd->in_explicit_contract || pd->vdm_tx)
return -EBUSY; return -EBUSY;
vdm_tx = kzalloc(sizeof(*vdm_tx), GFP_KERNEL); vdm_tx = kzalloc(sizeof(*vdm_tx), GFP_KERNEL);
@ -967,8 +999,10 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos)
vdm_tx->size = num_vdos + 1; /* include the header */ vdm_tx->size = num_vdos + 1; /* include the header */
/* VDM will get sent in PE_SRC/SNK_READY state handling */ /* VDM will get sent in PE_SRC/SNK_READY state handling */
list_add_tail(&vdm_tx->entry, &pd->vdm_tx_queue); pd->vdm_tx = vdm_tx;
queue_work(pd->wq, &pd->sm_work);
/* slight delay before queuing to prioritize handling of incoming VDM */
kick_sm(pd, 5);
return 0; return 0;
} }
@ -994,8 +1028,8 @@ static void handle_vdm_rx(struct usbpd *pd)
u16 svid = VDM_HDR_SVID(vdm_hdr); u16 svid = VDM_HDR_SVID(vdm_hdr);
u16 *psvid; u16 *psvid;
u8 i, num_vdos = pd->rx_msg_len - 1; /* num objects minus header */ u8 i, num_vdos = pd->rx_msg_len - 1; /* num objects minus header */
u8 cmd = VDM_HDR_CMD(vdm_hdr); u8 cmd = SVDM_HDR_CMD(vdm_hdr);
u8 cmd_type = VDM_HDR_CMD_TYPE(vdm_hdr); u8 cmd_type = SVDM_HDR_CMD_TYPE(vdm_hdr);
struct usbpd_svid_handler *handler; struct usbpd_svid_handler *handler;
usbpd_dbg(&pd->dev, "VDM rx: svid:%x cmd:%x cmd_type:%x vdm_hdr:%x\n", usbpd_dbg(&pd->dev, "VDM rx: svid:%x cmd:%x cmd_type:%x vdm_hdr:%x\n",
@ -1005,7 +1039,7 @@ static void handle_vdm_rx(struct usbpd *pd)
handler = find_svid_handler(pd, svid); handler = find_svid_handler(pd, svid);
/* Unstructured VDM */ /* Unstructured VDM */
if (!VDM_HDR_TYPE(vdm_hdr)) { if (!VDM_IS_SVDM(vdm_hdr)) {
if (handler && handler->vdm_received) if (handler && handler->vdm_received)
handler->vdm_received(handler, vdm_hdr, vdos, num_vdos); handler->vdm_received(handler, vdm_hdr, vdos, num_vdos);
return; return;
@ -1016,7 +1050,19 @@ static void handle_vdm_rx(struct usbpd *pd)
switch (cmd_type) { switch (cmd_type) {
case SVDM_CMD_TYPE_INITIATOR: case SVDM_CMD_TYPE_INITIATOR:
if (cmd == USBPD_SVDM_DISCOVER_IDENTITY) { /*
* if this interrupts a previous exchange, abort the previous
* outgoing response
*/
if (pd->vdm_tx) {
usbpd_dbg(&pd->dev, "Discarding previously queued SVDM tx (SVID:0x%04x)\n",
VDM_HDR_SVID(pd->vdm_tx->data[0]));
kfree(pd->vdm_tx);
pd->vdm_tx = NULL;
}
if (svid == USBPD_SID && cmd == USBPD_SVDM_DISCOVER_IDENTITY) {
u32 tx_vdos[3] = { u32 tx_vdos[3] = {
ID_HDR_USB_HOST | ID_HDR_USB_DEVICE | ID_HDR_USB_HOST | ID_HDR_USB_DEVICE |
ID_HDR_PRODUCT_PER_MASK | ID_HDR_VID, ID_HDR_PRODUCT_PER_MASK | ID_HDR_VID,
@ -1027,9 +1073,9 @@ static void handle_vdm_rx(struct usbpd *pd)
usbpd_send_svdm(pd, USBPD_SID, cmd, usbpd_send_svdm(pd, USBPD_SID, cmd,
SVDM_CMD_TYPE_RESP_ACK, 0, tx_vdos, 3); SVDM_CMD_TYPE_RESP_ACK, 0, tx_vdos, 3);
} else { } else if (cmd != USBPD_SVDM_ATTENTION) {
usbpd_send_svdm(pd, USBPD_SID, cmd, usbpd_send_svdm(pd, svid, cmd, SVDM_CMD_TYPE_RESP_NAK,
SVDM_CMD_TYPE_RESP_NAK, 0, NULL, 0); SVDM_HDR_OBJ_POS(vdm_hdr), NULL, 0);
} }
break; break;
@ -1061,19 +1107,37 @@ static void handle_vdm_rx(struct usbpd *pd)
kfree(pd->vdm_tx_retry); kfree(pd->vdm_tx_retry);
pd->vdm_tx_retry = NULL; pd->vdm_tx_retry = NULL;
kfree(pd->discovered_svids);
/* TODO: handle > 12 SVIDs */
pd->discovered_svids = kzalloc((2 * num_vdos + 1) *
sizeof(u16),
GFP_KERNEL);
if (!pd->discovered_svids) { if (!pd->discovered_svids) {
usbpd_err(&pd->dev, "unable to allocate SVIDs\n"); pd->num_svids = 2 * num_vdos;
break; pd->discovered_svids = kcalloc(pd->num_svids,
sizeof(u16),
GFP_KERNEL);
if (!pd->discovered_svids) {
usbpd_err(&pd->dev, "unable to allocate SVIDs\n");
break;
}
psvid = pd->discovered_svids;
} else { /* handle > 12 SVIDs */
void *ptr;
size_t oldsize = pd->num_svids * sizeof(u16);
size_t newsize = oldsize +
(2 * num_vdos * sizeof(u16));
ptr = krealloc(pd->discovered_svids, newsize,
GFP_KERNEL);
if (!ptr) {
usbpd_err(&pd->dev, "unable to realloc SVIDs\n");
break;
}
pd->discovered_svids = ptr;
psvid = pd->discovered_svids + pd->num_svids;
memset(psvid, 0, (2 * num_vdos));
pd->num_svids += 2 * num_vdos;
} }
/* convert 32-bit VDOs to list of 16-bit SVIDs */ /* convert 32-bit VDOs to list of 16-bit SVIDs */
psvid = pd->discovered_svids;
for (i = 0; i < num_vdos * 2; i++) { for (i = 0; i < num_vdos * 2; i++) {
/* /*
* Within each 32-bit VDO, * Within each 32-bit VDO,
@ -1097,8 +1161,22 @@ static void handle_vdm_rx(struct usbpd *pd)
usbpd_dbg(&pd->dev, "Discovered SVID: 0x%04x\n", usbpd_dbg(&pd->dev, "Discovered SVID: 0x%04x\n",
svid); svid);
*psvid++ = svid; *psvid++ = svid;
}
}
/* if SVID supported notify handler */ /* if more than 12 SVIDs, resend the request */
if (num_vdos == 6 && vdos[5] != 0) {
usbpd_send_svdm(pd, USBPD_SID,
USBPD_SVDM_DISCOVER_SVIDS,
SVDM_CMD_TYPE_INITIATOR, 0,
NULL, 0);
break;
}
/* now that all SVIDs are discovered, notify handlers */
for (i = 0; i < pd->num_svids; i++) {
svid = pd->discovered_svids[i];
if (svid) {
handler = find_svid_handler(pd, svid); handler = find_svid_handler(pd, svid);
if (handler && handler->connect) if (handler && handler->connect)
handler->connect(handler); handler->connect(handler);
@ -1148,10 +1226,9 @@ static void handle_vdm_rx(struct usbpd *pd)
} }
/* wait tVDMBusy, then retry */ /* wait tVDMBusy, then retry */
list_move(&pd->vdm_tx_retry->entry, &pd->vdm_tx_queue); pd->vdm_tx = pd->vdm_tx_retry;
pd->vdm_tx_retry = NULL; pd->vdm_tx_retry = NULL;
hrtimer_start(&pd->timer, ms_to_ktime(VDM_BUSY_TIME), kick_sm(pd, VDM_BUSY_TIME);
HRTIMER_MODE_REL);
break; break;
default: default:
break; break;
@ -1165,16 +1242,14 @@ static void handle_vdm_tx(struct usbpd *pd)
int ret; int ret;
/* only send one VDM at a time */ /* only send one VDM at a time */
if (!list_empty(&pd->vdm_tx_queue)) { if (pd->vdm_tx) {
struct vdm_tx *vdm_tx = list_first_entry(&pd->vdm_tx_queue, u32 vdm_hdr = pd->vdm_tx->data[0];
struct vdm_tx, entry);
u32 vdm_hdr = vdm_tx->data[0];
ret = pd_send_msg(pd, MSG_VDM, vdm_tx->data, vdm_tx->size, ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data,
SOP_MSG); pd->vdm_tx->size, SOP_MSG);
if (ret) { if (ret) {
usbpd_err(&pd->dev, "Error sending VDM command %d\n", usbpd_err(&pd->dev, "Error sending VDM command %d\n",
VDM_HDR_CMD(vdm_tx->data[0])); SVDM_HDR_CMD(pd->vdm_tx->data[0]));
usbpd_set_state(pd, pd->current_pr == PR_SRC ? usbpd_set_state(pd, pd->current_pr == PR_SRC ?
PE_SRC_SEND_SOFT_RESET : PE_SRC_SEND_SOFT_RESET :
PE_SNK_SEND_SOFT_RESET); PE_SNK_SEND_SOFT_RESET);
@ -1183,24 +1258,25 @@ static void handle_vdm_tx(struct usbpd *pd)
return; return;
} }
list_del(&vdm_tx->entry);
/* /*
* special case: keep initiated Discover ID/SVIDs * special case: keep initiated Discover ID/SVIDs
* around in case we need to re-try when receiving BUSY * around in case we need to re-try when receiving BUSY
*/ */
if (VDM_HDR_TYPE(vdm_hdr) && if (VDM_IS_SVDM(vdm_hdr) &&
VDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR && SVDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR &&
VDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) { SVDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) {
if (pd->vdm_tx_retry) { if (pd->vdm_tx_retry) {
usbpd_err(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n", usbpd_err(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n",
VDM_HDR_CMD(pd->vdm_tx_retry->data[0])); SVDM_HDR_CMD(
pd->vdm_tx_retry->data[0]));
kfree(pd->vdm_tx_retry); kfree(pd->vdm_tx_retry);
} }
pd->vdm_tx_retry = vdm_tx; pd->vdm_tx_retry = pd->vdm_tx;
} else { } else {
kfree(vdm_tx); kfree(pd->vdm_tx);
} }
pd->vdm_tx = NULL;
} }
} }
@ -1216,13 +1292,9 @@ static void reset_vdm_state(struct usbpd *pd)
pd->vdm_tx_retry = NULL; pd->vdm_tx_retry = NULL;
kfree(pd->discovered_svids); kfree(pd->discovered_svids);
pd->discovered_svids = NULL; pd->discovered_svids = NULL;
while (!list_empty(&pd->vdm_tx_queue)) { pd->num_svids = 0;
struct vdm_tx *vdm_tx = kfree(pd->vdm_tx);
list_first_entry(&pd->vdm_tx_queue, pd->vdm_tx = NULL;
struct vdm_tx, entry);
list_del(&vdm_tx->entry);
kfree(vdm_tx);
}
} }
static void dr_swap(struct usbpd *pd) static void dr_swap(struct usbpd *pd)
@ -1252,6 +1324,34 @@ static void dr_swap(struct usbpd *pd)
pd_phy_update_roles(pd->current_dr, pd->current_pr); pd_phy_update_roles(pd->current_dr, pd->current_pr);
} }
static void vconn_swap(struct usbpd *pd)
{
int ret;
if (pd->vconn_enabled) {
pd->current_state = PE_VCS_WAIT_FOR_VCONN;
kick_sm(pd, VCONN_ON_TIME);
} else {
ret = regulator_enable(pd->vconn);
if (ret) {
usbpd_err(&pd->dev, "Unable to enable vconn\n");
return;
}
pd->vconn_enabled = true;
ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
if (ret) {
usbpd_err(&pd->dev, "Error sending PS_RDY\n");
usbpd_set_state(pd, pd->current_pr == PR_SRC ?
PE_SRC_SEND_SOFT_RESET :
PE_SNK_SEND_SOFT_RESET);
return;
}
}
}
/* Handles current state and determines transitions */ /* Handles current state and determines transitions */
static void usbpd_sm(struct work_struct *w) static void usbpd_sm(struct work_struct *w)
{ {
@ -1265,6 +1365,7 @@ static void usbpd_sm(struct work_struct *w)
usbpd_state_strings[pd->current_state]); usbpd_state_strings[pd->current_state]);
hrtimer_cancel(&pd->timer); hrtimer_cancel(&pd->timer);
pd->sm_queued = false;
if (pd->rx_msg_len) if (pd->rx_msg_len)
data_recvd = pd->rx_msg_type; data_recvd = pd->rx_msg_type;
@ -1274,7 +1375,7 @@ static void usbpd_sm(struct work_struct *w)
/* Disconnect? */ /* Disconnect? */
if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) { if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
if (pd->current_state == PE_UNKNOWN) if (pd->current_state == PE_UNKNOWN)
return; goto sm_done;
usbpd_info(&pd->dev, "USB PD disconnect\n"); usbpd_info(&pd->dev, "USB PD disconnect\n");
@ -1328,7 +1429,7 @@ static void usbpd_sm(struct work_struct *w)
pd->current_state = PE_UNKNOWN; pd->current_state = PE_UNKNOWN;
return; goto sm_done;
} }
/* Hard reset? */ /* Hard reset? */
@ -1339,7 +1440,8 @@ static void usbpd_sm(struct work_struct *w)
usbpd_set_state(pd, PE_SNK_TRANSITION_TO_DEFAULT); usbpd_set_state(pd, PE_SNK_TRANSITION_TO_DEFAULT);
else else
usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT); usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT);
pd->hard_reset = false;
goto sm_done;
} }
/* Soft reset? */ /* Soft reset? */
@ -1400,8 +1502,7 @@ static void usbpd_sm(struct work_struct *w)
break; break;
} }
hrtimer_start(&pd->timer, ms_to_ktime(SRC_CAP_TIME), kick_sm(pd, SRC_CAP_TIME);
HRTIMER_MODE_REL);
break; break;
} }
@ -1416,14 +1517,16 @@ static void usbpd_sm(struct work_struct *w)
/* wait for REQUEST */ /* wait for REQUEST */
pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT; pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT;
hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME), kick_sm(pd, SENDER_RESPONSE_TIME);
HRTIMER_MODE_REL);
break; break;
case PE_SRC_SEND_CAPABILITIES_WAIT: case PE_SRC_SEND_CAPABILITIES_WAIT:
if (data_recvd == MSG_REQUEST) { if (data_recvd == MSG_REQUEST) {
pd->rdo = pd->rx_payload[0]; pd->rdo = pd->rx_payload[0];
usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY); usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY);
} else if (data_recvd || ctrl_recvd) {
usbpd_err(&pd->dev, "Unexpected message received\n");
usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
} else { } else {
usbpd_set_state(pd, PE_SRC_HARD_RESET); usbpd_set_state(pd, PE_SRC_HARD_RESET);
} }
@ -1439,6 +1542,14 @@ static void usbpd_sm(struct work_struct *w)
usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
break; break;
} }
} else if (ctrl_recvd == MSG_GET_SINK_CAP) {
ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES,
default_snk_caps,
ARRAY_SIZE(default_snk_caps), SOP_MSG);
if (ret) {
usbpd_err(&pd->dev, "Error sending Sink Caps\n");
usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
}
} else if (data_recvd == MSG_REQUEST) { } else if (data_recvd == MSG_REQUEST) {
pd->rdo = pd->rx_payload[0]; pd->rdo = pd->rx_payload[0];
usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY); usbpd_set_state(pd, PE_SRC_NEGOTIATE_CAPABILITY);
@ -1470,10 +1581,17 @@ static void usbpd_sm(struct work_struct *w)
} }
pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF; pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF;
hrtimer_start(&pd->timer, kick_sm(pd, SRC_TRANSITION_TIME);
ms_to_ktime(SRC_TRANSITION_TIME),
HRTIMER_MODE_REL);
break; break;
} else if (ctrl_recvd == MSG_VCONN_SWAP) {
ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
if (ret) {
usbpd_err(&pd->dev, "Error sending Accept\n");
usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
break;
}
vconn_swap(pd);
} else { } else {
if (data_recvd == MSG_VDM) if (data_recvd == MSG_VDM)
handle_vdm_rx(pd); handle_vdm_rx(pd);
@ -1538,6 +1656,9 @@ static void usbpd_sm(struct work_struct *w)
else else
usbpd_set_state(pd, usbpd_set_state(pd,
PE_SNK_WAIT_FOR_CAPABILITIES); PE_SNK_WAIT_FOR_CAPABILITIES);
} else if (pd->rx_msg_type) {
usbpd_err(&pd->dev, "Invalid response to sink request\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
} else { } else {
/* timed out; go to hard reset */ /* timed out; go to hard reset */
usbpd_set_state(pd, PE_SNK_HARD_RESET); usbpd_set_state(pd, PE_SNK_HARD_RESET);
@ -1566,9 +1687,9 @@ static void usbpd_sm(struct work_struct *w)
break; break;
case PE_SNK_READY: case PE_SNK_READY:
if (data_recvd == MSG_SOURCE_CAPABILITIES) if (data_recvd == MSG_SOURCE_CAPABILITIES) {
usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY);
else if (ctrl_recvd == MSG_GET_SINK_CAP) { } else if (ctrl_recvd == MSG_GET_SINK_CAP) {
ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES, ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES,
default_snk_caps, default_snk_caps,
ARRAY_SIZE(default_snk_caps), SOP_MSG); ARRAY_SIZE(default_snk_caps), SOP_MSG);
@ -1576,6 +1697,15 @@ static void usbpd_sm(struct work_struct *w)
usbpd_err(&pd->dev, "Error sending Sink Caps\n"); usbpd_err(&pd->dev, "Error sending Sink Caps\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
} }
} else if (ctrl_recvd == MSG_GET_SOURCE_CAP) {
ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES,
default_src_caps,
ARRAY_SIZE(default_src_caps), SOP_MSG);
if (ret) {
usbpd_err(&pd->dev, "Error sending SRC CAPs\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
} else if (ctrl_recvd == MSG_DR_SWAP) { } else if (ctrl_recvd == MSG_DR_SWAP) {
if (pd->vdm_state == MODE_ENTERED) { if (pd->vdm_state == MODE_ENTERED) {
usbpd_set_state(pd, PE_SNK_HARD_RESET); usbpd_set_state(pd, PE_SNK_HARD_RESET);
@ -1606,6 +1736,32 @@ static void usbpd_sm(struct work_struct *w)
pd->in_pr_swap = true; pd->in_pr_swap = true;
usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF); usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
break; break;
} else if (ctrl_recvd == MSG_VCONN_SWAP) {
/*
* if VCONN is connected to VBUS, make sure we are
* not in high voltage contract, otherwise reject.
*/
if (!pd->vconn_is_external &&
(pd->requested_voltage > 5000000)) {
ret = pd_send_msg(pd, MSG_REJECT, NULL, 0,
SOP_MSG);
if (ret) {
usbpd_err(&pd->dev, "Error sending Reject\n");
usbpd_set_state(pd,
PE_SNK_SEND_SOFT_RESET);
}
break;
}
ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
if (ret) {
usbpd_err(&pd->dev, "Error sending Accept\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
vconn_swap(pd);
} else { } else {
if (data_recvd == MSG_VDM) if (data_recvd == MSG_VDM)
handle_vdm_rx(pd); handle_vdm_rx(pd);
@ -1623,7 +1779,7 @@ static void usbpd_sm(struct work_struct *w)
POWER_SUPPLY_PROP_TYPEC_MODE, &val); POWER_SUPPLY_PROP_TYPEC_MODE, &val);
if (val.intval == POWER_SUPPLY_TYPEC_NONE) { if (val.intval == POWER_SUPPLY_TYPEC_NONE) {
pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; pd->typec_mode = POWER_SUPPLY_TYPEC_NONE;
queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0);
} }
} }
break; break;
@ -1701,8 +1857,7 @@ static void usbpd_sm(struct work_struct *w)
} }
pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF; pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF;
hrtimer_start(&pd->timer, ms_to_ktime(SRC_TRANSITION_TIME), kick_sm(pd, SRC_TRANSITION_TIME);
HRTIMER_MODE_REL);
break; break;
case PE_PRS_SRC_SNK_TRANSITION_TO_OFF: case PE_PRS_SRC_SNK_TRANSITION_TO_OFF:
@ -1727,8 +1882,7 @@ static void usbpd_sm(struct work_struct *w)
} }
pd->current_state = PE_PRS_SRC_SNK_WAIT_SOURCE_ON; pd->current_state = PE_PRS_SRC_SNK_WAIT_SOURCE_ON;
hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_ON), kick_sm(pd, PS_SOURCE_ON);
HRTIMER_MODE_REL);
break; break;
case PE_PRS_SRC_SNK_WAIT_SOURCE_ON: case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
@ -1778,6 +1932,26 @@ static void usbpd_sm(struct work_struct *w)
usbpd_set_state(pd, PE_SRC_STARTUP); usbpd_set_state(pd, PE_SRC_STARTUP);
break; break;
case PE_VCS_WAIT_FOR_VCONN:
if (ctrl_recvd == MSG_PS_RDY) {
/*
* hopefully redundant check but in case not enabled
* avoids unbalanced regulator disable count
*/
if (pd->vconn_enabled)
regulator_disable(pd->vconn);
pd->vconn_enabled = false;
pd->current_state = pd->current_pr == PR_SRC ?
PE_SRC_READY : PE_SNK_READY;
} else {
/* timed out; go to hard reset */
usbpd_set_state(pd, pd->current_pr == PR_SRC ?
PE_SRC_HARD_RESET : PE_SNK_HARD_RESET);
}
break;
default: default:
usbpd_err(&pd->dev, "Unhandled state %s\n", usbpd_err(&pd->dev, "Unhandled state %s\n",
usbpd_state_strings[pd->current_state]); usbpd_state_strings[pd->current_state]);
@ -1786,6 +1960,10 @@ static void usbpd_sm(struct work_struct *w)
/* Rx message should have been consumed now */ /* Rx message should have been consumed now */
pd->rx_msg_type = pd->rx_msg_len = 0; pd->rx_msg_type = pd->rx_msg_len = 0;
sm_done:
if (!pd->sm_queued)
pm_relax(&pd->dev);
} }
static inline const char *src_current(enum power_supply_typec_mode typec_mode) static inline const char *src_current(enum power_supply_typec_mode typec_mode)
@ -1897,7 +2075,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
switch (typec_mode) { switch (typec_mode) {
/* Disconnect */ /* Disconnect */
case POWER_SUPPLY_TYPEC_NONE: case POWER_SUPPLY_TYPEC_NONE:
queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0);
break; break;
/* Sink states */ /* Sink states */
@ -1909,7 +2087,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
if (pd->current_pr != PR_SINK || if (pd->current_pr != PR_SINK ||
pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT) { pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT) {
pd->current_pr = PR_SINK; pd->current_pr = PR_SINK;
queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0);
} }
break; break;
@ -1921,7 +2099,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
"" : " (powered)"); "" : " (powered)");
if (pd->current_pr != PR_SRC) { if (pd->current_pr != PR_SRC) {
pd->current_pr = PR_SRC; pd->current_pr = PR_SRC;
queue_work(pd->wq, &pd->sm_work); kick_sm(pd, 0);
} }
break; break;
@ -2359,6 +2537,10 @@ struct usbpd *usbpd_create(struct device *parent)
if (ret) if (ret)
goto free_pd; goto free_pd;
ret = device_init_wakeup(&pd->dev, true);
if (ret)
goto free_pd;
ret = device_add(&pd->dev); ret = device_add(&pd->dev);
if (ret) if (ret)
goto free_pd; goto free_pd;
@ -2414,11 +2596,13 @@ struct usbpd *usbpd_create(struct device *parent)
goto unreg_psy; goto unreg_psy;
} }
pd->vconn_is_external = device_property_present(parent,
"qcom,vconn-uses-external-source");
pd->current_pr = PR_NONE; pd->current_pr = PR_NONE;
pd->current_dr = DR_NONE; pd->current_dr = DR_NONE;
list_add_tail(&pd->instance, &_usbpd); list_add_tail(&pd->instance, &_usbpd);
INIT_LIST_HEAD(&pd->vdm_tx_queue);
INIT_LIST_HEAD(&pd->svid_handlers); INIT_LIST_HEAD(&pd->svid_handlers);
/* force read initial power_supply values */ /* force read initial power_supply values */

View file

@ -216,6 +216,9 @@ enum power_supply_property {
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ALLOWED,
POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_PD_ACTIVE,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET,
POWER_SUPPLY_PROP_PD_CURRENT_MAX,
POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED,
POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP,
POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
POWER_SUPPLY_PROP_PARALLEL_DISABLE, POWER_SUPPLY_PROP_PARALLEL_DISABLE,