| /* |
| * USB PD Driver - Protocol Layer |
| */ |
| |
| #include <linux/device.h> |
| #include <linux/slab.h> |
| #include <linux/sched.h> |
| #include <linux/ccic/usbpd.h> |
| #include <linux/delay.h> |
| #include <linux/workqueue.h> |
| #include <linux/completion.h> |
| |
| #ifdef CONFIG_BATTERY_SAMSUNG |
| #ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER |
| #include <linux/battery/battery_notifier.h> |
| #endif |
| |
| #ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER |
| extern struct pdic_notifier_struct pd_noti; |
| #endif |
| #endif |
| |
| #define MS_TO_NS(msec) ((msec) * 1000 * 1000) |
| |
| void usbpd_timer1_start(struct usbpd_data *pd_data) |
| { |
| do_gettimeofday(&pd_data->time1); |
| } |
| |
| int usbpd_check_time1(struct usbpd_data *pd_data) |
| { |
| int ms = 0; |
| int sec = 0; |
| struct timeval time; |
| |
| do_gettimeofday(&time); |
| |
| sec = time.tv_sec - pd_data->time1.tv_sec; |
| ms = (time.tv_usec - pd_data->time1.tv_usec) / 1000; |
| |
| return (sec * 1000) + ms; |
| } |
| |
| void usbpd_timer2_start(struct usbpd_data *pd_data) |
| { |
| do_gettimeofday(&pd_data->time2); |
| } |
| |
| int usbpd_check_time2(struct usbpd_data *pd_data) |
| { |
| int ms = 0; |
| int sec = 0; |
| struct timeval time; |
| |
| do_gettimeofday(&time); |
| |
| sec = time.tv_sec - pd_data->time2.tv_sec; |
| ms = (time.tv_usec - pd_data->time2.tv_usec) / 1000; |
| |
| return (sec * 1000) + ms; |
| } |
| |
| static void increase_message_id_counter(struct usbpd_data *pd_data) |
| { |
| pd_data->counter.message_id_counter++; |
| pd_data->counter.message_id_counter %= 8; |
| /* |
| if (pd_data->counter.message_id_counter++ > USBPD_nMessageIDCount) |
| pd_data->counter.message_id_counter = 0; |
| */ |
| } |
| |
| static void rx_layer_init(struct protocol_data *rx) |
| { |
| int i; |
| |
| rx->stored_message_id = USBPD_nMessageIDCount+1; |
| rx->msg_header.word = 0; |
| rx->state = 0; |
| rx->status = DEFAULT_PROTOCOL_NONE; |
| for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++) |
| rx->data_obj[i].object = 0; |
| } |
| |
| static void tx_layer_init(struct protocol_data *tx) |
| { |
| int i; |
| |
| tx->stored_message_id = USBPD_nMessageIDCount+1; |
| tx->msg_header.word = 0; |
| tx->state = 0; |
| tx->status = DEFAULT_PROTOCOL_NONE; |
| for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++) |
| tx->data_obj[i].object = 0; |
| } |
| |
| static void tx_discard_message(struct protocol_data *tx) |
| { |
| int i; |
| |
| tx->msg_header.word = 0; |
| for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++) |
| tx->data_obj[i].object = 0; |
| } |
| |
| void usbpd_init_protocol(struct usbpd_data *pd_data) |
| { |
| rx_layer_init(&pd_data->protocol_rx); |
| tx_layer_init(&pd_data->protocol_tx); |
| pd_data->msg_id = USBPD_nMessageIDCount + 1; |
| } |
| |
| void usbpd_init_counters(struct usbpd_data *pd_data) |
| { |
| pr_info("%s: init counter\n", __func__); |
| pd_data->counter.retry_counter = 0; |
| pd_data->counter.message_id_counter = 0; |
| pd_data->counter.caps_counter = 0; |
| #if 0 |
| pd_data->counter.hard_reset_counter = 0; |
| #endif |
| pd_data->counter.swap_hard_reset_counter = 0; |
| pd_data->counter.discover_identity_counter = 0; |
| } |
| |
| void usbpd_policy_reset(struct usbpd_data *pd_data, unsigned flag) |
| { |
| |
| if (flag == HARDRESET_RECEIVED) { |
| pd_data->policy.rx_hardreset = 1; |
| dev_info(pd_data->dev, "%s Hard reset\n", __func__); |
| } else if (flag == SOFTRESET_RECEIVED) { |
| pd_data->policy.rx_softreset = 1; |
| dev_info(pd_data->dev, "%s Soft reset\n", __func__); |
| } else if (flag == PLUG_EVENT) { |
| if (!pd_data->policy.plug_valid) |
| pd_data->policy.plug = 1; |
| pd_data->policy.plug_valid = 1; |
| dev_info(pd_data->dev, "%s ATTACHED\n", __func__); |
| } else if (flag == PLUG_DETACHED) { |
| pd_data->policy.plug_valid = 0; |
| pd_data->pd_nego = false; |
| dev_info(pd_data->dev, "%s DETACHED\n", __func__); |
| pd_data->counter.hard_reset_counter = 0; |
| } |
| } |
| |
| protocol_state usbpd_protocol_tx_phy_layer_reset(struct protocol_data *tx) |
| { |
| return PRL_Tx_Wait_for_Message_Request; |
| } |
| |
| protocol_state usbpd_protocol_tx_wait_for_message_request(struct protocol_data |
| *tx) |
| { |
| struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx); |
| protocol_state state = PRL_Tx_Wait_for_Message_Request; |
| |
| /* S2MM004 PDIC already retry. |
| if (pd_data->counter.retry_counter > USBPD_nRetryCount) { |
| pd_data->counter.retry_counter = 0; |
| return state; |
| } |
| */ |
| if (pd_data->counter.retry_counter > 0) { |
| pd_data->counter.retry_counter = 0; |
| return state; |
| } |
| |
| pd_data->counter.retry_counter = 0; |
| |
| if (!tx->msg_header.word) |
| return state; |
| |
| if (tx->msg_header.num_data_objs == 0 && |
| tx->msg_header.msg_type == USBPD_Soft_Reset) |
| state = PRL_Tx_Layer_Reset_for_Transmit; |
| else |
| state = PRL_Tx_Construct_Message; |
| |
| return state; |
| } |
| |
| protocol_state usbpd_protocol_tx_layer_reset_for_transmit(struct protocol_data *tx) |
| { |
| struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx); |
| |
| dev_info(pd_data->dev, "%s\n", __func__); |
| |
| pd_data->counter.message_id_counter = 0; |
| pd_data->protocol_rx.state = PRL_Rx_Wait_for_PHY_Message; |
| |
| /* TODO: check Layer Reset Complete */ |
| return PRL_Tx_Construct_Message; |
| } |
| |
| protocol_state usbpd_protocol_tx_construct_message(struct protocol_data *tx) |
| { |
| struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx); |
| |
| tx->msg_header.msg_id = pd_data->counter.message_id_counter; |
| tx->status = DEFAULT_PROTOCOL_NONE; |
| |
| if (pd_data->phy_ops.tx_msg(pd_data, &tx->msg_header, tx->data_obj)) { |
| dev_err(pd_data->dev, "%s error\n", __func__); |
| return PRL_Tx_Construct_Message; |
| } |
| return PRL_Tx_Wait_for_PHY_Response; |
| } |
| |
| protocol_state usbpd_protocol_tx_wait_for_phy_response(struct protocol_data *tx) |
| { |
| #if 0 |
| struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx); |
| protocol_state state = PRL_Tx_Wait_for_PHY_Response; |
| u8 CrcCheck_cnt = 0; |
| |
| /* wait to get goodcrc */ |
| /* mdelay(1); */ |
| |
| /* polling */ |
| /* pd_data->phy_ops.poll_status(pd_data); */ |
| |
| for (CrcCheck_cnt = 0; CrcCheck_cnt < 2; CrcCheck_cnt++) { |
| if (pd_data->phy_ops.get_status(pd_data, MSG_GOODCRC)) { |
| pr_info("%s : %p\n", __func__, pd_data); |
| state = PRL_Tx_Message_Sent; |
| dev_info(pd_data->dev, "got GoodCRC.\n"); |
| return state; |
| } |
| |
| if (!CrcCheck_cnt) |
| pd_data->phy_ops.poll_status(pd_data); /* polling */ |
| } |
| |
| return PRL_Tx_Check_RetryCounter; |
| #endif |
| return PRL_Tx_Message_Sent; |
| } |
| |
| protocol_state usbpd_protocol_tx_match_messageid(struct protocol_data *tx) |
| { |
| /* We don't use this function. |
| S2MM004 PDIC already check message id for incoming GoodCRC. |
| |
| struct usbpd_data *pd_data = protocol_tx_to_usbpd(protocol_tx); |
| protocol_state state = PRL_Tx_Match_MessageID; |
| |
| dev_info(pd_data->dev, "%s\n",__func__); |
| |
| if (pd_data->protocol_rx.msg_header.msg_id |
| == pd_data->counter.message_id_counter) |
| state = PRL_Tx_Message_Sent; |
| else |
| state = PRL_Tx_Check_RetryCounter; |
| |
| return state; |
| */ |
| return PRL_Tx_Message_Sent; |
| } |
| |
| protocol_state usbpd_protocol_tx_message_sent(struct protocol_data *tx) |
| { |
| struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx); |
| |
| increase_message_id_counter(pd_data); |
| tx->status = MESSAGE_SENT; |
| /* clear protocol header buffer */ |
| tx->msg_header.word = 0; |
| |
| return PRL_Tx_Wait_for_Message_Request; |
| } |
| |
| protocol_state usbpd_protocol_tx_check_retrycounter(struct protocol_data *tx) |
| { |
| struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx); |
| |
| /* S2MM004 PDIC already do retry. |
| Driver SW doesn't do retry. |
| |
| if (++pd_data->counter.retry_counter > USBPD_nRetryCount) { |
| state = PRL_Tx_Transmission_Error; |
| } else { |
| state = PRL_Tx_Construct_Message; |
| } |
| |
| return PRL_Tx_Check_RetryCounter; |
| */ |
| ++pd_data->counter.retry_counter; |
| return PRL_Tx_Transmission_Error; |
| } |
| |
| protocol_state usbpd_protocol_tx_transmission_error(struct protocol_data *tx) |
| { |
| struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx); |
| |
| dev_err(pd_data->dev, "%s\n", __func__); |
| |
| increase_message_id_counter(pd_data); |
| tx->status = TRANSMISSION_ERROR; |
| |
| return PRL_Tx_Wait_for_Message_Request; |
| } |
| |
| protocol_state usbpd_protocol_tx_discard_message(struct protocol_data *tx) |
| { |
| /* This state is for Only Ping message */ |
| struct usbpd_data *pd_data = protocol_tx_to_usbpd(tx); |
| |
| dev_err(pd_data->dev, "%s\n", __func__); |
| tx_discard_message(tx); |
| increase_message_id_counter(pd_data); |
| |
| return PRL_Tx_PHY_Layer_Reset; |
| } |
| |
| void usbpd_set_ops(struct device *dev, usbpd_phy_ops_type *ops) |
| { |
| struct usbpd_data *pd_data = (struct usbpd_data *) dev_get_drvdata(dev); |
| |
| pd_data->phy_ops.tx_msg = ops->tx_msg; |
| pd_data->phy_ops.rx_msg = ops->rx_msg; |
| pd_data->phy_ops.hard_reset = ops->hard_reset; |
| pd_data->phy_ops.soft_reset = ops->soft_reset; |
| pd_data->phy_ops.set_power_role = ops->set_power_role; |
| pd_data->phy_ops.get_power_role = ops->get_power_role; |
| pd_data->phy_ops.set_data_role = ops->set_data_role; |
| pd_data->phy_ops.get_data_role = ops->get_data_role; |
| pd_data->phy_ops.get_vconn_source = ops->get_vconn_source; |
| pd_data->phy_ops.set_vconn_source = ops->set_vconn_source; |
| pd_data->phy_ops.get_status = ops->get_status; |
| pd_data->phy_ops.poll_status = ops->poll_status; |
| pd_data->phy_ops.driver_reset = ops->driver_reset; |
| pd_data->phy_ops.set_otg_control = ops->set_otg_control; |
| pd_data->phy_ops.get_vbus_short_check = ops->get_vbus_short_check; |
| pd_data->phy_ops.pd_vbus_short_check = ops->pd_vbus_short_check; |
| pd_data->phy_ops.set_cc_control = ops->set_cc_control; |
| pd_data->phy_ops.get_side_check = ops->get_side_check; |
| pd_data->phy_ops.pr_swap = ops->pr_swap; |
| pd_data->phy_ops.vbus_on_check = ops->vbus_on_check; |
| pd_data->phy_ops.set_rp_control = ops->set_rp_control; |
| pd_data->phy_ops.set_pwr_opmode = ops->set_pwr_opmode; |
| pd_data->phy_ops.cc_instead_of_vbus = ops->cc_instead_of_vbus; |
| pd_data->phy_ops.op_mode_clear = ops->op_mode_clear; |
| } |
| |
| protocol_state usbpd_protocol_rx_layer_reset_for_receive(struct protocol_data *rx) |
| { |
| struct usbpd_data *pd_data = protocol_rx_to_usbpd(rx); |
| |
| dev_info(pd_data->dev, "%s\n", __func__); |
| /* |
| rx_layer_init(protocol_rx); |
| pd_data->protocol_tx.state = PRL_Tx_PHY_Layer_Reset; |
| |
| usbpd_rx_soft_reset(pd_data); |
| */ |
| return PRL_Rx_Layer_Reset_for_Receive; |
| |
| /*return PRL_Rx_Send_GoodCRC;*/ |
| } |
| |
| protocol_state usbpd_protocol_rx_wait_for_phy_message(struct protocol_data *rx) |
| { |
| struct usbpd_data *pd_data = protocol_rx_to_usbpd(rx); |
| protocol_state state = PRL_Rx_Wait_for_PHY_Message; |
| |
| if (pd_data->phy_ops.rx_msg(pd_data, &rx->msg_header, rx->data_obj)) { |
| dev_err(pd_data->dev, "%s IO Error\n", __func__); |
| return state; |
| } else { |
| if (rx->msg_header.word == 0) { |
| dev_err(pd_data->dev, "%s No Message\n", __func__); |
| return state; /* no message */ |
| } else if (pd_data->phy_ops.get_status(pd_data, MSG_SOFTRESET)) { |
| dev_err(pd_data->dev, "[Rx] Got SOFTRESET.\n"); |
| state = PRL_Rx_Layer_Reset_for_Receive; |
| } else { |
| if (rx->stored_message_id == rx->msg_header.msg_id) |
| return state; |
| |
| dev_err(pd_data->dev, "[Rx] [0x%x] [0x%x]\n", |
| rx->msg_header.word, rx->data_obj[0].object); |
| /* new message is coming */ |
| state = PRL_Rx_Send_GoodCRC; |
| } |
| } |
| return state; |
| } |
| |
| protocol_state usbpd_protocol_rx_send_goodcrc(struct protocol_data *rx) |
| { |
| /* Goodcrc sent by PDIC(HW) */ |
| return PRL_Rx_Check_MessageID; |
| } |
| |
| protocol_state usbpd_protocol_rx_store_messageid(struct protocol_data *rx) |
| { |
| struct usbpd_data *pd_data = protocol_rx_to_usbpd(rx); |
| |
| rx->stored_message_id = rx->msg_header.msg_id; |
| usbpd_read_msg(pd_data); |
| /* |
| return PRL_Rx_Wait_for_PHY_Message; |
| */ |
| return PRL_Rx_Store_MessageID; |
| } |
| |
| protocol_state usbpd_protocol_rx_check_messageid(struct protocol_data *rx) |
| { |
| protocol_state state; |
| |
| if (rx->stored_message_id == rx->msg_header.msg_id) |
| state = PRL_Rx_Wait_for_PHY_Message; |
| else |
| state = PRL_Rx_Store_MessageID; |
| return state; |
| } |
| |
| void usbpd_protocol_tx(struct usbpd_data *pd_data) |
| { |
| struct protocol_data *tx = &pd_data->protocol_tx; |
| protocol_state next_state = tx->state; |
| protocol_state saved_state; |
| |
| do { |
| saved_state = next_state; |
| switch (next_state) { |
| case PRL_Tx_PHY_Layer_Reset: |
| next_state = usbpd_protocol_tx_phy_layer_reset(tx); |
| break; |
| case PRL_Tx_Wait_for_Message_Request: |
| next_state = usbpd_protocol_tx_wait_for_message_request(tx); |
| break; |
| case PRL_Tx_Layer_Reset_for_Transmit: |
| next_state = usbpd_protocol_tx_layer_reset_for_transmit(tx); |
| break; |
| case PRL_Tx_Construct_Message: |
| next_state = usbpd_protocol_tx_construct_message(tx); |
| break; |
| case PRL_Tx_Wait_for_PHY_Response: |
| next_state = usbpd_protocol_tx_wait_for_phy_response(tx); |
| break; |
| case PRL_Tx_Match_MessageID: |
| next_state = usbpd_protocol_tx_match_messageid(tx); |
| break; |
| case PRL_Tx_Message_Sent: |
| next_state = usbpd_protocol_tx_message_sent(tx); |
| break; |
| case PRL_Tx_Check_RetryCounter: |
| next_state = usbpd_protocol_tx_check_retrycounter(tx); |
| break; |
| case PRL_Tx_Transmission_Error: |
| next_state = usbpd_protocol_tx_transmission_error(tx); |
| break; |
| case PRL_Tx_Discard_Message: |
| next_state = usbpd_protocol_tx_discard_message(tx); |
| break; |
| default: |
| next_state = PRL_Tx_Wait_for_Message_Request; |
| break; |
| } |
| } while (saved_state != next_state); |
| |
| tx->state = next_state; |
| } |
| |
| void usbpd_protocol_rx(struct usbpd_data *pd_data) |
| { |
| struct protocol_data *rx = &pd_data->protocol_rx; |
| protocol_state next_state = rx->state; |
| protocol_state saved_state; |
| |
| do { |
| saved_state = next_state; |
| switch (next_state) { |
| case PRL_Rx_Layer_Reset_for_Receive: |
| next_state = usbpd_protocol_rx_layer_reset_for_receive(rx); |
| break; |
| case PRL_Rx_Wait_for_PHY_Message: |
| next_state = usbpd_protocol_rx_wait_for_phy_message(rx); |
| break; |
| case PRL_Rx_Send_GoodCRC: |
| next_state = usbpd_protocol_rx_send_goodcrc(rx); |
| break; |
| case PRL_Rx_Store_MessageID: |
| next_state = usbpd_protocol_rx_store_messageid(rx); |
| break; |
| case PRL_Rx_Check_MessageID: |
| next_state = usbpd_protocol_rx_check_messageid(rx); |
| break; |
| default: |
| next_state = PRL_Rx_Wait_for_PHY_Message; |
| break; |
| } |
| } while (saved_state != next_state); |
| /* |
| rx->state = next_state; |
| */ |
| rx->state = PRL_Rx_Wait_for_PHY_Message; |
| } |
| |
| void usbpd_read_msg(struct usbpd_data *pd_data) |
| { |
| int i; |
| |
| pd_data->policy.rx_msg_header.word |
| = pd_data->protocol_rx.msg_header.word; |
| for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++) { |
| pd_data->policy.rx_data_obj[i].object |
| = pd_data->protocol_rx.data_obj[i].object; |
| } |
| } |
| |
| /* return 1: sent with goodcrc, 0: fail */ |
| bool usbpd_send_msg(struct usbpd_data *pd_data, msg_header_type *header, |
| data_obj_type *obj) |
| { |
| int i; |
| |
| if (obj) |
| for (i = 0; i < USBPD_MAX_COUNT_MSG_OBJECT; i++) |
| pd_data->protocol_tx.data_obj[i].object = obj[i].object; |
| else |
| header->num_data_objs = 0; |
| header->spec_revision = pd_data->specification_revision; |
| pd_data->protocol_tx.msg_header.word = header->word; |
| usbpd_protocol_tx(pd_data); |
| |
| if (pd_data->protocol_tx.status == MESSAGE_SENT) |
| return true; |
| else |
| return false; |
| } |
| |
| inline bool usbpd_send_ctrl_msg(struct usbpd_data *d, msg_header_type *h, |
| unsigned msg, unsigned dr, unsigned pr) |
| { |
| h->msg_type = msg; |
| h->port_data_role = dr; |
| h->port_power_role = pr; |
| h->num_data_objs = 0; |
| return usbpd_send_msg(d, h, 0); |
| } |
| |
| /* return: 0 if timed out, positive is status */ |
| inline unsigned usbpd_wait_msg(struct usbpd_data *pd_data, |
| unsigned msg_status, unsigned ms) |
| { |
| unsigned long ret; |
| |
| ret = pd_data->phy_ops.get_status(pd_data, msg_status); |
| if (ret) { |
| pd_data->policy.abnormal_state = false; |
| return ret; |
| } |
| |
| pr_info("%s, %d\n", __func__, __LINE__); |
| /* wait */ |
| reinit_completion(&pd_data->msg_arrived); |
| pd_data->wait_for_msg_arrived = msg_status; |
| ret = wait_for_completion_timeout(&pd_data->msg_arrived, |
| msecs_to_jiffies(ms)); |
| |
| if (!pd_data->policy.state) { |
| dev_err(pd_data->dev, "%s : return for policy state error\n", __func__); |
| pd_data->policy.abnormal_state = true; |
| return 0; |
| } |
| |
| pd_data->policy.abnormal_state = false; |
| |
| return pd_data->phy_ops.get_status(pd_data, msg_status); |
| } |
| |
| void usbpd_rx_hard_reset(struct device *dev) |
| { |
| struct usbpd_data *pd_data = dev_get_drvdata(dev); |
| |
| usbpd_reinit(dev); |
| usbpd_policy_reset(pd_data, HARDRESET_RECEIVED); |
| } |
| |
| void usbpd_rx_soft_reset(struct usbpd_data *pd_data) |
| { |
| usbpd_reinit(pd_data->dev); |
| usbpd_policy_reset(pd_data, SOFTRESET_RECEIVED); |
| } |
| |
| void usbpd_reinit(struct device *dev) |
| { |
| struct usbpd_data *pd_data = dev_get_drvdata(dev); |
| |
| usbpd_init_counters(pd_data); |
| usbpd_init_protocol(pd_data); |
| usbpd_init_policy(pd_data); |
| usbpd_init_manager_val(pd_data); |
| reinit_completion(&pd_data->msg_arrived); |
| pd_data->wait_for_msg_arrived = 0; |
| pd_data->is_prswap = false; |
| complete(&pd_data->msg_arrived); |
| } |
| |
| /* |
| * usbpd_init - alloc usbpd data |
| * |
| * Returns 0 on success; negative errno on failure |
| */ |
| int usbpd_init(struct device *dev, void *phy_driver_data) |
| { |
| struct usbpd_data *pd_data; |
| |
| if (!dev) |
| return -EINVAL; |
| |
| pd_data = kzalloc(sizeof(struct usbpd_data), GFP_KERNEL); |
| |
| if (!pd_data) |
| return -ENOMEM; |
| |
| pd_data->dev = dev; |
| pd_data->phy_driver_data = phy_driver_data; |
| dev_set_drvdata(dev, pd_data); |
| |
| #ifdef CONFIG_BATTERY_SAMSUNG |
| #ifdef CONFIG_USB_TYPEC_MANAGER_NOTIFIER |
| pd_noti.pd_data = pd_data; |
| pd_noti.sink_status.current_pdo_num = 0; |
| pd_noti.sink_status.selected_pdo_num = 0; |
| #endif |
| #endif |
| usbpd_init_counters(pd_data); |
| usbpd_init_protocol(pd_data); |
| usbpd_init_policy(pd_data); |
| usbpd_init_manager(pd_data); |
| |
| mutex_init(&pd_data->accept_mutex); |
| |
| pd_data->policy_wqueue = |
| create_singlethread_workqueue(dev_name(dev)); |
| if (!pd_data->policy_wqueue) |
| pr_err("%s: Fail to Create Workqueue\n", __func__); |
| |
| INIT_WORK(&pd_data->worker, usbpd_policy_work); |
| |
| init_completion(&pd_data->msg_arrived); |
| pd_data->is_prswap = false; |
| pd_data->pd_nego = false; |
| |
| return 0; |
| } |