blob: 2327426782f6cc4d4669e456ea86a9ef9639fba5 [file] [log] [blame]
/*
* 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;
}