mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 16:16:15 -04:00
pd: Add rt1715 driver initial version
PD/rt1715 initial sample code from Richtek Change-Id: Ide34829746b768c5ed8e7bdd5efd3567d7dd7886 Reviewed-on: https://gerrit.mot.com/2038928 Reviewed-by: Huosheng Liao <liaohs@motorola.com> SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Submit-Approved: Jira Key
This commit is contained in:
parent
ac23a64f12
commit
94c57f4137
61 changed files with 38217 additions and 0 deletions
34
drivers/usb/typec/mmi_tcpc/Android.mk
Normal file
34
drivers/usb/typec/mmi_tcpc/Android.mk
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
#ifeq ($(TCPC_RT1711H),true)
|
||||
KERNEL_CFLAGS += CONFIG_TCPC_RT1711H=y
|
||||
#endif
|
||||
|
||||
#ifeq ($(TCPC_CLASS),true)
|
||||
KERNEL_CFLAGS += CONFIG_TCPC_CLASS=y
|
||||
#endif
|
||||
|
||||
#ifeq ($(USB_POWER_DELIVERY),true)
|
||||
KERNEL_CFLAGS += CONFIG_USB_POWER_DELIVERY=y
|
||||
#endif
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE := tcpc_rt1711h.ko
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE := tcpc_class.ko
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE := rt_pd_manager.ko
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
37
drivers/usb/typec/mmi_tcpc/Kbuild
Normal file
37
drivers/usb/typec/mmi_tcpc/Kbuild
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include \
|
||||
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/usb/typec/mmi_tcpc
|
||||
|
||||
subdir-ccflags-y += -Wall -Werror -DCONFIG_RT_REGMAP
|
||||
|
||||
#ifneq ($(filter m y,$(CONFIG_TCPC_CLASS)),)
|
||||
EXTRA_CFLAGS += -DCONFIG_TCPC_CLASS
|
||||
#endif
|
||||
|
||||
#ifneq ($(filter m y,$(CONFIG_USB_POWER_DELIVERY)),)
|
||||
EXTRA_CFLAGS += -DCONFIG_USB_POWER_DELIVERY
|
||||
#endif
|
||||
|
||||
#ifneq ($(filter m y,$(CONFIG_TCPC_RT1711H)),)
|
||||
obj-m += tcpc_rt1711h.o
|
||||
#endif
|
||||
|
||||
tcpc_class-objs += tcpci_core.o tcpci_typec.o tcpci_timer.o \
|
||||
tcpm.o tcpci.o pd_dbg_info.o tcpci_alert.o rt-regmap.o tcpci_dual_role.o
|
||||
|
||||
#ifneq ($(filter m y,$(CONFIG_USB_POWER_DELIVERY)),)
|
||||
tcpc_class-objs += tcpci_event.o \
|
||||
pd_core.o pd_policy_engine.o pd_process_evt.o \
|
||||
pd_dpm_core.o pd_dpm_uvdm.o pd_dpm_alt_mode_dp.o pd_dpm_pdo_select.o\
|
||||
pd_dpm_reaction.o \
|
||||
pd_process_evt_snk.o pd_process_evt_src.o pd_process_evt_vdm.o \
|
||||
pd_process_evt_drs.o pd_process_evt_prs.o pd_process_evt_vcs.o \
|
||||
pd_process_evt_dbg.o pd_process_evt_tcp.o pd_process_evt_com.o \
|
||||
pd_policy_engine_src.o pd_policy_engine_snk.o pd_policy_engine_ufp.o pd_policy_engine_vcs.o \
|
||||
pd_policy_engine_dfp.o pd_policy_engine_dr.o pd_policy_engine_drs.o pd_policy_engine_prs.o \
|
||||
pd_policy_engine_dbg.o pd_policy_engine_com.o pd_dpm_alt_mode_dc.o
|
||||
#endif
|
||||
|
||||
obj-m += tcpc_class.o
|
||||
obj-m += rt_pd_manager.o
|
||||
11
drivers/usb/typec/mmi_tcpc/Makefile
Normal file
11
drivers/usb/typec/mmi_tcpc/Makefile
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
||||
|
||||
1634
drivers/usb/typec/mmi_tcpc/inc/pd_core.h
Normal file
1634
drivers/usb/typec/mmi_tcpc/inc/pd_core.h
Normal file
File diff suppressed because it is too large
Load diff
41
drivers/usb/typec/mmi_tcpc/inc/pd_dbg_info.h
Normal file
41
drivers/usb/typec/mmi_tcpc/inc/pd_dbg_info.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef PD_DBG_INFO_H_INCLUDED
|
||||
#define PD_DBG_INFO_H_INCLUDED
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include "tcpci_config.h"
|
||||
|
||||
#ifdef CONFIG_PD_DBG_INFO
|
||||
extern int pd_dbg_info(const char *fmt, ...);
|
||||
extern void pd_dbg_info_lock(void);
|
||||
extern void pd_dbg_info_unlock(void);
|
||||
extern int pd_dbg_info_init(void);
|
||||
extern void pd_dbg_info_exit(void);
|
||||
#else
|
||||
static inline int pd_dbg_info(const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void pd_dbg_info_lock(void) {}
|
||||
static inline void pd_dbg_info_unlock(void) {}
|
||||
static inline int pd_dbg_info_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void pd_dbg_info_exit(void) {}
|
||||
#endif /* CONFIG_PD_DBG_INFO */
|
||||
|
||||
#endif /* PD_DBG_INFO_H_INCLUDED */
|
||||
405
drivers/usb/typec/mmi_tcpc/inc/pd_dpm_core.h
Normal file
405
drivers/usb/typec/mmi_tcpc/inc/pd_dpm_core.h
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef PD_DPM_CORE_H
|
||||
#define PD_DPM_CORE_H
|
||||
|
||||
#include "tcpci.h"
|
||||
#include "pd_core.h"
|
||||
#include "pd_process_evt.h"
|
||||
|
||||
/* ---- MISC ---- */
|
||||
int pd_dpm_core_init(struct pd_port *pd_port);
|
||||
int pd_dpm_enable_vconn(struct pd_port *pd_port, bool en);
|
||||
int pd_dpm_send_sink_caps(struct pd_port *pd_port);
|
||||
int pd_dpm_send_source_caps(struct pd_port *pd_port);
|
||||
|
||||
void pd_dpm_inform_cable_id(struct pd_port *pd_port, bool src_startup);
|
||||
|
||||
void pd_dpm_dynamic_enable_vconn(struct pd_port *pd_port);
|
||||
void pd_dpm_dynamic_disable_vconn(struct pd_port *pd_port);
|
||||
|
||||
/* ---- SNK ---- */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
void pd_dpm_start_pps_request_thread(struct pd_port *pd_port, bool en);
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
int pd_dpm_update_tcp_request(struct pd_port *pd_port,
|
||||
struct tcp_dpm_pd_request *pd_req);
|
||||
|
||||
int pd_dpm_update_tcp_request_ex(struct pd_port *pd_port,
|
||||
struct tcp_dpm_pd_request_ex *pd_req);
|
||||
|
||||
int pd_dpm_update_tcp_request_again(struct pd_port *pd_port);
|
||||
|
||||
void pd_dpm_snk_evaluate_caps(struct pd_port *pd_port);
|
||||
void pd_dpm_snk_standby_power(struct pd_port *pd_port);
|
||||
void pd_dpm_snk_transition_power(struct pd_port *pd_port);
|
||||
void pd_dpm_snk_hard_reset(struct pd_port *pd_port);
|
||||
|
||||
/* ---- SRC ---- */
|
||||
|
||||
void pd_dpm_src_evaluate_request(struct pd_port *pd_port);
|
||||
void pd_dpm_src_transition_power(struct pd_port *pd_port);
|
||||
void pd_dpm_src_hard_reset(struct pd_port *pd_port);
|
||||
|
||||
/* ---- UFP : Handle VDM Request ---- */
|
||||
|
||||
void pd_dpm_ufp_request_id_info(struct pd_port *pd_port);
|
||||
void pd_dpm_ufp_request_svid_info(struct pd_port *pd_port);
|
||||
void pd_dpm_ufp_request_mode_info(struct pd_port *pd_port);
|
||||
void pd_dpm_ufp_request_enter_mode(struct pd_port *pd_port);
|
||||
void pd_dpm_ufp_request_exit_mode(struct pd_port *pd_port);
|
||||
|
||||
/* ---- UFP : DP Only ---- */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
int pd_dpm_ufp_request_dp_status(struct pd_port *pd_port);
|
||||
int pd_dpm_ufp_request_dp_config(struct pd_port *pd_port);
|
||||
void pd_dpm_ufp_send_dp_attention(struct pd_port *pd_port);
|
||||
#endif
|
||||
|
||||
/* ---- DFP : Inform VDM Result ---- */
|
||||
|
||||
void pd_dpm_dfp_inform_id(struct pd_port *pd_port, bool ack);
|
||||
void pd_dpm_dfp_inform_svids(struct pd_port *pd_port, bool ack);
|
||||
void pd_dpm_dfp_inform_modes(struct pd_port *pd_port, bool ack);
|
||||
void pd_dpm_dfp_inform_enter_mode(struct pd_port *pd_port, bool ack);
|
||||
void pd_dpm_dfp_inform_exit_mode(struct pd_port *pd_port);
|
||||
void pd_dpm_dfp_inform_attention(struct pd_port *pd_port);
|
||||
|
||||
/* ---- DFP : DP Only ---- */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
void pd_dpm_dfp_send_dp_status_update(struct pd_port *pd_port);
|
||||
void pd_dpm_dfp_inform_dp_status_update(struct pd_port *pd_port, bool ack);
|
||||
|
||||
void pd_dpm_dfp_send_dp_configuration(struct pd_port *pd_port);
|
||||
void pd_dpm_dfp_inform_dp_configuration(struct pd_port *pd_port, bool ack);
|
||||
#endif
|
||||
|
||||
/* ---- SVDM/UVDM ---- */
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
|
||||
void pd_dpm_ufp_recv_uvdm(struct pd_port *pd_port);
|
||||
void pd_dpm_dfp_send_uvdm(struct pd_port *pd_port);
|
||||
void pd_dpm_dfp_inform_uvdm(struct pd_port *pd_port, bool ack);
|
||||
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
/* ---- DRP : Inform PowerCap ---- */
|
||||
|
||||
void pd_dpm_dr_inform_sink_cap(struct pd_port *pd_port);
|
||||
void pd_dpm_dr_inform_source_cap(struct pd_port *pd_port);
|
||||
|
||||
/* ---- DRP : Data Role Swap ---- */
|
||||
|
||||
void pd_dpm_drs_evaluate_swap(struct pd_port *pd_port, uint8_t role);
|
||||
void pd_dpm_drs_change_role(struct pd_port *pd_port, uint8_t role);
|
||||
|
||||
/* ---- DRP : Power Role Swap ---- */
|
||||
|
||||
void pd_dpm_prs_evaluate_swap(struct pd_port *pd_port, uint8_t role);
|
||||
void pd_dpm_prs_turn_off_power_sink(struct pd_port *pd_port);
|
||||
void pd_dpm_prs_enable_power_source(struct pd_port *pd_port, bool en);
|
||||
void pd_dpm_prs_change_role(struct pd_port *pd_port, uint8_t role);
|
||||
|
||||
/* ---- DRP : Vconn Swap ---- */
|
||||
|
||||
void pd_dpm_vcs_evaluate_swap(struct pd_port *pd_port);
|
||||
void pd_dpm_vcs_enable_vconn(struct pd_port *pd_port, uint8_t role);
|
||||
|
||||
|
||||
/*
|
||||
* PE : PD3.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
int pd_dpm_send_source_cap_ext(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
void pd_dpm_inform_source_cap_ext(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_LOCAL
|
||||
int pd_dpm_send_battery_cap(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_REMOTE
|
||||
void pd_dpm_inform_battery_cap(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL
|
||||
int pd_dpm_send_battery_status(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE
|
||||
void pd_dpm_inform_battery_status(struct pd_port *pd_port);
|
||||
#endif /* #ifdef CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL
|
||||
int pd_dpm_send_mfrs_info(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE
|
||||
void pd_dpm_inform_mfrs_info(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL
|
||||
int pd_dpm_send_country_codes(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE
|
||||
void pd_dpm_inform_country_codes(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL
|
||||
int pd_dpm_send_country_info(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE
|
||||
void pd_dpm_inform_country_info(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
int pd_dpm_send_alert(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
void pd_dpm_inform_alert(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
int pd_dpm_send_status(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
void pd_dpm_inform_status(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
void pd_dpm_inform_pps_status(struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
void pd_dpm_inform_not_support(struct pd_port *pd_port);
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
/* PE : Notify DPM */
|
||||
|
||||
int pd_dpm_notify_pe_startup(struct pd_port *pd_port);
|
||||
int pd_dpm_notify_pe_hardreset(struct pd_port *pd_port);
|
||||
|
||||
/* TCPCI - VBUS Control */
|
||||
|
||||
static inline int pd_dpm_check_vbus_valid(struct pd_port *pd_port)
|
||||
{
|
||||
return tcpci_check_vbus_valid(pd_port->tcpc);
|
||||
}
|
||||
|
||||
static inline int pd_dpm_sink_vbus(struct pd_port *pd_port, bool en)
|
||||
{
|
||||
int mv = en ? TCPC_VBUS_SINK_5V : TCPC_VBUS_SINK_0V;
|
||||
|
||||
return tcpci_sink_vbus(pd_port->tcpc,
|
||||
TCP_VBUS_CTRL_REQUEST, mv, -1);
|
||||
}
|
||||
|
||||
static inline int pd_dpm_source_vbus(struct pd_port *pd_port, bool en)
|
||||
{
|
||||
int mv = en ? TCPC_VBUS_SOURCE_5V : TCPC_VBUS_SOURCE_0V;
|
||||
|
||||
return tcpci_source_vbus(pd_port->tcpc,
|
||||
TCP_VBUS_CTRL_REQUEST, mv, -1);
|
||||
}
|
||||
|
||||
/* Mode Operations */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
|
||||
extern bool dp_dfp_u_notify_discover_id(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
|
||||
extern bool dp_dfp_u_notify_discover_svid(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data, bool ack);
|
||||
|
||||
extern bool dp_dfp_u_notify_discover_modes(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data, bool ack);
|
||||
|
||||
|
||||
extern bool dp_dfp_u_notify_enter_mode(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, uint8_t ops, bool ack);
|
||||
|
||||
extern bool dp_dfp_u_notify_exit_mode(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data, uint8_t ops);
|
||||
|
||||
extern bool dp_dfp_u_notify_attention(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
|
||||
extern void dp_ufp_u_request_enter_mode(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data, uint8_t ops);
|
||||
|
||||
extern void dp_ufp_u_request_exit_mode(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data, uint8_t ops);
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
extern bool dp_dfp_u_notify_pe_startup(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data);
|
||||
|
||||
extern int dp_dfp_u_notify_pe_ready(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
|
||||
extern bool dp_reset_state(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data);
|
||||
|
||||
extern bool dp_parse_svid_data(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data);
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_RICHTEK_UVDM
|
||||
extern bool richtek_dfp_notify_pe_startup(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data);
|
||||
|
||||
extern int richtek_dfp_notify_pe_ready(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
|
||||
extern bool richtek_dfp_notify_uvdm(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
extern bool richtek_ufp_notify_uvdm(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
#endif /* CONFIG_USB_PD_RICHTEK_UVDM */
|
||||
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
extern bool dc_dfp_notify_discover_id(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
|
||||
extern bool dc_dfp_notify_discover_svid(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
|
||||
extern bool dc_dfp_notify_discover_modes(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
|
||||
extern bool dc_dfp_notify_enter_mode(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, uint8_t ops, bool ack);
|
||||
|
||||
extern bool dc_dfp_notify_exit_mode(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, uint8_t ops);
|
||||
|
||||
extern bool dc_dfp_notify_pe_startup(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data);
|
||||
|
||||
extern int dc_dfp_notify_pe_ready(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
|
||||
extern bool dc_dfp_notify_uvdm(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
extern bool dc_ufp_notify_uvdm(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
|
||||
extern bool dc_reset_state(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
|
||||
extern bool dc_parse_svid_data(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
|
||||
|
||||
/**
|
||||
* pd_dpm_get_ready_reaction
|
||||
*
|
||||
* Get a pending event from the reaction's table definied by DPM.
|
||||
*
|
||||
* Returns TCP_DPM_EVT_ID if succeeded;
|
||||
* Returns Zero to indicate there is no pending event.
|
||||
* Returns DPM_READY_REACTION_BUSY to indicate
|
||||
* waiting for previous reaction is finished.
|
||||
*/
|
||||
|
||||
#define DPM_READY_REACTION_BUSY (0xff)
|
||||
extern uint8_t pd_dpm_get_ready_reaction(struct pd_port *pd_port);
|
||||
|
||||
/* ---- DPM reactions ---- */
|
||||
|
||||
|
||||
|
||||
/* If receive reject/wait, cancel reaction */
|
||||
#define DPM_REACTION_REQUEST_PR_SWAP (1<<0)
|
||||
#define DPM_REACTION_REQUEST_DR_SWAP (1<<1)
|
||||
#define DPM_REACTION_GET_SINK_CAP (1<<2)
|
||||
#define DPM_REACTION_GET_SOURCE_CAP (1<<3)
|
||||
#define DPM_REACTION_ATTEMPT_GET_FLAG (1<<4)
|
||||
#define DPM_REACTION_REQUEST_VCONN_SRC (1<<5)
|
||||
#define DPM_REACTION_RETURN_VCONN_SRC (1<<6)
|
||||
#define DPM_REACTION_REJECT_CANCEL (1<<7) /* FLAG ONLY */
|
||||
|
||||
#define DPM_REACTION_DFP_FLOW_DELAY (1<<10)
|
||||
#define DPM_REACTION_UFP_FLOW_DELAY (1<<11)
|
||||
#define DPM_REACTION_VCONN_STABLE_DELAY (1<<12)
|
||||
|
||||
#define DPM_REACTION_DISCOVER_ID (1<<16)
|
||||
#define DPM_REACTION_DISCOVER_SVID (1<<17)
|
||||
#define DPM_REACTION_DISCOVER_CABLE (1<<18)
|
||||
#define DPM_REACTION_DYNAMIC_VCONN (1<<19)
|
||||
|
||||
#define DPM_REACTION_DISCOVER_CABLE_FLOW (\
|
||||
DPM_REACTION_DISCOVER_CABLE | \
|
||||
DPM_REACTION_REQUEST_VCONN_SRC |\
|
||||
DPM_REACTION_VCONN_STABLE_DELAY |\
|
||||
DPM_REACTION_DYNAMIC_VCONN)
|
||||
|
||||
#define DPM_REACTION_GET_SOURCE_CAP_EXT (1<<24)
|
||||
|
||||
#define DPM_REACTION_CAP_RESET_CABLE (1<<28)
|
||||
#define DPM_REACTION_CAP_READY_ONCE (1<<29)
|
||||
#define DPM_REACTION_CAP_DISCOVER_CABLE (1<<30)
|
||||
#define DPM_REACTION_CAP_ALWAYS (1<<31)
|
||||
|
||||
static inline void dpm_reaction_clear(struct pd_port *pd_port, uint32_t mask)
|
||||
{
|
||||
pd_port->pe_data.dpm_ready_reactions &= ~mask;
|
||||
}
|
||||
|
||||
static inline void dpm_reaction_set(struct pd_port *pd_port, uint32_t mask)
|
||||
{
|
||||
pd_port->pe_data.dpm_ready_reactions |= mask;
|
||||
}
|
||||
|
||||
static inline void dpm_reaction_set_ready_once(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_check_pe_state_ready(pd_port))
|
||||
dpm_reaction_set(pd_port, DPM_REACTION_CAP_READY_ONCE);
|
||||
}
|
||||
|
||||
static inline void dpm_reaction_set_clear(
|
||||
struct pd_port *pd_port, uint32_t set, uint32_t clear)
|
||||
{
|
||||
uint32_t val = pd_port->pe_data.dpm_ready_reactions | set;
|
||||
|
||||
pd_port->pe_data.dpm_ready_reactions = val & (~clear);
|
||||
}
|
||||
|
||||
static inline uint32_t dpm_reaction_check(
|
||||
struct pd_port *pd_port, uint32_t mask)
|
||||
{
|
||||
return pd_port->pe_data.dpm_ready_reactions & mask;
|
||||
}
|
||||
#endif /* PD_DPM_CORE_H */
|
||||
63
drivers/usb/typec/mmi_tcpc/inc/pd_dpm_pdo_select.h
Normal file
63
drivers/usb/typec/mmi_tcpc/inc/pd_dpm_pdo_select.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef PD_DPM_PDO_SELECT_H
|
||||
#define PD_DPM_PDO_SELECT_H
|
||||
|
||||
#include "inc/tcpci.h"
|
||||
|
||||
struct dpm_pdo_info_t {
|
||||
uint8_t type;
|
||||
uint8_t apdo_type;
|
||||
uint8_t pwr_limit;
|
||||
int vmin;
|
||||
int vmax;
|
||||
int uw;
|
||||
int ma;
|
||||
};
|
||||
|
||||
struct dpm_rdo_info_t {
|
||||
uint8_t pos;
|
||||
uint8_t type;
|
||||
bool mismatch;
|
||||
|
||||
int vmin;
|
||||
int vmax;
|
||||
|
||||
union {
|
||||
uint32_t max_uw;
|
||||
uint32_t max_ma;
|
||||
};
|
||||
|
||||
union {
|
||||
uint32_t oper_uw;
|
||||
uint32_t oper_ma;
|
||||
};
|
||||
};
|
||||
|
||||
#define DPM_PDO_TYPE_FIXED TCPM_POWER_CAP_VAL_TYPE_FIXED
|
||||
#define DPM_PDO_TYPE_VAR TCPM_POWER_CAP_VAL_TYPE_VARIABLE
|
||||
#define DPM_PDO_TYPE_BAT TCPM_POWER_CAP_VAL_TYPE_BATTERY
|
||||
#define DPM_PDO_TYPE_APDO TCPM_POWER_CAP_VAL_TYPE_AUGMENT
|
||||
|
||||
#define DPM_APDO_TYPE_PPS (TCPM_POWER_CAP_APDO_TYPE_PPS)
|
||||
#define DPM_APDO_TYPE_PPS_CF (TCPM_POWER_CAP_APDO_TYPE_PPS_CF)
|
||||
|
||||
extern void dpm_extract_pdo_info(
|
||||
uint32_t pdo, struct dpm_pdo_info_t *info);
|
||||
|
||||
extern bool dpm_find_match_req_info(struct dpm_rdo_info_t *req_info,
|
||||
struct dpm_pdo_info_t *sink, int cnt, uint32_t *src_pdos,
|
||||
int min_uw, uint32_t select_rule);
|
||||
|
||||
#endif /* PD_DPM_PDO_SELECT_H */
|
||||
933
drivers/usb/typec/mmi_tcpc/inc/pd_policy_engine.h
Normal file
933
drivers/usb/typec/mmi_tcpc/inc/pd_policy_engine.h
Normal file
|
|
@ -0,0 +1,933 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef PD_POLICY_ENGINE_H_
|
||||
#define PD_POLICY_ENGINE_H_
|
||||
|
||||
#include "pd_core.h"
|
||||
|
||||
/* ---- Policy Engine State ---- */
|
||||
|
||||
enum pd_pe_state_machine {
|
||||
PE_STATE_MACHINE_IDLE = 0,
|
||||
PE_STATE_MACHINE_NORMAL,
|
||||
PE_STATE_MACHINE_DR_SWAP,
|
||||
PE_STATE_MACHINE_PR_SWAP,
|
||||
PE_STATE_MACHINE_VCONN_SWAP,
|
||||
};
|
||||
|
||||
/* ---- Policy Engine Runtime Flags ---- */
|
||||
|
||||
#define PE_STATE_FLAG_BACK_READY_IF_RECV_WAIT (1<<0)
|
||||
#define PE_STATE_FLAG_BACK_READY_IF_RECV_REJECT (1<<1)
|
||||
#define PE_STATE_FLAG_BACK_READY_IF_SR_TIMER_TOUT (1<<2)
|
||||
#define PE_STATE_FLAG_BACK_READY_IF_TX_FAILED (1<<3)
|
||||
#define PE_STATE_FLAG_HRESET_IF_SR_TIMEOUT (1<<4)
|
||||
#define PE_STATE_FLAG_HRESET_IF_TX_FAILED (1<<5)
|
||||
#define PE_STATE_FLAG_IGNORE_UNKNOWN_EVENT (1<<6)
|
||||
#define PE_STATE_FLAG_ENABLE_SENDER_RESPONSE_TIMER (1<<7)
|
||||
|
||||
#define PE_STATE_WAIT_RESPONSE(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_ENABLE_SENDER_RESPONSE_TIMER; }
|
||||
|
||||
#define PE_STATE_WAIT_MSG(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_BACK_READY_IF_SR_TIMER_TOUT |\
|
||||
PE_STATE_FLAG_ENABLE_SENDER_RESPONSE_TIMER; }
|
||||
|
||||
#define PE_STATE_WAIT_MSG_HRESET_IF_TOUT(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_HRESET_IF_SR_TIMEOUT |\
|
||||
PE_STATE_FLAG_ENABLE_SENDER_RESPONSE_TIMER; }
|
||||
|
||||
#define PE_STATE_WAIT_MSG_OR_TX_FAILED(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_BACK_READY_IF_TX_FAILED |\
|
||||
PE_STATE_FLAG_BACK_READY_IF_SR_TIMER_TOUT |\
|
||||
PE_STATE_FLAG_ENABLE_SENDER_RESPONSE_TIMER; }
|
||||
|
||||
#define PE_STATE_WAIT_MSG_OR_RJ(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_BACK_READY_IF_RECV_REJECT |\
|
||||
PE_STATE_FLAG_BACK_READY_IF_SR_TIMER_TOUT |\
|
||||
PE_STATE_FLAG_ENABLE_SENDER_RESPONSE_TIMER; }
|
||||
|
||||
#define PE_STATE_WAIT_ANSWER_MSG(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_BACK_READY_IF_RECV_WAIT |\
|
||||
PE_STATE_FLAG_BACK_READY_IF_RECV_REJECT |\
|
||||
PE_STATE_FLAG_BACK_READY_IF_SR_TIMER_TOUT |\
|
||||
PE_STATE_FLAG_ENABLE_SENDER_RESPONSE_TIMER; }
|
||||
|
||||
#define PE_STATE_HRESET_IF_TX_FAILED(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_HRESET_IF_TX_FAILED; }
|
||||
|
||||
#define PE_STATE_IGNORE_UNKNOWN_EVENT(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_IGNORE_UNKNOWN_EVENT; }
|
||||
|
||||
#define PE_STATE_RECV_SOFT_RESET(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_HRESET_IF_TX_FAILED | \
|
||||
PE_STATE_FLAG_IGNORE_UNKNOWN_EVENT; }
|
||||
|
||||
#define PE_STATE_SEND_SOFT_RESET(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags = \
|
||||
PE_STATE_FLAG_HRESET_IF_TX_FAILED |\
|
||||
PE_STATE_FLAG_HRESET_IF_SR_TIMEOUT |\
|
||||
PE_STATE_FLAG_IGNORE_UNKNOWN_EVENT |\
|
||||
PE_STATE_FLAG_ENABLE_SENDER_RESPONSE_TIMER; }
|
||||
|
||||
#define PE_STATE_FLAG_BACK_READY_IF_RECV_GOOD_CRC (1<<0)
|
||||
#define PE_STATE_FLAG_BACK_READY_IF_DPM_ACK (1<<1)
|
||||
#define PE_STATE_FLAG_DPM_ACK_IMMEDIATELY (1<<7)
|
||||
|
||||
#define PE_STATE_WAIT_TX_SUCCESS(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags2 = \
|
||||
PE_STATE_FLAG_BACK_READY_IF_RECV_GOOD_CRC; }
|
||||
|
||||
#define PE_STATE_DPM_INFORMED(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags2 = \
|
||||
PE_STATE_FLAG_BACK_READY_IF_DPM_ACK |\
|
||||
PE_STATE_FLAG_DPM_ACK_IMMEDIATELY; }
|
||||
|
||||
#define PE_STATE_WAIT_DPM_ACK(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags2 = \
|
||||
PE_STATE_FLAG_BACK_READY_IF_DPM_ACK; }
|
||||
|
||||
#define PE_STATE_DPM_ACK_IMMEDIATELY(pd_port) {\
|
||||
pd_port->pe_data.pe_state_flags2 |= \
|
||||
PE_STATE_FLAG_DPM_ACK_IMMEDIATELY; }
|
||||
|
||||
#define VDM_STATE_FLAG_ENABLE_VDM_RESPONSE_TIMER (1<<0)
|
||||
#define VDM_STATE_FLAG_DPM_ACK_IMMEDIATELY (1<<4)
|
||||
#define VDM_STATE_FLAG_BACK_READY_IF_DPM_ACK (1<<6)
|
||||
#define VDM_STATE_FLAG_BACK_READY_IF_RECV_GOOD_CRC (1<<7)
|
||||
|
||||
#define VDM_STATE_DPM_INFORMED(pd_port) {\
|
||||
pd_port->pe_data.vdm_state_flags = \
|
||||
VDM_STATE_FLAG_BACK_READY_IF_DPM_ACK |\
|
||||
VDM_STATE_FLAG_DPM_ACK_IMMEDIATELY; }
|
||||
|
||||
#define VDM_STATE_REPLY_SVDM_REQUEST(pd_port) {\
|
||||
pd_port->pe_data.vdm_state_flags = \
|
||||
VDM_STATE_FLAG_BACK_READY_IF_RECV_GOOD_CRC; }
|
||||
|
||||
#define VDM_STATE_NORESP_CMD(pd_port) {\
|
||||
pd_port->pe_data.vdm_state_flags = \
|
||||
VDM_STATE_FLAG_BACK_READY_IF_RECV_GOOD_CRC; }
|
||||
|
||||
#define VDM_STATE_RESPONSE_CMD(pd_port, timer_id) {\
|
||||
pd_port->pe_data.vdm_state_flags = \
|
||||
VDM_STATE_FLAG_ENABLE_VDM_RESPONSE_TIMER; \
|
||||
pd_port->pe_data.vdm_state_timer = timer_id; }
|
||||
|
||||
static inline bool pd_check_pe_during_hard_reset(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_port->tcpc->pd_wait_hard_reset_complete;
|
||||
}
|
||||
|
||||
enum pd_pe_state {
|
||||
PE_STATE_START_ID = -1,
|
||||
/******************* Source *******************/
|
||||
#ifdef CONFIG_USB_PD_PE_SOURCE
|
||||
PE_SRC_STARTUP,
|
||||
PE_SRC_DISCOVERY,
|
||||
PE_SRC_SEND_CAPABILITIES,
|
||||
PE_SRC_NEGOTIATE_CAPABILITIES,
|
||||
PE_SRC_TRANSITION_SUPPLY,
|
||||
PE_SRC_TRANSITION_SUPPLY2,
|
||||
PE_SRC_READY,
|
||||
PE_SRC_DISABLED,
|
||||
PE_SRC_CAPABILITY_RESPONSE,
|
||||
PE_SRC_HARD_RESET,
|
||||
PE_SRC_HARD_RESET_RECEIVED,
|
||||
PE_SRC_TRANSITION_TO_DEFAULT,
|
||||
PE_SRC_GET_SINK_CAP,
|
||||
PE_SRC_WAIT_NEW_CAPABILITIES,
|
||||
PE_SRC_SEND_SOFT_RESET,
|
||||
PE_SRC_SOFT_RESET,
|
||||
|
||||
/* Source Startup Discover Cable */
|
||||
#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
|
||||
#ifdef CONFIG_PD_SRC_RESET_CABLE
|
||||
PE_SRC_CBL_SEND_SOFT_RESET,
|
||||
#endif /* CONFIG_PD_SRC_RESET_CABLE */
|
||||
PE_SRC_VDM_IDENTITY_REQUEST,
|
||||
PE_SRC_VDM_IDENTITY_ACKED,
|
||||
PE_SRC_VDM_IDENTITY_NAKED,
|
||||
#endif /* PD_CAP_PE_SRC_STARTUP_DISCOVER_ID */
|
||||
|
||||
/* Source for PD30 */
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
PE_SRC_SEND_NOT_SUPPORTED,
|
||||
PE_SRC_NOT_SUPPORTED_RECEIVED,
|
||||
PE_SRC_CHUNK_RECEIVED,
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
PE_SRC_SEND_SOURCE_ALERT,
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
PE_SRC_SINK_ALERT_RECEIVED,
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
PE_SRC_GIVE_SOURCE_CAP_EXT,
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
PE_SRC_GIVE_SOURCE_STATUS,
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
PE_SRC_GET_SINK_STATUS,
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SOURCE
|
||||
PE_SRC_GIVE_PPS_STATUS,
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SOURCE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
#endif /* CONFIG_USB_PD_PE_SOURCE */
|
||||
|
||||
/******************* Sink *******************/
|
||||
#ifdef CONFIG_USB_PD_PE_SINK
|
||||
/* Sink Init */
|
||||
PE_SNK_STARTUP,
|
||||
PE_SNK_DISCOVERY,
|
||||
PE_SNK_WAIT_FOR_CAPABILITIES,
|
||||
PE_SNK_EVALUATE_CAPABILITY,
|
||||
PE_SNK_SELECT_CAPABILITY,
|
||||
PE_SNK_TRANSITION_SINK,
|
||||
PE_SNK_READY,
|
||||
PE_SNK_HARD_RESET,
|
||||
PE_SNK_TRANSITION_TO_DEFAULT,
|
||||
PE_SNK_GIVE_SINK_CAP,
|
||||
PE_SNK_GET_SOURCE_CAP,
|
||||
|
||||
PE_SNK_SEND_SOFT_RESET,
|
||||
PE_SNK_SOFT_RESET,
|
||||
|
||||
/* Sink for PD30 */
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
PE_SNK_SEND_NOT_SUPPORTED,
|
||||
PE_SNK_NOT_SUPPORTED_RECEIVED,
|
||||
PE_SNK_CHUNK_RECEIVED,
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
PE_SNK_SOURCE_ALERT_RECEIVED,
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
PE_SNK_SEND_SINK_ALERT,
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
PE_SNK_GET_SOURCE_CAP_EXT,
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
PE_SNK_GET_SOURCE_STATUS,
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
PE_SNK_GIVE_SINK_STATUS,
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
PE_SNK_GET_PPS_STATUS,
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
#endif /* CONFIG_USB_PD_PE_SINK */
|
||||
|
||||
/******************* DR_SWAP *******************/
|
||||
#ifdef CONFIG_USB_PD_DR_SWAP
|
||||
/* DR_SWAP_DFP */
|
||||
PE_DRS_DFP_UFP_EVALUATE_DR_SWAP,
|
||||
PE_DRS_DFP_UFP_ACCEPT_DR_SWAP,
|
||||
PE_DRS_DFP_UFP_CHANGE_TO_UFP,
|
||||
PE_DRS_DFP_UFP_SEND_DR_SWAP,
|
||||
PE_DRS_DFP_UFP_REJECT_DR_SWAP,
|
||||
/* DR_SWAP_UFP */
|
||||
PE_DRS_UFP_DFP_EVALUATE_DR_SWAP,
|
||||
PE_DRS_UFP_DFP_ACCEPT_DR_SWAP,
|
||||
PE_DRS_UFP_DFP_CHANGE_TO_DFP,
|
||||
PE_DRS_UFP_DFP_SEND_DR_SWAP,
|
||||
PE_DRS_UFP_DFP_REJECT_DR_SWAP,
|
||||
#endif /* CONFIG_USB_PD_DR_SWAP */
|
||||
|
||||
/******************* PR_SWAP *******************/
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
/* PR_SWAP_SRC */
|
||||
PE_PRS_SRC_SNK_EVALUATE_PR_SWAP,
|
||||
PE_PRS_SRC_SNK_ACCEPT_PR_SWAP,
|
||||
PE_PRS_SRC_SNK_TRANSITION_TO_OFF,
|
||||
PE_PRS_SRC_SNK_ASSERT_RD,
|
||||
PE_PRS_SRC_SNK_WAIT_SOURCE_ON,
|
||||
PE_PRS_SRC_SNK_SEND_SWAP,
|
||||
PE_PRS_SRC_SNK_REJECT_PR_SWAP,
|
||||
|
||||
/* PR_SWAP_SNK */
|
||||
PE_PRS_SNK_SRC_EVALUATE_PR_SWAP,
|
||||
PE_PRS_SNK_SRC_ACCEPT_PR_SWAP,
|
||||
PE_PRS_SNK_SRC_TRANSITION_TO_OFF,
|
||||
PE_PRS_SNK_SRC_ASSERT_RP,
|
||||
PE_PRS_SNK_SRC_SOURCE_ON,
|
||||
PE_PRS_SNK_SRC_SEND_SWAP,
|
||||
PE_PRS_SNK_SRC_REJECT_SWAP,
|
||||
|
||||
/* get same role cap */
|
||||
PE_DR_SRC_GET_SOURCE_CAP,
|
||||
PE_DR_SRC_GIVE_SINK_CAP,
|
||||
PE_DR_SNK_GET_SINK_CAP,
|
||||
PE_DR_SNK_GIVE_SOURCE_CAP,
|
||||
|
||||
/* get same role cap for PD30 */
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
PE_DR_SNK_GIVE_SOURCE_CAP_EXT,
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
PE_DR_SRC_GET_SOURCE_CAP_EXT,
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
/******************* VCONN_SWAP *******************/
|
||||
#ifdef CONFIG_USB_PD_VCONN_SWAP
|
||||
PE_VCS_SEND_SWAP,
|
||||
PE_VCS_EVALUATE_SWAP,
|
||||
PE_VCS_ACCEPT_SWAP,
|
||||
PE_VCS_REJECT_VCONN_SWAP,
|
||||
PE_VCS_WAIT_FOR_VCONN,
|
||||
PE_VCS_TURN_OFF_VCONN,
|
||||
PE_VCS_TURN_ON_VCONN,
|
||||
PE_VCS_SEND_PS_RDY,
|
||||
#endif /* CONFIG_USB_PD_VCONN_SWAP */
|
||||
|
||||
/******************* UFP_VDM *******************/
|
||||
PE_UFP_VDM_GET_IDENTITY,
|
||||
PE_UFP_VDM_GET_SVIDS,
|
||||
PE_UFP_VDM_GET_MODES,
|
||||
PE_UFP_VDM_EVALUATE_MODE_ENTRY,
|
||||
PE_UFP_VDM_MODE_EXIT,
|
||||
PE_UFP_VDM_ATTENTION_REQUEST,
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
PE_UFP_VDM_DP_STATUS_UPDATE,
|
||||
PE_UFP_VDM_DP_CONFIGURE,
|
||||
#endif/* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
/******************* DFP_VDM *******************/
|
||||
PE_DFP_UFP_VDM_IDENTITY_REQUEST,
|
||||
PE_DFP_UFP_VDM_IDENTITY_ACKED,
|
||||
PE_DFP_UFP_VDM_IDENTITY_NAKED,
|
||||
PE_DFP_CBL_VDM_IDENTITY_REQUEST,
|
||||
PE_DFP_CBL_VDM_IDENTITY_ACKED,
|
||||
PE_DFP_CBL_VDM_IDENTITY_NAKED,
|
||||
|
||||
PE_DFP_VDM_SVIDS_REQUEST,
|
||||
PE_DFP_VDM_SVIDS_ACKED,
|
||||
PE_DFP_VDM_SVIDS_NAKED,
|
||||
PE_DFP_VDM_MODES_REQUEST,
|
||||
PE_DFP_VDM_MODES_ACKED,
|
||||
PE_DFP_VDM_MODES_NAKED,
|
||||
PE_DFP_VDM_MODE_ENTRY_REQUEST,
|
||||
PE_DFP_VDM_MODE_ENTRY_ACKED,
|
||||
PE_DFP_VDM_MODE_ENTRY_NAKED,
|
||||
PE_DFP_VDM_MODE_EXIT_REQUEST,
|
||||
PE_DFP_VDM_MODE_EXIT_ACKED,
|
||||
PE_DFP_VDM_ATTENTION_REQUEST,
|
||||
|
||||
#ifdef CONFIG_PD_DFP_RESET_CABLE
|
||||
PE_DFP_CBL_SEND_SOFT_RESET,
|
||||
PE_DFP_CBL_SEND_CABLE_RESET,
|
||||
#endif /* CONFIG_PD_DFP_RESET_CABLE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
PE_DFP_VDM_DP_STATUS_UPDATE_REQUEST,
|
||||
PE_DFP_VDM_DP_STATUS_UPDATE_ACKED,
|
||||
PE_DFP_VDM_DP_STATUS_UPDATE_NAKED,
|
||||
|
||||
PE_DFP_VDM_DP_CONFIGURATION_REQUEST,
|
||||
PE_DFP_VDM_DP_CONFIGURATION_ACKED,
|
||||
PE_DFP_VDM_DP_CONFIGURATION_NAKED,
|
||||
#endif/* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
|
||||
/******************* UVDM & SVDM *******************/
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
PE_UFP_UVDM_RECV,
|
||||
PE_DFP_UVDM_SEND,
|
||||
PE_DFP_UVDM_ACKED,
|
||||
PE_DFP_UVDM_NAKED,
|
||||
#endif/* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
/******************* PD30 Common *******************/
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_REMOTE
|
||||
PE_GET_BATTERY_CAP,
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_LOCAL
|
||||
PE_GIVE_BATTERY_CAP,
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE
|
||||
PE_GET_BATTERY_STATUS,
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL
|
||||
PE_GIVE_BATTERY_STATUS,
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE
|
||||
PE_GET_MANUFACTURER_INFO,
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL
|
||||
PE_GIVE_MANUFACTURER_INFO,
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE
|
||||
PE_GET_COUNTRY_CODES,
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL
|
||||
PE_GIVE_COUNTRY_CODES,
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE
|
||||
PE_GET_COUNTRY_INFO,
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL
|
||||
PE_GIVE_COUNTRY_INFO,
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL */
|
||||
PE_VDM_NOT_SUPPORTED,
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
/******************* Others *******************/
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
|
||||
PE_DBG_READY,
|
||||
#endif/* CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
|
||||
#ifdef CONFIG_USB_PD_RECV_HRESET_COUNTER
|
||||
PE_OVER_RECV_HRESET_LIMIT,
|
||||
#endif/* CONFIG_USB_PD_RECV_HRESET_COUNTER */
|
||||
|
||||
PE_REJECT,
|
||||
PE_ERROR_RECOVERY,
|
||||
#ifdef CONFIG_USB_PD_ERROR_RECOVERY_ONCE
|
||||
PE_ERROR_RECOVERY_ONCE,
|
||||
#endif /* CONFIG_USB_PD_ERROR_RECOVERY_ONCE */
|
||||
PE_BIST_TEST_DATA,
|
||||
PE_BIST_CARRIER_MODE_2,
|
||||
/* Wait tx finished */
|
||||
PE_IDLE1,
|
||||
PE_IDLE2,
|
||||
PD_NR_PE_STATES,
|
||||
};
|
||||
|
||||
/**
|
||||
* pd_policy_engine_run
|
||||
*
|
||||
* Driving the PE to get next event, and take the corresponding actions.
|
||||
*
|
||||
*
|
||||
* Returns True if a pending event is processed;
|
||||
* Returns Zero to indicate there is no pending event.
|
||||
* Returns Negative Value if an error occurs.
|
||||
*/
|
||||
|
||||
int pd_policy_engine_run(struct tcpc_device *tcpc);
|
||||
|
||||
|
||||
/* ---- Policy Engine (General) ---- */
|
||||
|
||||
void pe_power_ready_entry(struct pd_port *pd_port);
|
||||
|
||||
static inline void pe_send_swap_request_entry(
|
||||
struct pd_port *pd_port, uint8_t msg)
|
||||
{
|
||||
PE_STATE_WAIT_ANSWER_MSG(pd_port);
|
||||
pd_send_sop_ctrl_msg(pd_port, msg);
|
||||
}
|
||||
|
||||
/******************* Source *******************/
|
||||
#ifdef CONFIG_USB_PD_PE_SOURCE
|
||||
void pe_src_startup_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_discovery_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_send_capabilities_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_negotiate_capabilities_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_transition_supply_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_transition_supply_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_transition_supply2_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_ready_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_disabled_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_capability_response_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_hard_reset_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_hard_reset_received_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_transition_to_default_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_transition_to_default_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_get_sink_cap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_get_sink_cap_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_wait_new_capabilities_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_send_soft_reset_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_soft_reset_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
/* Source Startup Discover Cable */
|
||||
#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
|
||||
#ifdef CONFIG_PD_SRC_RESET_CABLE
|
||||
void pe_src_cbl_send_soft_reset_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_PD_SRC_RESET_CABLE */
|
||||
void pe_src_vdm_identity_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_vdm_identity_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_vdm_identity_naked_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* PD_CAP_PE_SRC_STARTUP_DISCOVER_ID */
|
||||
|
||||
/* Source for PD30 */
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
void pe_src_send_not_supported_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_not_supported_received_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_chunk_received_entry(
|
||||
struct pd_port *pd_port);
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
void pe_src_send_source_alert_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
void pe_src_sink_alert_received_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
void pe_src_give_source_cap_ext_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
void pe_src_give_source_status_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
void pe_src_get_sink_status_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_src_get_sink_status_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SOURCE
|
||||
void pe_src_give_pps_status_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SOURCE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
#endif /* CONFIG_USB_PD_PE_SOURCE */
|
||||
|
||||
/******************* Sink *******************/
|
||||
#ifdef CONFIG_USB_PD_PE_SINK
|
||||
/* Sink Init */
|
||||
void pe_snk_startup_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_discovery_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_wait_for_capabilities_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_evaluate_capability_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_select_capability_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_select_capability_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_transition_sink_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_transition_sink_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_ready_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_hard_reset_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_transition_to_default_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_give_sink_cap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_get_source_cap_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
void pe_snk_send_soft_reset_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_soft_reset_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
/* Sink for PD30 */
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
void pe_snk_send_not_supported_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_not_supported_received_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_chunk_received_entry(
|
||||
struct pd_port *pd_port);
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
void pe_snk_source_alert_received_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
void pe_snk_send_sink_alert_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
void pe_snk_get_source_cap_ext_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_get_source_cap_ext_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
void pe_snk_get_source_status_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_get_source_status_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
void pe_snk_give_sink_status_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
void pe_snk_get_pps_status_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_snk_get_pps_status_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
#endif /* CONFIG_USB_PD_PE_SINK */
|
||||
|
||||
/******************* DR_SWAP *******************/
|
||||
#ifdef CONFIG_USB_PD_DR_SWAP
|
||||
/* DR_SWAP_DFP */
|
||||
void pe_drs_dfp_ufp_evaluate_dr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_drs_dfp_ufp_accept_dr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_drs_dfp_ufp_change_to_ufp_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_drs_dfp_ufp_send_dr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_drs_dfp_ufp_reject_dr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
/* DR_SWAP_UFP */
|
||||
void pe_drs_ufp_dfp_evaluate_dr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_drs_ufp_dfp_accept_dr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_drs_ufp_dfp_change_to_dfp_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_drs_ufp_dfp_send_dr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_drs_ufp_dfp_reject_dr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_DR_SWAP */
|
||||
|
||||
/******************* PR_SWAP *******************/
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
/* PR_SWAP_SRC */
|
||||
void pe_prs_src_snk_evaluate_pr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_src_snk_accept_pr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_src_snk_transition_to_off_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_src_snk_assert_rd_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_src_snk_wait_source_on_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_src_snk_wait_source_on_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_src_snk_send_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_src_snk_reject_pr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
/* PR_SWAP_SNK */
|
||||
void pe_prs_snk_src_evaluate_pr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_snk_src_accept_pr_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_snk_src_transition_to_off_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_snk_src_transition_to_off_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_snk_src_assert_rp_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_snk_src_source_on_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_snk_src_source_on_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_snk_src_send_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_prs_snk_src_reject_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
/* get same role cap */
|
||||
void pe_dr_src_get_source_cap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dr_src_get_source_cap_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dr_src_give_sink_cap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dr_snk_get_sink_cap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dr_snk_get_sink_cap_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dr_snk_give_source_cap_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
/* get same role cap for PD30 */
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
void pe_dr_snk_give_source_cap_ext_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
void pe_dr_src_get_source_cap_ext_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dr_src_get_source_cap_ext_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
/******************* VCONN_SWAP *******************/
|
||||
#ifdef CONFIG_USB_PD_VCONN_SWAP
|
||||
void pe_vcs_send_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_vcs_evaluate_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_vcs_accept_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_vcs_reject_vconn_swap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_vcs_wait_for_vconn_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_vcs_wait_for_vconn_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_vcs_turn_off_vconn_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_vcs_turn_on_vconn_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_vcs_send_ps_rdy_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_VCONN_SWAP */
|
||||
|
||||
/******************* UFP_VDM *******************/
|
||||
void pe_ufp_vdm_get_identity_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_send_identity_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_get_identity_nak_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_get_svids_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_send_svids_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_get_svids_nak_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_get_modes_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_send_modes_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_get_modes_nak_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_evaluate_mode_entry_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_mode_entry_ack_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_mode_entry_nak_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_mode_exit_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_mode_exit_ack_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_mode_exit_nak_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
void pe_ufp_vdm_attention_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
void pe_ufp_vdm_dp_status_update_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_ufp_vdm_dp_configure_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif/* CONFIG_USB_PD_ALT_MODE */
|
||||
/******************* DFP_VDM *******************/
|
||||
void pe_dfp_ufp_vdm_identity_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_ufp_vdm_identity_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_ufp_vdm_identity_naked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_cbl_vdm_identity_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_cbl_vdm_identity_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_cbl_vdm_identity_naked_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
void pe_dfp_vdm_svids_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_svids_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_svids_naked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_modes_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_modes_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_modes_naked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_mode_entry_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_mode_entry_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_mode_entry_naked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_mode_exit_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_mode_exit_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_attention_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
#ifdef CONFIG_PD_DFP_RESET_CABLE
|
||||
void pe_dfp_cbl_send_soft_reset_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_cbl_send_cable_reset_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_PD_DFP_RESET_CABLE */
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
void pe_dfp_vdm_dp_status_update_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_dp_status_update_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_dp_status_update_naked_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
void pe_dfp_vdm_dp_configuration_request_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_dp_configuration_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_vdm_dp_configuration_naked_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif/* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
/******************* UVDM & SVDM *******************/
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
void pe_ufp_uvdm_recv_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_uvdm_send_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_uvdm_acked_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_dfp_uvdm_naked_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif/* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
/******************* PD30 Common *******************/
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_REMOTE
|
||||
void pe_get_battery_cap_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_get_battery_cap_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_LOCAL
|
||||
void pe_give_battery_cap_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE
|
||||
void pe_get_battery_status_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_get_battery_status_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL
|
||||
void pe_give_battery_status_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE
|
||||
void pe_get_manufacturer_info_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_get_manufacturer_info_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL
|
||||
void pe_give_manufacturer_info_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE
|
||||
void pe_get_country_codes_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_get_country_codes_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL
|
||||
void pe_give_country_codes_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL */
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE
|
||||
void pe_get_country_info_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_get_country_info_exit(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE */
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL
|
||||
void pe_give_country_info_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL */
|
||||
void pe_vdm_not_supported_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
/******************* Others *******************/
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
|
||||
void pe_dbg_ready_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif/* CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
|
||||
#ifdef CONFIG_USB_PD_RECV_HRESET_COUNTER
|
||||
void pe_over_recv_hreset_limit_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif/* CONFIG_USB_PD_RECV_HRESET_COUNTER */
|
||||
void pe_reject_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_error_recovery_entry(
|
||||
struct pd_port *pd_port);
|
||||
#ifdef CONFIG_USB_PD_ERROR_RECOVERY_ONCE
|
||||
void pe_error_recovery_once_entry(
|
||||
struct pd_port *pd_port);
|
||||
#endif /* CONFIG_USB_PD_ERROR_RECOVERY_ONCE */
|
||||
void pe_bist_test_data_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_bist_test_data_exit(
|
||||
struct pd_port *pd_port);
|
||||
void pe_bist_carrier_mode_2_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_bist_carrier_mode_2_exit(
|
||||
struct pd_port *pd_port);
|
||||
/* Wait tx finished */
|
||||
void pe_idle1_entry(
|
||||
struct pd_port *pd_port);
|
||||
void pe_idle2_entry(
|
||||
struct pd_port *pd_port);
|
||||
|
||||
#endif /* PD_POLICY_ENGINE_H_ */
|
||||
205
drivers/usb/typec/mmi_tcpc/inc/pd_process_evt.h
Normal file
205
drivers/usb/typec/mmi_tcpc/inc/pd_process_evt.h
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef PD_PROCESS_EVT_H_
|
||||
#define PD_PROCESS_EVT_H_
|
||||
|
||||
#include "tcpci.h"
|
||||
#include "pd_policy_engine.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
struct pe_state_transition {
|
||||
uint8_t curr_state; /*state, msg, or cmd */
|
||||
uint8_t next_state;
|
||||
};
|
||||
|
||||
struct pe_state_reaction {
|
||||
uint16_t nr_transition;
|
||||
const struct pe_state_transition *state_transition;
|
||||
};
|
||||
|
||||
#define DECL_PE_STATE_TRANSITION(state) \
|
||||
static const struct pe_state_transition state##_state_transition[]
|
||||
|
||||
#define DECL_PE_STATE_REACTION(state) \
|
||||
static const struct pe_state_reaction state##_reactions = {\
|
||||
.nr_transition = ARRAY_SIZE(state##_state_transition),\
|
||||
.state_transition = state##_state_transition,\
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Sink & Source Common Event
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool pd_process_protocol_error(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event);
|
||||
|
||||
bool pd_process_tx_failed(struct pd_port *pd_port);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#define PE_TRANSIT_STATE(pd_port, state) \
|
||||
(pd_port->pe_state_next = state)
|
||||
|
||||
#define PE_TRANSIT_DATA_STATE(pd_port, ufp, dfp) \
|
||||
(pd_port->pe_state_next =\
|
||||
((pd_port->data_role == PD_ROLE_UFP) ? ufp : dfp))
|
||||
|
||||
static inline uint8_t pe_get_curr_ready_state(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_port->curr_ready_state;
|
||||
}
|
||||
|
||||
static inline uint8_t pe_get_curr_hard_reset_state(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_port->curr_hreset_state;
|
||||
}
|
||||
|
||||
static inline uint8_t pe_get_curr_soft_reset_state(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_port->curr_sreset_state;
|
||||
}
|
||||
|
||||
static inline uint8_t pe_get_curr_evaluate_pr_swap_state(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->power_role == PD_ROLE_SINK)
|
||||
return PE_PRS_SNK_SRC_EVALUATE_PR_SWAP;
|
||||
|
||||
return PE_PRS_SRC_SNK_EVALUATE_PR_SWAP;
|
||||
}
|
||||
|
||||
static inline uint8_t pe_get_curr_send_pr_swap_state(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->power_role == PD_ROLE_SINK)
|
||||
return PE_PRS_SNK_SRC_SEND_SWAP;
|
||||
|
||||
return PE_PRS_SRC_SNK_SEND_SWAP;
|
||||
}
|
||||
|
||||
static inline uint8_t pd_get_curr_hard_reset_recv_state(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->power_role == PD_ROLE_SINK)
|
||||
return PE_SNK_TRANSITION_TO_DEFAULT;
|
||||
|
||||
return PE_SRC_HARD_RESET_RECEIVED;
|
||||
}
|
||||
|
||||
static inline uint8_t pd_get_curr_soft_reset_recv_state(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->power_role == PD_ROLE_SINK)
|
||||
return PE_SNK_SOFT_RESET;
|
||||
|
||||
return PE_SRC_SOFT_RESET;
|
||||
}
|
||||
|
||||
static inline void pe_transit_ready_state(struct pd_port *pd_port)
|
||||
{
|
||||
PE_TRANSIT_STATE(pd_port, pe_get_curr_ready_state(pd_port));
|
||||
}
|
||||
|
||||
static inline void pe_transit_hard_reset_state(struct pd_port *pd_port)
|
||||
{
|
||||
PE_TRANSIT_STATE(pd_port, pe_get_curr_hard_reset_state(pd_port));
|
||||
}
|
||||
|
||||
static inline void pe_transit_soft_reset_state(struct pd_port *pd_port)
|
||||
{
|
||||
PE_TRANSIT_STATE(pd_port, pe_get_curr_soft_reset_state(pd_port));
|
||||
}
|
||||
|
||||
static inline void pe_transit_soft_reset_recv_state(struct pd_port *pd_port)
|
||||
{
|
||||
PE_TRANSIT_STATE(pd_port, pd_get_curr_soft_reset_recv_state(pd_port));
|
||||
}
|
||||
|
||||
static inline void pe_transit_evaluate_pr_swap_state(struct pd_port *pd_port)
|
||||
{
|
||||
PE_TRANSIT_STATE(pd_port,
|
||||
pe_get_curr_evaluate_pr_swap_state(pd_port));
|
||||
}
|
||||
|
||||
static inline void pe_transit_send_pr_swap_state(struct pd_port *pd_port)
|
||||
{
|
||||
PE_TRANSIT_STATE(pd_port,
|
||||
pe_get_curr_send_pr_swap_state(pd_port));
|
||||
}
|
||||
|
||||
static inline void pe_transit_hard_reset_recv_state(struct pd_port *pd_port)
|
||||
{
|
||||
PE_TRANSIT_STATE(pd_port,
|
||||
pd_get_curr_hard_reset_recv_state(pd_port));
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static inline bool pd_check_pe_state_ready(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t ready_state = pe_get_curr_ready_state(pd_port);
|
||||
|
||||
return pd_port->pe_state_curr == ready_state;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#define PE_MAKE_STATE_TRANSIT_SINGLE(reaction, next) \
|
||||
pd_make_pe_state_transit_single(\
|
||||
pd_port, pd_port->pe_state_curr, reaction, next)
|
||||
/* PE_MAKE_STATE_TRANSIT_SINGLE */
|
||||
|
||||
#define PE_MAKE_STATE_TRANSIT_TO_HRESET(reaction) \
|
||||
PE_MAKE_STATE_TRANSIT_SINGLE(reaction, \
|
||||
pe_get_curr_hard_reset_state(pd_port))
|
||||
/* PE_MAKE_STATE_TRANSIT_TO_HRESET */
|
||||
|
||||
#define PE_MAKE_STATE_TRANSIT(state) \
|
||||
pd_make_pe_state_transit(\
|
||||
pd_port, pd_port->pe_state_curr, &state##_reactions)
|
||||
/* PE_MAKE_STATE_TRANSIT */
|
||||
|
||||
|
||||
static inline bool pd_make_pe_state_transit_single(struct pd_port *pd_port,
|
||||
uint8_t curr_state, uint8_t reaction_state, uint8_t next_state)
|
||||
{
|
||||
if (curr_state == reaction_state) {
|
||||
PE_TRANSIT_STATE(pd_port, next_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pd_make_pe_state_transit(struct pd_port *pd_port, uint8_t curr_state,
|
||||
const struct pe_state_reaction *state_reaction);
|
||||
|
||||
bool pd_process_event(struct pd_port *pd_port, struct pd_event *pd_event);
|
||||
|
||||
extern bool pd_process_event_snk(struct pd_port *pd_port, struct pd_event *evt);
|
||||
extern bool pd_process_event_src(struct pd_port *pd_port, struct pd_event *evt);
|
||||
extern bool pd_process_event_drs(struct pd_port *pd_port, struct pd_event *evt);
|
||||
extern bool pd_process_event_prs(struct pd_port *pd_port, struct pd_event *evt);
|
||||
extern bool pd_process_event_vdm(struct pd_port *pd_port, struct pd_event *evt);
|
||||
extern bool pd_process_event_vcs(struct pd_port *pd_port, struct pd_event *evt);
|
||||
extern bool pd_process_event_com(struct pd_port *pd_port, struct pd_event *evt);
|
||||
extern bool pd_process_event_tcp(struct pd_port *pd_port, struct pd_event *evt);
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
|
||||
extern bool pd_process_event_dbg(struct pd_port *pd_port, struct pd_event *evt);
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
|
||||
#endif /* PD_PROCESS_EVT_H_ */
|
||||
218
drivers/usb/typec/mmi_tcpc/inc/rt-regmap.h
Normal file
218
drivers/usb/typec/mmi_tcpc/inc/rt-regmap.h
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2020 MediaTek Inc.
|
||||
* Author: cy_huang <cy_huang@richtek.com>
|
||||
*/
|
||||
|
||||
#ifndef LINUX_MISC_RT_REGMAP_H
|
||||
#define LINUX_MISC_RT_REGMAP_H
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
enum rt_access_mode {
|
||||
RT_1BYTE_MODE = 1,
|
||||
RT_2BYTE_MODE = 2,
|
||||
RT_4BYTE_MODE = 4,
|
||||
RT_DUMMY_MODE = -1,
|
||||
};
|
||||
|
||||
/* start: the start address of group
|
||||
* end: the end address of group
|
||||
* mode: access mode (1,2,4 bytes)
|
||||
*/
|
||||
struct rt_access_group {
|
||||
u32 start;
|
||||
u32 end;
|
||||
enum rt_access_mode mode;
|
||||
};
|
||||
|
||||
/* rt_reg_type
|
||||
* RT_NORMAL : Write without mask, Read from cache
|
||||
* RT_WBITS : Write with mask, Read from cache
|
||||
* RT_VOLATILE : Write to chip directly, Read from chip
|
||||
* RT_RESERVE : Reserve registers (Write/Read as RT_NORMAL)
|
||||
*/
|
||||
#define RT_REG_TYPE_MASK (0x03)
|
||||
#define RT_NORMAL (0x00)
|
||||
#define RT_WBITS (0x01)
|
||||
#define RT_VOLATILE (0x02)
|
||||
#define RT_RESERVE (0x03)
|
||||
|
||||
/* RT_WR_ONCE: if write data = cache data, data will not be written.
|
||||
*/
|
||||
#define RT_WR_ONCE (0x08)
|
||||
#define RT_NORMAL_WR_ONCE (RT_NORMAL | RT_WR_ONCE)
|
||||
#define RT_WBITS_WR_ONCE (RT_WBITS | RT_WR_ONCE)
|
||||
|
||||
enum rt_data_format {
|
||||
RT_LITTLE_ENDIAN,
|
||||
RT_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
/* rt_regmap_mode
|
||||
* 0 0 0 0 0 0 0 0
|
||||
* | | | | | |
|
||||
* | | | |__| byte_mode
|
||||
* | |__| ||
|
||||
* | || Cache_mode
|
||||
* | Block_mode
|
||||
* Debug_mode
|
||||
*/
|
||||
|
||||
#define RT_BYTE_MODE_MASK (0x01)
|
||||
/* 1 byte for each register */
|
||||
#define RT_SINGLE_BYTE (0 << 0)
|
||||
/* multi bytes for each regiseter */
|
||||
#define RT_MULTI_BYTE (1 << 0)
|
||||
|
||||
#define RT_CACHE_MODE_MASK (0x06)
|
||||
/* write to cache and chip synchronously */
|
||||
#define RT_CACHE_WR_THROUGH (0 << 1)
|
||||
/* write to cache and chip asynchronously */
|
||||
#define RT_CACHE_WR_BACK (1 << 1)
|
||||
/* disable cache */
|
||||
#define RT_CACHE_DISABLE (2 << 1)
|
||||
|
||||
#define RT_IO_BLK_MODE_MASK (0x18)
|
||||
/* pass through all write function */
|
||||
#define RT_IO_PASS_THROUGH (0 << 3)
|
||||
/* block all write function */
|
||||
#define RT_IO_BLK_ALL (1 << 3)
|
||||
/* block cache write function */
|
||||
#define RT_IO_BLK_CACHE (2 << 3)
|
||||
/* block chip write function */
|
||||
#define RT_IO_BLK_CHIP (3 << 3)
|
||||
|
||||
#define RT_DBG_MODE_MASK (0x20)
|
||||
/* create general debugfs for register map */
|
||||
#define RT_DBG_GENERAL (0 << 5)
|
||||
/* create node for each regisetr map by register address */
|
||||
#define RT_DBG_SPECIAL (1 << 5)
|
||||
|
||||
|
||||
/* struct rt_register
|
||||
*
|
||||
* Ricktek register map structure for storing mapping data
|
||||
* @addr: register address.
|
||||
* @size: register size in byte.
|
||||
* @reg_type: register R/W type (RT_NORMAL, RT_WBITS, RT_VOLATILE, RT_RESERVE).
|
||||
* @wbit_mask: register writeable bits mask.
|
||||
*/
|
||||
struct rt_register {
|
||||
u32 addr;
|
||||
unsigned int size;
|
||||
unsigned char reg_type;
|
||||
unsigned char *wbit_mask;
|
||||
};
|
||||
|
||||
/* Declare a rt_register by RT_REG_DECL
|
||||
*/
|
||||
#define RT_REG_DECL(_addr, _reg_length, _reg_type, _mask_...) \
|
||||
static unsigned char rt_writable_mask_##_addr[_reg_length] = _mask_; \
|
||||
static struct rt_register rt_register_##_addr = { \
|
||||
.addr = _addr, \
|
||||
.size = _reg_length, \
|
||||
.reg_type = _reg_type, \
|
||||
.wbit_mask = rt_writable_mask_##_addr, \
|
||||
}
|
||||
|
||||
#define rt_register_map_t struct rt_register *
|
||||
|
||||
#define RT_REG(_addr) (&rt_register_##_addr)
|
||||
|
||||
/* rt_regmap_properties
|
||||
* @name: the name of debug node.
|
||||
* @aliases: alisis name of rt_regmap_device.
|
||||
* @rm: rt_regiseter_map pointer array.
|
||||
* @register_num: the number of rt_register_map registers.
|
||||
* @group: register map access group.
|
||||
* @rt_format: default is little endian.
|
||||
* @rt_regmap_mode: rt_regmap_device mode.
|
||||
* @io_log_en: enable/disable io log
|
||||
*/
|
||||
struct rt_regmap_properties {
|
||||
const char *name;
|
||||
const char *aliases;
|
||||
const rt_register_map_t *rm;
|
||||
int register_num;
|
||||
struct rt_access_group *group;
|
||||
const enum rt_data_format rt_format;
|
||||
unsigned char rt_regmap_mode;
|
||||
unsigned char io_log_en:1;
|
||||
};
|
||||
|
||||
/* A passing struct for rt_regmap_reg_read and rt_regmap_reg_write function
|
||||
* reg: regmap addr.
|
||||
* mask: mask for update bits.
|
||||
* rt_data: register value.
|
||||
*/
|
||||
struct rt_reg_data {
|
||||
u32 reg;
|
||||
u32 mask;
|
||||
union {
|
||||
u32 data_u32;
|
||||
u16 data_u16;
|
||||
u8 data_u8;
|
||||
u8 data[4];
|
||||
} rt_data;
|
||||
};
|
||||
|
||||
struct rt_regmap_device;
|
||||
|
||||
/* basic chip read/write function */
|
||||
struct rt_regmap_fops {
|
||||
int (*read_device)(void *client, u32 addr, int len, void *dst);
|
||||
int (*write_device)(void *client, u32 addr, int len, const void *src);
|
||||
};
|
||||
|
||||
/* with device address */
|
||||
extern struct rt_regmap_device*
|
||||
rt_regmap_device_register_ex(struct rt_regmap_properties *props,
|
||||
struct rt_regmap_fops *rops,
|
||||
struct device *parent,
|
||||
void *client, int dev_addr, void *drvdata);
|
||||
|
||||
static inline struct rt_regmap_device*
|
||||
rt_regmap_device_register(struct rt_regmap_properties *props,
|
||||
struct rt_regmap_fops *rops,
|
||||
struct device *parent,
|
||||
struct i2c_client *client, void *drvdata)
|
||||
{
|
||||
return rt_regmap_device_register_ex(props, rops, parent,
|
||||
client, client->addr, drvdata);
|
||||
}
|
||||
|
||||
extern void rt_regmap_device_unregister(struct rt_regmap_device *rd);
|
||||
|
||||
extern int rt_regmap_cache_reload(struct rt_regmap_device *rd);
|
||||
|
||||
extern int rt_regmap_block_write(struct rt_regmap_device *rd, u32 reg,
|
||||
int bytes, const void *src);
|
||||
extern int rt_asyn_regmap_block_write(struct rt_regmap_device *rd, u32 reg,
|
||||
int bytes, const void *src);
|
||||
extern int rt_regmap_block_read(struct rt_regmap_device *rd, u32 reg,
|
||||
int bytes, void *dst);
|
||||
extern int rt_regmap_reg_read(struct rt_regmap_device *rd,
|
||||
struct rt_reg_data *rrd, u32 reg);
|
||||
extern int rt_regmap_reg_write(struct rt_regmap_device *rd,
|
||||
struct rt_reg_data *rrd, u32 reg,
|
||||
const u32 data);
|
||||
extern int rt_asyn_regmap_reg_write(struct rt_regmap_device *rd,
|
||||
struct rt_reg_data *rrd, u32 reg,
|
||||
const u32 data);
|
||||
extern int rt_regmap_update_bits(struct rt_regmap_device *rd,
|
||||
struct rt_reg_data *rrd, u32 reg,
|
||||
u32 mask, u32 data);
|
||||
extern void rt_regmap_cache_sync(struct rt_regmap_device *rd);
|
||||
extern void rt_regmap_cache_write_back(struct rt_regmap_device *rd, u32 reg);
|
||||
extern int rt_is_reg_volatile(struct rt_regmap_device *rd, u32 reg);
|
||||
extern int rt_get_regsize(struct rt_regmap_device *rd, u32 reg);
|
||||
extern void rt_cache_getlasterror(struct rt_regmap_device *rd, char *buf,
|
||||
size_t size);
|
||||
extern void rt_cache_clrlasterror(struct rt_regmap_device *rd);
|
||||
extern int rt_regmap_add_debugfs(struct rt_regmap_device *rd, const char *name,
|
||||
umode_t mode, void *data,
|
||||
const struct file_operations *fops);
|
||||
extern int regmap_plat_init(void);
|
||||
extern void regmap_plat_exit(void);
|
||||
#endif /* LINUX_MISC_RT_REGMAP_H */
|
||||
204
drivers/usb/typec/mmi_tcpc/inc/rt1711h.h
Normal file
204
drivers/usb/typec/mmi_tcpc/inc/rt1711h.h
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RT1711H_H
|
||||
#define __LINUX_RT1711H_H
|
||||
|
||||
#include "std_tcpci_v10.h"
|
||||
#include "pd_dbg_info.h"
|
||||
|
||||
/*show debug message or not */
|
||||
#define ENABLE_RT1711_DBG 0
|
||||
|
||||
/* RT1711H Private RegMap */
|
||||
|
||||
#define RT1711H_REG_CONFIG_GPIO0 (0x71)
|
||||
|
||||
#define RT1711H_REG_PHY_CTRL1 (0x80)
|
||||
|
||||
#define RT1711H_REG_CLK_CTRL2 (0x87)
|
||||
#define RT1711H_REG_CLK_CTRL3 (0x88)
|
||||
|
||||
#define RT1711H_REG_PRL_FSM_RESET (0x8D)
|
||||
|
||||
#define RT1711H_REG_BMC_CTRL (0x90)
|
||||
#define RT1711H_REG_BMCIO_RXDZSEL (0x93)
|
||||
#define RT1711H_REG_VCONN_CLIMITEN (0x95)
|
||||
|
||||
#define RT1711H_REG_RT_STATUS (0x97)
|
||||
#define RT1711H_REG_RT_INT (0x98)
|
||||
#define RT1711H_REG_RT_MASK (0x99)
|
||||
|
||||
#define RT1711H_REG_IDLE_CTRL (0x9B)
|
||||
#define RT1711H_REG_INTRST_CTRL (0x9C)
|
||||
#define RT1711H_REG_WATCHDOG_CTRL (0x9D)
|
||||
#define RT1711H_REG_I2CRST_CTRL (0X9E)
|
||||
|
||||
#define RT1711H_REG_SWRESET (0xA0)
|
||||
#define RT1711H_REG_TTCPC_FILTER (0xA1)
|
||||
#define RT1711H_REG_DRP_TOGGLE_CYCLE (0xA2)
|
||||
#define RT1711H_REG_DRP_DUTY_CTRL (0xA3)
|
||||
#define RT1711H_REG_BMCIO_RXDZEN (0xAF)
|
||||
|
||||
#define RT1711H_REG_UNLOCK_PW_2 (0xF0)
|
||||
#define RT1711H_REG_UNLOCK_PW_1 (0xF1)
|
||||
#define RT1711H_REG_EFUSE5 (0xF6)
|
||||
|
||||
/*
|
||||
* Device ID
|
||||
*/
|
||||
|
||||
#define RT1711H_DID_A 0x2170
|
||||
#define RT1711H_DID_B 0x2171
|
||||
#define RT1711H_DID_C 0x2172
|
||||
|
||||
#define RT1715_DID_D 0x2173
|
||||
|
||||
/*
|
||||
* RT1711H_REG_PHY_CTRL1 (0x80)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_PHY_CTRL1_SET( \
|
||||
retry_discard, toggle_cnt, bus_idle_cnt, rx_filter) \
|
||||
((retry_discard << 7) | (toggle_cnt << 4) | \
|
||||
(bus_idle_cnt << 2) | (rx_filter & 0x03))
|
||||
|
||||
/*
|
||||
* RT1711H_REG_CLK_CTRL2 (0x87)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_CLK_DIV_600K_EN (1<<7)
|
||||
#define RT1711H_REG_CLK_BCLK2_EN (1<<6)
|
||||
#define RT1711H_REG_CLK_BCLK2_TG_EN (1<<5)
|
||||
#define RT1711H_REG_CLK_DIV_300K_EN (1<<3)
|
||||
#define RT1711H_REG_CLK_CK_300K_EN (1<<2)
|
||||
#define RT1711H_REG_CLK_BCLK_EN (1<<1)
|
||||
#define RT1711H_REG_CLK_BCLK_TH_EN (1<<0)
|
||||
|
||||
/*
|
||||
* RT1711H_REG_CLK_CTRL3 (0x88)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_CLK_OSCMUX_RG_EN (1<<7)
|
||||
#define RT1711H_REG_CLK_CK_24M_EN (1<<6)
|
||||
#define RT1711H_REG_CLK_OSC_RG_EN (1<<5)
|
||||
#define RT1711H_REG_CLK_DIV_2P4M_EN (1<<4)
|
||||
#define RT1711H_REG_CLK_CK_2P4M_EN (1<<3)
|
||||
#define RT1711H_REG_CLK_PCLK_EN (1<<2)
|
||||
#define RT1711H_REG_CLK_PCLK_RG_EN (1<<1)
|
||||
#define RT1711H_REG_CLK_PCLK_TG_EN (1<<0)
|
||||
|
||||
/*
|
||||
* RT1711H_REG_BMC_CTRL (0x90)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_IDLE_EN (1<<6)
|
||||
#define RT1711H_REG_DISCHARGE_EN (1<<5)
|
||||
#define RT1711H_REG_BMCIO_LPRPRD (1<<4)
|
||||
#define RT1711H_REG_BMCIO_LPEN (1<<3)
|
||||
#define RT1711H_REG_BMCIO_BG_EN (1<<2)
|
||||
#define RT1711H_REG_VBUS_DET_EN (1<<1)
|
||||
#define RT1711H_REG_BMCIO_OSC_EN (1<<0)
|
||||
|
||||
/*
|
||||
* RT1711H_REG_RT_STATUS (0x97)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_RA_DETACH (1<<5)
|
||||
#define RT1711H_REG_VBUS_80 (1<<1)
|
||||
|
||||
/*
|
||||
* RT1711H_REG_RT_INT (0x98)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_INT_RA_DETACH (1<<5)
|
||||
#define RT1711H_REG_INT_WATCHDOG (1<<2)
|
||||
#define RT1711H_REG_INT_VBUS_80 (1<<1)
|
||||
#define RT1711H_REG_INT_WAKEUP (1<<0)
|
||||
|
||||
/*
|
||||
* RT1711H_REG_RT_MASK (0x99)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_M_RA_DETACH (1<<5)
|
||||
#define RT1711H_REG_M_WATCHDOG (1<<2)
|
||||
#define RT1711H_REG_M_VBUS_80 (1<<1)
|
||||
#define RT1711H_REG_M_WAKEUP (1<<0)
|
||||
|
||||
/*
|
||||
* RT1711H_REG_IDLE_CTRL (0x9B)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_CK_300K_SEL (1<<7)
|
||||
#define RT1711H_REG_SHIPPING_OFF (1<<5)
|
||||
#define RT1711H_REG_ENEXTMSG (1<<4)
|
||||
#define RT1711H_REG_AUTOIDLE_EN (1<<3)
|
||||
|
||||
/*
|
||||
* RT1711H_REG_EFUSE5 (0xF6)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_M_VBUS_CAL GENMASK(7, 5)
|
||||
#define RT1711H_REG_S_VBUS_CAL 5
|
||||
#define RT1711H_REG_MIN_VBUS_CAL -4
|
||||
|
||||
/* timeout = (tout*2+1) * 6.4ms */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#define RT1711H_REG_IDLE_SET(ck300, ship_dis, auto_idle, tout) \
|
||||
((ck300 << 7) | (ship_dis << 5) | (auto_idle << 3) \
|
||||
| (tout & 0x07) | RT1711H_REG_ENEXTMSG)
|
||||
#else
|
||||
#define RT1711H_REG_IDLE_SET(ck300, ship_dis, auto_idle, tout) \
|
||||
((ck300 << 7) | (ship_dis << 5) | (auto_idle << 3) | (tout & 0x07))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* RT1711H_REG_INTRST_CTRL (0x9C)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_INTRST_EN (1<<7)
|
||||
|
||||
/* timeout = (tout+1) * 0.2sec */
|
||||
#define RT1711H_REG_INTRST_SET(en, tout) \
|
||||
((en << 7) | (tout & 0x03))
|
||||
|
||||
/*
|
||||
* RT1711H_REG_WATCHDOG_CTRL (0x9D)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_WATCHDOG_EN (1<<7)
|
||||
|
||||
/* timeout = (tout+1) * 0.4sec */
|
||||
#define RT1711H_REG_WATCHDOG_CTRL_SET(en, tout) \
|
||||
((en << 7) | (tout & 0x07))
|
||||
|
||||
/*
|
||||
* RT1711H_REG_I2CRST_CTRL (0x9E)
|
||||
*/
|
||||
|
||||
#define RT1711H_REG_I2CRST_EN (1<<7)
|
||||
|
||||
/* timeout = (tout+1) * 12.5ms */
|
||||
#define RT1711H_REG_I2CRST_SET(en, tout) \
|
||||
((en << 7) | (tout & 0x0f))
|
||||
|
||||
#if ENABLE_RT1711_DBG
|
||||
#define RT1711_INFO(format, args...) \
|
||||
pd_dbg_info("%s() line-%d: " format,\
|
||||
__func__, __LINE__, ##args)
|
||||
#else
|
||||
#define RT1711_INFO(foramt, args...)
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef __LINUX_RT1711H_H */
|
||||
201
drivers/usb/typec/mmi_tcpc/inc/std_tcpci_v10.h
Normal file
201
drivers/usb/typec/mmi_tcpc/inc/std_tcpci_v10.h
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef STD_TCPCI_V10_H_
|
||||
#define STD_TCPCI_V10_H_
|
||||
|
||||
/* Standard TCPC V10 RegMap */
|
||||
|
||||
#define TCPC_V10_REG_VID (0x00)
|
||||
#define TCPC_V10_REG_PID (0x02)
|
||||
#define TCPC_V10_REG_DID (0x04)
|
||||
#define TCPC_V10_REG_TYPEC_REV (0x06)
|
||||
#define TCPC_V10_REG_PD_REV (0x08)
|
||||
#define TCPC_V10_REG_PDIF_REV (0x0A)
|
||||
|
||||
#define TCPC_V10_REG_ALERT (0x10)
|
||||
#define TCPC_V10_REG_ALERT_MASK (0x12)
|
||||
#define TCPC_V10_REG_POWER_STATUS_MASK (0x14)
|
||||
#define TCPC_V10_REG_FAULT_STATUS_MASK (0x15)
|
||||
#define TCPC_V10_REG_EXT_STATUS_MASK (0x16)
|
||||
|
||||
#define TCPC_V10_REG_TCPC_CTRL (0x19)
|
||||
#define TCPC_V10_REG_ROLE_CTRL (0x1A)
|
||||
#define TCPC_V10_REG_FAULT_CTRL (0x1B)
|
||||
#define TCPC_V10_REG_POWER_CTRL (0x1C)
|
||||
|
||||
#define TCPC_V10_REG_CC_STATUS (0x1D)
|
||||
#define TCPC_V10_REG_POWER_STATUS (0x1E)
|
||||
#define TCPC_V10_REG_FAULT_STATUS (0x1F)
|
||||
#define TCPC_V10_REG_EXT_STATUS (0x20)
|
||||
|
||||
#define TCPC_V10_REG_COMMAND (0x23)
|
||||
|
||||
#define TCPC_V10_REG_MSG_HDR_INFO (0x2e)
|
||||
|
||||
#define TCPC_V10_REG_RX_DETECT (0x2f)
|
||||
|
||||
#define TCPC_V10_REG_RX_BYTE_CNT (0x30)
|
||||
#define TCPC_V10_REG_RX_BUF_FRAME_TYPE (0x31)
|
||||
#define TCPC_V10_REG_RX_HDR (0x32)
|
||||
#define TCPC_V10_REG_RX_DATA (0x34)
|
||||
|
||||
#define TCPC_V10_REG_TRANSMIT (0x50)
|
||||
#define TCPC_V10_REG_TX_BYTE_CNT (0x51)
|
||||
#define TCPC_V10_REG_TX_HDR (0x52)
|
||||
#define TCPC_V10_REG_TX_DATA (0x54)/* through 0x6f */
|
||||
|
||||
#define TCPC_V10_REG_VBUS_SINK_DISCONNECT_THD (0x72)
|
||||
#define TCPC_V10_REG_VBUS_STOP_DISCHARGE_THD (0x74)
|
||||
#define TCPC_V10_REG_VBUS_VOLTAGE_ALARM_HI (0x76)
|
||||
#define TCPC_V10_REG_VBUS_VOLTAGE_ALARM_LO (0x78)
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_ALERT (0x10)
|
||||
* TCPC_V10_REG_ALERT_MASK (0x12)
|
||||
*/
|
||||
#define TCPC_V10_REG_ALERT_VENDOR_DEFINED (1<<15)
|
||||
#define TCPC_V10_REG_VBUS_SINK_DISCONNECT (1<<11)
|
||||
#define TCPC_V10_REG_RX_OVERFLOW (1<<10)
|
||||
#define TCPC_V10_REG_ALERT_FAULT (1<<9)
|
||||
#define TCPC_V10_REG_ALERT_LO_VOLT (1<<8)
|
||||
#define TCPC_V10_REG_ALERT_HI_VOLT (1<<7)
|
||||
#define TCPC_V10_REG_ALERT_TX_SUCCESS (1<<6)
|
||||
#define TCPC_V10_REG_ALERT_TX_DISCARDED (1<<5)
|
||||
#define TCPC_V10_REG_ALERT_TX_FAILED (1<<4)
|
||||
#define TCPC_V10_REG_ALERT_RX_HARD_RST (1<<3)
|
||||
#define TCPC_V10_REG_ALERT_RX_STATUS (1<<2)
|
||||
#define TCPC_V10_REG_ALERT_POWER_STATUS (1<<1)
|
||||
#define TCPC_V10_REG_ALERT_CC_STATUS (1<<0)
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_POWER_STATUS_MASK (0x14)
|
||||
* TCPC_V10_REG_POWER_STATUS (0x1E)
|
||||
*/
|
||||
|
||||
#define TCPC_V10_REG_POWER_STATUS_TCPC_INITIAL (1<<6)
|
||||
#define TCPC_V10_REG_POWER_STATUS_SRC_HV (1<<5)
|
||||
#define TCPC_V10_REG_POWER_STATUS_SRC_VBUS (1<<4)
|
||||
#define TCPC_V10_REG_POWER_STATUS_VBUS_PRES_DET (1<<3)
|
||||
#define TCPC_V10_REG_POWER_STATUS_VBUS_PRES (1<<2)
|
||||
#define TCPC_V10_REG_POWER_STATUS_VCONN_PRES (1<<1)
|
||||
#define TCPC_V10_REG_POWER_STATUS_SINK_VBUS (1<<0)
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_FAULT_STATUS_MASK (0x15)
|
||||
* TCPC_V10_REG_FAULT_STATUS (0x1F)
|
||||
*/
|
||||
|
||||
/* VCONN_OV should not be here */
|
||||
#define TCPC_V10_REG_FAULT_STATUS_VCONN_OV (1<<7)
|
||||
#define TCPC_V10_REG_FAULT_STATUS_FORCE_OFF_VBUS (1<<6)
|
||||
#define TCPC_V10_REG_FAULT_STATUS_AUTO_DISC_FAIL (1<<5)
|
||||
#define TCPC_V10_REG_FAULT_STATUS_FORCE_DISC_FAIL (1<<4)
|
||||
#define TCPC_V10_REG_FAULT_STATUS_VBUS_OC (1<<3)
|
||||
#define TCPC_V10_REG_FAULT_STATUS_VBUS_OV (1<<2)
|
||||
#define TCPC_V10_REG_FAULT_STATUS_VCONN_OC (1<<1)
|
||||
#define TCPC_V10_REG_FAULT_STATUS_I2C_ERROR (1<<0)
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_ROLE_CTRL (0x1A)
|
||||
*/
|
||||
|
||||
#define TCPC_V10_REG_ROLE_CTRL_DRP (1<<6)
|
||||
|
||||
#define TCPC_V10_REG_ROLE_CTRL_RES_SET(drp, rp, cc1, cc2) \
|
||||
((drp) << 6 | (rp) << 4 | (cc2) << 2 | (cc1))
|
||||
|
||||
#define CC_RD 0x02
|
||||
#define CC_RP 0x01
|
||||
#define CC_OPEN 0x03
|
||||
#define CC_RA 0x00
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_TCPC_CTRL (0x19)
|
||||
*/
|
||||
|
||||
#define TCPC_V10_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT (1<<6)
|
||||
#define TCPC_V10_REG_TCPC_CTRL_EN_WDT (1<<5)
|
||||
#define TCPC_V10_REG_TCPC_CTRL_BIST_TEST_MODE (1<<1)
|
||||
#define TCPC_V10_REG_TCPC_CTRL_PLUG_ORIENT (1<<0)
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_FAULT_CTRL (0x1B)
|
||||
*/
|
||||
|
||||
#define TCPC_V10_REG_FAULT_CTRL_DIS_VCONN_OV (1<<7)
|
||||
#define TCPC_V10_REG_FAULT_CTRL_DIS_SNK_VBUS_OC (1<<2)
|
||||
#define TCPC_V10_REG_FAULT_CTRL_DIS_VCONN_OC (1<<0)
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_POWER_CTRL (0x1C)
|
||||
*/
|
||||
|
||||
#define TCPC_V10_REG_VBUS_MONITOR (1<<6)
|
||||
#define TCPC_V10_REG_BLEED_DISC_EN (1<<3)
|
||||
#define TCPC_V10_REG_FORCE_DISC_EN (1<<2)
|
||||
#define TCPC_V10_REG_POWER_CTRL_VCONN (1<<0)
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_CC_STATUS (0x1D)
|
||||
*/
|
||||
|
||||
#define TCPC_V10_REG_CC_STATUS_DRP_TOGGLING (1<<5)
|
||||
#define TCPC_V10_REG_CC_STATUS_DRP_RESULT(reg) (((reg) & 0x10) >> 4)
|
||||
#define TCPC_V10_REG_CC_STATUS_CC2(reg) (((reg) & 0xc) >> 2)
|
||||
#define TCPC_V10_REG_CC_STATUS_CC1(reg) ((reg) & 0x3)
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_COMMAND (0x23)
|
||||
*/
|
||||
|
||||
enum tcpm_v10_command {
|
||||
TCPM_CMD_WAKE_I2C = 0x11,
|
||||
TCPM_CMD_DISABLE_VBUS_DETECT = 0x22,
|
||||
TCPM_CMD_ENABLE_VBUS_DETECT = 0x33,
|
||||
TCPM_CMD_DISABLE_SINK_VBUS = 0x44,
|
||||
TCPM_CMD_ENABLE_SINK_VBUS = 0x55,
|
||||
TCPM_CMD_DISABLE_SOURCE_VBUS = 0x66,
|
||||
TCPM_CMD_ENABLE_SOURCE_VBUS = 0x77,
|
||||
TCPM_CMD_SOURCE_VBUS_HV = 0x88,
|
||||
TCPM_CMD_LOOK_CONNECTION = 0x99,
|
||||
TCPM_CMD_RX_ONE_MODE = 0xAA,
|
||||
TCPM_CMD_I2C_IDLE = 0xFF,
|
||||
};
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_MSG_HDR_INFO (0x2e)
|
||||
* According to PD30_Rev11 ECR,
|
||||
* The sender of a GoodCRC Message should set :
|
||||
* the Specification Revsiion field to 10b.
|
||||
*/
|
||||
|
||||
#define TCPC_V10_REG_MSG_HDR_INFO_SET(drole, prole) \
|
||||
((drole) << 3 | ((PD_REV20) << 1) | (prole))
|
||||
#define TCPC_V10_REG_MSG_HDR_INFO_DROLE(reg) (((reg) & 0x8) >> 3)
|
||||
#define TCPC_V10_REG_MSG_HDR_INFO_PROLE(reg) ((reg) & 0x1)
|
||||
|
||||
|
||||
/*
|
||||
* TCPC_V10_REG_TRANSMIT (0x50)
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#define TCPC_V10_REG_TRANSMIT_SET(retry, type) \
|
||||
((retry) << 4 | (type))
|
||||
#else
|
||||
#define TCPC_V10_REG_TRANSMIT_SET(retry, type) \
|
||||
(PD_RETRY_COUNT << 4 | (type))
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
#endif /* STD_TCPCI_V10_H_ */
|
||||
201
drivers/usb/typec/mmi_tcpc/inc/tcpci.h
Normal file
201
drivers/usb/typec/mmi_tcpc/inc/tcpci.h
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RT_TCPC_H
|
||||
#define __LINUX_RT_TCPC_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/pm_wakeup.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#ifdef CONFIG_DUAL_ROLE_USB_INTF
|
||||
#include <linux/usb/class-dual-role.h>
|
||||
#endif /* CONFIG_DUAL_ROLE_USB_INTF */
|
||||
|
||||
#include "tcpci_core.h"
|
||||
|
||||
#ifdef CONFIG_PD_DBG_INFO
|
||||
#include "pd_dbg_info.h"
|
||||
#endif /* CONFIG_PD_DBG_INFO */
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
#include "pd_core.h"
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#define PE_STATE_FULL_NAME 0
|
||||
|
||||
#define TCPC_LOW_RP_DUTY (100) /* 10 % */
|
||||
#define TCPC_NORMAL_RP_DUTY (330) /* 33 % */
|
||||
|
||||
/* provide to TCPC interface */
|
||||
extern int tcpci_report_usb_port_changed(struct tcpc_device *tcpc);
|
||||
extern int tcpci_set_wake_lock(
|
||||
struct tcpc_device *tcpc, bool pd_lock, bool user_lock);
|
||||
extern int tcpci_report_power_control(struct tcpc_device *tcpc, bool en);
|
||||
extern int tcpc_typec_init(struct tcpc_device *tcpc, uint8_t typec_role);
|
||||
extern void tcpc_typec_deinit(struct tcpc_device *tcpc);
|
||||
extern int tcpc_dual_role_phy_init(struct tcpc_device *tcpc);
|
||||
|
||||
extern struct tcpc_device *tcpc_device_register(
|
||||
struct device *parent, struct tcpc_desc *tcpc_desc,
|
||||
struct tcpc_ops *ops, void *drv_data);
|
||||
extern void tcpc_device_unregister(
|
||||
struct device *dev, struct tcpc_device *tcpc);
|
||||
|
||||
extern int tcpc_schedule_init_work(struct tcpc_device *tcpc);
|
||||
|
||||
extern void *tcpc_get_dev_data(struct tcpc_device *tcpc);
|
||||
extern void tcpci_lock_typec(struct tcpc_device *tcpc);
|
||||
extern void tcpci_unlock_typec(struct tcpc_device *tcpc);
|
||||
extern int tcpci_alert(struct tcpc_device *tcpc);
|
||||
|
||||
extern void tcpci_vbus_level_init(
|
||||
struct tcpc_device *tcpc, uint16_t power_status);
|
||||
|
||||
static inline int tcpci_check_vbus_valid(struct tcpc_device *tcpc)
|
||||
{
|
||||
return tcpc->vbus_level >= TCPC_VBUS_VALID;
|
||||
}
|
||||
|
||||
int tcpci_check_vbus_valid_from_ic(struct tcpc_device *tcpc);
|
||||
int tcpci_check_vsafe0v(struct tcpc_device *tcpc, bool detect_en);
|
||||
int tcpci_alert_status_clear(struct tcpc_device *tcpc, uint32_t mask);
|
||||
int tcpci_fault_status_clear(struct tcpc_device *tcpc, uint8_t status);
|
||||
int tcpci_set_alert_mask(struct tcpc_device *tcpc, uint32_t mask);
|
||||
int tcpci_get_alert_mask(struct tcpc_device *tcpc, uint32_t *mask);
|
||||
int tcpci_get_alert_status(struct tcpc_device *tcpc, uint32_t *alert);
|
||||
int tcpci_get_fault_status(struct tcpc_device *tcpc, uint8_t *fault);
|
||||
int tcpci_get_power_status(struct tcpc_device *tcpc, uint16_t *pw_status);
|
||||
int tcpci_init(struct tcpc_device *tcpc, bool sw_reset);
|
||||
int tcpci_init_alert_mask(struct tcpc_device *tcpc);
|
||||
|
||||
int tcpci_get_cc(struct tcpc_device *tcpc);
|
||||
int tcpci_set_cc(struct tcpc_device *tcpc, int pull);
|
||||
int tcpci_set_polarity(struct tcpc_device *tcpc, int polarity);
|
||||
int tcpci_set_low_rp_duty(struct tcpc_device *tcpc, bool low_rp);
|
||||
int tcpci_set_vconn(struct tcpc_device *tcpc, int enable);
|
||||
|
||||
int tcpci_is_low_power_mode(struct tcpc_device *tcpc);
|
||||
int tcpci_set_low_power_mode(struct tcpc_device *tcpc, bool en, int pull);
|
||||
int tcpci_idle_poll_ctrl(struct tcpc_device *tcpc, bool en, bool lock);
|
||||
int tcpci_set_watchdog(struct tcpc_device *tcpc, bool en);
|
||||
int tcpci_alert_vendor_defined_handler(struct tcpc_device *tcpc);
|
||||
#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
int tcpci_is_vsafe0v(struct tcpc_device *tcpc);
|
||||
#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
|
||||
|
||||
#ifdef CONFIG_WATER_DETECTION
|
||||
int tcpci_is_water_detected(struct tcpc_device *tcpc);
|
||||
int tcpci_set_water_protection(struct tcpc_device *tcpc, bool en);
|
||||
int tcpci_set_usbid_polling(struct tcpc_device *tcpc, bool en);
|
||||
int tcpci_notify_wd_status(struct tcpc_device *tcpc, bool water_detected);
|
||||
#endif /* CONFIG_WATER_DETECTION */
|
||||
|
||||
#ifdef CONFIG_CABLE_TYPE_DETECTION
|
||||
int tcpci_notify_cable_type(struct tcpc_device *tcpc);
|
||||
#endif /* CONFIG_CABLE_TYPE_DETECTION */
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
|
||||
int tcpci_set_msg_header(struct tcpc_device *tcpc,
|
||||
uint8_t power_role, uint8_t data_role);
|
||||
|
||||
int tcpci_set_rx_enable(struct tcpc_device *tcpc, uint8_t enable);
|
||||
|
||||
int tcpci_protocol_reset(struct tcpc_device *tcpc);
|
||||
|
||||
int tcpci_get_message(struct tcpc_device *tcpc,
|
||||
uint32_t *payload, uint16_t *head, enum tcpm_transmit_type *type);
|
||||
|
||||
int tcpci_transmit(struct tcpc_device *tcpc,
|
||||
enum tcpm_transmit_type type, uint16_t header, const uint32_t *data);
|
||||
|
||||
int tcpci_set_bist_test_mode(struct tcpc_device *tcpc, bool en);
|
||||
|
||||
int tcpci_set_bist_carrier_mode(struct tcpc_device *tcpc, uint8_t pattern);
|
||||
|
||||
#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
|
||||
int tcpci_retransmit(struct tcpc_device *tcpc);
|
||||
#endif /* CONFIG_USB_PD_RETRY_CRC_DISCARD */
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
int tcpci_notify_typec_state(struct tcpc_device *tcpc);
|
||||
|
||||
int tcpci_notify_role_swap(
|
||||
struct tcpc_device *tcpc, uint8_t event, uint8_t role);
|
||||
int tcpci_notify_pd_state(struct tcpc_device *tcpc, uint8_t connect);
|
||||
|
||||
int tcpci_set_intrst(struct tcpc_device *tcpc, bool en);
|
||||
int tcpci_enable_watchdog(struct tcpc_device *tcpc, bool en);
|
||||
|
||||
int tcpci_source_vbus(struct tcpc_device *tcpc, uint8_t type, int mv, int ma);
|
||||
int tcpci_sink_vbus(struct tcpc_device *tcpc, uint8_t type, int mv, int ma);
|
||||
int tcpci_disable_vbus_control(struct tcpc_device *tcpc);
|
||||
int tcpci_notify_attachwait_state(struct tcpc_device *tcpc, bool as_sink);
|
||||
int tcpci_enable_auto_discharge(struct tcpc_device *tcpc, bool en);
|
||||
int tcpci_enable_force_discharge(struct tcpc_device *tcpc, bool en, int mv);
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
|
||||
int tcpci_notify_hard_reset_state(struct tcpc_device *tcpc, uint8_t state);
|
||||
|
||||
int tcpci_enter_mode(struct tcpc_device *tcpc,
|
||||
uint16_t svid, uint8_t ops, uint32_t mode);
|
||||
int tcpci_exit_mode(struct tcpc_device *tcpc, uint16_t svid);
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
int tcpci_report_hpd_state(struct tcpc_device *tcpc, uint32_t dp_status);
|
||||
int tcpci_dp_status_update(struct tcpc_device *tcpc, uint32_t dp_status);
|
||||
int tcpci_dp_configure(struct tcpc_device *tcpc, uint32_t dp_config);
|
||||
int tcpci_dp_attention(struct tcpc_device *tcpc, uint32_t dp_status);
|
||||
|
||||
int tcpci_dp_notify_status_update_done(
|
||||
struct tcpc_device *tcpc, uint32_t dp_status, bool ack);
|
||||
|
||||
int tcpci_dp_notify_config_start(struct tcpc_device *tcpc);
|
||||
int tcpci_dp_notify_config_done(struct tcpc_device *tcpc,
|
||||
uint32_t local_cfg, uint32_t remote_cfg, bool ack);
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
int tcpci_notify_uvdm(struct tcpc_device *tcpc, bool ack);
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
int tcpci_dc_notify_en_unlock(struct tcpc_device *tcpc);
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
int tcpci_notify_alert(struct tcpc_device *tcpc, uint32_t ado);
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
int tcpci_notify_status(struct tcpc_device *tcpc, struct pd_status *sdb);
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_INFO
|
||||
int tcpci_notify_request_bat_info(
|
||||
struct tcpc_device *tcpc, enum pd_battery_reference ref);
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_INFO */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#endif /* #ifndef __LINUX_RT_TCPC_H */
|
||||
436
drivers/usb/typec/mmi_tcpc/inc/tcpci_config.h
Normal file
436
drivers/usb/typec/mmi_tcpc/inc/tcpci_config.h
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_TCPC_CONFIG_H
|
||||
#define __LINUX_TCPC_CONFIG_H
|
||||
|
||||
#if IS_ENABLED(CONFIG_TCPC_CLASS)
|
||||
/* default config */
|
||||
|
||||
/* #define CONFIG_TYPEC_USE_DIS_VBUS_CTRL */
|
||||
#define CONFIG_TYPEC_POWER_CTRL_INIT
|
||||
|
||||
#define CONFIG_TYPEC_CAP_TRY_SOURCE
|
||||
#define CONFIG_TYPEC_CAP_TRY_SINK
|
||||
|
||||
#define CONFIG_TYPEC_CAP_DBGACC
|
||||
#define CONFIG_TYPEC_CAP_DBGACC_SNK
|
||||
#define CONFIG_TYPEC_CAP_CUSTOM_SRC
|
||||
#define CONFIG_TYPEC_CAP_NORP_SRC
|
||||
#define CONFIG_COMPATIBLE_APPLE_TA
|
||||
|
||||
#if 0 /* CONFIG_MTK_GAUGE_VERSION == 30 */
|
||||
#define CONFIG_RECV_BAT_ABSENT_NOTIFY
|
||||
#endif /* CONFIG_MTK_GAUGE_VERSION */
|
||||
|
||||
/* #define CONFIG_TYPEC_ATTACHED_SRC_SAFE0V_DELAY */
|
||||
#define CONFIG_TYPEC_ATTACHED_SRC_SAFE0V_TIMEOUT
|
||||
|
||||
#define CONFIG_TYPEC_CHECK_LEGACY_CABLE
|
||||
#define CONFIG_TYPEC_CHECK_LEGACY_CABLE2
|
||||
#define CONFIG_TYPEC_LEGACY2_AUTO_RECYCLE
|
||||
/* #define CONFIG_TYPEC_CHECK_SRC_UNATTACH_OPEN */
|
||||
|
||||
#define CONFIG_TYPEC_CAP_RA_DETACH
|
||||
#define CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG
|
||||
|
||||
#define CONFIG_TYPEC_CAP_POWER_OFF_CHARGE
|
||||
|
||||
#define CONFIG_TYPEC_CAP_ROLE_SWAP
|
||||
#define CONFIG_TYPEC_CAP_ROLE_SWAP_TOUT 1200
|
||||
|
||||
#define CONFIG_TYPEC_CAP_DISCHARGE_TOUT 50
|
||||
|
||||
#define CONFIG_TYPEC_CAP_AUTO_DISCHARGE
|
||||
/* #define CONFIG_TCPC_AUTO_DISCHARGE_IC */
|
||||
|
||||
#define CONFIG_TYPEC_CAP_FORCE_DISCHARGE
|
||||
/* #define CONFIG_TCPC_FORCE_DISCHARGE_IC */
|
||||
#define CONFIG_TCPC_FORCE_DISCHARGE_EXT
|
||||
|
||||
#define CONFIG_TYPEC_CAP_AUDIO_ACC_SINK_VBUS
|
||||
|
||||
#define CONFIG_TYPEC_CAP_LOW_RP_DUTY
|
||||
#define CONFIG_TYPEC_WAKEUP_ONCE_LOW_DUTY
|
||||
|
||||
/* #define CONFIG_TYPEC_CAP_CUSTOM_HV */
|
||||
|
||||
#define CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SNK
|
||||
/* #define CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SRC */
|
||||
|
||||
#define CONFIG_TCPC_ATTACH_WAKE_LOCK_TOUT 5000
|
||||
|
||||
/* #define CONFIG_TCPC_LOG_WITH_PORT_NAME */
|
||||
|
||||
#ifdef CONFIG_TCPC_LOG_WITH_PORT_NAME
|
||||
#define CONFIG_TCPC_DBG_PRESTR "{%s}TCPC-"
|
||||
#else
|
||||
#define CONFIG_TCPC_DBG_PRESTR "TCPC-"
|
||||
#endif /* CONFIG_TCPC_LOG_WITH_PORT_NAME */
|
||||
|
||||
/*
|
||||
* USB 2.0 & 3.0 current
|
||||
* Unconfigured : 100 / 150 mA
|
||||
* Configured : 500 / 900 mA
|
||||
* http://www.testusb.com/power_issue.htm
|
||||
*/
|
||||
|
||||
#define CONFIG_TYPEC_SNK_CURR_DFT 100
|
||||
#define CONFIG_TYPEC_SRC_CURR_DFT 500
|
||||
#define CONFIG_TYPEC_SNK_CURR_LIMIT 0
|
||||
|
||||
#define CONFIG_TCPC_SOURCE_VCONN
|
||||
#define CONFIG_TCPC_VCONN_SUPPLY_MODE
|
||||
|
||||
#define CONFIG_TCPC_VSAFE0V_DETECT
|
||||
/* #define CONFIG_TCPC_VSAFE0V_DETECT_EXT */
|
||||
#define CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
|
||||
#define CONFIG_TCPC_LPM_CONFIRM
|
||||
#define CONFIG_TCPC_LPM_POSTPONE
|
||||
|
||||
#define CONFIG_TCPC_LOW_POWER_MODE
|
||||
#define CONFIG_TCPC_CLOCK_GATING
|
||||
|
||||
/* #define CONFIG_TCPC_WATCHDOG_EN */
|
||||
/* #define CONFIG_TCPC_INTRST_EN */
|
||||
#define CONFIG_TCPC_I2CRST_EN
|
||||
|
||||
#define CONFIG_TCPC_SHUTDOWN_CC_DETACH
|
||||
#define CONFIG_TCPC_SHUTDOWN_VBUS_DISABLE
|
||||
|
||||
#define CONFIG_TCPC_NOTIFIER_LATE_SYNC
|
||||
|
||||
#define CONFIG_TCPC_NOTIFICATION_NON_BLOCKING
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
|
||||
/* Experimental for CodeSize */
|
||||
#define CONFIG_USB_PD_DR_SWAP
|
||||
#define CONFIG_USB_PD_PR_SWAP
|
||||
#define CONFIG_USB_PD_VCONN_SWAP
|
||||
#define CONFIG_USB_PD_PE_SINK
|
||||
#define CONFIG_USB_PD_PE_SOURCE
|
||||
/* #define CONFIG_USB_PD_DISABLE_PE */
|
||||
|
||||
#define CONFIG_USB_PD_TCPM_CB_RETRY 3
|
||||
#define CONFIG_USB_PD_TCPM_CB_2ND
|
||||
#define CONFIG_USB_PD_BLOCK_TCPM
|
||||
|
||||
/* #define CONFIG_USB_PD_RICHTEK_UVDM */
|
||||
|
||||
/**********************************************************
|
||||
* Mode Operation
|
||||
**********************************************************/
|
||||
|
||||
#define CONFIG_USB_PD_MODE_OPERATION
|
||||
|
||||
#ifdef CONFIG_USB_PD_MODE_OPERATION
|
||||
|
||||
#define CONFIG_USB_PD_ATTEMP_ENTER_MODE
|
||||
|
||||
#define CONFIG_USB_PD_ALT_MODE
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
#define CONFIG_USB_PD_ALT_MODE_DFP
|
||||
#define CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
/* #define CONFIG_USB_PD_DP_CHECK_CABLE */
|
||||
/* #define CONFIG_USB_PD_RTDC_CHECK_CABLE */
|
||||
|
||||
#endif /* CONFIG_USB_PD_MODE_OPERATION */
|
||||
|
||||
/**********************************************************
|
||||
* PD revision 3.0 feature
|
||||
**********************************************************/
|
||||
|
||||
#define CONFIG_USB_PD_REV30
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
#define CONFIG_USB_PD_REV30_SYNC_SPEC_REV
|
||||
#define CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
|
||||
/*
|
||||
* If DUT send a PD command immediately after Policy Engine is ready,
|
||||
* it may interrupt the compliance test process and getting a failed result.
|
||||
* even you make sure the CC state is SinkTxNG or SinkTxOK.
|
||||
*
|
||||
* SRC_FLOW_DELAY_STARTUP: For Ellisys
|
||||
* SNK_FLOW_DELAY_STARTUP: For MQP
|
||||
*/
|
||||
|
||||
#define CONFIG_USB_PD_REV30_SRC_FLOW_DELAY_STARTUP
|
||||
#define CONFIG_USB_PD_REV30_SNK_FLOW_DELAY_STARTUP
|
||||
|
||||
#define CONFIG_USB_PD_REV30_DISCOVER_CABLE_WITH_VCONN
|
||||
|
||||
/* PD30 Common Feature */
|
||||
|
||||
#define CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
|
||||
#define CONFIG_USB_PD_REV30_BAT_CAP_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_BAT_CAP_REMOTE
|
||||
|
||||
#define CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE
|
||||
|
||||
#define CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE
|
||||
|
||||
#define CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE
|
||||
|
||||
#define CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE
|
||||
|
||||
#define CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
|
||||
#define CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
|
||||
/* #define CONFIG_USB_PD_REV30_CHUNKING_BY_PE */
|
||||
|
||||
#define CONFIG_USB_PD_REV30_PPS_SINK
|
||||
/* #define CONFIG_USB_PD_REV30_PPS_SOURCE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_STATUS_LOCAL_TEMP
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_BAT_INFO
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL
|
||||
#undef CONFIG_USB_PD_REV30_BAT_INFO
|
||||
#define CONFIG_USB_PD_REV30_BAT_INFO
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL
|
||||
#define CONFIG_USB_PD_REV30_COUNTRY_AUTHORITY
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL
|
||||
#undef CONFIG_USB_PD_REV30_COUNTRY_AUTHORITY
|
||||
#define CONFIG_USB_PD_REV30_COUNTRY_AUTHORITY
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
#define CONFIG_USB_PD_DPM_AUTO_SEND_ALERT
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
#define CONFIG_USB_PD_DPM_AUTO_GET_STATUS
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
|
||||
#define CONFIG_MTK_HANDLE_PPS_TIMEOUT
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
/**********************************************************
|
||||
* PD direct charge support
|
||||
**********************************************************/
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
#define CONFIG_USB_PD_DIRECT_CHARGE
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
#undef CONFIG_USB_PD_DIRECT_CHARGE
|
||||
#define CONFIG_USB_PD_DIRECT_CHARGE
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
#define CONFIG_USB_PD_KEEP_PARTNER_ID
|
||||
#define CONFIG_USB_PD_KEEP_SVIDS
|
||||
#define CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
|
||||
#define CONFIG_USB_PD_DFP_READY_DISCOVER_ID
|
||||
#define CONFIG_USB_PD_RESET_CABLE
|
||||
|
||||
#define CONFIG_USB_PD_RANDOM_FLOW_DELAY
|
||||
|
||||
#define CONFIG_USB_PD_DFP_FLOW_DELAY
|
||||
#define CONFIG_USB_PD_DFP_FLOW_DELAY_STARTUP
|
||||
#define CONFIG_USB_PD_DFP_FLOW_DELAY_DRSWAP
|
||||
#define CONFIG_USB_PD_DFP_FLOW_DELAY_RESET
|
||||
|
||||
/* Only in startup */
|
||||
#define CONFIG_USB_PD_UFP_FLOW_DELAY
|
||||
#define CONFIG_USB_PD_VCONN_STABLE_DELAY
|
||||
#define CONFIG_USB_PD_VCONN_SAFE5V_ONLY
|
||||
|
||||
#define CONFIG_USB_PD_ATTEMP_DISCOVER_ID
|
||||
#define CONFIG_USB_PD_ATTEMP_DISCOVER_SVID
|
||||
|
||||
#define CONFIG_USB_PD_DISCOVER_CABLE_REQUEST_VCONN
|
||||
#define CONFIG_USB_PD_DISCOVER_CABLE_RETURN_VCONN
|
||||
|
||||
#define CONFIG_USB_PD_PR_SWAP_ERROR_RECOVERY
|
||||
|
||||
#define CONFIG_USB_PD_CUSTOM_VDM
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
#define CONFIG_USB_PD_SVDM
|
||||
#define CONFIG_USB_PD_UVDM
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_DBGACC_SNK
|
||||
/* #define CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
#endif /* CONFIG_TYPEC_CAP_DBGACC_SNK */
|
||||
|
||||
/* S/W patch for ESD issue: repeat HReset Alert */
|
||||
/* #define CONFIG_USB_PD_RECV_HRESET_COUNTER */
|
||||
|
||||
/* S/W patch for NoGoodCRC if SNK_DFT */
|
||||
#define CONFIG_USB_PD_SNK_DFT_NO_GOOD_CRC
|
||||
|
||||
/* S/W patch for NoGoodCRC after PR_SWAP (repeat PS_RDY) */
|
||||
#define CONFIG_USB_PD_IGNORE_PS_RDY_AFTER_PR_SWAP
|
||||
|
||||
/* S/W patch for delayed ps_change related to PS_RDY during PR_SWAP */
|
||||
#define CONFIG_USB_PD_VBUS_DETECTION_DURING_PR_SWAP
|
||||
|
||||
/*
|
||||
* S/W patch for INT handler was stuck by other task (system busy)
|
||||
*
|
||||
* If the communication fails due to a timeout,
|
||||
* check the rx buffer is empty or not.
|
||||
*
|
||||
* If the rx buffer isn't empty, postpone timer.
|
||||
*/
|
||||
|
||||
#define CONFIG_USB_PD_CHECK_RX_PENDING_IF_SRTOUT
|
||||
#define CONFIG_USB_PD_ONLY_PRINT_SYSTEM_BUSY
|
||||
|
||||
/*
|
||||
* S/W patch for
|
||||
* If the CC pin is shorted to ground and our receive ability is better,
|
||||
* then we may receive message however always send failed.
|
||||
*
|
||||
* For the source role, it becomes an infinite hard reset loop.
|
||||
* For the sink role, it becomes an infinite error recovery loop.
|
||||
*
|
||||
* RENEGOTIATION_COUNTER:
|
||||
* Auto error recovery
|
||||
* if retried hard reset many times still negotiation failed.
|
||||
*
|
||||
* ERROR_RECOVERY_ONCE:
|
||||
* If we have tried an error recovery,
|
||||
* using pure typec mode during next time we reconnect.
|
||||
*
|
||||
*/
|
||||
|
||||
#define CONFIG_USB_PD_RENEGOTIATION_COUNTER
|
||||
#define CONFIG_USB_PD_ERROR_RECOVERY_ONCE
|
||||
|
||||
#define CONFIG_USB_PD_IGNORE_HRESET_COMPLETE_TIMER
|
||||
#define CONFIG_USB_PD_DROP_REPEAT_PING
|
||||
#define CONFIG_USB_PD_CHECK_DATA_ROLE
|
||||
#define CONFIG_USB_PD_RETRY_CRC_DISCARD
|
||||
#define CONFIG_USB_PD_PARTNER_CTRL_MSG_FIRST
|
||||
|
||||
#define CONFIG_USB_PD_SNK_HRESET_KEEP_DRAW
|
||||
/* #define CONFIG_USB_PD_SNK_IGNORE_HRESET_IF_TYPEC_ONLY */
|
||||
#define CONFIG_USB_PD_SNK_STANDBY_POWER
|
||||
#define CONFIG_USB_PD_SNK_GOTOMIN
|
||||
|
||||
/* #define CONFIG_USB_PD_SRC_HIGHCAP_POWER */
|
||||
#define CONFIG_USB_PD_SRC_TRY_PR_SWAP_IF_BAD_PW
|
||||
|
||||
#define CONFIG_USB_PD_TRANSMIT_BIST2
|
||||
#define CONFIG_USB_PD_POSTPONE_VDM
|
||||
#define CONFIG_USB_PD_POSTPONE_RETRY_VDM
|
||||
#define CONFIG_USB_PD_POSTPONE_FIRST_VDM
|
||||
#define CONFIG_USB_PD_POSTPONE_OTHER_VDM
|
||||
/* #define CONFIG_USB_PD_STOP_SEND_VDM_IF_RX_BUSY */
|
||||
#define CONFIG_USB_PD_STOP_REPLY_VDM_IF_RX_BUSY
|
||||
|
||||
/* #define CONFIG_USB_PD_SAFE0V_DELAY */
|
||||
/* #define CONFIG_USB_PD_SAFE0V_TIMEOUT */
|
||||
|
||||
#ifndef CONFIG_USB_PD_DPM_SVDM_RETRY
|
||||
#define CONFIG_USB_PD_DPM_SVDM_RETRY 2
|
||||
#endif /* CONFIG_USB_PD_DPM_SVDM_RETRY */
|
||||
|
||||
#ifndef CONFIG_USB_PD_DFP_FLOW_RETRY_MAX
|
||||
#define CONFIG_USB_PD_DFP_FLOW_RETRY_MAX 2
|
||||
#endif /* CONFIG_USB_PD_DFP_FLOW_RETRY_MAX */
|
||||
|
||||
#ifndef CONFIG_USB_PD_VBUS_STABLE_TOUT
|
||||
#define CONFIG_USB_PD_VBUS_STABLE_TOUT 125
|
||||
#endif /* CONFIG_USB_PD_VBUS_STABLE_TOUT */
|
||||
|
||||
#ifndef CONFIG_USB_PD_VBUS_PRESENT_TOUT
|
||||
#define CONFIG_USB_PD_VBUS_PRESENT_TOUT 20
|
||||
#endif /* CONFIG_USB_PD_VBUS_PRESENT_TOUT */
|
||||
|
||||
#ifndef CONFIG_USB_PD_CUSTOM_VDM_TOUT
|
||||
#define CONFIG_USB_PD_CUSTOM_VDM_TOUT 500
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM_TOUT */
|
||||
|
||||
#ifndef CONFIG_USB_PD_VCONN_READY_TOUT
|
||||
#define CONFIG_USB_PD_VCONN_READY_TOUT 5
|
||||
#endif /* CONFIG_USB_PD_VCONN_READY_TOUT */
|
||||
|
||||
#ifndef CONFIG_USB_PD_DFP_FLOW_DLY
|
||||
#define CONFIG_USB_PD_DFP_FLOW_DLY 30
|
||||
#endif /* CONFIG_USB_PD_DFP_FLOW_DLY */
|
||||
|
||||
#ifndef CONFIG_USB_PD_UFP_FLOW_DLY
|
||||
#define CONFIG_USB_PD_UFP_FLOW_DLY 300
|
||||
#endif /* CONFIG_USB_PD_UFP_FLOW_DLY */
|
||||
|
||||
#ifndef CONFIG_USB_PD_PPS_REQUEST_INTERVAL
|
||||
#define CONFIG_USB_PD_PPS_REQUEST_INTERVAL 7000
|
||||
#endif /* CONFIG_USB_PD_PPS_REQUEST_INTERVAL */
|
||||
|
||||
#undef CONFIG_USB_PD_WAIT_BC12
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
/* debug config */
|
||||
#define CONFIG_USB_PD_DBG_ALERT_STATUS
|
||||
/* #define CONFIG_USB_PD_DBG_SKIP_ALERT_HANDLER */
|
||||
#define CONFIG_USB_PD_DBG_DP_DFP_D_AUTO_UPDATE
|
||||
|
||||
/**********************************************************
|
||||
* TypeC Shield Protection
|
||||
**********************************************************/
|
||||
|
||||
#ifdef CONFIG_MTK_TYPEC_WATER_DETECT
|
||||
#define CONFIG_WATER_DETECTION
|
||||
#endif /* CONFIG_MTK_TYPEC_WATER_DETECT */
|
||||
|
||||
#ifdef CONFIG_WATER_DETECTION
|
||||
#define CONFIG_WD_SBU_POLLING
|
||||
/* #define CONFIG_WATER_CALIBRATION */
|
||||
#define CONFIG_WD_SBU_CALIB_INIT 1800 /* mV */
|
||||
#define CONFIG_WD_SBU_PL_BOUND 200 /* mV */
|
||||
#define CONFIG_WD_SBU_PH_AUDDEV 200 /* mV */
|
||||
#define CONFIG_WD_SBU_PH_LBOUND 1180 /* mV */
|
||||
#define CONFIG_WD_SBU_PH_LBOUND1_C2C 2850 /* mV */
|
||||
#define CONFIG_WD_SBU_PH_UBOUND1_C2C 3150 /* mV */
|
||||
#define CONFIG_WD_SBU_PH_UBOUND2_C2C 3800 /* mV */
|
||||
#define CONFIG_WD_SBU_AUD_UBOUND 1600 /* mV */
|
||||
#define CONFIG_WD_PROTECT_RETRY_COUNT 3
|
||||
#endif /* CONFIG_WATER_DETECTION */
|
||||
|
||||
#ifdef CONFIG_WD_SBU_POLLING
|
||||
#define CONFIG_WD_POLLING_ONLY
|
||||
#endif /* CONFIG_WD_SBU_POLLING */
|
||||
|
||||
#define CONFIG_CABLE_TYPE_DETECTION
|
||||
|
||||
#endif /* CONFIG_TCPC_CLASS */
|
||||
#endif /* __LINUX_TCPC_CONFIG_H */
|
||||
694
drivers/usb/typec/mmi_tcpc/inc/tcpci_core.h
Normal file
694
drivers/usb/typec/mmi_tcpc/inc/tcpci_core.h
Normal file
|
|
@ -0,0 +1,694 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RT_TCPCI_CORE_H
|
||||
#define __LINUX_RT_TCPCI_CORE_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/alarmtimer.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/pm_wakeup.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "tcpm.h"
|
||||
#include "tcpci_timer.h"
|
||||
#include "tcpci_config.h"
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
#include "pd_core.h"
|
||||
#ifdef CONFIG_USB_PD_WAIT_BC12
|
||||
#include <linux/power_supply.h>
|
||||
#endif /* CONFIG_USB_PD_WAIT_BC12 */
|
||||
#endif
|
||||
|
||||
/* The switch of log message */
|
||||
#define TYPEC_INFO_ENABLE 1
|
||||
#define TYPEC_INFO2_ENABLE 1
|
||||
#define PE_EVENT_DBG_ENABLE 1
|
||||
#define PE_STATE_INFO_ENABLE 1
|
||||
#define TCPC_INFO_ENABLE 1
|
||||
#define TCPC_TIMER_DBG_EN 0
|
||||
#define TCPC_TIMER_INFO_EN 0
|
||||
#define PE_INFO_ENABLE 1
|
||||
#define TCPC_DBG_ENABLE 0
|
||||
#define TCPC_DBG2_ENABLE 0
|
||||
#define DPM_INFO_ENABLE 1
|
||||
#define DPM_INFO2_ENABLE 1
|
||||
#define DPM_DBG_ENABLE 0
|
||||
#define PD_ERR_ENABLE 1
|
||||
#define PE_DBG_ENABLE 0
|
||||
#define TYPEC_DBG_ENABLE 0
|
||||
|
||||
|
||||
#define DP_INFO_ENABLE 1
|
||||
#define DP_DBG_ENABLE 1
|
||||
|
||||
#define UVDM_INFO_ENABLE 1
|
||||
#define TCPM_DBG_ENABLE 1
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
#define DC_INFO_ENABLE 1
|
||||
#define DC_DBG_ENABLE 1
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
|
||||
#define TCPC_ENABLE_ANYMSG \
|
||||
((TCPC_DBG_ENABLE)|(TCPC_DBG2_ENABLE)|\
|
||||
(DPM_DBG_ENABLE)|\
|
||||
(PD_ERR_ENABLE)|(PE_INFO_ENABLE)|(TCPC_TIMER_INFO_EN)|\
|
||||
(PE_DBG_ENABLE)|(PE_EVENT_DBG_ENABLE)|\
|
||||
(PE_STATE_INFO_ENABLE)|(TCPC_INFO_ENABLE)|\
|
||||
(TCPC_TIMER_DBG_EN)|(TYPEC_DBG_ENABLE)|\
|
||||
(TYPEC_INFO_ENABLE)|\
|
||||
(DP_INFO_ENABLE)|(DP_DBG_ENABLE)|\
|
||||
(UVDM_INFO_ENABLE)|(TCPM_DBG_ENABLE))
|
||||
|
||||
/* Disable VDM DBG Msg */
|
||||
#define PE_STATE_INFO_VDM_DIS 0
|
||||
#define PE_EVT_INFO_VDM_DIS 0
|
||||
#define PE_DBG_RESET_VDM_DIS 1
|
||||
|
||||
#define PD_BUG_ON(x) WARN_ON(x)
|
||||
|
||||
extern struct class *tcpc_class;
|
||||
struct tcpc_device;
|
||||
|
||||
struct tcpc_desc {
|
||||
uint8_t role_def;
|
||||
uint8_t rp_lvl;
|
||||
uint8_t vconn_supply;
|
||||
int notifier_supply_num;
|
||||
char *name;
|
||||
};
|
||||
|
||||
int tcpc_device_irq_enable(struct tcpc_device *tcpc);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SNK
|
||||
#define CONFIG_TYPEC_NOTIFY_ATTACHWAIT
|
||||
#endif /* CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SNK */
|
||||
|
||||
#ifdef CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SRC
|
||||
#undef CONFIG_TYPEC_NOTIFY_ATTACHWAIT
|
||||
#define CONFIG_TYPEC_NOTIFY_ATTACHWAIT
|
||||
#endif /* CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SNK */
|
||||
|
||||
|
||||
#ifdef CONFIG_TCPC_FORCE_DISCHARGE_EXT
|
||||
#define CONFIG_TCPC_EXT_DISCHARGE
|
||||
#endif /* CONFIG_TCPC_FORCE_DISCHARGE_EXT */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/* TCPC Power Register Define */
|
||||
#define TCPC_REG_POWER_STATUS_EXT_VSAFE0V (1<<15) /* extend */
|
||||
#define TCPC_REG_POWER_STATUS_VBUS_PRES (1<<2)
|
||||
|
||||
/* TCPC Alert Register Define */
|
||||
#define TCPC_REG_ALERT_EXT_RA_DETACH (1<<(16+5))
|
||||
#define TCPC_REG_ALERT_EXT_WATCHDOG (1<<(16+2))
|
||||
#define TCPC_REG_ALERT_EXT_VBUS_80 (1<<(16+1))
|
||||
#define TCPC_REG_ALERT_EXT_WAKEUP (1<<(16+0))
|
||||
|
||||
#define TCPC_REG_ALERT_VBUS_DISCNCT (1<<11)
|
||||
#define TCPC_REG_ALERT_RX_BUF_OVF (1<<10)
|
||||
#define TCPC_REG_ALERT_FAULT (1<<9)
|
||||
#define TCPC_REG_ALERT_V_ALARM_LO (1<<8)
|
||||
#define TCPC_REG_ALERT_V_ALARM_HI (1<<7)
|
||||
#define TCPC_REG_ALERT_TX_SUCCESS (1<<6)
|
||||
#define TCPC_REG_ALERT_TX_DISCARDED (1<<5)
|
||||
#define TCPC_REG_ALERT_TX_FAILED (1<<4)
|
||||
#define TCPC_REG_ALERT_RX_HARD_RST (1<<3)
|
||||
#define TCPC_REG_ALERT_RX_STATUS (1<<2)
|
||||
#define TCPC_REG_ALERT_POWER_STATUS (1<<1)
|
||||
#define TCPC_REG_ALERT_CC_STATUS (1<<0)
|
||||
|
||||
#define TCPC_REG_ALERT_RX_MASK \
|
||||
(TCPC_REG_ALERT_RX_STATUS | TCPC_REG_ALERT_RX_BUF_OVF)
|
||||
|
||||
#define TCPC_REG_ALERT_RX_ALL_MASK \
|
||||
(TCPC_REG_ALERT_RX_MASK | TCPC_REG_ALERT_RX_HARD_RST)
|
||||
|
||||
#define TCPC_REG_ALERT_HRESET_SUCCESS \
|
||||
(TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED)
|
||||
|
||||
#define TCPC_REG_ALERT_TX_MASK (TCPC_REG_ALERT_TX_SUCCESS | \
|
||||
TCPC_REG_ALERT_TX_FAILED | TCPC_REG_ALERT_TX_DISCARDED)
|
||||
|
||||
#define TCPC_REG_ALERT_TXRX_MASK \
|
||||
(TCPC_REG_ALERT_TX_MASK | TCPC_REG_ALERT_RX_MASK)
|
||||
|
||||
/* TCPC Behavior Flags */
|
||||
#define TCPC_FLAGS_RETRY_CRC_DISCARD (1<<0)
|
||||
#define TCPC_FLAGS_WAIT_HRESET_COMPLETE (1<<1) /* Always true */
|
||||
#define TCPC_FLAGS_CHECK_CC_STABLE (1<<2)
|
||||
#define TCPC_FLAGS_LPM_WAKEUP_WATCHDOG (1<<3)
|
||||
#define TCPC_FLAGS_CHECK_RA_DETACHE (1<<4)
|
||||
#define TCPC_FLAGS_PREFER_LEGACY2 (1<<5)
|
||||
#define TCPC_FLAGS_DISABLE_LEGACY (1<<6)
|
||||
|
||||
#define TCPC_FLAGS_PD_REV30 (1<<7)
|
||||
|
||||
#define TCPC_FLAGS_WATCHDOG_EN (1<<8)
|
||||
#define TCPC_FLAGS_WATER_DETECTION (1<<9)
|
||||
#define TCPC_FLAGS_CABLE_TYPE_DETECTION (1<<10)
|
||||
#define TCPC_FLAGS_VCONN_SAFE5V_ONLY (1<<11)
|
||||
#define TCPC_FLAGS_ALERT_V10 (1<<12)
|
||||
|
||||
enum tcpc_cc_pull {
|
||||
TYPEC_CC_RA = 0,
|
||||
TYPEC_CC_RP = 1,
|
||||
TYPEC_CC_RD = 2,
|
||||
TYPEC_CC_OPEN = 3,
|
||||
TYPEC_CC_DRP = 4, /* from Rd */
|
||||
|
||||
TYPEC_CC_RP_DFT = 1, /* 0x00 + 1 */
|
||||
TYPEC_CC_RP_1_5 = 9, /* 0x08 + 1*/
|
||||
TYPEC_CC_RP_3_0 = 17, /* 0x10 + 1 */
|
||||
|
||||
TYPEC_CC_DRP_DFT = 4, /* 0x00 + 4 */
|
||||
TYPEC_CC_DRP_1_5 = 12, /* 0x08 + 4 */
|
||||
TYPEC_CC_DRP_3_0 = 20, /* 0x10 + 4 */
|
||||
};
|
||||
|
||||
#define TYPEC_CC_PULL_GET_RES(pull) (pull & 0x07)
|
||||
#define TYPEC_CC_PULL_GET_RP_LVL(pull) ((pull & 0x18) >> 3)
|
||||
|
||||
enum tcpm_rx_cap_type {
|
||||
TCPC_RX_CAP_SOP = 1 << 0,
|
||||
TCPC_RX_CAP_SOP_PRIME = 1 << 1,
|
||||
TCPC_RX_CAP_SOP_PRIME_PRIME = 1 << 2,
|
||||
TCPC_RX_CAP_SOP_DEBUG_PRIME = 1 << 3,
|
||||
TCPC_RX_CAP_SOP_DEBUG_PRIME_PRIME = 1 << 4,
|
||||
TCPC_RX_CAP_HARD_RESET = 1 << 5,
|
||||
TCPC_RX_CAP_CABLE_RESET = 1 << 6,
|
||||
};
|
||||
|
||||
struct tcpc_ops {
|
||||
int (*init)(struct tcpc_device *tcpc, bool sw_reset);
|
||||
int (*init_alert_mask)(struct tcpc_device *tcpc);
|
||||
int (*alert_status_clear)(struct tcpc_device *tcpc, uint32_t mask);
|
||||
int (*fault_status_clear)(struct tcpc_device *tcpc, uint8_t status);
|
||||
int (*set_alert_mask)(struct tcpc_device *tcpc, uint32_t mask);
|
||||
int (*get_alert_mask)(struct tcpc_device *tcpc, uint32_t *mask);
|
||||
int (*get_alert_status)(struct tcpc_device *tcpc, uint32_t *alert);
|
||||
int (*get_power_status)(struct tcpc_device *tcpc, uint16_t *pwr_status);
|
||||
int (*get_fault_status)(struct tcpc_device *tcpc, uint8_t *status);
|
||||
int (*get_cc)(struct tcpc_device *tcpc, int *cc1, int *cc2);
|
||||
int (*set_cc)(struct tcpc_device *tcpc, int pull);
|
||||
int (*set_polarity)(struct tcpc_device *tcpc, int polarity);
|
||||
int (*set_low_rp_duty)(struct tcpc_device *tcpc, bool low_rp);
|
||||
int (*set_vconn)(struct tcpc_device *tcpc, int enable);
|
||||
int (*deinit)(struct tcpc_device *tcpc);
|
||||
int (*alert_vendor_defined_handler)(struct tcpc_device *tcpc);
|
||||
|
||||
#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
int (*is_vsafe0v)(struct tcpc_device *tcpc);
|
||||
#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
|
||||
|
||||
#ifdef CONFIG_WATER_DETECTION
|
||||
int (*is_water_detected)(struct tcpc_device *tcpc);
|
||||
int (*set_water_protection)(struct tcpc_device *tcpc, bool en);
|
||||
int (*set_usbid_polling)(struct tcpc_device *tcpc, bool en);
|
||||
#endif /* CONFIG_WATER_DETECTION */
|
||||
|
||||
#ifdef CONFIG_TCPC_LOW_POWER_MODE
|
||||
int (*is_low_power_mode)(struct tcpc_device *tcpc);
|
||||
int (*set_low_power_mode)(struct tcpc_device *tcpc, bool en, int pull);
|
||||
#endif /* CONFIG_TCPC_LOW_POWER_MODE */
|
||||
|
||||
int (*set_watchdog)(struct tcpc_device *tcpc, bool en);
|
||||
|
||||
#ifdef CONFIG_TCPC_INTRST_EN
|
||||
int (*set_intrst)(struct tcpc_device *tcpc, bool en);
|
||||
#endif /* CONFIG_TCPC_INTRST_EN */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_AUTO_DISCHARGE
|
||||
#ifdef CONFIG_TCPC_AUTO_DISCHARGE_IC
|
||||
int (*set_auto_discharge)(struct tcpc_device *tcpc, bool en);
|
||||
#endif /* CONFIG_TCPC_AUTO_DISCHARGE_IC */
|
||||
#endif /* CONFIG_TYPEC_CAP_AUTO_DISCHARGE */
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
int (*set_msg_header)(struct tcpc_device *tcpc,
|
||||
uint8_t power_role, uint8_t data_role);
|
||||
int (*set_rx_enable)(struct tcpc_device *tcpc, uint8_t enable);
|
||||
int (*get_message)(struct tcpc_device *tcpc, uint32_t *payload,
|
||||
uint16_t *head, enum tcpm_transmit_type *type);
|
||||
int (*protocol_reset)(struct tcpc_device *tcpc);
|
||||
int (*transmit)(struct tcpc_device *tcpc,
|
||||
enum tcpm_transmit_type type,
|
||||
uint16_t header, const uint32_t *data);
|
||||
int (*set_bist_test_mode)(struct tcpc_device *tcpc, bool en);
|
||||
int (*set_bist_carrier_mode)(struct tcpc_device *tcpc, uint8_t pattern);
|
||||
|
||||
#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
|
||||
int (*retransmit)(struct tcpc_device *tcpc);
|
||||
#endif /* CONFIG_USB_PD_RETRY_CRC_DISCARD */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_FORCE_DISCHARGE
|
||||
#ifdef CONFIG_TCPC_FORCE_DISCHARGE_IC
|
||||
int (*set_force_discharge)(struct tcpc_device *tcpc, bool en, int mv);
|
||||
#endif /* CONFIG_TCPC_FORCE_DISCHARGE_IC */
|
||||
#endif /* CONFIG_TYPEC_CAP_FORCE_DISCHARGE */
|
||||
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
};
|
||||
|
||||
#define TCPC_VBUS_SOURCE_0V (0)
|
||||
#define TCPC_VBUS_SOURCE_5V (5000)
|
||||
|
||||
#define TCPC_VBUS_SINK_0V (0)
|
||||
#define TCPC_VBUS_SINK_5V (5000)
|
||||
|
||||
#define TCPC_LOW_POWER_MODE_RETRY 5
|
||||
|
||||
/*
|
||||
* Confirm DUT is connected to legacy cable or not
|
||||
* after suupect_counter > this threshold (0 = always check)
|
||||
*/
|
||||
|
||||
#define TCPC_LEGACY_CABLE_SUSPECT_THD 1
|
||||
|
||||
/*
|
||||
* Try another s/w workaround after retry_counter more than this value
|
||||
* Try which soltuion first is determined by tcpc_flags
|
||||
*/
|
||||
|
||||
#define TCPC_LEGACY_CABLE_RETRY_SOLUTION 2
|
||||
|
||||
struct tcpc_managed_res;
|
||||
|
||||
/*
|
||||
* tcpc device
|
||||
*/
|
||||
|
||||
struct tcpc_device {
|
||||
struct i2c_client *client;
|
||||
struct tcpc_ops *ops;
|
||||
void *drv_data;
|
||||
struct tcpc_desc desc;
|
||||
struct device dev;
|
||||
bool wake_lock_user;
|
||||
uint8_t wake_lock_pd;
|
||||
struct wakeup_source *attach_wake_lock;
|
||||
struct wakeup_source *detach_wake_lock;
|
||||
|
||||
/* For tcpc timer & event */
|
||||
uint32_t timer_handle_index;
|
||||
struct hrtimer tcpc_timer[PD_TIMER_NR];
|
||||
|
||||
struct alarm wake_up_timer;
|
||||
struct delayed_work wake_up_work;
|
||||
struct wakeup_source *wakeup_wake_lock;
|
||||
|
||||
ktime_t last_expire[PD_TIMER_NR];
|
||||
struct mutex access_lock;
|
||||
struct mutex typec_lock;
|
||||
struct mutex timer_lock;
|
||||
struct semaphore timer_enable_mask_lock;
|
||||
spinlock_t timer_tick_lock;
|
||||
atomic_t pending_event;
|
||||
uint64_t timer_tick;
|
||||
uint64_t timer_enable_mask;
|
||||
wait_queue_head_t event_wait_que;
|
||||
wait_queue_head_t timer_wait_que;
|
||||
struct task_struct *event_task;
|
||||
struct task_struct *timer_task;
|
||||
|
||||
struct delayed_work init_work;
|
||||
struct delayed_work event_init_work;
|
||||
struct workqueue_struct *evt_wq;
|
||||
struct srcu_notifier_head evt_nh[TCP_NOTIFY_IDX_NR];
|
||||
struct tcpc_managed_res *mr_head;
|
||||
struct mutex mr_lock;
|
||||
|
||||
/* For TCPC TypeC */
|
||||
uint8_t typec_state;
|
||||
uint8_t typec_role;
|
||||
uint8_t typec_role_new;
|
||||
uint8_t typec_attach_old;
|
||||
uint8_t typec_attach_new;
|
||||
uint8_t typec_local_cc;
|
||||
uint8_t typec_local_rp_level;
|
||||
uint8_t typec_remote_cc[2];
|
||||
uint8_t typec_remote_rp_level;
|
||||
uint8_t typec_wait_ps_change;
|
||||
bool typec_polarity;
|
||||
bool typec_drp_try_timeout;
|
||||
bool typec_lpm;
|
||||
bool typec_cable_only;
|
||||
bool typec_power_ctrl;
|
||||
bool typec_watchdog;
|
||||
bool typec_reach_vsafe0v;
|
||||
bool typec_is_attached_src;
|
||||
|
||||
int typec_usb_sink_curr;
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_CUSTOM_HV
|
||||
bool typec_during_custom_hv;
|
||||
#endif /* CONFIG_TYPEC_CAP_CUSTOM_HV */
|
||||
|
||||
uint8_t typec_lpm_pull;
|
||||
uint8_t typec_lpm_retry;
|
||||
|
||||
#ifdef CONFIG_TYPEC_WAKEUP_ONCE_LOW_DUTY
|
||||
bool typec_wakeup_once;
|
||||
bool typec_low_rp_duty_cntdown;
|
||||
#endif /* CONFIG_TYPEC_WAKEUP_ONCE_LOW_DUTY */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE
|
||||
uint8_t typec_legacy_cable;
|
||||
#if TCPC_LEGACY_CABLE_SUSPECT_THD
|
||||
uint8_t typec_legacy_cable_suspect;
|
||||
#endif /* TCPC_LEGACY_CABLE_SUSPECT_THD */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE2
|
||||
uint8_t typec_legacy_retry_wk;
|
||||
#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE2 */
|
||||
#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_ROLE_SWAP
|
||||
uint8_t typec_during_role_swap;
|
||||
#endif /* CONFIG_TYPEC_CAP_ROLE_SWAP */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_AUTO_DISCHARGE
|
||||
#ifdef CONFIG_TCPC_AUTO_DISCHARGE_IC
|
||||
bool typec_auto_discharge;
|
||||
#endif /* CONFIG_TCPC_AUTO_DISCHARGE_IC */
|
||||
#endif /* CONFIG_TYPEC_CAP_AUTO_DISCHARGE */
|
||||
|
||||
#ifdef CONFIG_TCPC_EXT_DISCHARGE
|
||||
bool typec_ext_discharge;
|
||||
#endif /* CONFIG_TCPC_EXT_DISCHARGE */
|
||||
|
||||
#ifdef CONFIG_TCPC_VCONN_SUPPLY_MODE
|
||||
uint8_t tcpc_vconn_supply;
|
||||
#endif /* CONFIG_TCPC_VCONN_SUPPLY_MODE */
|
||||
|
||||
#ifdef CONFIG_TCPC_SOURCE_VCONN
|
||||
bool tcpc_source_vconn;
|
||||
#endif /* CONFIG_TCPC_SOURCE_VCONN */
|
||||
|
||||
uint32_t tcpc_flags;
|
||||
|
||||
#ifdef CONFIG_DUAL_ROLE_USB_INTF
|
||||
struct dual_role_phy_instance *dr_usb;
|
||||
uint8_t dual_role_supported_modes;
|
||||
uint8_t dual_role_mode;
|
||||
uint8_t dual_role_pr;
|
||||
uint8_t dual_role_dr;
|
||||
uint8_t dual_role_vconn;
|
||||
#endif /* CONFIG_DUAL_ROLE_USB_INTF */
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
/* Event */
|
||||
uint8_t pd_event_count;
|
||||
uint8_t pd_event_head_index;
|
||||
uint8_t pd_msg_buffer_allocated;
|
||||
|
||||
uint8_t pd_last_vdm_msg_id;
|
||||
bool pd_pending_vdm_event;
|
||||
bool pd_pending_vdm_reset;
|
||||
bool pd_pending_vdm_good_crc;
|
||||
bool pd_pending_vdm_discard;
|
||||
bool pd_pending_vdm_attention;
|
||||
bool pd_postpone_vdm_timeout;
|
||||
|
||||
struct pd_msg pd_last_vdm_msg;
|
||||
struct pd_msg pd_attention_vdm_msg;
|
||||
struct pd_event pd_vdm_event;
|
||||
|
||||
struct pd_msg pd_msg_buffer[PD_MSG_BUF_SIZE];
|
||||
struct pd_event pd_event_ring_buffer[PD_EVENT_BUF_SIZE];
|
||||
|
||||
uint8_t tcp_event_count;
|
||||
uint8_t tcp_event_head_index;
|
||||
struct tcp_dpm_event tcp_event_ring_buffer[TCP_EVENT_BUF_SIZE];
|
||||
|
||||
bool pd_pe_running;
|
||||
bool pd_wait_pe_idle;
|
||||
bool pd_hard_reset_event_pending;
|
||||
bool pd_wait_hard_reset_complete;
|
||||
bool pd_wait_pr_swap_complete;
|
||||
bool pd_ping_event_pending;
|
||||
uint8_t pd_bist_mode;
|
||||
uint8_t pd_transmit_state;
|
||||
uint8_t pd_wait_vbus_once;
|
||||
|
||||
#ifdef CONFIG_USB_PD_DIRECT_CHARGE
|
||||
bool pd_during_direct_charge;
|
||||
#endif /* CONFIG_USB_PD_DIRECT_CHARGE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
|
||||
bool pd_discard_pending;
|
||||
#endif /* CONFIG_USB_PD_RETRY_CRC_DISCARD */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_FORCE_DISCHARGE
|
||||
#ifdef CONFIG_TCPC_FORCE_DISCHARGE_IC
|
||||
bool pd_force_discharge;
|
||||
#endif /* CONFIG_TCPC_FORCE_DISCHARGE_IC */
|
||||
#endif /* CONFIG_TYPEC_CAP_FORCE_DISCHARGE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
uint8_t pd_retry_count;
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DISABLE_PE
|
||||
bool disable_pe; /* typec only */
|
||||
#endif /* CONFIG_USB_PD_DISABLE_PE */
|
||||
|
||||
struct pd_port pd_port;
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
struct notifier_block bat_nb;
|
||||
struct delayed_work bat_update_work;
|
||||
struct power_supply *bat_psy;
|
||||
uint8_t charging_status;
|
||||
int bat_soc;
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
#ifdef CONFIG_USB_PD_WAIT_BC12
|
||||
uint8_t pd_wait_bc12_count;
|
||||
struct power_supply *usb_psy;
|
||||
#endif /* CONFIG_USB_PD_WAIT_BC12 */
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
u8 vbus_level:2;
|
||||
bool vbus_safe0v;
|
||||
bool vbus_present;
|
||||
u8 irq_enabled:1;
|
||||
u8 pd_inited_flag:1;
|
||||
|
||||
/* TypeC Shield Protection */
|
||||
#ifdef CONFIG_WATER_DETECTION
|
||||
int usbid_calib;
|
||||
#endif /* CONFIG_WATER_DETECTION */
|
||||
#ifdef CONFIG_CABLE_TYPE_DETECTION
|
||||
enum tcpc_cable_type typec_cable_type;
|
||||
#endif /* CONFIG_CABLE_TYPE_DETECTION */
|
||||
};
|
||||
|
||||
#define to_tcpc_device(obj) container_of(obj, struct tcpc_device, dev)
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
static inline uint8_t pd_get_rev(struct pd_port *pd_port, uint8_t sop_type)
|
||||
{
|
||||
uint8_t pd_rev = PD_REV20;
|
||||
#ifdef CONFIG_USB_PD_REV30_SYNC_SPEC_REV
|
||||
struct pe_data *pe_data = &pd_port->pe_data;
|
||||
struct tcpc_device *tcpc = pd_port->tcpc;
|
||||
|
||||
if (sop_type == TCPC_TX_SOP) {
|
||||
pd_rev = pd_port->pd_revision[0];
|
||||
} else {
|
||||
if (pe_data->explicit_contract || pe_data->cable_rev_discovered)
|
||||
pd_rev = pd_port->pd_revision[1];
|
||||
else if (tcpc->tcpc_flags & TCPC_FLAGS_PD_REV30)
|
||||
pd_rev = PD_REV30;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_SYNC_SPEC_REV */
|
||||
|
||||
return pd_rev;
|
||||
}
|
||||
|
||||
static inline bool pd_check_rev30(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_get_rev(pd_port, TCPC_TX_SOP) >= PD_REV30;
|
||||
}
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#ifdef CONFIG_PD_DBG_INFO
|
||||
#define __RT_DBG_INFO pd_dbg_info
|
||||
#else
|
||||
#define __RT_DBG_INFO pr_info
|
||||
#endif /* CONFIG_PD_DBG_INFO */
|
||||
|
||||
#ifdef CONFIG_TCPC_LOG_WITH_PORT_NAME
|
||||
#define RT_DBG_INFO(format, args...) __RT_DBG_INFO(format, \
|
||||
tcpc->desc.name, ##args)
|
||||
#else
|
||||
#define RT_DBG_INFO(format, args...) __RT_DBG_INFO(format, ##args)
|
||||
#endif /* CONFIG_TCPC_LOG_WITH_PORT_NAME */
|
||||
|
||||
#if TYPEC_DBG_ENABLE
|
||||
#define TYPEC_DBG(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "TYPEC:" format, ##args)
|
||||
#else
|
||||
#define TYPEC_DBG(format, args...)
|
||||
#endif /* TYPEC_DBG_ENABLE */
|
||||
|
||||
#if TYPEC_INFO_ENABLE
|
||||
#define TYPEC_INFO(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "TYPEC:" format, ##args)
|
||||
#else
|
||||
#define TYPEC_INFO(format, args...)
|
||||
#endif /* TYPEC_INFO_ENABLE */
|
||||
|
||||
#if TYPEC_INFO2_ENABLE
|
||||
#define TYPEC_INFO2(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "TYPEC:" format, ##args)
|
||||
#else
|
||||
#define TYPEC_INFO2(format, args...)
|
||||
#endif /* TYPEC_INFO_ENABLE */
|
||||
|
||||
#if TCPC_INFO_ENABLE
|
||||
#define TCPC_INFO(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "TCPC:" format, ##args)
|
||||
#else
|
||||
#define TCPC_INFO(foramt, args...)
|
||||
#endif /* TCPC_INFO_ENABLE */
|
||||
|
||||
#if TCPC_DBG_ENABLE
|
||||
#define TCPC_DBG(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "TCPC:" format, ##args)
|
||||
#else
|
||||
#define TCPC_DBG(format, args...)
|
||||
#endif /* TCPC_DBG_ENABLE */
|
||||
|
||||
#if TCPC_DBG2_ENABLE
|
||||
#define TCPC_DBG2(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "TCPC:" format, ##args)
|
||||
#else
|
||||
#define TCPC_DBG2(format, args...)
|
||||
#endif /* TCPC_DBG2_ENABLE */
|
||||
|
||||
#define TCPC_ERR(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "TCPC-ERR:" format, ##args)
|
||||
|
||||
#define DP_ERR(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "DP-ERR:" format, ##args)
|
||||
|
||||
#if DPM_INFO_ENABLE
|
||||
#define DPM_INFO(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "DPM:" format, ##args)
|
||||
#else
|
||||
#define DPM_INFO(format, args...)
|
||||
#endif /* DPM_DBG_INFO */
|
||||
|
||||
#if DPM_INFO2_ENABLE
|
||||
#define DPM_INFO2(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "DPM:" format, ##args)
|
||||
#else
|
||||
#define DPM_INFO2(format, args...)
|
||||
#endif /* DPM_DBG_INFO */
|
||||
|
||||
#if DPM_DBG_ENABLE
|
||||
#define DPM_DBG(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "DPM:" format, ##args)
|
||||
#else
|
||||
#define DPM_DBG(format, args...)
|
||||
#endif /* DPM_DBG_ENABLE */
|
||||
|
||||
#if PD_ERR_ENABLE
|
||||
#define PD_ERR(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "PD-ERR:" format, ##args)
|
||||
#else
|
||||
#define PD_ERR(format, args...)
|
||||
#endif /* PD_ERR_ENABLE */
|
||||
|
||||
#if PE_INFO_ENABLE
|
||||
#define PE_INFO(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "PE:" format, ##args)
|
||||
#else
|
||||
#define PE_INFO(format, args...)
|
||||
#endif /* PE_INFO_ENABLE */
|
||||
|
||||
#if PE_EVENT_DBG_ENABLE
|
||||
#define PE_EVT_INFO(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "PE-EVT:" format, ##args)
|
||||
#else
|
||||
#define PE_EVT_INFO(format, args...)
|
||||
#endif /* PE_EVENT_DBG_ENABLE */
|
||||
|
||||
#if PE_DBG_ENABLE
|
||||
#define PE_DBG(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "PE:" format, ##args)
|
||||
#else
|
||||
#define PE_DBG(format, args...)
|
||||
#endif /* PE_DBG_ENABLE */
|
||||
|
||||
#if PE_STATE_INFO_ENABLE
|
||||
#define PE_STATE_INFO(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "PE:" format, ##args)
|
||||
#else
|
||||
#define PE_STATE_INFO(format, args...)
|
||||
#endif /* PE_STATE_IFNO_ENABLE */
|
||||
|
||||
#if DP_INFO_ENABLE
|
||||
#define DP_INFO(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "DP:" format, ##args)
|
||||
#else
|
||||
#define DP_INFO(format, args...)
|
||||
#endif /* DP_INFO_ENABLE */
|
||||
|
||||
#if DP_DBG_ENABLE
|
||||
#define DP_DBG(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "DP:" format, ##args)
|
||||
#else
|
||||
#define DP_DBG(format, args...)
|
||||
#endif /* DP_DBG_ENABLE */
|
||||
|
||||
#if UVDM_INFO_ENABLE
|
||||
#define UVDM_INFO(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "UVDM:" format, ##args)
|
||||
#else
|
||||
#define UVDM_INFO(format, args...)
|
||||
#endif
|
||||
|
||||
#if TCPM_DBG_ENABLE
|
||||
#define TCPM_DBG(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "TCPM:" format, ##args)
|
||||
#else
|
||||
#define TCPM_DBG(format, args...)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
|
||||
#if DC_INFO_ENABLE
|
||||
#define DC_INFO(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "DC> " format, ##args)
|
||||
#else
|
||||
#define DC_INFO(format, args...)
|
||||
#endif
|
||||
|
||||
#if DC_DBG_ENABLE
|
||||
#define DC_DBG(format, args...) \
|
||||
RT_DBG_INFO(CONFIG_TCPC_DBG_PRESTR "DC> " format, ##args)
|
||||
#else
|
||||
#define DC_DBG(format, args...)
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
|
||||
#endif /* #ifndef __LINUX_RT_TCPCI_CORE_H */
|
||||
264
drivers/usb/typec/mmi_tcpc/inc/tcpci_event.h
Normal file
264
drivers/usb/typec/mmi_tcpc/inc/tcpci_event.h
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef TCPC_EVENT_BUF_H_INCLUDED
|
||||
#define TCPC_EVENT_BUF_H_INCLUDED
|
||||
|
||||
#include "tcpci_timer.h"
|
||||
#include "tcpm.h"
|
||||
|
||||
|
||||
#define PD_MSG_BUF_SIZE (4*2)
|
||||
#define PD_EVENT_BUF_SIZE (8*2)
|
||||
#define TCP_EVENT_BUF_SIZE (2*2)
|
||||
|
||||
struct tcpc_device;
|
||||
|
||||
struct pd_msg {
|
||||
uint8_t frame_type;
|
||||
uint16_t msg_hdr;
|
||||
uint32_t payload[7];
|
||||
};
|
||||
|
||||
struct pd_event {
|
||||
uint8_t event_type;
|
||||
uint8_t msg;
|
||||
uint8_t msg_sec;
|
||||
struct pd_msg *pd_msg;
|
||||
};
|
||||
|
||||
struct pd_msg *pd_alloc_msg(struct tcpc_device *tcpc);
|
||||
void pd_free_msg(struct tcpc_device *tcpc, struct pd_msg *pd_msg);
|
||||
|
||||
bool pd_get_event(struct tcpc_device *tcpc, struct pd_event *pd_event);
|
||||
bool pd_put_event(struct tcpc_device *tcpc,
|
||||
const struct pd_event *pd_event, bool from_port_partner);
|
||||
void pd_free_event(struct tcpc_device *tcpc, struct pd_event *pd_event);
|
||||
|
||||
bool pd_get_vdm_event(struct tcpc_device *tcpc, struct pd_event *pd_event);
|
||||
bool pd_put_vdm_event(struct tcpc_device *tcpc,
|
||||
struct pd_event *pd_event, bool from_port_partner);
|
||||
|
||||
bool pd_put_last_vdm_event(struct tcpc_device *tcpc);
|
||||
|
||||
bool pd_get_deferred_tcp_event(
|
||||
struct tcpc_device *tcpc, struct tcp_dpm_event *tcp_event);
|
||||
bool pd_put_deferred_tcp_event(
|
||||
struct tcpc_device *tcpc, const struct tcp_dpm_event *tcp_event);
|
||||
|
||||
extern int tcpci_event_init(struct tcpc_device *tcpc);
|
||||
extern int tcpci_event_deinit(struct tcpc_device *tcpc);
|
||||
extern void pd_event_buf_reset(struct tcpc_device *tcpc);
|
||||
|
||||
bool __pd_put_cc_attached_event(struct tcpc_device *tcpc, uint8_t type);
|
||||
bool pd_put_cc_attached_event(struct tcpc_device *tcpc, uint8_t type);
|
||||
void pd_put_cc_detached_event(struct tcpc_device *tcpc);
|
||||
void pd_put_recv_hard_reset_event(struct tcpc_device *tcpc);
|
||||
void pd_put_sent_hard_reset_event(struct tcpc_device *tcpc);
|
||||
bool pd_put_pd_msg_event(struct tcpc_device *tcpc, struct pd_msg *pd_msg);
|
||||
void pd_put_hard_reset_completed_event(struct tcpc_device *tcpc);
|
||||
void pd_put_vbus_changed_event(struct tcpc_device *tcpc, bool from_ic);
|
||||
void pd_put_vbus_safe0v_event(struct tcpc_device *tcpc);
|
||||
void pd_put_vbus_stable_event(struct tcpc_device *tcpc);
|
||||
void pd_put_vbus_present_event(struct tcpc_device *tcpc);
|
||||
|
||||
enum pd_event_type {
|
||||
PD_EVT_PD_MSG = 0, /* either ctrl msg or data msg */
|
||||
PD_EVT_CTRL_MSG,
|
||||
PD_EVT_DATA_MSG,
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
PD_EVT_EXT_MSG,
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
PD_EVT_PD_MSG_END,
|
||||
|
||||
PD_EVT_DPM_MSG = PD_EVT_PD_MSG_END,
|
||||
PD_EVT_HW_MSG,
|
||||
PD_EVT_PE_MSG,
|
||||
PD_EVT_TIMER_MSG,
|
||||
|
||||
PD_EVT_TCP_MSG,
|
||||
};
|
||||
|
||||
enum pd_msg_type {
|
||||
/* Control Message type */
|
||||
/* 0 Reserved */
|
||||
PD_CTRL_GOOD_CRC = 1,
|
||||
PD_CTRL_GOTO_MIN = 2,
|
||||
PD_CTRL_ACCEPT = 3,
|
||||
PD_CTRL_REJECT = 4,
|
||||
PD_CTRL_PING = 5,
|
||||
PD_CTRL_PS_RDY = 6,
|
||||
PD_CTRL_GET_SOURCE_CAP = 7,
|
||||
PD_CTRL_GET_SINK_CAP = 8,
|
||||
PD_CTRL_DR_SWAP = 9,
|
||||
PD_CTRL_PR_SWAP = 10,
|
||||
PD_CTRL_VCONN_SWAP = 11,
|
||||
PD_CTRL_WAIT = 12,
|
||||
PD_CTRL_SOFT_RESET = 13,
|
||||
/* 14-15 Reserved */
|
||||
PD_CTRL_PD30_START = 0x10 + 0,
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
PD_CTRL_NOT_SUPPORTED = 0x10 + 0,
|
||||
PD_CTRL_GET_SOURCE_CAP_EXT = 0x10 + 1,
|
||||
PD_CTRL_GET_STATUS = 0x10 + 2,
|
||||
PD_CTRL_FR_SWAP = 0x10 + 3,
|
||||
PD_CTRL_GET_PPS_STATUS = 0x10 + 4,
|
||||
PD_CTRL_GET_COUNTRY_CODE = 0x10 + 5,
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
/* 22-31 Reserved */
|
||||
PD_CTRL_MSG_NR,
|
||||
/* Data message type */
|
||||
/* 0 Reserved */
|
||||
PD_DATA_SOURCE_CAP = 1,
|
||||
PD_DATA_REQUEST = 2,
|
||||
PD_DATA_BIST = 3,
|
||||
PD_DATA_SINK_CAP = 4,
|
||||
PD_DATA_PD30_START = 5,
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
PD_DATA_BAT_STATUS = 5,
|
||||
PD_DATA_ALERT = 6,
|
||||
PD_DATA_GET_COUNTRY_INFO = 7,
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
/* 7-14 Reserved */
|
||||
PD_DATA_VENDOR_DEF = 15,
|
||||
PD_DATA_MSG_NR,
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
/* Extended message type */
|
||||
/* 0 Reserved */
|
||||
PD_EXT_SOURCE_CAP_EXT = 1,
|
||||
PD_EXT_STATUS = 2,
|
||||
PD_EXT_GET_BAT_CAP = 3,
|
||||
PD_EXT_GET_BAT_STATUS = 4,
|
||||
PD_EXT_BAT_CAP = 5,
|
||||
PD_EXT_GET_MFR_INFO = 6,
|
||||
PD_EXT_MFR_INFO = 7,
|
||||
PD_EXT_SEC_REQUEST = 8,
|
||||
PD_EXT_SEC_RESPONSE = 9,
|
||||
PD_EXT_FW_UPDATE_REQUEST = 10,
|
||||
PD_EXT_FW_UPDATE_RESPONSE = 11,
|
||||
PD_EXT_PPS_STATUS = 12,
|
||||
PD_EXT_COUNTRY_INFO = 13,
|
||||
PD_EXT_COUNTRY_CODES = 14,
|
||||
/* 15 Reserved */
|
||||
PD_EXT_MSG_NR,
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
/* HW Message type */
|
||||
PD_HW_CC_DETACHED = 0,
|
||||
PD_HW_CC_ATTACHED,
|
||||
PD_HW_RECV_HARD_RESET,
|
||||
PD_HW_VBUS_PRESENT,
|
||||
PD_HW_VBUS_ABSENT,
|
||||
PD_HW_VBUS_SAFE0V,
|
||||
PD_HW_VBUS_STABLE,
|
||||
PD_HW_TX_FAILED, /* no good crc or discard */
|
||||
PD_HW_TX_DISCARD, /* discard vdm msg */
|
||||
PD_HW_RETRY_VDM, /* discard vdm msg (retry) */
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
PD_HW_SINK_TX_CHANGE,
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
PD_HW_MSG_NR,
|
||||
/* PE Message type*/
|
||||
PD_PE_RESET_PRL_COMPLETED = 0,
|
||||
PD_PE_POWER_ROLE_AT_DEFAULT,
|
||||
PD_PE_HARD_RESET_COMPLETED,
|
||||
PD_PE_IDLE,
|
||||
PD_PE_VDM_RESET,
|
||||
PD_PE_VDM_NOT_SUPPORT,
|
||||
PD_PE_MSG_NR,
|
||||
/* DPM Message type */
|
||||
PD_DPM_NOTIFIED = 0,
|
||||
PD_DPM_ACK = PD_DPM_NOTIFIED,
|
||||
PD_DPM_NAK,
|
||||
PD_DPM_CAP_CHANGED,
|
||||
PD_DPM_NOT_SUPPORT,
|
||||
PD_DPM_MSG_NR,
|
||||
};
|
||||
|
||||
enum pd_dpm_notify_type {
|
||||
PD_DPM_NOTIFY_OK = 0,
|
||||
PD_DPM_NOTIFY_CAP_MISMATCH,
|
||||
};
|
||||
|
||||
enum pd_dpm_nak_type {
|
||||
PD_DPM_NAK_REJECT = 0,
|
||||
PD_DPM_NAK_WAIT = 1,
|
||||
};
|
||||
|
||||
enum pd_tcp_sec_msg_type {
|
||||
PD_TCP_FROM_TCPM = 0,
|
||||
PD_TCP_FROM_PE = 1,
|
||||
};
|
||||
|
||||
enum pd_tx_transmit_state {
|
||||
PD_TX_STATE_GOOD_CRC = 0,
|
||||
PD_TX_STATE_NO_GOOD_CRC,
|
||||
PD_TX_STATE_DISCARD,
|
||||
PD_TX_STATE_HARD_RESET,
|
||||
PD_TX_STATE_NO_RESPONSE,
|
||||
|
||||
PD_TX_STATE_WAIT,
|
||||
PD_TX_STATE_WAIT_CRC_VDM = PD_TX_STATE_WAIT,
|
||||
PD_TX_STATE_WAIT_CRC_PD,
|
||||
PD_TX_STATE_WAIT_HARD_RESET,
|
||||
};
|
||||
|
||||
static inline bool pd_event_msg_match(struct pd_event *pd_event,
|
||||
uint8_t type, uint8_t msg)
|
||||
{
|
||||
if (pd_event->event_type != type)
|
||||
return false;
|
||||
|
||||
return pd_event->msg == msg;
|
||||
}
|
||||
|
||||
static inline bool pd_event_ctrl_msg_match(
|
||||
struct pd_event *pd_event, uint8_t msg)
|
||||
{
|
||||
return pd_event_msg_match(pd_event, PD_EVT_CTRL_MSG, msg);
|
||||
}
|
||||
|
||||
static inline bool pd_event_data_msg_match(
|
||||
struct pd_event *pd_event, uint8_t msg)
|
||||
{
|
||||
return pd_event_msg_match(pd_event, PD_EVT_DATA_MSG, msg);
|
||||
}
|
||||
|
||||
static inline bool pd_event_hw_msg_match(struct pd_event *pd_event, uint8_t msg)
|
||||
{
|
||||
return pd_event_msg_match(pd_event, PD_EVT_HW_MSG, msg);
|
||||
}
|
||||
|
||||
static inline bool pd_event_pe_msg_match(struct pd_event *pd_event, uint8_t msg)
|
||||
{
|
||||
return pd_event_msg_match(pd_event, PD_EVT_PE_MSG, msg);
|
||||
}
|
||||
|
||||
static inline bool pd_event_timer_msg_match(
|
||||
struct pd_event *pd_event, uint8_t msg)
|
||||
{
|
||||
return pd_event_msg_match(pd_event, PD_EVT_TIMER_MSG, msg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
static inline bool pd_event_ext_msg_match(
|
||||
struct pd_event *pd_event, uint8_t msg)
|
||||
{
|
||||
return pd_event_msg_match(pd_event, PD_EVT_EXT_MSG, msg);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
#endif /* TCPC_EVENT_BUF_H_INCLUDED */
|
||||
136
drivers/usb/typec/mmi_tcpc/inc/tcpci_timer.h
Normal file
136
drivers/usb/typec/mmi_tcpc/inc/tcpci_timer.h
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef TCPC_TIMER_H_INCLUDED
|
||||
#define TCPC_TIMER_H_INCLUDED
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include "tcpci_config.h"
|
||||
|
||||
struct tcpc_device;
|
||||
enum {
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
PD_TIMER_DISCOVER_ID = 0,
|
||||
PD_TIMER_BIST_CONT_MODE,
|
||||
PD_TIMER_HARD_RESET_COMPLETE,
|
||||
PD_TIMER_NO_RESPONSE,
|
||||
PD_TIMER_PS_HARD_RESET,
|
||||
PD_TIMER_PS_SOURCE_OFF,
|
||||
PD_TIMER_PS_SOURCE_ON,
|
||||
PD_TIMER_PS_TRANSITION,
|
||||
PD_TIMER_SENDER_RESPONSE,
|
||||
PD_TIMER_SINK_REQUEST,
|
||||
PD_TIMER_SINK_WAIT_CAP,
|
||||
PD_TIMER_SOURCE_CAPABILITY,
|
||||
PD_TIMER_SOURCE_START,
|
||||
PD_TIMER_VCONN_ON,
|
||||
#ifdef CONFIG_USB_PD_VCONN_STABLE_DELAY
|
||||
PD_TIMER_VCONN_STABLE,
|
||||
#endif /* CONFIG_USB_PD_VCONN_STABLE_DELAY */
|
||||
PD_TIMER_VDM_MODE_ENTRY,
|
||||
PD_TIMER_VDM_MODE_EXIT,
|
||||
PD_TIMER_VDM_RESPONSE,
|
||||
PD_TIMER_SOURCE_TRANSITION,
|
||||
PD_TIMER_SRC_RECOVER,
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
PD_TIMER_CK_NOT_SUPPORTED,
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
PD_TIMER_SINK_TX,
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SOURCE
|
||||
PD_TIMER_SOURCE_PPS_TIMEOUT,
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SOURCE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
/* PD_TIMER (out of spec )*/
|
||||
PD_TIMER_VSAFE0V_DELAY,
|
||||
PD_TIMER_VSAFE0V_TOUT,
|
||||
PD_TIMER_DISCARD,
|
||||
PD_TIMER_VBUS_STABLE,
|
||||
PD_TIMER_VBUS_PRESENT,
|
||||
PD_TIMER_UVDM_RESPONSE,
|
||||
PD_TIMER_DFP_FLOW_DELAY,
|
||||
PD_TIMER_UFP_FLOW_DELAY,
|
||||
PD_TIMER_VCONN_READY,
|
||||
PD_PE_VDM_POSTPONE,
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
PD_TIMER_DEFERRED_EVT,
|
||||
#ifdef CONFIG_USB_PD_REV30_SNK_FLOW_DELAY_STARTUP
|
||||
PD_TIMER_SNK_FLOW_DELAY,
|
||||
#endif /* CONFIG_USB_PD_REV30_SNK_FLOW_DELAY_STARTUP */
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
PD_TIMER_PE_IDLE_TOUT,
|
||||
PD_PE_TIMER_END_ID,
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
/* TYPEC_RT_TIMER (out of spec )*/
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
TYPEC_RT_TIMER_START_ID = PD_PE_TIMER_END_ID,
|
||||
#else
|
||||
TYPEC_RT_TIMER_START_ID = 0,
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
TYPEC_RT_TIMER_SAFE0V_DELAY = TYPEC_RT_TIMER_START_ID,
|
||||
TYPEC_RT_TIMER_SAFE0V_TOUT,
|
||||
TYPEC_RT_TIMER_ROLE_SWAP_START,
|
||||
TYPEC_RT_TIMER_ROLE_SWAP_STOP,
|
||||
TYPEC_RT_TIMER_STATE_CHANGE,
|
||||
TYPEC_RT_TIMER_NOT_LEGACY,
|
||||
TYPEC_RT_TIMER_LEGACY_STABLE,
|
||||
TYPEC_RT_TIMER_LEGACY_RECYCLE,
|
||||
TYPEC_RT_TIMER_DISCHARGE,
|
||||
TYPEC_RT_TIMER_LOW_POWER_MODE,
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
TYPEC_RT_TIMER_PE_IDLE,
|
||||
#ifdef CONFIG_USB_PD_WAIT_BC12
|
||||
TYPEC_RT_TIMER_PD_WAIT_BC12,
|
||||
#endif /* CONFIG_USB_PD_WAIT_BC12 */
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
TYPEC_TIMER_ERROR_RECOVERY,
|
||||
/* TYPEC-TRY-TIMER */
|
||||
TYPEC_TRY_TIMER_START_ID,
|
||||
TYPEC_TRY_TIMER_DRP_TRY = TYPEC_TRY_TIMER_START_ID,
|
||||
TYPEC_TRY_TIMER_DRP_TRYWAIT,
|
||||
/* TYPEC-DEBOUNCE-TIMER */
|
||||
TYPEC_TIMER_START_ID,
|
||||
TYPEC_TIMER_CCDEBOUNCE = TYPEC_TIMER_START_ID,
|
||||
TYPEC_TIMER_PDDEBOUNCE,
|
||||
#ifdef CONFIG_COMPATIBLE_APPLE_TA
|
||||
TYPEC_TIMER_APPLE_CC_OPEN,
|
||||
#endif /* CONFIG_COMPATIBLE_APPLE_TA */
|
||||
TYPEC_TIMER_TRYCCDEBOUNCE,
|
||||
TYPEC_TIMER_SRCDISCONNECT,
|
||||
TYPEC_TIMER_DRP_SRC_TOGGLE,
|
||||
#ifdef CONFIG_TYPEC_CAP_NORP_SRC
|
||||
TYPEC_TIMER_NORP_SRC,
|
||||
#endif /* CONFIG_TYPEC_CAP_NORP_SRC */
|
||||
PD_TIMER_NR,
|
||||
};
|
||||
|
||||
extern int tcpci_timer_init(struct tcpc_device *tcpc);
|
||||
extern int tcpci_timer_deinit(struct tcpc_device *tcpc);
|
||||
extern void tcpc_restart_timer(struct tcpc_device *tcpc, uint32_t timer_id);
|
||||
extern void tcpc_enable_timer(struct tcpc_device *tcpc, uint32_t timer_id);
|
||||
extern void tcpc_enable_wakeup_timer(struct tcpc_device *tcpc, bool en);
|
||||
extern void tcpc_disable_timer(
|
||||
struct tcpc_device *tcpc, uint32_t timer_id);
|
||||
extern void tcpc_reset_typec_try_timer(struct tcpc_device *tcpc);
|
||||
extern void tcpc_reset_typec_debounce_timer(struct tcpc_device *tcpc);
|
||||
|
||||
extern void tcpc_reset_pe_timer(struct tcpc_device *tcpc);
|
||||
#endif /* TCPC_TIMER_H_INCLUDED */
|
||||
74
drivers/usb/typec/mmi_tcpc/inc/tcpci_typec.h
Normal file
74
drivers/usb/typec/mmi_tcpc/inc/tcpci_typec.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_TCPCI_TYPEC_H
|
||||
#define __LINUX_TCPCI_TYPEC_H
|
||||
#include "tcpci.h"
|
||||
|
||||
struct tcpc_device;
|
||||
extern bool tcpc_typec_is_act_as_sink_role(struct tcpc_device *tcpc);
|
||||
|
||||
/******************************************************************************
|
||||
* Call following function to trigger TYPEC Connection State Change
|
||||
*
|
||||
* 1. H/W -> CC/PS Change.
|
||||
* 2. Timer -> CCDebounce or PDDebounce or others Timeout
|
||||
* 3. Policy Engine -> PR_SWAP, Error_Recovery, PE_Idle
|
||||
*****************************************************************************/
|
||||
|
||||
extern int tcpc_typec_enter_lpm_again(struct tcpc_device *tcpc);
|
||||
extern int tcpc_typec_handle_cc_change(struct tcpc_device *tcpc);
|
||||
|
||||
extern int tcpc_typec_handle_ps_change(
|
||||
struct tcpc_device *tcpc, int vbus_level);
|
||||
|
||||
extern int tcpc_typec_handle_timeout(
|
||||
struct tcpc_device *tcpc, uint32_t timer_id);
|
||||
|
||||
extern int tcpc_typec_handle_vsafe0v(struct tcpc_device *tcpc);
|
||||
|
||||
extern int tcpc_typec_set_rp_level(struct tcpc_device *tcpc, uint8_t res);
|
||||
|
||||
extern int tcpc_typec_error_recovery(struct tcpc_device *tcpc);
|
||||
|
||||
extern int tcpc_typec_disable(struct tcpc_device *tcpc);
|
||||
extern int tcpc_typec_enable(struct tcpc_device *tcpc);
|
||||
|
||||
extern int tcpc_typec_change_role(
|
||||
struct tcpc_device *tcpc, uint8_t typec_role, bool postpone);
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
extern int tcpc_typec_handle_pe_pr_swap(struct tcpc_device *tcpc);
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_ROLE_SWAP
|
||||
extern int tcpc_typec_swap_role(struct tcpc_device *tcpc);
|
||||
#endif /* CONFIG_TYPEC_CAP_ROLE_SWAP */
|
||||
|
||||
#ifdef CONFIG_WATER_DETECTION
|
||||
extern int tcpc_typec_handle_wd(struct tcpc_device *tcpc, bool wd);
|
||||
#endif /* CONFIG_WATER_DETECTION */
|
||||
|
||||
#ifdef CONFIG_CABLE_TYPE_DETECTION
|
||||
extern int tcpc_typec_handle_ctd(struct tcpc_device *tcpc,
|
||||
enum tcpc_cable_type cable_type);
|
||||
#endif /* CONFIG_CABLE_TYPEC_DETECTION */
|
||||
|
||||
#define typec_get_cc1() \
|
||||
tcpc->typec_remote_cc[0]
|
||||
#define typec_get_cc2() \
|
||||
tcpc->typec_remote_cc[1]
|
||||
#define typec_get_cc_res() \
|
||||
(tcpc->typec_polarity ? typec_get_cc2() : typec_get_cc1())
|
||||
|
||||
#endif /* #ifndef __LINUX_TCPCI_TYPEC_H */
|
||||
1921
drivers/usb/typec/mmi_tcpc/inc/tcpm.h
Normal file
1921
drivers/usb/typec/mmi_tcpc/inc/tcpm.h
Normal file
File diff suppressed because it is too large
Load diff
334
drivers/usb/typec/mmi_tcpc/inc/tcpm_pd.h
Normal file
334
drivers/usb/typec/mmi_tcpc/inc/tcpm_pd.h
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef TCPM_PD_H_
|
||||
#define TCPM_PD_H_
|
||||
|
||||
#include "tcpci_config.h"
|
||||
|
||||
/* --- PD data message helpers --- */
|
||||
|
||||
#define PD_DATA_OBJ_SIZE (7)
|
||||
#define PDO_MAX_NR (PD_DATA_OBJ_SIZE)
|
||||
#define VDO_MAX_NR (PD_DATA_OBJ_SIZE-1)
|
||||
#define VDO_MAX_SVID_NR (VDO_MAX_NR*2)
|
||||
|
||||
#define VDO_DISCOVER_ID_IDH 0
|
||||
#define VDO_DISCOVER_ID_CSTAT 1
|
||||
#define VDO_DISCOVER_ID_PRODUCT 2
|
||||
#define VDO_DISCOVER_ID_CABLE 3
|
||||
#define VDO_DISCOVER_ID_AMA 3
|
||||
|
||||
/******************* PD30 *******************/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_CHUNKING_BY_PE
|
||||
#define MAX_EXTENDED_MSG_LEN 260
|
||||
#else
|
||||
#define MAX_EXTENDED_MSG_LEN 26
|
||||
#endif /* CONFIG_USB_PD_REV30_CHUNKING */
|
||||
|
||||
/* PD30 Data Message Data Object */
|
||||
|
||||
#define PD_BSDO_SIZE 1
|
||||
#define PD_CCDO_SIZE 1
|
||||
#define PD_ADO_SIZE 1
|
||||
|
||||
/*
|
||||
* Battery Status Data Object (BSDO)
|
||||
* ----------
|
||||
* <31:16> :: Battery Present Capacity (1/10 WH, 0xFFFF = SOC unknown)
|
||||
* <15:8> :: Battery Info
|
||||
* <7:0> :: Reserved and Shall be set to zero
|
||||
*/
|
||||
|
||||
#define BSDO(cap, info) (((cap) << 16) | ((info) << 8))
|
||||
|
||||
#define BSDO_BAT_INFO(x) ((x>>8) & 0xff)
|
||||
|
||||
#define BSDO_BAT_INFO_INVALID_REF (1<<0)
|
||||
#define BSDO_BAT_INFO_PRESENT (1<<1)
|
||||
#define BSDO_BAT_INFO_CHARGING ((0<<2) | BSDO_BAT_INFO_PRESENT)
|
||||
#define BSDO_BAT_INFO_DISCHARGING ((1<<2) | BSDO_BAT_INFO_PRESENT)
|
||||
#define BSDO_BAT_INFO_IDLE ((2<<2) | BSDO_BAT_INFO_PRESENT)
|
||||
|
||||
#define BSDO_BAT_CAP_UNKNOWN (0xffff)
|
||||
|
||||
/*
|
||||
* Country Code Data Object (CCDO)
|
||||
* ----------
|
||||
* <31:24> :: First character of the Alpha-2 Country Code
|
||||
* <23:16> :: Second character of the Alpha-2 Country Code
|
||||
* <15:0> :: Reserved and Shall be set to zero
|
||||
*/
|
||||
|
||||
#define CCDO(code) ((code) << 16)
|
||||
|
||||
#define CCDO_COUNTRY_CODE(x) ((x >> 16) & 0xffff)
|
||||
#define CCDO_COUNTRY_CODE1(x) ((x >> 24) & 0xff)
|
||||
#define CCDO_COUNTRY_CODE2(x) ((x >> 16) & 0xff)
|
||||
|
||||
/*
|
||||
* Alert Data Object (ADO)
|
||||
* ----------
|
||||
* <31:24> :: Type Of Alert
|
||||
* <23:20> :: Fixed Batteries (bit field)
|
||||
* <19:16> :: Hot Swappable Batteries (bit field)
|
||||
*/
|
||||
|
||||
#define ADO_ALERT_BAT_CHANGED (1<<1)
|
||||
#define ADO_ALERT_OCP (1<<2)
|
||||
#define ADO_ALERT_OTP (1<<3)
|
||||
#define ADO_ALERT_OPER_CHANGED (1<<4)
|
||||
#define ADO_ALERT_SRC_IN_CHANGED (1<<5)
|
||||
#define ADO_ALERT_OVP (1<<6)
|
||||
|
||||
#define ADO_ALERT_TYPE(raw) (raw >> 24)
|
||||
#define ADO_FIXED_BAT(raw) ((raw >> 20) & 0x0f)
|
||||
#define ADO_HOT_SWAP_BAT(raw) ((raw >> 16) & 0x0f)
|
||||
|
||||
#define ADO_ALERT_TYPE_SET(type) (type << 24)
|
||||
#define ADO_FIXED_BAT_SET(i) ((i) << 20)
|
||||
#define ADO_HOT_SWAP_BAT_SET(i) ((i) << 16)
|
||||
|
||||
#define ADO(type, fixed, swap) \
|
||||
(((type) << 24) | ((fixed) << 20) | ((swap) << 16))
|
||||
|
||||
#define ADO_GET_STATUS_ONCE_MASK ADO(\
|
||||
ADO_ALERT_BAT_CHANGED|ADO_ALERT_SRC_IN_CHANGED,\
|
||||
0xff, 0xff)
|
||||
|
||||
/* PD30 Extend Message Data Object */
|
||||
|
||||
enum pd_present_temperature_flag {
|
||||
PD_PTF_NO_SUPPORT = 0,
|
||||
PD_PTF_NORMAL,
|
||||
PD_PTF_WARNING,
|
||||
PD_PTF_OVER_TEMP,
|
||||
};
|
||||
|
||||
enum pd_battery_reference {
|
||||
PD_BAT_REF_FIXED0 = 0,
|
||||
PD_BAT_REF_FIXED1,
|
||||
PD_BAT_REF_FIXED2,
|
||||
PD_BAT_REF_FIXED3,
|
||||
|
||||
PD_BAT_REF_SWAP0 = 4,
|
||||
PD_BAT_REF_SWAP1,
|
||||
PD_BAT_REF_SWAP2,
|
||||
PD_BAT_REF_SWAP3,
|
||||
|
||||
PD_BAT_REF_MAX,
|
||||
|
||||
/* 8 ~ 255 are reserved and shall not be used */
|
||||
};
|
||||
|
||||
|
||||
/* SCEDB, Source_Capabilities_Extended */
|
||||
|
||||
#define PD_SCEDB_SIZE 24
|
||||
|
||||
#define PD_SCEDB_VR(load_step, ioc) \
|
||||
((load_step) | (ioc << 2))
|
||||
|
||||
enum {
|
||||
PD_SCEDB_VR_LOAD_STEP_150 = 0x00,
|
||||
PD_SCEDB_VR_LOAD_STEP_500 = 0x01,
|
||||
};
|
||||
|
||||
enum {
|
||||
PD_SCEDB_VR_IOC_25 = 0x00,
|
||||
PD_SCEDB_VR_IOC_90 = 0x01,
|
||||
};
|
||||
|
||||
#define PD_SCEDB_COMPLIANCE_LPS (1<<0)
|
||||
#define PD_SCEDB_COMPLIANCE_PS1 (1<<1)
|
||||
#define PD_SCEDB_COMPLIANCE_PS2 (1<<2)
|
||||
|
||||
#define PD_SCEDB_TC_LOW_TC (1<<0)
|
||||
#define PD_SCEDB_TC_GROUND (1<<1)
|
||||
#define PD_SCEDB_TC_GROUND_INTEND (1<<2)
|
||||
|
||||
#define PD_SCEDB_TT_IEC_60950 0
|
||||
#define PD_SCEDB_TT_IEC_62368_TS1 1
|
||||
#define PD_SCEDB_TT_IEC_62368_TS2 2
|
||||
|
||||
#define PD_SCEDB_INPUT_EXT (1<<0)
|
||||
#define PD_SCEDB_INPUT_EXT_UNCONSTRAINED (1<<1)
|
||||
#define PD_SCEDB_INPUT_INT (1<<2)
|
||||
|
||||
#define PD_SCEDB_BATTERIES(swap_nr, fixed_nr) \
|
||||
(swap_nr << 4 | fixed_nr)
|
||||
|
||||
#define PD_SCEDB_FIX_BAT_NR(raw) (raw & 0xf)
|
||||
#define PD_SCEDB_SWAP_BAT_NR(raw) ((raw >> 4) & 0xf)
|
||||
|
||||
struct pd_source_cap_ext {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
uint32_t xid;
|
||||
uint8_t fw_ver;
|
||||
uint8_t hw_ver;
|
||||
uint8_t voltage_regulation;
|
||||
uint8_t hold_time_ms;
|
||||
uint8_t compliance; /* bit field */
|
||||
uint8_t touch_current; /* bit field */
|
||||
uint16_t peak_current[3];
|
||||
uint8_t touch_temp;
|
||||
uint8_t source_inputs; /* bit field */
|
||||
uint8_t batteries;
|
||||
uint8_t source_pdp;
|
||||
};
|
||||
|
||||
/* GBSDB, Get_Battery_Status */
|
||||
|
||||
#define PD_GBSDB_SIZE 1
|
||||
|
||||
struct pd_get_battery_status {
|
||||
uint8_t bat_status_ref; /* pd_battery_reference */
|
||||
};
|
||||
|
||||
/* GBCDB, Get_Battery_Cap */
|
||||
|
||||
#define PD_GBCDB_SIZE 1
|
||||
|
||||
struct pd_get_battery_capabilities {
|
||||
uint8_t bat_cap_ref; /* pd_battery_reference */
|
||||
};
|
||||
|
||||
/* BCDB, Battery_Capabilities */
|
||||
|
||||
#define PD_BCDB_SIZE 9
|
||||
|
||||
#define PD_BCDB_BAT_CAP_NOT_PRESENT 0x0000
|
||||
#define PD_BCDB_BAT_CAP_UNKNOWN 0Xffff
|
||||
#define PD_BCDB_BAT_CAP_RAW(cap_wh) (cap_wh*10)
|
||||
#define PD_BCDB_BAT_CAP_VAL(raw) (raw/10)
|
||||
|
||||
#define PD_BCDB_BAT_TYPE_INVALID (1<<0)
|
||||
|
||||
struct pd_battery_capabilities {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
uint16_t bat_design_cap;
|
||||
uint16_t bat_last_full_cap;
|
||||
uint8_t bat_type;
|
||||
};
|
||||
|
||||
/* GMIDB, Get_Manufacturer_Info */
|
||||
|
||||
#define PD_GMIDB_SIZE 2
|
||||
|
||||
#define PD_GMIDB_TARGET_PORT 0
|
||||
#define PD_GMIDB_TARGET_BATTRY 1
|
||||
|
||||
struct pd_get_manufacturer_info {
|
||||
uint8_t info_target;
|
||||
uint8_t info_ref;
|
||||
};
|
||||
|
||||
/* MIDB, Manufacturer_Info */
|
||||
|
||||
#define PD_MIDB_MIN_SIZE 4
|
||||
#define PD_MIDB_MAX_SIZE 26
|
||||
#define PD_MIDB_DYNAMIC_SIZE (PD_MIDB_MAX_SIZE-PD_MIDB_MIN_SIZE)
|
||||
|
||||
struct pd_manufacturer_info {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
uint8_t mfrs_string[PD_MIDB_DYNAMIC_SIZE];
|
||||
};
|
||||
|
||||
/* CCDB, Country_Codes */
|
||||
|
||||
#define PD_CCDB_MIN_SIZE 4
|
||||
#define PD_CCDB_MAX_SIZE MAX_EXTENDED_MSG_LEN
|
||||
#define PD_CCDB_DYNAMIC_SIZE (PD_CCDB_MAX_SIZE-PD_CCDB_MIN_SIZE)
|
||||
|
||||
struct pd_country_codes {
|
||||
uint16_t length;
|
||||
uint16_t country_code[1+PD_CCDB_DYNAMIC_SIZE/2];
|
||||
};
|
||||
|
||||
/* CIDB, country_info */
|
||||
|
||||
#define PD_CIDB_MIN_SIZE 4
|
||||
#define PD_CIDB_MAX_SIZE MAX_EXTENDED_MSG_LEN
|
||||
|
||||
#define PD_CIDB_DYNAMIC_SIZE (PD_CIDB_MAX_SIZE-PD_CIDB_MIN_SIZE)
|
||||
|
||||
struct pd_country_info {
|
||||
uint16_t country_code;
|
||||
uint16_t reserved;
|
||||
uint8_t country_special_data[PD_CIDB_DYNAMIC_SIZE];
|
||||
};
|
||||
|
||||
/* SDB, Status */
|
||||
|
||||
#define PD_SDB_SIZE 6
|
||||
|
||||
#define PD_STATUS_INPUT_EXT_POWER (1<<1)
|
||||
#define PD_STATUS_INPUT_EXT_POWER_FROM_AC (1<<2)
|
||||
#define PD_STATUS_INPUT_INT_POWER_BAT (1<<3)
|
||||
#define PD_STATUS_INPUT_INT_POWER_NOT_BAT (1<<4)
|
||||
|
||||
#define PD_STASUS_EVENT_OCP (1<<1)
|
||||
#define PD_STATUS_EVENT_OTP (1<<2)
|
||||
#define PD_STATUS_EVENT_OVP (1<<3)
|
||||
#define PD_STATUS_EVENT_CF_MODE (1<<4)
|
||||
|
||||
#define PD_STASUS_EVENT_READ_CLEAR (\
|
||||
PD_STASUS_EVENT_OCP|PD_STATUS_EVENT_OTP|PD_STATUS_EVENT_OVP)
|
||||
|
||||
#define PD_STASUS_EVENT_MASK (\
|
||||
PD_STASUS_EVENT_OCP|PD_STATUS_EVENT_OTP|PD_STATUS_EVENT_OVP|\
|
||||
PD_STATUS_EVENT_CF_MODE)
|
||||
|
||||
#define PD_STATUS_TEMP_PTF(raw) ((raw & 0x06) >> 1)
|
||||
#define PD_STATUS_TEMP_SET_PTF(val) ((val & 0x03) << 1)
|
||||
|
||||
struct pd_status {
|
||||
uint8_t internal_temp; /* 0 means no support */
|
||||
uint8_t present_input; /* bit filed */
|
||||
uint8_t present_battey_input; /* bit filed */
|
||||
uint8_t event_flags; /* bit filed */
|
||||
uint8_t temp_status; /* bit filed */
|
||||
uint8_t power_status; /* bit filed */
|
||||
};
|
||||
|
||||
/* PPSSDB, PPSStatus */
|
||||
|
||||
#define PD_PPSSDB_SIZE 4 /* PPS_Status */
|
||||
|
||||
#define PD_PPS_GET_OUTPUT_MV(raw) (raw*20)
|
||||
#define PD_PPS_GET_OUTPUT_MA(raw) (raw*50)
|
||||
|
||||
#define PD_PPS_SET_OUTPUT_MV(mv) (((mv) / 20) & 0xFFFF)
|
||||
#define PD_PPS_SET_OUTPUT_MA(ma) (((ma) / 50) & 0xFF)
|
||||
|
||||
#define PD_PPS_FLAGS_CFF (1 << 3)
|
||||
#define PD_PPS_FLGAS_PTF(raw) ((raw & 0x06) >> 1)
|
||||
|
||||
#define PD_PPS_FLAGS_SET_PTF(flags) ((flags & 0x03) << 1)
|
||||
|
||||
struct pd_pps_status_raw {
|
||||
uint16_t output_vol_raw; /* 0xffff means no support */
|
||||
uint8_t output_curr_raw; /* 0xff means no support */
|
||||
uint8_t real_time_flags;
|
||||
};
|
||||
|
||||
struct pd_pps_status {
|
||||
int output_mv;
|
||||
int output_ma;
|
||||
uint8_t real_time_flags;
|
||||
};
|
||||
#endif /* TCPM_PD_H_ */
|
||||
1477
drivers/usb/typec/mmi_tcpc/pd_core.c
Normal file
1477
drivers/usb/typec/mmi_tcpc/pd_core.c
Normal file
File diff suppressed because it is too large
Load diff
165
drivers/usb/typec/mmi_tcpc/pd_dbg_info.c
Normal file
165
drivers/usb/typec/mmi_tcpc/pd_dbg_info.c
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/clock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kthread.h>
|
||||
#include "inc/pd_dbg_info.h"
|
||||
|
||||
#ifdef CONFIG_PD_DBG_INFO
|
||||
|
||||
#define PD_INFO_BUF_SIZE (2048*256)
|
||||
#define MSG_POLLING_MS 20
|
||||
|
||||
#define OUT_BUF_MAX (128)
|
||||
static struct {
|
||||
int used;
|
||||
char buf[PD_INFO_BUF_SIZE + 1 + OUT_BUF_MAX];
|
||||
} pd_dbg_buffer[2];
|
||||
|
||||
static struct mutex buff_lock;
|
||||
static unsigned int using_buf;
|
||||
static wait_queue_head_t print_out_wait_que;
|
||||
static atomic_t pending_print_out;
|
||||
static atomic_t busy = ATOMIC_INIT(0);
|
||||
|
||||
void pd_dbg_info_lock(void)
|
||||
{
|
||||
atomic_inc(&busy);
|
||||
}
|
||||
|
||||
void pd_dbg_info_unlock(void)
|
||||
{
|
||||
atomic_dec_if_positive(&busy);
|
||||
}
|
||||
|
||||
static inline bool pd_dbg_print_out(void)
|
||||
{
|
||||
char temp;
|
||||
int used;
|
||||
unsigned int index, i;
|
||||
|
||||
mutex_lock(&buff_lock);
|
||||
index = using_buf;
|
||||
using_buf ^= 0x01; /* exchange buffer */
|
||||
mutex_unlock(&buff_lock);
|
||||
|
||||
used = pd_dbg_buffer[index].used;
|
||||
|
||||
if (used == 0)
|
||||
return false;
|
||||
|
||||
pd_dbg_buffer[index].buf[used] = '\0';
|
||||
|
||||
pr_info("///PD dbg info %ud\n", used);
|
||||
|
||||
for (i = 0; i < used; i += OUT_BUF_MAX) {
|
||||
temp = pd_dbg_buffer[index].buf[OUT_BUF_MAX + i];
|
||||
pd_dbg_buffer[index].buf[OUT_BUF_MAX + i] = '\0';
|
||||
|
||||
while (atomic_read(&busy))
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
pr_notice("%s", pd_dbg_buffer[index].buf + i);
|
||||
pd_dbg_buffer[index].buf[OUT_BUF_MAX + i] = temp;
|
||||
}
|
||||
|
||||
/* pr_info("PD dbg info///\n"); */
|
||||
pd_dbg_buffer[index].used = 0;
|
||||
msleep(MSG_POLLING_MS);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int print_out_thread_fn(void *data)
|
||||
{
|
||||
while (true) {
|
||||
wait_event(print_out_wait_que,
|
||||
atomic_read(&pending_print_out) ||
|
||||
kthread_should_stop());
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
do {
|
||||
atomic_dec_if_positive(&pending_print_out);
|
||||
} while (pd_dbg_print_out() && !kthread_should_stop());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pd_dbg_info(const char *fmt, ...)
|
||||
{
|
||||
unsigned int index;
|
||||
va_list args;
|
||||
int r;
|
||||
int used;
|
||||
u64 ts;
|
||||
unsigned long rem_usec;
|
||||
|
||||
ts = local_clock();
|
||||
rem_usec = do_div(ts, 1000000000) / 1000 / 1000;
|
||||
va_start(args, fmt);
|
||||
mutex_lock(&buff_lock);
|
||||
index = using_buf;
|
||||
used = pd_dbg_buffer[index].used;
|
||||
r = snprintf(pd_dbg_buffer[index].buf + used,
|
||||
PD_INFO_BUF_SIZE - used, "<%5lu.%03lu>",
|
||||
(unsigned long)ts, rem_usec);
|
||||
if (r > 0)
|
||||
used += r;
|
||||
r = vsnprintf(pd_dbg_buffer[index].buf + used,
|
||||
PD_INFO_BUF_SIZE - used, fmt, args);
|
||||
if (r > 0)
|
||||
used += r;
|
||||
|
||||
if (pd_dbg_buffer[index].used == 0) {
|
||||
atomic_inc(&pending_print_out);
|
||||
wake_up(&print_out_wait_que);
|
||||
}
|
||||
|
||||
pd_dbg_buffer[index].used = used;
|
||||
mutex_unlock(&buff_lock);
|
||||
va_end(args);
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(pd_dbg_info);
|
||||
|
||||
static struct task_struct *print_out_task;
|
||||
|
||||
int pd_dbg_info_init(void)
|
||||
{
|
||||
pr_info("%s\n", __func__);
|
||||
mutex_init(&buff_lock);
|
||||
init_waitqueue_head(&print_out_wait_que);
|
||||
atomic_set(&pending_print_out, 0);
|
||||
print_out_task = kthread_run(print_out_thread_fn, NULL, "pd_dbg_info");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pd_dbg_info_exit(void)
|
||||
{
|
||||
kthread_stop(print_out_task);
|
||||
mutex_destroy(&buff_lock);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("PD Debug Info Module");
|
||||
MODULE_AUTHOR("Patrick Chang <patrick_chang@richtek.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#endif /* CONFIG_PD_DBG_INFO */
|
||||
603
drivers/usb/typec/mmi_tcpc/pd_dpm_alt_mode_dc.c
Normal file
603
drivers/usb/typec/mmi_tcpc/pd_dpm_alt_mode_dc.c
Normal file
|
|
@ -0,0 +1,603 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* PD Device Policy Manager for Direct Charge
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/random.h>
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "pd_dpm_prv.h"
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
|
||||
#define RTDC_UVDM_EN_UNLOCK 0x2024
|
||||
#define RTDC_UVDM_RECV_EN_UNLOCK 0x4024
|
||||
#define RTDC_SVDM_PPS_AUTHORIZATION 0x10
|
||||
|
||||
#define RTDC_VALID_MODE 0x01
|
||||
#define RTDC_UVDM_EN_UNLOCK_SUCCESS 0x01
|
||||
|
||||
void crcbits(uint32_t data, uint32_t *crc, uint32_t *ppolynomial)
|
||||
{
|
||||
uint32_t i, newbit, newword, rl_crc;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
newbit = ((*crc >> 31) ^ ((data >> i) & 1)) & 1;
|
||||
if (newbit)
|
||||
newword = *ppolynomial;
|
||||
else
|
||||
newword = 0;
|
||||
rl_crc = (*crc << 1) | newbit;
|
||||
*crc = rl_crc ^ newword;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t crcwrap(uint32_t V)
|
||||
{
|
||||
uint32_t ret = 0, i, j, bit;
|
||||
|
||||
V = ~V;
|
||||
for (i = 0; i < 32; i++) {
|
||||
j = 31 - i;
|
||||
bit = (V >> i) & 1;
|
||||
ret |= bit << j;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t dc_get_random_code(void)
|
||||
{
|
||||
uint32_t num;
|
||||
|
||||
get_random_bytes(&num, sizeof(num));
|
||||
return num;
|
||||
}
|
||||
|
||||
static uint32_t dc_get_authorization_code(uint32_t data)
|
||||
{
|
||||
uint32_t dwpolynomial = 0x04C11DB6, dwCrc = 0xFFFFFFFF;
|
||||
|
||||
crcbits(data, &dwCrc, &dwpolynomial);
|
||||
dwCrc = crcwrap(dwCrc);
|
||||
return dwCrc;
|
||||
}
|
||||
|
||||
static inline bool dc_dfp_send_en_unlock(struct pd_port *pd_port,
|
||||
uint32_t cmd, uint32_t data0, uint32_t data1)
|
||||
{
|
||||
pd_port->uvdm_cnt = 3;
|
||||
pd_port->uvdm_wait_resp = true;
|
||||
|
||||
pd_port->uvdm_data[0] = PD_UVDM_HDR(USB_VID_DIRECTCHARGE, cmd);
|
||||
pd_port->uvdm_data[1] = data0;
|
||||
pd_port->uvdm_data[2] = data1;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
if (pd_port->pe_data.dc_pps_mode) {
|
||||
pd_port->uvdm_data[0] = VDO_S(
|
||||
USB_VID_DIRECTCHARGE,
|
||||
SVDM_REV20,
|
||||
CMDT_INIT,
|
||||
RTDC_SVDM_PPS_AUTHORIZATION,
|
||||
0);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
return pd_put_tcp_vdm_event(pd_port, TCP_DPM_EVT_UVDM);
|
||||
}
|
||||
|
||||
enum pd_dc_dfp_state {
|
||||
DC_DFP_NONE = 0,
|
||||
DC_DFP_DISCOVER_ID,
|
||||
DC_DFP_DISCOVER_SVIDS,
|
||||
DC_DFP_DISCOVER_MODES,
|
||||
DC_DFP_ENTER_MODE,
|
||||
DC_DFP_EN_UNLOCK1,
|
||||
DC_DFP_EN_UNLOCK2,
|
||||
DC_DFP_OPERATION,
|
||||
|
||||
#ifdef RTDC_TA_EMULATE
|
||||
DC_UFP_T0,
|
||||
DC_UFP_T1,
|
||||
DC_UFP_T2,
|
||||
#endif
|
||||
|
||||
DC_DFP_STATE_NR,
|
||||
|
||||
DC_DFP_ERR = 0X10,
|
||||
|
||||
DC_DFP_ERR_DISCOVER_ID_TYPE,
|
||||
DC_DFP_ERR_DISCOVER_ID_NAK_TIMEOUT,
|
||||
|
||||
DC_DFP_ERR_DISCOVER_SVID_DC_SID,
|
||||
DC_DFP_ERR_DISCOVER_SVID_NAK_TIMEOUT,
|
||||
|
||||
DC_DFP_ERR_DISCOVER_CABLE,
|
||||
|
||||
DC_DFP_ERR_DISCOVER_MODE_DC_SID,
|
||||
DC_DFP_ERR_DISCOVER_MODE_CAP,
|
||||
DC_DFP_ERR_DISCOVER_MODE_NAK_TIMEROUT,
|
||||
|
||||
DC_DFP_ERR_ENTER_MODE_DC_SID,
|
||||
DC_DFP_ERR_ENTER_MODE_NAK_TIMEOUT,
|
||||
|
||||
DC_DFP_ERR_EXIT_MODE_DC_SID,
|
||||
DC_DFP_ERR_EXIT_MODE_NAK_TIMEOUT,
|
||||
|
||||
DC_DFP_ERR_EN_UNLOCK1_FAILED,
|
||||
DC_DFP_ERR_EN_UNLOCK1_NAK_TIMEOUT,
|
||||
|
||||
DC_DFP_ERR_EN_UNLOCK2_FAILED,
|
||||
DC_DFP_ERR_EN_UNLOCK2_NAK_TIMEOUT,
|
||||
|
||||
DC_DFP_ERR_PD_REV30,
|
||||
};
|
||||
|
||||
#if DC_DBG_ENABLE
|
||||
static const char * const dc_dfp_state_name[] = {
|
||||
"dc_dfp_none",
|
||||
"dc_dfp_discover_id",
|
||||
"dc_dfp_discover_svids",
|
||||
"dc_dfp_discover_modes",
|
||||
"dc_dfp_enter_mode",
|
||||
"dc_dfp_en_unlock1",
|
||||
"dc_dfp_en_unlock2",
|
||||
"dc_dfp_operation",
|
||||
|
||||
#ifdef RTDC_TA_EMULATE
|
||||
"dc1",
|
||||
"dc2",
|
||||
"dc3",
|
||||
#endif
|
||||
|
||||
};
|
||||
#endif /* DC_DBG_ENABLE */
|
||||
|
||||
void dc_dfp_set_state(struct pd_port *pd_port, uint8_t state)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
pd_port->dc_dfp_state = state;
|
||||
|
||||
if (pd_port->dc_dfp_state < DC_DFP_STATE_NR)
|
||||
DC_DBG("%s\n", dc_dfp_state_name[state]);
|
||||
else
|
||||
DC_DBG("dc_dfp_stop (%d)\n", state);
|
||||
}
|
||||
|
||||
bool dc_dfp_start_en_unlock1(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t rn_code[2];
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
rn_code[0] = dc_get_random_code();
|
||||
rn_code[1] = dc_get_random_code();
|
||||
pd_port->dc_pass_code = dc_get_authorization_code(
|
||||
(rn_code[0] & 0xffff) | (rn_code[1] & 0xffff0000));
|
||||
|
||||
DC_DBG("en_unlock1: 0x%x, 0x%x\n", rn_code[0], rn_code[1]);
|
||||
|
||||
dc_dfp_send_en_unlock(
|
||||
pd_port, RTDC_UVDM_EN_UNLOCK, rn_code[0], rn_code[1]);
|
||||
|
||||
dc_dfp_set_state(pd_port, DC_DFP_EN_UNLOCK1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define SVDM_CMD_STATE_MASK(raw) (raw & (0x80df))
|
||||
#define SVDM_CMD_STATE(cmd, cmd_type) \
|
||||
((1 << 15) | (cmd & 0x1f) | ((cmd_type & 0x03) << 6))
|
||||
|
||||
bool dc_dfp_verify_en_unlock1(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t resp_cmd, expect_resp;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
expect_resp = RTDC_UVDM_RECV_EN_UNLOCK;
|
||||
resp_cmd = PD_UVDM_HDR_CMD(pd_port->uvdm_data[0]);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
if (pd_port->pe_data.dc_pps_mode) {
|
||||
resp_cmd = SVDM_CMD_STATE_MASK(pd_port->uvdm_data[0]);
|
||||
expect_resp = SVDM_CMD_STATE(
|
||||
RTDC_SVDM_PPS_AUTHORIZATION, CMDT_RSP_ACK);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
if (resp_cmd != expect_resp) {
|
||||
DC_INFO("en_unlock1: unexpect resp (0x%x)\n", resp_cmd);
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_EN_UNLOCK1_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pd_port->dc_pass_code != pd_port->uvdm_data[1]) {
|
||||
DC_INFO("en_unlock1: pass wrong 0x%x 0x%x\n",
|
||||
pd_port->dc_pass_code, pd_port->uvdm_data[1]);
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_EN_UNLOCK1_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool dc_dfp_start_en_unlock2(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t rn_code = dc_get_random_code();
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
pd_port->dc_pass_code =
|
||||
dc_get_authorization_code(pd_port->uvdm_data[2]);
|
||||
|
||||
DC_DBG("en_unlock2: 0x%x, 0x%x\n", pd_port->dc_pass_code, rn_code);
|
||||
|
||||
dc_dfp_send_en_unlock(pd_port, RTDC_UVDM_EN_UNLOCK,
|
||||
pd_port->dc_pass_code, rn_code);
|
||||
|
||||
dc_dfp_set_state(pd_port, DC_DFP_EN_UNLOCK2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_dfp_verify_en_unlock2(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t resp_cmd, expect_resp;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
expect_resp = RTDC_UVDM_RECV_EN_UNLOCK;
|
||||
resp_cmd = PD_UVDM_HDR_CMD(pd_port->uvdm_data[0]);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
if (pd_port->pe_data.dc_pps_mode) {
|
||||
resp_cmd = SVDM_CMD_STATE_MASK(pd_port->uvdm_data[0]);
|
||||
expect_resp = SVDM_CMD_STATE(
|
||||
RTDC_SVDM_PPS_AUTHORIZATION, CMDT_RSP_ACK);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
if (resp_cmd != expect_resp) {
|
||||
DC_INFO("en_unlock2: unexpect resp (0x%x)\n", resp_cmd);
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_EN_UNLOCK2_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pd_port->uvdm_data[1] != RTDC_UVDM_EN_UNLOCK_SUCCESS) {
|
||||
DC_INFO("en_unlock2: failed\n");
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_EN_UNLOCK2_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_dfp_notify_pe_startup(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data)
|
||||
{
|
||||
if (!(pd_port->id_vdos[0] & PD_IDH_MODAL_SUPPORT))
|
||||
return false;
|
||||
|
||||
if (pd_port->dpm_caps & DPM_CAP_ATTEMP_ENTER_DC_MODE)
|
||||
dc_dfp_set_state(pd_port, DC_DFP_DISCOVER_ID);
|
||||
|
||||
#ifdef RTDC_TA_EMULATE
|
||||
dc_dfp_set_state(pd_port, DC_UFP_T0);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int dc_dfp_notify_pe_ready(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
#ifdef RTDC_TA_EMULATE
|
||||
if (pd_port->data_role == PD_ROLE_DFP && svid_data->exist) {
|
||||
pd_put_tcp_pd_event(pd_port, TCP_DPM_EVT_DR_SWAP_AS_UFP);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pd_port->data_role != PD_ROLE_DFP)
|
||||
return 0;
|
||||
|
||||
if (pd_port->dc_dfp_state != DC_DFP_DISCOVER_MODES)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_USB_PD_RTDC_CHECK_CABLE
|
||||
if (!pd_port->pe_data.power_cable_present) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_DISCOVER_CABLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pd_get_cable_curr_lvl(pd_port) != CABLE_CURR_5A) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_DISCOVER_CABLE);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_RTDC_CHECK_CABLE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
/* If TA support pd revision30, using standard PPS flow */
|
||||
if (pd_check_rev30(pd_port)) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_PD_REV30);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pd_is_source_support_apdo(pd_port)) {
|
||||
DC_INFO("pps_mode\n");
|
||||
pd_port->pe_data.dc_pps_mode = true;
|
||||
return dc_dfp_start_en_unlock1(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
pd_port->mode_svid = USB_VID_DIRECTCHARGE;
|
||||
pd_put_tcp_vdm_event(pd_port, TCP_DPM_EVT_DISCOVER_MODES);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool dc_dfp_notify_discover_id(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack)
|
||||
{
|
||||
if (pd_port->dc_dfp_state != DC_DFP_DISCOVER_ID)
|
||||
return true;
|
||||
|
||||
if (!ack) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_DISCOVER_ID_NAK_TIMEOUT);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO: Check device ID or Type */
|
||||
|
||||
dc_dfp_set_state(pd_port, DC_DFP_DISCOVER_SVIDS);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_dfp_notify_discover_svid(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack)
|
||||
{
|
||||
if (pd_port->dc_dfp_state != DC_DFP_DISCOVER_SVIDS)
|
||||
return false;
|
||||
|
||||
if (!ack) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_DISCOVER_SVID_NAK_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!svid_data->exist) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_DISCOVER_SVID_DC_SID);
|
||||
return false;
|
||||
}
|
||||
|
||||
dpm_reaction_set(pd_port, DPM_REACTION_DISCOVER_CABLE_FLOW);
|
||||
dc_dfp_set_state(pd_port, DC_DFP_DISCOVER_MODES);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_dfp_notify_discover_modes(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack)
|
||||
{
|
||||
if (pd_port->dc_dfp_state != DC_DFP_DISCOVER_MODES)
|
||||
return false;
|
||||
|
||||
if (!ack) {
|
||||
dc_dfp_set_state(pd_port,
|
||||
DC_DFP_ERR_DISCOVER_MODE_NAK_TIMEROUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (svid_data->remote_mode.mode_cnt == 0) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_DISCOVER_MODE_DC_SID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (svid_data->remote_mode.mode_vdo[0] != RTDC_VALID_MODE) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_DISCOVER_MODE_CAP);
|
||||
return false;
|
||||
}
|
||||
|
||||
pd_port->mode_obj_pos = 1;
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ENTER_MODE);
|
||||
pd_put_tcp_vdm_event(pd_port, TCP_DPM_EVT_ENTER_MODE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_dfp_notify_enter_mode(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, uint8_t ops, bool ack)
|
||||
{
|
||||
if (pd_port->dc_dfp_state != DC_DFP_ENTER_MODE)
|
||||
return true;
|
||||
|
||||
if (!ack) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_ENTER_MODE_NAK_TIMEOUT);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (svid_data->active_mode == 0) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_ENTER_MODE_DC_SID);
|
||||
return false;
|
||||
}
|
||||
|
||||
return dc_dfp_start_en_unlock1(pd_port);
|
||||
}
|
||||
|
||||
bool dc_dfp_notify_exit_mode(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, uint8_t ops)
|
||||
{
|
||||
if (pd_port->dc_dfp_state <= DC_DFP_ENTER_MODE)
|
||||
return false;
|
||||
|
||||
if (svid_data->svid != USB_VID_DIRECTCHARGE)
|
||||
return false;
|
||||
|
||||
dc_dfp_set_state(pd_port, DC_DFP_NONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool dc_dfp_notify_en_unlock1(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack)
|
||||
{
|
||||
if (pd_port->dc_dfp_state != DC_DFP_EN_UNLOCK1)
|
||||
return false;
|
||||
|
||||
if (!ack) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_EN_UNLOCK1_NAK_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dc_dfp_verify_en_unlock1(pd_port))
|
||||
return false;
|
||||
|
||||
return dc_dfp_start_en_unlock2(pd_port);
|
||||
}
|
||||
|
||||
static inline bool dc_dfp_notify_en_unlock2(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack)
|
||||
{
|
||||
if (pd_port->dc_dfp_state != DC_DFP_EN_UNLOCK2)
|
||||
return false;
|
||||
|
||||
if (!ack) {
|
||||
dc_dfp_set_state(pd_port, DC_DFP_ERR_EN_UNLOCK2_NAK_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dc_dfp_verify_en_unlock2(pd_port))
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
#ifdef CONFIG_USB_PD_REV30_SYNC_SPEC_REV
|
||||
if (pd_port->pe_data.dc_pps_mode)
|
||||
pd_port->pd_revision[0] = PD_REV30;
|
||||
#endif /* CONFIG_USB_PD_REV30_SYNC_SPEC_REV */
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
dc_dfp_set_state(pd_port, DC_DFP_OPERATION);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
/* PPS shoult not use en_unlock to notify system */
|
||||
if (pd_port->pe_data.dc_pps_mode)
|
||||
return true;
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
tcpci_dc_notify_en_unlock(pd_port->tcpc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_dfp_notify_uvdm(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack)
|
||||
{
|
||||
switch (pd_port->dc_dfp_state) {
|
||||
case DC_DFP_EN_UNLOCK1:
|
||||
dc_dfp_notify_en_unlock1(pd_port, svid_data, ack);
|
||||
break;
|
||||
|
||||
case DC_DFP_EN_UNLOCK2:
|
||||
dc_dfp_notify_en_unlock2(pd_port, svid_data, ack);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_ufp_notify_uvdm(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data)
|
||||
{
|
||||
#ifdef RTDC_TA_EMULATE
|
||||
uint32_t reply_cmd[3];
|
||||
uint32_t recv_code[2], rn_code, pass_code;
|
||||
|
||||
reply_cmd[0] = PD_UVDM_HDR(0x29cf, RTDC_UVDM_EN_UNLOCK);
|
||||
uint32_t cmd = PD_UVDM_HDR_CMD(pd_port->uvdm_data[0]);
|
||||
|
||||
if (cmd != RTDC_UVDM_EN_UNLOCK) {
|
||||
DC_INFO("What!?");
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (pd_port->dc_dfp_state) {
|
||||
case DC_UFP_T0:
|
||||
{
|
||||
recv_code[0] = pd_port->uvdm_data[1];
|
||||
recv_code[1] = pd_port->uvdm_data[2];
|
||||
DC_INFO("T0: recv_code: 0x%x, 0x%x\n",
|
||||
recv_code[0], recv_code[1]);
|
||||
|
||||
pass_code = dc_get_authorization_code(
|
||||
(recv_code[0] & 0xffff) |
|
||||
(recv_code[1] & 0xffff0000));
|
||||
|
||||
rn_code = dc_get_random_code();
|
||||
|
||||
pd_port->dc_pass_code =
|
||||
dc_get_authorization_code(rn_code);
|
||||
|
||||
DC_INFO("T0: reply: 0x%x, 0x%x\n",
|
||||
rn_code, pd_port->dc_pass_code);
|
||||
|
||||
reply_cmd[1] = pass_code;
|
||||
reply_cmd[2] = rn_code;
|
||||
|
||||
pd_reply_custom_vdm(pd_port, TCPC_TX_SOP, 3, reply_cmd);
|
||||
dc_dfp_set_state(pd_port, DC_UFP_T1);
|
||||
}
|
||||
break;
|
||||
|
||||
case DC_UFP_T1:
|
||||
{
|
||||
recv_code[0] = pd_port->uvdm_data[1];
|
||||
recv_code[1] = pd_port->uvdm_data[2];
|
||||
DC_INFO("T1: recv_code: 0x%x, 0x%x\n",
|
||||
recv_code[0], recv_code[1]);
|
||||
|
||||
if (recv_code[0] != pd_port->dc_pass_code) {
|
||||
DC_INFO("T1: pass_code error\n");
|
||||
reply_cmd[1] = 0;
|
||||
} else {
|
||||
DC_INFO("T1: pass_code success\n");
|
||||
reply_cmd[1] = 1;
|
||||
}
|
||||
|
||||
reply_cmd[2] = dc_get_random_code();
|
||||
pd_reply_custom_vdm(pd_port, TCPC_TX_SOP, 3, reply_cmd);
|
||||
dc_dfp_set_state(pd_port, DC_UFP_T2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* RTDC_TA_EMULATE */
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_reset_state(struct pd_port *pd_port, struct svdm_svid_data *svid_data)
|
||||
{
|
||||
dc_dfp_set_state(pd_port, DC_DFP_NONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dc_parse_svid_data(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data)
|
||||
{
|
||||
svid_data->local_mode.mode_cnt = 1;
|
||||
svid_data->local_mode.mode_vdo[0] = 0x00;
|
||||
pd_port->dpm_caps |= DPM_CAP_ATTEMP_ENTER_DC_MODE;
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
1112
drivers/usb/typec/mmi_tcpc/pd_dpm_alt_mode_dp.c
Normal file
1112
drivers/usb/typec/mmi_tcpc/pd_dpm_alt_mode_dp.c
Normal file
File diff suppressed because it is too large
Load diff
2342
drivers/usb/typec/mmi_tcpc/pd_dpm_core.c
Normal file
2342
drivers/usb/typec/mmi_tcpc/pd_dpm_core.c
Normal file
File diff suppressed because it is too large
Load diff
389
drivers/usb/typec/mmi_tcpc/pd_dpm_pdo_select.c
Normal file
389
drivers/usb/typec/mmi_tcpc/pd_dpm_pdo_select.c
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Core Driver
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_dpm_pdo_select.h"
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
|
||||
struct dpm_select_info_t {
|
||||
uint8_t pos;
|
||||
int max_uw;
|
||||
int cur_mv;
|
||||
uint8_t policy;
|
||||
};
|
||||
|
||||
static inline void dpm_extract_apdo_info(
|
||||
uint32_t pdo, struct dpm_pdo_info_t *info)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
switch (APDO_TYPE(pdo)) {
|
||||
case APDO_TYPE_PPS:
|
||||
info->apdo_type = DPM_APDO_TYPE_PPS;
|
||||
|
||||
if (pdo & APDO_PPS_CURR_FOLDBACK)
|
||||
info->apdo_type |= DPM_APDO_TYPE_PPS_CF;
|
||||
|
||||
info->pwr_limit = APDO_PPS_EXTRACT_PWR_LIMIT(pdo);
|
||||
info->ma = APDO_PPS_EXTRACT_CURR(pdo);
|
||||
info->vmin = APDO_PPS_EXTRACT_MIN_VOLT(pdo);
|
||||
info->vmax = APDO_PPS_EXTRACT_MAX_VOLT(pdo);
|
||||
info->uw = info->ma * info->vmax;
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
info->type = TCPM_POWER_CAP_VAL_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
void dpm_extract_pdo_info(
|
||||
uint32_t pdo, struct dpm_pdo_info_t *info)
|
||||
{
|
||||
memset(info, 0, sizeof(struct dpm_pdo_info_t));
|
||||
|
||||
info->type = PDO_TYPE_VAL(pdo);
|
||||
|
||||
switch (PDO_TYPE(pdo)) {
|
||||
case PDO_TYPE_FIXED:
|
||||
info->ma = PDO_FIXED_EXTRACT_CURR(pdo);
|
||||
info->vmax = info->vmin = PDO_FIXED_EXTRACT_VOLT(pdo);
|
||||
info->uw = info->ma * info->vmax;
|
||||
break;
|
||||
case PDO_TYPE_VARIABLE:
|
||||
info->ma = PDO_VAR_EXTRACT_CURR(pdo);
|
||||
info->vmin = PDO_VAR_EXTRACT_MIN_VOLT(pdo);
|
||||
info->vmax = PDO_VAR_EXTRACT_MAX_VOLT(pdo);
|
||||
info->uw = info->ma * info->vmax;
|
||||
break;
|
||||
|
||||
case PDO_TYPE_BATTERY:
|
||||
info->uw = PDO_BATT_EXTRACT_OP_POWER(pdo) * 1000;
|
||||
info->vmin = PDO_BATT_EXTRACT_MIN_VOLT(pdo);
|
||||
info->vmax = PDO_BATT_EXTRACT_MAX_VOLT(pdo);
|
||||
info->ma = info->uw / info->vmin;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
case PDO_TYPE_APDO:
|
||||
dpm_extract_apdo_info(pdo, info);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a < b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
static inline int dpm_calc_src_cap_power_uw(
|
||||
struct dpm_pdo_info_t *source, struct dpm_pdo_info_t *sink)
|
||||
{
|
||||
int uw, ma;
|
||||
|
||||
if (source->type == DPM_PDO_TYPE_BAT) {
|
||||
uw = source->uw;
|
||||
|
||||
if (sink->type == DPM_PDO_TYPE_BAT)
|
||||
uw = MIN(uw, sink->uw);
|
||||
} else {
|
||||
ma = source->ma;
|
||||
|
||||
if (sink->type != DPM_PDO_TYPE_BAT)
|
||||
ma = MIN(ma, sink->ma);
|
||||
|
||||
uw = ma * source->vmax;
|
||||
}
|
||||
|
||||
return uw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select PDO from VSafe5V
|
||||
*/
|
||||
|
||||
static bool dpm_select_pdo_from_vsafe5v(
|
||||
struct dpm_select_info_t *select_info,
|
||||
struct dpm_pdo_info_t *sink, struct dpm_pdo_info_t *source)
|
||||
{
|
||||
int uw;
|
||||
|
||||
if ((sink->vmax != TCPC_VBUS_SINK_5V) ||
|
||||
(sink->vmin != TCPC_VBUS_SINK_5V) ||
|
||||
(source->vmax != TCPC_VBUS_SINK_5V) ||
|
||||
(source->vmin != TCPC_VBUS_SINK_5V))
|
||||
return false;
|
||||
|
||||
uw = dpm_calc_src_cap_power_uw(source, sink);
|
||||
if (uw > select_info->max_uw) {
|
||||
select_info->max_uw = uw;
|
||||
select_info->cur_mv = source->vmax;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select PDO from Direct Charge
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
static bool dpm_select_pdo_from_direct_charge(
|
||||
struct dpm_select_info_t *select_info,
|
||||
struct dpm_pdo_info_t *sink, struct dpm_pdo_info_t *source)
|
||||
{
|
||||
int uw;
|
||||
|
||||
if (sink->type != DPM_PDO_TYPE_VAR
|
||||
|| source->type != DPM_PDO_TYPE_VAR)
|
||||
return false;
|
||||
|
||||
if (source->vmin >= TCPC_VBUS_SINK_5V)
|
||||
return false;
|
||||
|
||||
if (sink->vmax < source->vmax)
|
||||
return false;
|
||||
|
||||
if (sink->vmin > source->vmin)
|
||||
return false;
|
||||
|
||||
uw = dpm_calc_src_cap_power_uw(source, sink);
|
||||
if (uw > select_info->max_uw) {
|
||||
select_info->max_uw = uw;
|
||||
select_info->cur_mv = source->vmax;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
|
||||
/*
|
||||
* Select PDO from Custom
|
||||
*/
|
||||
|
||||
static bool dpm_select_pdo_from_custom(
|
||||
struct dpm_select_info_t *select_info,
|
||||
struct dpm_pdo_info_t *sink, struct dpm_pdo_info_t *source)
|
||||
{
|
||||
/* TODO */
|
||||
return dpm_select_pdo_from_vsafe5v(select_info, sink, source);
|
||||
}
|
||||
|
||||
/*
|
||||
* Select PDO from Max Power
|
||||
*/
|
||||
|
||||
static inline bool dpm_is_valid_pdo_pair(struct dpm_pdo_info_t *sink,
|
||||
struct dpm_pdo_info_t *source, uint32_t policy)
|
||||
{
|
||||
if (sink->vmax < source->vmax)
|
||||
return false;
|
||||
|
||||
if (sink->vmin > source->vmin)
|
||||
return false;
|
||||
|
||||
if (policy & DPM_CHARGING_POLICY_IGNORE_MISMATCH_CURR)
|
||||
return true;
|
||||
|
||||
return sink->ma <= source->ma;
|
||||
}
|
||||
|
||||
static bool dpm_select_pdo_from_max_power(
|
||||
struct dpm_select_info_t *select_info,
|
||||
struct dpm_pdo_info_t *sink, struct dpm_pdo_info_t *source)
|
||||
{
|
||||
bool overload;
|
||||
int uw;
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
/* Variable for direct charge only */
|
||||
if ((sink->type == DPM_PDO_TYPE_VAR) && (sink->vmin < 5000))
|
||||
return false;
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
if (sink->type == DPM_PDO_TYPE_APDO)
|
||||
return false;
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
if (!dpm_is_valid_pdo_pair(sink, source, select_info->policy))
|
||||
return false;
|
||||
|
||||
uw = dpm_calc_src_cap_power_uw(source, sink);
|
||||
|
||||
overload = uw > select_info->max_uw;
|
||||
|
||||
if ((!overload) && (uw == select_info->max_uw)) {
|
||||
if (select_info->policy &
|
||||
DPM_CHARGING_POLICY_PREFER_LOW_VOLTAGE)
|
||||
overload = (source->vmax < select_info->cur_mv);
|
||||
else if (select_info->policy &
|
||||
DPM_CHARGING_POLICY_PREFER_HIGH_VOLTAGE)
|
||||
overload = (source->vmax > select_info->cur_mv);
|
||||
}
|
||||
|
||||
if (overload) {
|
||||
select_info->max_uw = uw;
|
||||
select_info->cur_mv = source->vmax;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select PDO from PPS
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
static bool dpm_select_pdo_from_pps(
|
||||
struct dpm_select_info_t *select_info,
|
||||
struct dpm_pdo_info_t *sink, struct dpm_pdo_info_t *source)
|
||||
{
|
||||
bool overload;
|
||||
int uw, diff_mv;
|
||||
const int tolerance = 300; /* 5900 * 5% */
|
||||
|
||||
if (sink->type != DPM_PDO_TYPE_APDO ||
|
||||
source->type != DPM_PDO_TYPE_APDO)
|
||||
return false;
|
||||
|
||||
if (!(source->apdo_type & DPM_APDO_TYPE_PPS))
|
||||
return false;
|
||||
|
||||
if (sink->vmax > source->vmax)
|
||||
return false;
|
||||
|
||||
if (sink->vmin < source->vmin)
|
||||
return false;
|
||||
|
||||
if (!(select_info->policy & DPM_CHARGING_POLICY_IGNORE_MISMATCH_CURR)) {
|
||||
if (source->ma < sink->ma)
|
||||
return false;
|
||||
}
|
||||
|
||||
uw = sink->vmax * source->ma;
|
||||
diff_mv = source->vmax - sink->vmax;
|
||||
|
||||
if (uw > select_info->max_uw)
|
||||
overload = true;
|
||||
else if (uw < select_info->max_uw)
|
||||
overload = false;
|
||||
else if ((select_info->cur_mv < tolerance) && (diff_mv > tolerance))
|
||||
overload = true;
|
||||
else if (diff_mv < select_info->cur_mv)
|
||||
overload = true;
|
||||
else
|
||||
overload = false;
|
||||
|
||||
if (overload) {
|
||||
select_info->max_uw = uw;
|
||||
select_info->cur_mv = diff_mv;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
/*
|
||||
* Select PDO from defined rule ...
|
||||
*/
|
||||
|
||||
typedef bool (*dpm_select_pdo_fun)(
|
||||
struct dpm_select_info_t *select_info,
|
||||
struct dpm_pdo_info_t *sink, struct dpm_pdo_info_t *source);
|
||||
|
||||
bool dpm_find_match_req_info(struct dpm_rdo_info_t *req_info,
|
||||
struct dpm_pdo_info_t *sink, int cnt, uint32_t *src_pdos,
|
||||
int min_uw, uint32_t policy)
|
||||
{
|
||||
int i;
|
||||
struct dpm_select_info_t select;
|
||||
struct dpm_pdo_info_t source;
|
||||
dpm_select_pdo_fun select_pdo_fun;
|
||||
|
||||
select.pos = 0;
|
||||
select.cur_mv = 0;
|
||||
select.max_uw = min_uw;
|
||||
select.policy = policy;
|
||||
|
||||
switch (policy & DPM_CHARGING_POLICY_MASK) {
|
||||
case DPM_CHARGING_POLICY_MAX_POWER:
|
||||
select_pdo_fun = dpm_select_pdo_from_max_power;
|
||||
break;
|
||||
|
||||
case DPM_CHARGING_POLICY_CUSTOM:
|
||||
select_pdo_fun = dpm_select_pdo_from_custom;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
case DPM_CHARGING_POLICY_DIRECT_CHARGE:
|
||||
select_pdo_fun = dpm_select_pdo_from_direct_charge;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
case DPM_CHARGING_POLICY_PPS:
|
||||
select_pdo_fun = dpm_select_pdo_from_pps;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
default: /* DPM_CHARGING_POLICY_VSAFE5V */
|
||||
select_pdo_fun = dpm_select_pdo_from_vsafe5v;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
dpm_extract_pdo_info(src_pdos[i], &source);
|
||||
|
||||
if (select_pdo_fun(&select, sink, &source))
|
||||
select.pos = i+1;
|
||||
}
|
||||
|
||||
if (select.pos > 0) {
|
||||
dpm_extract_pdo_info(src_pdos[select.pos-1], &source);
|
||||
|
||||
req_info->pos = select.pos;
|
||||
req_info->type = source.type;
|
||||
req_info->vmax = source.vmax;
|
||||
req_info->vmin = source.vmin;
|
||||
|
||||
if (sink->type == DPM_PDO_TYPE_BAT)
|
||||
req_info->mismatch = select.max_uw < sink->uw;
|
||||
else
|
||||
req_info->mismatch = source.ma < sink->ma;
|
||||
|
||||
if (source.type == DPM_PDO_TYPE_BAT) {
|
||||
req_info->max_uw = sink->uw;
|
||||
req_info->oper_uw = select.max_uw;
|
||||
} else {
|
||||
req_info->max_ma = sink->ma;
|
||||
req_info->oper_ma = MIN(sink->ma, source.ma);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
if (source.type == DPM_PDO_TYPE_APDO) {
|
||||
req_info->vmax = sink->vmax;
|
||||
req_info->vmin = sink->vmin;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
290
drivers/usb/typec/mmi_tcpc/pd_dpm_prv.h
Normal file
290
drivers/usb/typec/mmi_tcpc/pd_dpm_prv.h
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef PD_DPM_PRV_H_INCLUDED
|
||||
#define PD_DPM_PRV_H_INCLUDED
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#define SVID_DATA_LOCAL_MODE(svid_data, n) \
|
||||
(svid_data->local_mode.mode_vdo[n])
|
||||
|
||||
#define SVID_DATA_REMOTE_MODE(svid_data, n) \
|
||||
(svid_data->remote_mode.mode_vdo[n])
|
||||
|
||||
#define SVID_DATA_DFP_GET_ACTIVE_MODE(svid_data)\
|
||||
SVID_DATA_REMOTE_MODE(svid_data, svid_data->active_mode-1)
|
||||
|
||||
#define SVID_DATA_UFP_GET_ACTIVE_MODE(svid_data)\
|
||||
SVID_DATA_LOCAL_MODE(svid_data, svid_data->active_mode-1)
|
||||
|
||||
extern int dpm_check_supported_modes(void);
|
||||
|
||||
struct svdm_svid_ops {
|
||||
const char *name;
|
||||
uint16_t svid;
|
||||
|
||||
bool (*dfp_inform_id)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
bool (*dfp_inform_svids)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
bool (*dfp_inform_modes)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
|
||||
bool (*dfp_inform_enter_mode)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, uint8_t ops, bool ack);
|
||||
bool (*dfp_inform_exit_mode)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, uint8_t ops);
|
||||
|
||||
bool (*dfp_inform_attention)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
|
||||
void (*ufp_request_enter_mode)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, uint8_t ops);
|
||||
void (*ufp_request_exit_mode)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, uint8_t ops);
|
||||
|
||||
bool (*notify_pe_startup)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
int (*notify_pe_ready)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
bool (*notify_pe_shutdown)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
bool (*dfp_notify_uvdm)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack);
|
||||
|
||||
bool (*ufp_notify_uvdm)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
#endif
|
||||
|
||||
bool (*reset_state)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
|
||||
bool (*parse_svid_data)(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data);
|
||||
};
|
||||
|
||||
static inline bool dpm_check_data_msg_event(
|
||||
struct pd_port *pd_port, uint8_t msg)
|
||||
{
|
||||
return pd_event_data_msg_match(
|
||||
pd_get_curr_pd_event(pd_port), msg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
static inline bool dpm_check_ext_msg_event(
|
||||
struct pd_port *pd_port, uint8_t msg)
|
||||
{
|
||||
return pd_event_ext_msg_match(
|
||||
pd_get_curr_pd_event(pd_port), msg);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
static inline uint8_t dpm_vdm_get_ops(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_port->curr_vdm_ops;
|
||||
}
|
||||
|
||||
static inline uint16_t dpm_vdm_get_svid(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_port->curr_vdm_svid;
|
||||
}
|
||||
|
||||
static inline int dpm_vdm_reply_svdm_request(
|
||||
struct pd_port *pd_port, bool ack)
|
||||
{
|
||||
return pd_reply_svdm_request_simply(
|
||||
pd_port, ack ? CMDT_RSP_ACK : CMDT_RSP_NAK);
|
||||
}
|
||||
|
||||
static inline int dpm_vdm_reply_svdm_nak(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_reply_svdm_request_simply(pd_port, CMDT_RSP_NAK);
|
||||
}
|
||||
|
||||
enum {
|
||||
GOOD_PW_NONE = 0, /* both no GP */
|
||||
GOOD_PW_PARTNER, /* partner has GP */
|
||||
GOOD_PW_LOCAL, /* local has GP */
|
||||
GOOD_PW_BOTH, /* both have GPs */
|
||||
};
|
||||
|
||||
int dpm_check_good_power(struct pd_port *pd_port);
|
||||
|
||||
/* SVDM */
|
||||
|
||||
extern struct svdm_svid_data *
|
||||
dpm_get_svdm_svid_data(struct pd_port *pd_port, uint16_t svid);
|
||||
|
||||
extern bool svdm_reset_state(struct pd_port *pd_port);
|
||||
extern bool svdm_notify_pe_startup(struct pd_port *pd_port);
|
||||
|
||||
static inline int svdm_notify_pe_ready(struct pd_port *pd_port)
|
||||
{
|
||||
int i, ret;
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
for (i = 0; i < pd_port->svid_data_cnt; i++) {
|
||||
svid_data = &pd_port->svid_data[i];
|
||||
if (svid_data->ops && svid_data->ops->notify_pe_ready) {
|
||||
ret = svid_data->ops->notify_pe_ready(
|
||||
pd_port, svid_data);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool svdm_notify_pe_shutdown(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
int i;
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
for (i = 0; i < pd_port->svid_data_cnt; i++) {
|
||||
svid_data = &pd_port->svid_data[i];
|
||||
if (svid_data->ops && svid_data->ops->notify_pe_shutdown) {
|
||||
svid_data->ops->notify_pe_shutdown(
|
||||
pd_port, svid_data);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool svdm_dfp_inform_id(struct pd_port *pd_port, bool ack)
|
||||
{
|
||||
int i;
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
for (i = 0; i < pd_port->svid_data_cnt; i++) {
|
||||
svid_data = &pd_port->svid_data[i];
|
||||
if (svid_data->ops && svid_data->ops->dfp_inform_id)
|
||||
svid_data->ops->dfp_inform_id(pd_port, svid_data, ack);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool svdm_dfp_inform_svids(struct pd_port *pd_port, bool ack)
|
||||
{
|
||||
int i;
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
for (i = 0; i < pd_port->svid_data_cnt; i++) {
|
||||
svid_data = &pd_port->svid_data[i];
|
||||
if (svid_data->ops && svid_data->ops->dfp_inform_svids)
|
||||
svid_data->ops->dfp_inform_svids(
|
||||
pd_port, svid_data, ack);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool svdm_dfp_inform_modes(
|
||||
struct pd_port *pd_port, uint16_t svid, bool ack)
|
||||
{
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
svid_data = dpm_get_svdm_svid_data(pd_port, svid);
|
||||
if (svid_data == NULL)
|
||||
return false;
|
||||
|
||||
if (svid_data->ops && svid_data->ops->dfp_inform_modes)
|
||||
svid_data->ops->dfp_inform_modes(pd_port, svid_data, ack);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool svdm_dfp_inform_enter_mode(
|
||||
struct pd_port *pd_port, uint16_t svid, uint8_t ops, bool ack)
|
||||
{
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
svid_data = dpm_get_svdm_svid_data(pd_port, svid);
|
||||
if (svid_data == NULL)
|
||||
return false;
|
||||
|
||||
if (svid_data->ops && svid_data->ops->dfp_inform_enter_mode)
|
||||
svid_data->ops->dfp_inform_enter_mode(
|
||||
pd_port, svid_data, ops, ack);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool svdm_dfp_inform_exit_mode(
|
||||
struct pd_port *pd_port, uint16_t svid, uint8_t ops)
|
||||
{
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
svid_data = dpm_get_svdm_svid_data(pd_port, svid);
|
||||
if (svid_data == NULL)
|
||||
return false;
|
||||
|
||||
if (svid_data->ops && svid_data->ops->dfp_inform_exit_mode)
|
||||
svid_data->ops->dfp_inform_exit_mode(pd_port, svid_data, ops);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool svdm_dfp_inform_attention(
|
||||
struct pd_port *pd_port, uint16_t svid)
|
||||
{
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
svid_data = dpm_get_svdm_svid_data(pd_port, svid);
|
||||
if (svid_data == NULL)
|
||||
return false;
|
||||
|
||||
if (svid_data->ops && svid_data->ops->dfp_inform_attention)
|
||||
svid_data->ops->dfp_inform_attention(pd_port, svid_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool svdm_ufp_request_enter_mode(
|
||||
struct pd_port *pd_port, uint16_t svid, uint8_t ops)
|
||||
{
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
svid_data = dpm_get_svdm_svid_data(pd_port, svid);
|
||||
if (svid_data == NULL)
|
||||
return false;
|
||||
|
||||
if (svid_data->ops && svid_data->ops->ufp_request_enter_mode)
|
||||
svid_data->ops->ufp_request_enter_mode(pd_port, svid_data, ops);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool svdm_ufp_request_exit_mode(
|
||||
struct pd_port *pd_port, uint16_t svid, uint8_t ops)
|
||||
{
|
||||
struct svdm_svid_data *svid_data;
|
||||
|
||||
svid_data = dpm_get_svdm_svid_data(pd_port, svid);
|
||||
if (svid_data == NULL)
|
||||
return false;
|
||||
|
||||
if (svid_data->ops && svid_data->ops->ufp_request_exit_mode)
|
||||
svid_data->ops->ufp_request_exit_mode(pd_port, svid_data, ops);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* PD_DPM_PRV_H_INCLUDED */
|
||||
770
drivers/usb/typec/mmi_tcpc/pd_dpm_reaction.c
Normal file
770
drivers/usb/typec/mmi_tcpc/pd_dpm_reaction.c
Normal file
|
|
@ -0,0 +1,770 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* PD Device Policy Manager Ready State reactions
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/pd_dpm_pdo_select.h"
|
||||
#include "pd_dpm_prv.h"
|
||||
|
||||
#define DPM_REACTION_COND_ALWAYS (1<<0)
|
||||
#define DPM_REACTION_COND_UFP_ONLY (1<<1)
|
||||
#define DPM_REACTION_COND_DFP_ONLY (1<<2)
|
||||
#define DPM_REACTION_COND_PD30 (1<<3)
|
||||
|
||||
#define DPM_REACCOND_DFP \
|
||||
(DPM_REACTION_COND_ALWAYS | DPM_REACTION_COND_DFP_ONLY)
|
||||
|
||||
#define DPM_REACCOND_UFP \
|
||||
(DPM_REACTION_COND_ALWAYS | DPM_REACTION_COND_UFP_ONLY)
|
||||
|
||||
#define DPM_REACTION_COND_CHECK_ONCE (1<<5)
|
||||
#define DPM_REACTION_COND_ONE_SHOT (1<<6)
|
||||
#define DPM_REACTION_COND_LIMITED_RETRIES (1<<7)
|
||||
|
||||
/*
|
||||
* DPM flow delay reactions
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_UFP_FLOW_DELAY
|
||||
static uint8_t dpm_reaction_ufp_flow_delay(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
DPM_INFO("UFP Delay\n");
|
||||
pd_restart_timer(pd_port, PD_TIMER_UFP_FLOW_DELAY);
|
||||
return DPM_READY_REACTION_BUSY;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_UFP_FLOW_DELAY */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DFP_FLOW_DELAY
|
||||
static uint8_t dpm_reaction_dfp_flow_delay(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
DPM_INFO("DFP Delay\n");
|
||||
pd_restart_timer(pd_port, PD_TIMER_DFP_FLOW_DELAY);
|
||||
return DPM_READY_REACTION_BUSY;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DFP_FLOW_DELAY */
|
||||
|
||||
#ifdef CONFIG_USB_PD_VCONN_STABLE_DELAY
|
||||
static uint8_t dpm_reaction_vconn_stable_delay(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_port->vconn_role == PD_ROLE_VCONN_DYNAMIC_ON) {
|
||||
DPM_INFO("VStable Delay\n");
|
||||
return DPM_READY_REACTION_BUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_VCONN_STABLE_DELAY */
|
||||
|
||||
/*
|
||||
* DPM get cap reaction
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
static uint8_t dpm_reaction_get_source_cap_ext(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->power_role == PD_ROLE_SINK)
|
||||
return TCP_DPM_EVT_GET_SOURCE_CAP_EXT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
static uint8_t dpm_reaction_get_sink_cap(struct pd_port *pd_port)
|
||||
{
|
||||
return TCP_DPM_EVT_GET_SINK_CAP;
|
||||
}
|
||||
|
||||
static uint8_t dpm_reaction_get_source_cap(struct pd_port *pd_port)
|
||||
{
|
||||
return TCP_DPM_EVT_GET_SOURCE_CAP;
|
||||
}
|
||||
|
||||
static uint8_t dpm_reaction_attemp_get_flag(struct pd_port *pd_port)
|
||||
{
|
||||
return TCP_DPM_EVT_GET_SINK_CAP;
|
||||
}
|
||||
|
||||
/*
|
||||
* DPM swap reaction
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
static uint8_t dpm_reaction_request_pr_swap(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t prefer_role =
|
||||
DPM_CAP_EXTRACT_PR_CHECK(pd_port->dpm_caps);
|
||||
|
||||
if (!(pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER))
|
||||
return 0;
|
||||
|
||||
if (pd_port->power_role == PD_ROLE_SINK) {
|
||||
if (prefer_role == DPM_CAP_PR_CHECK_PREFER_SRC)
|
||||
return TCP_DPM_EVT_PR_SWAP_AS_SRC;
|
||||
} else {
|
||||
#ifdef CONFIG_USB_PD_SRC_TRY_PR_SWAP_IF_BAD_PW
|
||||
if (dpm_check_good_power(pd_port) == GOOD_PW_PARTNER)
|
||||
return TCP_DPM_EVT_PR_SWAP_AS_SNK;
|
||||
#endif /* CONFIG_USB_PD_SRC_TRY_PR_SWAP_IF_BAD_PW */
|
||||
|
||||
if (prefer_role == DPM_CAP_PR_CHECK_PREFER_SNK)
|
||||
return TCP_DPM_EVT_PR_SWAP_AS_SNK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DR_SWAP
|
||||
static uint8_t dpm_reaction_request_dr_swap(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t prefer_role =
|
||||
DPM_CAP_EXTRACT_DR_CHECK(pd_port->dpm_caps);
|
||||
|
||||
if (!(pd_port->dpm_caps & DPM_CAP_LOCAL_DR_DATA))
|
||||
return 0;
|
||||
|
||||
if (pd_port->data_role == PD_ROLE_DFP
|
||||
&& prefer_role == DPM_CAP_DR_CHECK_PREFER_UFP)
|
||||
return TCP_DPM_EVT_DR_SWAP_AS_UFP;
|
||||
|
||||
if (pd_port->data_role == PD_ROLE_UFP
|
||||
&& prefer_role == DPM_CAP_DR_CHECK_PREFER_DFP)
|
||||
return TCP_DPM_EVT_DR_SWAP_AS_DFP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* #ifdef CONFIG_USB_PD_DR_SWAP */
|
||||
|
||||
|
||||
/*
|
||||
* DPM DiscoverCable reaction
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_TCPC_VCONN_SUPPLY_MODE
|
||||
static uint8_t dpm_reaction_dynamic_vconn(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dynamic_enable_vconn(pd_port);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_TCPC_VCONN_SUPPLY_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DISCOVER_CABLE_REQUEST_VCONN
|
||||
static uint8_t dpm_reaction_request_vconn_source(struct pd_port *pd_port)
|
||||
{
|
||||
bool return_vconn = true;
|
||||
|
||||
if (!(pd_port->dpm_caps & DPM_CAP_LOCAL_VCONN_SUPPLY))
|
||||
return 0;
|
||||
|
||||
if (pd_port->vconn_role)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_TCPC_VCONN_SUPPLY_MODE
|
||||
if (pd_port->tcpc->tcpc_vconn_supply == TCPC_VCONN_SUPPLY_STARTUP)
|
||||
return_vconn = false;
|
||||
#endif /* CONFIG_TCPC_VCONN_SUPPLY_MODE */
|
||||
|
||||
if (pd_check_rev30(pd_port))
|
||||
return_vconn = false;
|
||||
|
||||
if (return_vconn)
|
||||
dpm_reaction_set(pd_port, DPM_REACTION_RETURN_VCONN_SRC);
|
||||
|
||||
return TCP_DPM_EVT_VCONN_SWAP_ON;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DISCOVER_CABLE_REQUEST_VCONN */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
|
||||
static uint8_t pd_dpm_reaction_discover_cable(struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_PD_DFP_RESET_CABLE
|
||||
if (pd_is_reset_cable(pd_port))
|
||||
return TCP_DPM_EVT_CABLE_SOFTRESET;
|
||||
#endif /* CONFIG_PD_DFP_RESET_CABLE */
|
||||
|
||||
if (pd_is_discover_cable(pd_port)) {
|
||||
pd_restart_timer(pd_port, PD_TIMER_DISCOVER_ID);
|
||||
return DPM_READY_REACTION_BUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DISCOVER_CABLE_RETURN_VCONN
|
||||
static uint8_t dpm_reaction_return_vconn_source(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_port->vconn_role) {
|
||||
DPM_DBG("VconnReturn\n");
|
||||
return TCP_DPM_EVT_VCONN_SWAP_OFF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DISCOVER_CABLE_RETURN_VCONN */
|
||||
|
||||
/*
|
||||
* DPM EnterMode reaction
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_ATTEMP_DISCOVER_ID
|
||||
static uint8_t dpm_reaction_discover_id(struct pd_port *pd_port)
|
||||
{
|
||||
return TCP_DPM_EVT_DISCOVER_ID;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_ATTEMP_DISCOVER_ID */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ATTEMP_DISCOVER_SVID
|
||||
static uint8_t dpm_reaction_discover_svid(struct pd_port *pd_port)
|
||||
{
|
||||
return TCP_DPM_EVT_DISCOVER_SVIDS;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_ATTEMP_DISCOVER_SVID */
|
||||
|
||||
#ifdef CONFIG_USB_PD_MODE_OPERATION
|
||||
static uint8_t dpm_reaction_mode_operation(struct pd_port *pd_port)
|
||||
{
|
||||
if (svdm_notify_pe_ready(pd_port))
|
||||
return DPM_READY_REACTION_BUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_MODE_OPERATION */
|
||||
|
||||
/*
|
||||
* DPM Local/Remote Alert reaction
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
#ifdef CONFIG_USB_PD_DPM_AUTO_SEND_ALERT
|
||||
|
||||
static uint8_t dpm_reaction_send_alert(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t alert_urgent;
|
||||
struct pe_data *pe_data = &pd_port->pe_data;
|
||||
|
||||
alert_urgent = pe_data->local_alert;
|
||||
alert_urgent &= ~ADO_GET_STATUS_ONCE_MASK;
|
||||
|
||||
if (!pe_data->get_status_once)
|
||||
pe_data->local_alert = alert_urgent;
|
||||
|
||||
if ((!pe_data->pe_ready) && (alert_urgent == 0))
|
||||
return 0;
|
||||
|
||||
if (pe_data->local_alert == 0)
|
||||
return 0;
|
||||
|
||||
return TCP_DPM_EVT_ALERT;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_DPM_AUTO_SEND_ALERT */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DPM_AUTO_GET_STATUS
|
||||
|
||||
const uint32_t c_get_status_alert_type = ADO_ALERT_OCP|
|
||||
ADO_ALERT_OTP|ADO_ALERT_OVP|ADO_ALERT_OPER_CHANGED|
|
||||
ADO_ALERT_SRC_IN_CHANGED;
|
||||
|
||||
static inline uint8_t dpm_reaction_alert_status_changed(struct pd_port *pd_port)
|
||||
{
|
||||
pd_port->pe_data.remote_alert &=
|
||||
~ADO_ALERT_TYPE_SET(c_get_status_alert_type);
|
||||
|
||||
return TCP_DPM_EVT_GET_STATUS;
|
||||
}
|
||||
|
||||
static inline uint8_t dpm_reaction_alert_battry_changed(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t mask;
|
||||
uint8_t bat_change_i = 255;
|
||||
uint8_t bat_change_mask1, bat_change_mask2;
|
||||
|
||||
bat_change_mask1 = ADO_FIXED_BAT(pd_port->pe_data.remote_alert);
|
||||
bat_change_mask2 = ADO_HOT_SWAP_BAT(pd_port->pe_data.remote_alert);
|
||||
|
||||
if (bat_change_mask1) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
mask = 1<<i;
|
||||
if (bat_change_mask1 & mask) {
|
||||
bat_change_i = i;
|
||||
bat_change_mask1 &= ~mask;
|
||||
pd_port->pe_data.remote_alert &=
|
||||
~ADO_FIXED_BAT_SET(bat_change_mask1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (bat_change_mask2) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
mask = 1<<i;
|
||||
if (bat_change_mask2 & mask) {
|
||||
bat_change_i = i + 4;
|
||||
bat_change_mask2 &= ~mask;
|
||||
pd_port->pe_data.remote_alert &=
|
||||
~ADO_HOT_SWAP_BAT_SET(bat_change_mask2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bat_change_mask1 == 0 && bat_change_mask2 == 0) {
|
||||
pd_port->pe_data.remote_alert &=
|
||||
~ADO_ALERT_TYPE_SET(ADO_ALERT_BAT_CHANGED);
|
||||
}
|
||||
|
||||
if (bat_change_i == 255)
|
||||
return 0;
|
||||
|
||||
pd_port->tcp_event.tcp_dpm_data.data_object[0] = bat_change_i;
|
||||
return TCP_DPM_EVT_GET_BAT_STATUS;
|
||||
}
|
||||
|
||||
static uint8_t dpm_reaction_handle_alert(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t alert_type = ADO_ALERT_TYPE(pd_port->pe_data.remote_alert);
|
||||
|
||||
if (alert_type & c_get_status_alert_type)
|
||||
return dpm_reaction_alert_status_changed(pd_port);
|
||||
|
||||
if (alert_type & ADO_ALERT_BAT_CHANGED)
|
||||
return dpm_reaction_alert_battry_changed(pd_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DPM_AUTO_GET_STATUS */
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
/*
|
||||
* DPM Idle reaction
|
||||
*/
|
||||
|
||||
static inline uint8_t dpm_get_pd_connect_state(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->power_role == PD_ROLE_SOURCE) {
|
||||
if (pd_check_rev30(pd_port))
|
||||
return PD_CONNECT_PE_READY_SRC_PD30;
|
||||
|
||||
return PD_CONNECT_PE_READY_SRC;
|
||||
}
|
||||
|
||||
if (pd_check_rev30(pd_port)) {
|
||||
if (pd_is_source_support_apdo(pd_port))
|
||||
return PD_CONNECT_PE_READY_SNK_APDO;
|
||||
|
||||
return PD_CONNECT_PE_READY_SNK_PD30;
|
||||
}
|
||||
|
||||
return PD_CONNECT_PE_READY_SNK;
|
||||
}
|
||||
|
||||
static inline void dpm_check_vconn_highv_prot(struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_VCONN_SAFE5V_ONLY
|
||||
struct tcpc_device *tcpc = pd_port->tcpc;
|
||||
struct pe_data *pe_data = &pd_port->pe_data;
|
||||
bool vconn_highv_prot = pd_port->request_v_new > 5000;
|
||||
|
||||
if (pe_data->vconn_highv_prot && !vconn_highv_prot &&
|
||||
tcpc->tcpc_flags & TCPC_FLAGS_VCONN_SAFE5V_ONLY) {
|
||||
DPM_INFO("VC_HIGHV_PROT: %d\n", vconn_highv_prot);
|
||||
pe_data->vconn_highv_prot = vconn_highv_prot;
|
||||
pd_set_vconn(pd_port, pe_data->vconn_highv_prot_role);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_VCONN_SAFE5V_ONLY */
|
||||
}
|
||||
|
||||
static uint8_t dpm_reaction_update_pe_ready(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t state;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (!pd_port->pe_data.pe_ready) {
|
||||
DPM_INFO("PE_READY\n");
|
||||
pd_port->pe_data.pe_ready = true;
|
||||
#ifdef CONFIG_DUAL_ROLE_USB_INTF
|
||||
dual_role_instance_changed(pd_port->tcpc->dr_usb);
|
||||
#endif /* CONFIG_DUAL_ROLE_USB_INTF */
|
||||
}
|
||||
|
||||
state = dpm_get_pd_connect_state(pd_port);
|
||||
pd_update_connect_state(pd_port, state);
|
||||
|
||||
dpm_check_vconn_highv_prot(pd_port);
|
||||
pd_dpm_dynamic_disable_vconn(pd_port);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
pd_port->pe_data.pd_traffic_idle = true;
|
||||
if (pd_check_rev30(pd_port) &&
|
||||
(pd_port->power_role == PD_ROLE_SOURCE))
|
||||
pd_set_sink_tx(pd_port, PD30_SINK_TX_OK);
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DPM reaction declaration
|
||||
*/
|
||||
|
||||
typedef uint8_t (*dpm_reaction_fun)(struct pd_port *pd_port);
|
||||
|
||||
struct dpm_ready_reaction {
|
||||
uint32_t bit_mask;
|
||||
uint8_t condition;
|
||||
dpm_reaction_fun handler;
|
||||
};
|
||||
|
||||
#define DECL_DPM_REACTION(xmask, xcond, xhandler) { \
|
||||
.bit_mask = xmask, \
|
||||
.condition = xcond, \
|
||||
.handler = xhandler, \
|
||||
}
|
||||
|
||||
#define DECL_DPM_REACTION_ALWAYS(xhandler) \
|
||||
DECL_DPM_REACTION(DPM_REACTION_CAP_ALWAYS, \
|
||||
DPM_REACTION_COND_ALWAYS, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_CHECK_ONCE(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_ALWAYS | \
|
||||
DPM_REACTION_COND_CHECK_ONCE, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_LIMITED_RETRIES(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_ALWAYS |\
|
||||
DPM_REACTION_COND_LIMITED_RETRIES, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_ONE_SHOT(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_ALWAYS | \
|
||||
DPM_REACTION_COND_ONE_SHOT, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_UFP(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_UFP_ONLY, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_DFP(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_DFP_ONLY, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_PD30(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_PD30, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_PD30_LIMITED_RETRIES(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_PD30 |\
|
||||
DPM_REACTION_COND_LIMITED_RETRIES, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_PD30_ONE_SHOT(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_PD30 | \
|
||||
DPM_REACTION_COND_ONE_SHOT, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_DFP_PD30_ONE_SHOT(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_DFP_ONLY |\
|
||||
DPM_REACTION_COND_PD30 | \
|
||||
DPM_REACTION_COND_ONE_SHOT, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_DFP_PD30_LIMITED_RETRIES(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_DFP_ONLY |\
|
||||
DPM_REACTION_COND_PD30 | \
|
||||
DPM_REACTION_COND_LIMITED_RETRIES, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_DFP_PD30_CHECK_ONCE(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_DFP_ONLY |\
|
||||
DPM_REACTION_COND_PD30 | \
|
||||
DPM_REACTION_COND_CHECK_ONCE, \
|
||||
xhandler)
|
||||
|
||||
#define DECL_DPM_REACTION_DFP_PD30_RUN_ONCE(xmask, xhandler) \
|
||||
DECL_DPM_REACTION(xmask, \
|
||||
DPM_REACTION_COND_DFP_ONLY |\
|
||||
DPM_REACTION_COND_PD30 | \
|
||||
DPM_REACTION_COND_CHECK_ONCE | \
|
||||
DPM_REACTION_COND_ONE_SHOT, \
|
||||
xhandler)
|
||||
|
||||
static const struct dpm_ready_reaction dpm_reactions[] = {
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_DPM_AUTO_SEND_ALERT
|
||||
DECL_DPM_REACTION_PD30(
|
||||
DPM_REACTION_CAP_ALWAYS,
|
||||
dpm_reaction_send_alert),
|
||||
#endif /* CONFIG_USB_PD_DPM_AUTO_SEND_ALERT */
|
||||
#ifdef CONFIG_USB_PD_DPM_AUTO_GET_STATUS
|
||||
DECL_DPM_REACTION_PD30(
|
||||
DPM_REACTION_CAP_ALWAYS,
|
||||
dpm_reaction_handle_alert),
|
||||
#endif /* CONFIG_USB_PD_DPM_AUTO_GET_STATUS */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DFP_FLOW_DELAY
|
||||
DECL_DPM_REACTION_DFP(
|
||||
DPM_REACTION_DFP_FLOW_DELAY,
|
||||
dpm_reaction_dfp_flow_delay),
|
||||
#endif /* CONFIG_USB_PD_DFP_FLOW_DELAY */
|
||||
|
||||
#ifdef CONFIG_USB_PD_UFP_FLOW_DELAY
|
||||
DECL_DPM_REACTION_UFP(
|
||||
DPM_REACTION_UFP_FLOW_DELAY,
|
||||
dpm_reaction_ufp_flow_delay),
|
||||
#endif /* CONFIG_USB_PD_UFP_FLOW_DELAY */
|
||||
|
||||
DECL_DPM_REACTION_LIMITED_RETRIES(
|
||||
DPM_REACTION_GET_SINK_CAP,
|
||||
dpm_reaction_get_sink_cap),
|
||||
|
||||
DECL_DPM_REACTION_LIMITED_RETRIES(
|
||||
DPM_REACTION_GET_SOURCE_CAP,
|
||||
dpm_reaction_get_source_cap),
|
||||
|
||||
DECL_DPM_REACTION_LIMITED_RETRIES(
|
||||
DPM_REACTION_ATTEMPT_GET_FLAG,
|
||||
dpm_reaction_attemp_get_flag),
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
DECL_DPM_REACTION_PD30_ONE_SHOT(
|
||||
DPM_REACTION_GET_SOURCE_CAP_EXT,
|
||||
dpm_reaction_get_source_cap_ext),
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
DECL_DPM_REACTION_CHECK_ONCE(
|
||||
DPM_REACTION_REQUEST_PR_SWAP,
|
||||
dpm_reaction_request_pr_swap),
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DR_SWAP
|
||||
DECL_DPM_REACTION_CHECK_ONCE(
|
||||
DPM_REACTION_REQUEST_DR_SWAP,
|
||||
dpm_reaction_request_dr_swap),
|
||||
#endif /* CONFIG_USB_PD_DR_SWAP */
|
||||
|
||||
#ifdef CONFIG_TCPC_VCONN_SUPPLY_MODE
|
||||
DECL_DPM_REACTION_DFP_PD30_CHECK_ONCE(
|
||||
DPM_REACTION_DYNAMIC_VCONN,
|
||||
dpm_reaction_dynamic_vconn),
|
||||
#endif /* CONFIG_TCPC_VCONN_SUPPLY_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DISCOVER_CABLE_REQUEST_VCONN
|
||||
DECL_DPM_REACTION_DFP_PD30_RUN_ONCE(
|
||||
DPM_REACTION_REQUEST_VCONN_SRC,
|
||||
dpm_reaction_request_vconn_source),
|
||||
#endif /* CONFIG_USB_PD_DISCOVER_CABLE_REQUEST_VCONN */
|
||||
|
||||
#ifdef CONFIG_USB_PD_VCONN_STABLE_DELAY
|
||||
DECL_DPM_REACTION_DFP_PD30_CHECK_ONCE(
|
||||
DPM_REACTION_VCONN_STABLE_DELAY,
|
||||
dpm_reaction_vconn_stable_delay),
|
||||
#endif /* CONFIG_USB_PD_VCONN_STABLE_DELAY */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
|
||||
DECL_DPM_REACTION_DFP_PD30_CHECK_ONCE(
|
||||
DPM_REACTION_DISCOVER_CABLE,
|
||||
pd_dpm_reaction_discover_cable),
|
||||
#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DISCOVER_CABLE_RETURN_VCONN
|
||||
DECL_DPM_REACTION_DFP_PD30_RUN_ONCE(
|
||||
DPM_REACTION_RETURN_VCONN_SRC,
|
||||
dpm_reaction_return_vconn_source),
|
||||
#endif /* CONFIG_USB_PD_DISCOVER_CABLE_RETURN_VCONN */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ATTEMP_DISCOVER_ID
|
||||
DECL_DPM_REACTION_DFP_PD30_LIMITED_RETRIES(
|
||||
DPM_REACTION_DISCOVER_ID,
|
||||
dpm_reaction_discover_id),
|
||||
#endif /* CONFIG_USB_PD_ATTEMP_DISCOVER_ID */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ATTEMP_DISCOVER_SVID
|
||||
DECL_DPM_REACTION_DFP_PD30_LIMITED_RETRIES(
|
||||
DPM_REACTION_DISCOVER_SVID,
|
||||
dpm_reaction_discover_svid),
|
||||
#endif /* CONFIG_USB_PD_ATTEMP_DISCOVER_SVID */
|
||||
|
||||
#ifdef CONFIG_USB_PD_MODE_OPERATION
|
||||
DECL_DPM_REACTION_ALWAYS(
|
||||
dpm_reaction_mode_operation),
|
||||
#endif /* CONFIG_USB_PD_MODE_OPERATION */
|
||||
|
||||
DECL_DPM_REACTION_ALWAYS(
|
||||
dpm_reaction_update_pe_ready),
|
||||
};
|
||||
|
||||
/**
|
||||
* dpm_get_reaction_env
|
||||
*
|
||||
* Get current reaction's environmental conditions.
|
||||
*
|
||||
* Returns environmental conditions.
|
||||
*/
|
||||
|
||||
static inline uint8_t dpm_get_reaction_env(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t conditions;
|
||||
|
||||
if (pd_port->data_role == PD_ROLE_DFP)
|
||||
conditions = DPM_REACCOND_DFP;
|
||||
else
|
||||
conditions = DPM_REACCOND_UFP;
|
||||
|
||||
if (pd_check_rev30(pd_port))
|
||||
conditions |= DPM_REACTION_COND_PD30;
|
||||
|
||||
return conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpm_check_reaction_busy
|
||||
*
|
||||
* check this reaction is still keep busy
|
||||
*
|
||||
* @ reaction : which reaction is checked.
|
||||
*
|
||||
* Return Boolean to indicate busy or not.
|
||||
*/
|
||||
|
||||
static inline bool dpm_check_reaction_busy(struct pd_port *pd_port,
|
||||
const struct dpm_ready_reaction *reaction)
|
||||
{
|
||||
if (reaction->bit_mask & DPM_REACTION_CAP_ALWAYS)
|
||||
return false;
|
||||
|
||||
return !dpm_reaction_check(
|
||||
pd_port, DPM_REACTION_CAP_READY_ONCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpm_check_reaction_available
|
||||
*
|
||||
* check this reaction is available.
|
||||
*
|
||||
* @ env : Environmental conditions of reaction table
|
||||
* @ reaction : which reaction is checked.
|
||||
*
|
||||
* Returns TCP_DPM_EVT_ID if available;
|
||||
* Returns Zero to indicate if not available.
|
||||
* Returns DPM_READY_REACTION_BUSY to indicate
|
||||
* this reaction is waiting for being finished.
|
||||
*/
|
||||
|
||||
static inline uint8_t dpm_check_reaction_available(struct pd_port *pd_port,
|
||||
uint8_t env, const struct dpm_ready_reaction *reaction)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!dpm_reaction_check(pd_port, reaction->bit_mask))
|
||||
return 0;
|
||||
|
||||
if (!(reaction->condition & env))
|
||||
return 0;
|
||||
|
||||
if (dpm_check_reaction_busy(pd_port, reaction))
|
||||
return DPM_READY_REACTION_BUSY;
|
||||
|
||||
ret = reaction->handler(pd_port);
|
||||
|
||||
if (ret == 0 &&
|
||||
reaction->condition & DPM_REACTION_COND_CHECK_ONCE)
|
||||
dpm_reaction_clear(pd_port, reaction->bit_mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpm_check_reset_reaction
|
||||
*
|
||||
* Once trigger one reaction,
|
||||
* check if automatically clear this reaction flag.
|
||||
*
|
||||
* For the following reactions type:
|
||||
* DPM_REACTION_COND_ONE_SHOT,
|
||||
* DPM_REACTION_COND_LIMITED_RETRIES
|
||||
*
|
||||
* @ reaction : which reaction is triggered.
|
||||
*
|
||||
* Return Boolean to indicate automatically clear or not.
|
||||
*/
|
||||
|
||||
static inline bool dpm_check_clear_reaction(struct pd_port *pd_port,
|
||||
const struct dpm_ready_reaction *reaction)
|
||||
{
|
||||
if (pd_port->pe_data.dpm_reaction_id != reaction->bit_mask)
|
||||
pd_port->pe_data.dpm_reaction_retry = 0;
|
||||
|
||||
pd_port->pe_data.dpm_reaction_retry++;
|
||||
pd_port->pe_data.dpm_reaction_id = reaction->bit_mask;
|
||||
|
||||
if (reaction->condition & DPM_REACTION_COND_ONE_SHOT)
|
||||
return true;
|
||||
|
||||
if (reaction->condition & DPM_REACTION_COND_LIMITED_RETRIES)
|
||||
return pd_port->pe_data.dpm_reaction_retry > 3;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t pd_dpm_get_ready_reaction(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t evt;
|
||||
uint8_t env;
|
||||
uint32_t clear_reaction = DPM_REACTION_CAP_READY_ONCE;
|
||||
const struct dpm_ready_reaction *reaction = dpm_reactions;
|
||||
const struct dpm_ready_reaction *reaction_last =
|
||||
dpm_reactions + ARRAY_SIZE(dpm_reactions);
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
env = dpm_get_reaction_env(pd_port);
|
||||
|
||||
do {
|
||||
evt = dpm_check_reaction_available(pd_port, env, reaction);
|
||||
} while ((evt == 0) && (++reaction < reaction_last));
|
||||
|
||||
if (evt > 0 && dpm_check_clear_reaction(pd_port, reaction)) {
|
||||
clear_reaction |= reaction->bit_mask;
|
||||
DPM_DBG("clear_reaction=%d\n", evt);
|
||||
}
|
||||
|
||||
dpm_reaction_clear(pd_port, clear_reaction);
|
||||
return evt;
|
||||
}
|
||||
99
drivers/usb/typec/mmi_tcpc/pd_dpm_uvdm.c
Normal file
99
drivers/usb/typec/mmi_tcpc/pd_dpm_uvdm.c
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* PD Device Policy Manager for UVDM
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "pd_dpm_prv.h"
|
||||
|
||||
#ifdef CONFIG_USB_PD_RICHTEK_UVDM
|
||||
|
||||
bool richtek_dfp_notify_pe_startup(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data)
|
||||
{
|
||||
UVDM_INFO("%s\n", __func__);
|
||||
pd_port->richtek_init_done = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int richtek_dfp_notify_pe_ready(
|
||||
struct pd_port *pd_port, struct svdm_svid_data *svid_data)
|
||||
{
|
||||
if (pd_port->data_role != PD_ROLE_DFP)
|
||||
return 0;
|
||||
|
||||
if (pd_port->richtek_init_done)
|
||||
return 0;
|
||||
|
||||
pd_port->richtek_init_done = true;
|
||||
UVDM_INFO("%s\n", __func__);
|
||||
|
||||
#if 0
|
||||
pd_port->uvdm_cnt = 3;
|
||||
pd_port->uvdm_wait_resp = true;
|
||||
|
||||
pd_port->uvdm_data[0] = PD_UVDM_HDR(USB_VID_RICHTEK, 0x4321);
|
||||
pd_port->uvdm_data[1] = 0x11223344;
|
||||
pd_port->uvdm_data[2] = 0x44332211;
|
||||
|
||||
pd_put_tcp_vdm_event(pd_port, TCP_DPM_EVT_UVDM);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool richtek_dfp_notify_uvdm(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data, bool ack)
|
||||
{
|
||||
uint32_t resp_cmd = 0;
|
||||
|
||||
if (ack) {
|
||||
if (pd_port->uvdm_wait_resp)
|
||||
resp_cmd = PD_UVDM_HDR_CMD(pd_port->uvdm_data[0]);
|
||||
|
||||
UVDM_INFO("dfp_notify: ACK (0x%x)\n", resp_cmd);
|
||||
} else
|
||||
UVDM_INFO("dfp_notify: NAK\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool richtek_ufp_notify_uvdm(struct pd_port *pd_port,
|
||||
struct svdm_svid_data *svid_data)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t reply_cmd[VDO_MAX_NR];
|
||||
uint16_t cmd = (uint16_t) PD_UVDM_HDR_CMD(pd_port->uvdm_data[0]);
|
||||
|
||||
UVDM_INFO("ufp_notify: 0x%x\n", cmd);
|
||||
|
||||
if (cmd >= 0x1000) {
|
||||
UVDM_INFO("uvdm_no_reply\n");
|
||||
VDM_STATE_DPM_INFORMED(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
reply_cmd[0] = PD_UVDM_HDR(USB_VID_RICHTEK, cmd+1);
|
||||
|
||||
for (i = 1; i < pd_port->uvdm_cnt; i++)
|
||||
reply_cmd[i] = ~pd_port->uvdm_data[i];
|
||||
|
||||
pd_reply_custom_vdm(pd_port, TCPC_TX_SOP,
|
||||
pd_port->uvdm_cnt, reply_cmd);
|
||||
VDM_STATE_NORESP_CMD(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_RICHTEK_UVDM */
|
||||
1361
drivers/usb/typec/mmi_tcpc/pd_policy_engine.c
Normal file
1361
drivers/usb/typec/mmi_tcpc/pd_policy_engine.c
Normal file
File diff suppressed because it is too large
Load diff
376
drivers/usb/typec/mmi_tcpc/pd_policy_engine_com.c
Normal file
376
drivers/usb/typec/mmi_tcpc/pd_policy_engine_com.c
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for Common
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
static inline void *pd_get_tcp_event_data_object(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_port->tcp_event.tcp_dpm_data.data_object;
|
||||
}
|
||||
|
||||
/*
|
||||
* Policy Engine General State Activity
|
||||
*/
|
||||
|
||||
static void pe_idle_reset_data(struct pd_port *pd_port)
|
||||
{
|
||||
pd_reset_pe_timer(pd_port);
|
||||
pd_reset_svid_data(pd_port);
|
||||
|
||||
pd_port->pe_data.pd_prev_connected = false;
|
||||
pd_port->state_machine = PE_STATE_MACHINE_IDLE;
|
||||
|
||||
pd_enable_bist_test_mode(pd_port, false);
|
||||
|
||||
#ifndef CONFIG_USB_PD_TRANSMIT_BIST2
|
||||
pd_disable_bist_mode2(pd_port);
|
||||
#endif /* CONFIG_USB_PD_TRANSMIT_BIST2 */
|
||||
|
||||
pd_enable_timer(pd_port, PD_TIMER_PE_IDLE_TOUT);
|
||||
|
||||
pd_unlock_msg_output(pd_port);
|
||||
}
|
||||
|
||||
void pe_idle1_entry(struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_ERROR_RECOVERY_ONCE
|
||||
pd_port->error_recovery_once = 0;
|
||||
#endif /* CONFIG_USB_PD_ERROR_RECOVERY_ONCE */
|
||||
|
||||
pe_idle_reset_data(pd_port);
|
||||
pd_try_put_pe_idle_event(pd_port);
|
||||
}
|
||||
|
||||
void pe_idle2_entry(struct pd_port *pd_port)
|
||||
{
|
||||
memset(&pd_port->pe_data, 0, sizeof(struct pe_data));
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_IDLE);
|
||||
pd_disable_timer(pd_port, PD_TIMER_PE_IDLE_TOUT);
|
||||
pd_notify_pe_idle(pd_port);
|
||||
}
|
||||
|
||||
void pe_reject_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_REJECT);
|
||||
}
|
||||
|
||||
void pe_error_recovery_entry(struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_ERROR_RECOVERY_ONCE
|
||||
pd_port->error_recovery_once++;
|
||||
#endif /* CONFIG_USB_PD_ERROR_RECOVERY_ONCE */
|
||||
|
||||
pe_idle_reset_data(pd_port);
|
||||
pd_notify_pe_error_recovery(pd_port);
|
||||
pd_try_put_pe_idle_event(pd_port);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_ERROR_RECOVERY_ONCE
|
||||
void pe_error_recovery_once_entry(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t state = PD_CONNECT_TYPEC_ONLY_SNK_DFT;
|
||||
|
||||
pd_notify_pe_hard_reset_completed(pd_port);
|
||||
|
||||
if (pd_port->power_role == PD_ROLE_SOURCE) {
|
||||
state = PD_CONNECT_TYPEC_ONLY_SRC;
|
||||
pd_dpm_dynamic_disable_vconn(pd_port);
|
||||
} else
|
||||
pd_dpm_sink_vbus(pd_port, true);
|
||||
|
||||
pd_update_connect_state(pd_port, state);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_ERROR_RECOVERY_ONCE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_RECV_HRESET_COUNTER
|
||||
void pe_over_recv_hreset_limit_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_INFO("OverHResetLimit++\n");
|
||||
pe_idle_reset_data(pd_port);
|
||||
pd_notify_pe_over_recv_hreset(pd_port);
|
||||
PE_INFO("OverHResetLimit--\n");
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_RECV_HRESET_COUNTER */
|
||||
|
||||
void pe_bist_test_data_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_IGNORE_UNKNOWN_EVENT(pd_port);
|
||||
|
||||
pd_enable_bist_test_mode(pd_port, true);
|
||||
}
|
||||
|
||||
void pe_bist_test_data_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_enable_bist_test_mode(pd_port, false);
|
||||
}
|
||||
|
||||
void pe_bist_carrier_mode_2_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_bist_mode2(pd_port);
|
||||
pd_enable_pe_state_timer(pd_port, PD_TIMER_BIST_CONT_MODE);
|
||||
}
|
||||
|
||||
void pe_bist_carrier_mode_2_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_disable_bist_mode2(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* Policy Engine Share State Activity
|
||||
*/
|
||||
|
||||
static inline uint8_t pe30_power_ready_entry(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t rx_cap = PD_RX_CAP_PE_READY_UFP;
|
||||
|
||||
if (pd_port->vconn_role)
|
||||
rx_cap = PD_RX_CAP_PE_READY_DFP;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
dpm_reaction_clear(pd_port,
|
||||
DPM_REACTION_DFP_FLOW_DELAY |
|
||||
DPM_REACTION_UFP_FLOW_DELAY);
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
|
||||
return rx_cap;
|
||||
}
|
||||
|
||||
static inline uint8_t pe20_power_ready_entry(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t rx_cap = PD_RX_CAP_PE_READY_UFP;
|
||||
|
||||
if (pd_port->data_role == PD_ROLE_DFP)
|
||||
rx_cap = PD_RX_CAP_PE_READY_DFP;
|
||||
|
||||
pd_port->pe_data.pe_state_flags |=
|
||||
PE_STATE_FLAG_IGNORE_UNKNOWN_EVENT;
|
||||
|
||||
return rx_cap;
|
||||
}
|
||||
|
||||
void pe_power_ready_entry(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t rx_cap;
|
||||
|
||||
pd_port->state_machine = PE_STATE_MACHINE_NORMAL;
|
||||
|
||||
pd_port->pe_data.during_swap = false;
|
||||
pd_port->pe_data.explicit_contract = true;
|
||||
|
||||
#ifdef CONFIG_USB_PD_RENEGOTIATION_COUNTER
|
||||
pd_port->pe_data.renegotiation_count = 0;
|
||||
#endif /* CONFIG_USB_PD_RENEGOTIATION_COUNTER */
|
||||
|
||||
if (pd_check_rev30(pd_port))
|
||||
rx_cap = pe30_power_ready_entry(pd_port);
|
||||
else
|
||||
rx_cap = pe20_power_ready_entry(pd_port);
|
||||
|
||||
pd_set_rx_enable(pd_port, rx_cap);
|
||||
|
||||
dpm_reaction_set(pd_port, DPM_REACTION_CAP_READY_ONCE);
|
||||
pd_notify_tcp_event_2nd_result(pd_port, TCP_DPM_RET_SUCCESS);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-85 Get Battery Capabilities State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_REMOTE
|
||||
void pe_get_battery_cap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
struct pd_get_battery_capabilities *gbcdb =
|
||||
pd_get_tcp_event_data_object(pd_port);
|
||||
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
pd_send_sop_ext_msg(pd_port,
|
||||
PD_EXT_GET_BAT_CAP, PD_GBCDB_SIZE, gbcdb);
|
||||
}
|
||||
|
||||
void pe_get_battery_cap_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_battery_cap(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-86 Give Battery Capabilities State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_LOCAL
|
||||
void pe_give_battery_cap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_battery_cap(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_LOCAL */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-87 Get Battery Status State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE
|
||||
void pe_get_battery_status_entry(struct pd_port *pd_port)
|
||||
{
|
||||
struct pd_get_battery_status *gbsdb =
|
||||
pd_get_tcp_event_data_object(pd_port);
|
||||
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
pd_send_sop_ext_msg(pd_port,
|
||||
PD_EXT_GET_BAT_STATUS, PD_GBSDB_SIZE, gbsdb);
|
||||
}
|
||||
|
||||
void pe_get_battery_status_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_battery_status(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-88 Give Battery Status State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL
|
||||
void pe_give_battery_status_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_battery_status(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-89 Get Manufacturer Information State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE
|
||||
|
||||
void pe_get_manufacturer_info_entry(struct pd_port *pd_port)
|
||||
{
|
||||
struct pd_get_manufacturer_info *gmidb =
|
||||
pd_get_tcp_event_data_object(pd_port);
|
||||
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
pd_send_sop_ext_msg(pd_port,
|
||||
PD_EXT_GET_MFR_INFO, PD_GMIDB_SIZE, gmidb);
|
||||
}
|
||||
|
||||
void pe_get_manufacturer_info_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_mfrs_info(pd_port);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-90 Give Manufacturer Information State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL
|
||||
|
||||
void pe_give_manufacturer_info_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_mfrs_info(pd_port);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-91 Get Country Codes State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE
|
||||
void pe_get_country_codes_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_COUNTRY_CODE);
|
||||
}
|
||||
|
||||
void pe_get_country_codes_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_country_codes(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-92 Give Country Codes State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL
|
||||
void pe_give_country_codes_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_country_codes(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-93 Get Country Information State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE
|
||||
void pe_get_country_info_entry(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t *ccdo =
|
||||
pd_get_tcp_event_data_object(pd_port);
|
||||
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
pd_send_sop_data_msg(pd_port,
|
||||
PD_DATA_GET_COUNTRY_INFO, PD_CCDO_SIZE, ccdo);
|
||||
}
|
||||
|
||||
void pe_get_country_info_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_country_info(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-94 Give Country Information State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL
|
||||
void pe_give_country_info_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_country_info(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_LOCAL */
|
||||
|
||||
/*
|
||||
* [PD3.0] Unsupported, Unrecognized UVDM and Unsupported SVDM.
|
||||
*/
|
||||
|
||||
void pe_vdm_not_supported_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
46
drivers/usb/typec/mmi_tcpc/pd_policy_engine_dbg.c
Normal file
46
drivers/usb/typec/mmi_tcpc/pd_policy_engine_dbg.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for DBGACC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
|
||||
|
||||
void pe_dbg_ready_entry(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t state;
|
||||
|
||||
if (pd_port->pe_data.pe_ready)
|
||||
return;
|
||||
|
||||
pd_port->pe_data.pe_ready = true;
|
||||
pd_reset_protocol_layer(pd_port, false);
|
||||
|
||||
if (pd_port->data_role == PD_ROLE_UFP) {
|
||||
PE_INFO("Custom_DBGACC : UFP\n");
|
||||
state = PD_CONNECT_PE_READY_DBGACC_UFP;
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_READY_UFP);
|
||||
} else {
|
||||
PE_INFO("Custom_DBGACC : DFP\n");
|
||||
state = PD_CONNECT_PE_READY_DBGACC_DFP;
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_READY_DFP);
|
||||
}
|
||||
|
||||
pd_update_connect_state(pd_port, state);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
221
drivers/usb/typec/mmi_tcpc/pd_policy_engine_dfp.c
Normal file
221
drivers/usb/typec/mmi_tcpc/pd_policy_engine_dfp.c
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for DFP
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-64 DFP to UFP VDM Discover Identity State Diagram
|
||||
*/
|
||||
|
||||
void pe_dfp_ufp_vdm_identity_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_vdm_discover_id(pd_port, TCPC_TX_SOP);
|
||||
}
|
||||
|
||||
void pe_dfp_ufp_vdm_identity_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_id(pd_port, true);
|
||||
}
|
||||
|
||||
void pe_dfp_ufp_vdm_identity_naked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_id(pd_port, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-65 DFP VDM Discover Identity State Diagram
|
||||
*/
|
||||
|
||||
void pe_dfp_cbl_vdm_identity_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_port->pe_data.discover_id_counter++;
|
||||
pd_send_vdm_discover_id(pd_port, TCPC_TX_SOP_PRIME);
|
||||
}
|
||||
|
||||
void pe_dfp_cbl_vdm_identity_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_cable_id(pd_port, false);
|
||||
}
|
||||
|
||||
void pe_dfp_cbl_vdm_identity_naked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_cable_id(pd_port, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-66 DFP VDM Discover SVIDs State Diagram
|
||||
*/
|
||||
|
||||
void pe_dfp_vdm_svids_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_vdm_discover_svids(pd_port, TCPC_TX_SOP);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_svids_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_svids(pd_port, true);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_svids_naked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_svids(pd_port, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-67 DFP VDM Discover Modes State Diagram
|
||||
*/
|
||||
|
||||
void pe_dfp_vdm_modes_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_vdm_discover_modes(pd_port, TCPC_TX_SOP, pd_port->mode_svid);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_modes_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_modes(pd_port, true);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_modes_naked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_modes(pd_port, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-68 DFP VDM Mode Entry State Diagram
|
||||
*/
|
||||
|
||||
void pe_dfp_vdm_mode_entry_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_vdm_enter_mode(pd_port, TCPC_TX_SOP,
|
||||
pd_port->mode_svid, pd_port->mode_obj_pos);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_mode_entry_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_enter_mode(pd_port, true);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_mode_entry_naked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_enter_mode(pd_port, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-69 DFP VDM Mode Exit State Diagram
|
||||
*/
|
||||
|
||||
void pe_dfp_vdm_mode_exit_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_vdm_exit_mode(pd_port, TCPC_TX_SOP,
|
||||
pd_port->mode_svid, pd_port->mode_obj_pos);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_mode_exit_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_exit_mode(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-70 DFP VDM Attention State Diagram
|
||||
*/
|
||||
|
||||
void pe_dfp_vdm_attention_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_attention(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-83 DFP Cable Soft Reset or Cable Reset State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PD_DFP_RESET_CABLE
|
||||
|
||||
void pe_dfp_cbl_send_soft_reset_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG_OR_TX_FAILED(pd_port);
|
||||
|
||||
pd_send_cable_soft_reset(pd_port);
|
||||
}
|
||||
|
||||
void pe_dfp_cbl_send_cable_reset_entry(struct pd_port *pd_port)
|
||||
{
|
||||
/* TODO : we don't do cable reset now */
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PD_DFP_RESET_CABLE */
|
||||
|
||||
/*
|
||||
* [PD2.0] Display Port
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
|
||||
void pe_dfp_vdm_dp_status_update_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_send_dp_status_update(pd_port);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_dp_status_update_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_dp_status_update(pd_port, true);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_dp_status_update_naked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_dp_status_update(pd_port, false);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_dp_configuration_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_send_dp_configuration(pd_port);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_dp_configuration_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_dp_configuration(pd_port, true);
|
||||
}
|
||||
|
||||
void pe_dfp_vdm_dp_configuration_naked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_dp_configuration(pd_port, false);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
|
||||
/*
|
||||
* UVDM
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
|
||||
void pe_dfp_uvdm_send_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_send_uvdm(pd_port);
|
||||
}
|
||||
|
||||
void pe_dfp_uvdm_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_uvdm(pd_port, true);
|
||||
}
|
||||
|
||||
void pe_dfp_uvdm_naked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dfp_inform_uvdm(pd_port, false);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
87
drivers/usb/typec/mmi_tcpc/pd_policy_engine_dr.c
Normal file
87
drivers/usb/typec/mmi_tcpc/pd_policy_engine_dr.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for DR
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
/*
|
||||
* [PD2.0]
|
||||
* Figure 8-53 Dual-Role (Source) Get Source Capabilities diagram
|
||||
* Figure 8-54 Dual-Role (Source) Give Sink Capabilities diagram
|
||||
* Figure 8-55 Dual-Role (Sink) Get Sink Capabilities State Diagram
|
||||
* Figure 8-56 Dual-Role (Sink) Give Source Capabilities State Diagram
|
||||
*/
|
||||
|
||||
void pe_dr_src_get_source_cap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG_OR_RJ(pd_port);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_SOURCE_CAP);
|
||||
}
|
||||
|
||||
void pe_dr_src_get_source_cap_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dr_inform_source_cap(pd_port);
|
||||
}
|
||||
|
||||
void pe_dr_src_give_sink_cap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_sink_caps(pd_port);
|
||||
}
|
||||
|
||||
void pe_dr_snk_get_sink_cap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG_OR_RJ(pd_port);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_SINK_CAP);
|
||||
}
|
||||
|
||||
void pe_dr_snk_get_sink_cap_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dr_inform_sink_cap(pd_port);
|
||||
}
|
||||
|
||||
void pe_dr_snk_give_source_cap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_source_caps(pd_port);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
void pe_dr_snk_give_source_cap_ext_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_source_cap_ext(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
void pe_dr_src_get_source_cap_ext_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_SOURCE_CAP_EXT);
|
||||
}
|
||||
|
||||
void pe_dr_src_get_source_cap_ext_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_source_cap_ext(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
82
drivers/usb/typec/mmi_tcpc/pd_policy_engine_drs.c
Normal file
82
drivers/usb/typec/mmi_tcpc/pd_policy_engine_drs.c
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for DRS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-49: Type-C DFP to UFP Data Role Swap State Diagram
|
||||
*/
|
||||
|
||||
void pe_drs_dfp_ufp_evaluate_dr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_drs_evaluate_swap(pd_port, PD_ROLE_UFP);
|
||||
}
|
||||
|
||||
void pe_drs_dfp_ufp_accept_dr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_ACCEPT);
|
||||
}
|
||||
|
||||
void pe_drs_dfp_ufp_change_to_ufp_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_drs_change_role(pd_port, PD_ROLE_UFP);
|
||||
}
|
||||
|
||||
void pe_drs_dfp_ufp_send_dr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pe_send_swap_request_entry(pd_port, PD_CTRL_DR_SWAP);
|
||||
}
|
||||
|
||||
void pe_drs_dfp_ufp_reject_dr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_reply_wait_reject_msg(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-50: Type-C UFP to DFP Data Role Swap State Diagram
|
||||
*/
|
||||
|
||||
void pe_drs_ufp_dfp_evaluate_dr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_drs_evaluate_swap(pd_port, PD_ROLE_DFP);
|
||||
}
|
||||
|
||||
void pe_drs_ufp_dfp_accept_dr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_ACCEPT);
|
||||
}
|
||||
|
||||
void pe_drs_ufp_dfp_change_to_dfp_entry(struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_RESET_CABLE
|
||||
dpm_reaction_set(pd_port, DPM_REACTION_CAP_RESET_CABLE);
|
||||
#endif /* CONFIG_USB_PD_RESET_CABLE */
|
||||
|
||||
pd_dpm_drs_change_role(pd_port, PD_ROLE_DFP);
|
||||
}
|
||||
|
||||
void pe_drs_ufp_dfp_send_dr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pe_send_swap_request_entry(pd_port, PD_CTRL_DR_SWAP);
|
||||
}
|
||||
|
||||
void pe_drs_ufp_dfp_reject_dr_swap_entry(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
pd_reply_wait_reject_msg(pd_port);
|
||||
}
|
||||
124
drivers/usb/typec/mmi_tcpc/pd_policy_engine_prs.c
Normal file
124
drivers/usb/typec/mmi_tcpc/pd_policy_engine_prs.c
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for PRS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-51:
|
||||
* Dual-Role Port in Source to Sink Power Role Swap State Diagram
|
||||
*/
|
||||
|
||||
void pe_prs_src_snk_evaluate_pr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_prs_evaluate_swap(pd_port, PD_ROLE_SINK);
|
||||
}
|
||||
|
||||
void pe_prs_src_snk_accept_pr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_notify_pe_execute_pr_swap(pd_port, true);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_ACCEPT);
|
||||
}
|
||||
|
||||
void pe_prs_src_snk_transition_to_off_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_lock_msg_output(pd_port); /* for tSRCTransition */
|
||||
pd_notify_pe_execute_pr_swap(pd_port, true);
|
||||
|
||||
pd_enable_timer(pd_port, PD_TIMER_SOURCE_TRANSITION);
|
||||
}
|
||||
|
||||
void pe_prs_src_snk_assert_rd_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_prs_change_role(pd_port, PD_ROLE_SINK);
|
||||
}
|
||||
|
||||
void pe_prs_src_snk_wait_source_on_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_HRESET_IF_TX_FAILED(pd_port);
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_PS_RDY);
|
||||
}
|
||||
|
||||
void pe_prs_src_snk_send_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pe_send_swap_request_entry(pd_port, PD_CTRL_PR_SWAP);
|
||||
}
|
||||
|
||||
void pe_prs_src_snk_reject_pr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_reply_wait_reject_msg(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-52:
|
||||
* Dual-role Port in Sink to Source Power Role Swap State Diagram
|
||||
*/
|
||||
|
||||
void pe_prs_snk_src_evaluate_pr_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_prs_evaluate_swap(pd_port, PD_ROLE_SOURCE);
|
||||
}
|
||||
|
||||
void pe_prs_snk_src_accept_pr_swap_entry(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
pd_notify_pe_execute_pr_swap(pd_port, true);
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_ACCEPT);
|
||||
}
|
||||
|
||||
void pe_prs_snk_src_transition_to_off_entry(struct pd_port *pd_port)
|
||||
{
|
||||
/*
|
||||
* Sink should call pd_notify_pe_execute_pr_swap before this state,
|
||||
* because source may turn off power & change CC before we got
|
||||
* GoodCRC or Accept.
|
||||
*/
|
||||
|
||||
pd_port->pe_data.during_swap = true;
|
||||
pd_enable_pe_state_timer(pd_port, PD_TIMER_PS_SOURCE_OFF);
|
||||
pd_dpm_prs_turn_off_power_sink(pd_port);
|
||||
}
|
||||
|
||||
void pe_prs_snk_src_assert_rp_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_prs_change_role(pd_port, PD_ROLE_SOURCE);
|
||||
}
|
||||
|
||||
void pe_prs_snk_src_source_on_entry(struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_RESET_CABLE
|
||||
dpm_reaction_set(pd_port, DPM_REACTION_CAP_RESET_CABLE);
|
||||
#endif /* CONFIG_USB_PD_RESET_CABLE */
|
||||
|
||||
PE_STATE_HRESET_IF_TX_FAILED(pd_port);
|
||||
pd_dpm_dynamic_enable_vconn(pd_port);
|
||||
pd_dpm_prs_enable_power_source(pd_port, true);
|
||||
|
||||
/* Send PS_Rdy in process_event after source_on */
|
||||
}
|
||||
|
||||
void pe_prs_snk_src_send_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_notify_pe_execute_pr_swap(pd_port, false);
|
||||
pe_send_swap_request_entry(pd_port, PD_CTRL_PR_SWAP);
|
||||
}
|
||||
|
||||
void pe_prs_snk_src_reject_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_reply_wait_reject_msg(pd_port);
|
||||
}
|
||||
319
drivers/usb/typec/mmi_tcpc/pd_policy_engine_snk.c
Normal file
319
drivers/usb/typec/mmi_tcpc/pd_policy_engine_snk.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for SNK
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-39 Sink Port state diagram
|
||||
*/
|
||||
|
||||
void pe_snk_startup_entry(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t rx_cap = PD_RX_CAP_PE_STARTUP;
|
||||
bool pr_swap = pd_port->state_machine == PE_STATE_MACHINE_PR_SWAP;
|
||||
|
||||
#ifdef CONFIG_USB_PD_IGNORE_PS_RDY_AFTER_PR_SWAP
|
||||
uint8_t msg_id_last = pd_port->pe_data.msg_id_rx[TCPC_TX_SOP];
|
||||
#endif /* CONFIG_USB_PD_IGNORE_PS_RDY_AFTER_PR_SWAP */
|
||||
|
||||
pd_reset_protocol_layer(pd_port, false);
|
||||
|
||||
if (pr_swap) {
|
||||
/*
|
||||
* If PE reset rx_cap to startup in here,
|
||||
* maybe can't meet tSwapSink for PR_SWAP case
|
||||
*/
|
||||
rx_cap = PD_RX_CAP_PE_SEND_WAIT_CAP;
|
||||
|
||||
#ifdef CONFIG_USB_PD_IGNORE_PS_RDY_AFTER_PR_SWAP
|
||||
pd_port->msg_id_pr_swap_last = msg_id_last;
|
||||
#endif /* CONFIG_USB_PD_IGNORE_PS_RDY_AFTER_PR_SWAP */
|
||||
}
|
||||
|
||||
pd_set_rx_enable(pd_port, rx_cap);
|
||||
pd_put_pe_event(pd_port, PD_PE_RESET_PRL_COMPLETED);
|
||||
}
|
||||
|
||||
void pe_snk_discovery_entry(struct pd_port *pd_port)
|
||||
{
|
||||
bool wait_valid = true;
|
||||
|
||||
if (pd_check_pe_during_hard_reset(pd_port)) {
|
||||
wait_valid = false;
|
||||
pd_enable_pe_state_timer(pd_port, PD_TIMER_PS_TRANSITION);
|
||||
}
|
||||
pd_enable_vbus_valid_detection(pd_port, wait_valid);
|
||||
}
|
||||
|
||||
void pe_snk_wait_for_capabilities_entry(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_SNK_HRESET_KEEP_DRAW
|
||||
/* Default current draw after HardReset */
|
||||
if (pd_check_pe_during_hard_reset(pd_port))
|
||||
pd_dpm_sink_vbus(pd_port, true);
|
||||
#endif /* CONFIG_USB_PD_SNK_HRESET_KEEP_DRAW */
|
||||
|
||||
pd_notify_pe_hard_reset_completed(pd_port);
|
||||
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_SEND_WAIT_CAP);
|
||||
pd_enable_pe_state_timer(pd_port, PD_TIMER_SINK_WAIT_CAP);
|
||||
}
|
||||
|
||||
void pe_snk_evaluate_capability_entry(struct pd_port *pd_port)
|
||||
{
|
||||
/* Disable UART output for Source SenderResponse */
|
||||
pd_lock_msg_output(pd_port);
|
||||
|
||||
pd_handle_hard_reset_recovery(pd_port);
|
||||
pd_handle_first_pd_command(pd_port);
|
||||
|
||||
pd_port->pe_data.explicit_contract = false;
|
||||
pd_dpm_snk_evaluate_caps(pd_port);
|
||||
}
|
||||
|
||||
void pe_snk_select_capability_entry(struct pd_port *pd_port)
|
||||
{
|
||||
struct pd_event *pd_event = pd_get_curr_pd_event(pd_port);
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
PE_STATE_WAIT_MSG_HRESET_IF_TOUT(pd_port);
|
||||
|
||||
if (pd_event->event_type == PD_EVT_DPM_MSG) {
|
||||
PE_DBG("SelectCap%d, rdo:0x%08x\n",
|
||||
pd_event->msg_sec, pd_port->last_rdo);
|
||||
} else {
|
||||
/* new request, for debug only */
|
||||
/* pd_dpm_sink_vbus(pd_port, false); */
|
||||
PE_DBG("NewReq, rdo:0x%08x\n", pd_port->last_rdo);
|
||||
}
|
||||
|
||||
/* Disable UART output for Sink SenderResponse */
|
||||
pd_lock_msg_output(pd_port);
|
||||
|
||||
pd_send_sop_data_msg(pd_port,
|
||||
PD_DATA_REQUEST, 1, &pd_port->last_rdo);
|
||||
}
|
||||
|
||||
void pe_snk_select_capability_exit(struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_RENEGOTIATION_COUNTER
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
#endif /* CONFIG_USB_PD_RENEGOTIATION_COUNTER */
|
||||
|
||||
if (pd_check_ctrl_msg_event(pd_port, PD_CTRL_ACCEPT)) {
|
||||
pd_port->pe_data.remote_selected_cap =
|
||||
RDO_POS(pd_port->last_rdo);
|
||||
pd_port->cap_miss_match = 0;
|
||||
} else if (pd_check_ctrl_msg_event(pd_port, PD_CTRL_REJECT)) {
|
||||
#ifdef CONFIG_USB_PD_RENEGOTIATION_COUNTER
|
||||
if (pd_port->cap_miss_match == 0x01) {
|
||||
PE_INFO("reset renegotiation cnt by cap mismatch\n");
|
||||
pd_port->pe_data.renegotiation_count = 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_RENEGOTIATION_COUNTER */
|
||||
pd_port->cap_miss_match |= (1 << 1);
|
||||
} else
|
||||
pd_port->cap_miss_match = 0;
|
||||
|
||||
/* Waiting for Hard-Reset Done */
|
||||
if (!pd_check_timer_msg_event(pd_port, PD_TIMER_SENDER_RESPONSE))
|
||||
pd_unlock_msg_output(pd_port);
|
||||
}
|
||||
|
||||
void pe_snk_transition_sink_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_enable_pe_state_timer(pd_port, PD_TIMER_PS_TRANSITION);
|
||||
|
||||
#ifdef CONFIG_USB_PD_SNK_GOTOMIN
|
||||
if (pd_check_ctrl_msg_event(pd_port, PD_CTRL_GOTO_MIN)) {
|
||||
if (pd_port->dpm_caps & DPM_CAP_LOCAL_GIVE_BACK)
|
||||
pd_port->request_i_new = pd_port->request_i_op;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_SNK_GOTOMIN */
|
||||
|
||||
pd_dpm_snk_standby_power(pd_port);
|
||||
}
|
||||
|
||||
void pe_snk_ready_entry(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_check_ctrl_msg_event(pd_port, PD_CTRL_WAIT))
|
||||
pd_enable_timer(pd_port, PD_TIMER_SINK_REQUEST);
|
||||
|
||||
pd_notify_pe_snk_explicit_contract(pd_port);
|
||||
pe_power_ready_entry(pd_port);
|
||||
}
|
||||
|
||||
void pe_snk_hard_reset_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_hard_reset(pd_port);
|
||||
}
|
||||
|
||||
void pe_snk_transition_to_default_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_reset_local_hw(pd_port);
|
||||
pd_dpm_snk_hard_reset(pd_port);
|
||||
}
|
||||
|
||||
void pe_snk_give_sink_cap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_sink_caps(pd_port);
|
||||
}
|
||||
|
||||
void pe_snk_get_source_cap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_TCPM_CB_2ND
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
#else
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
#endif /* CONFIG_USB_PD_TCPM_CB_2ND */
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_SOURCE_CAP);
|
||||
}
|
||||
|
||||
void pe_snk_send_soft_reset_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_soft_reset(pd_port);
|
||||
}
|
||||
|
||||
void pe_snk_soft_reset_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_handle_soft_reset(pd_port);
|
||||
}
|
||||
|
||||
/* ---- Policy Engine (PD30) ---- */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-71 Sink Port Not Supported Message State Diagram
|
||||
*/
|
||||
|
||||
void pe_snk_send_not_supported_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
void pe_snk_not_supported_received_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_DPM_INFORMED(pd_port);
|
||||
|
||||
pd_dpm_inform_not_support(pd_port);
|
||||
}
|
||||
|
||||
void pe_snk_chunk_received_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_enable_timer(pd_port, PD_TIMER_CK_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-74 Sink Port Source Alert State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
void pe_snk_source_alert_received_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_DPM_INFORMED(pd_port);
|
||||
|
||||
pd_dpm_inform_alert(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-75 Sink Port Sink Alert State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
void pe_snk_send_sink_alert_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
pd_dpm_send_alert(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-77 Sink Port Get Source Capabilities Extended State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
void pe_snk_get_source_cap_ext_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_SOURCE_CAP_EXT);
|
||||
}
|
||||
|
||||
void pe_snk_get_source_cap_ext_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_source_cap_ext(pd_port);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-79 Sink Port Get Source Status State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
void pe_snk_get_source_status_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_STATUS);
|
||||
}
|
||||
|
||||
void pe_snk_get_source_status_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_status(pd_port);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-82 Sink Give Sink Status State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
void pe_snk_give_sink_status_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_status(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-83 Sink Port Get Source PPS Status State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
void pe_snk_get_pps_status_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_PPS_STATUS);
|
||||
}
|
||||
|
||||
void pe_snk_get_pps_status_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_pps_status(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
311
drivers/usb/typec/mmi_tcpc/pd_policy_engine_src.c
Normal file
311
drivers/usb/typec/mmi_tcpc/pd_policy_engine_src.c
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for SRC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-38 Source Port Policy Engine state diagram
|
||||
*/
|
||||
|
||||
void pe_src_startup_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_reset_protocol_layer(pd_port, false);
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_STARTUP);
|
||||
|
||||
/*
|
||||
* When entering this state,
|
||||
* VBUS must be valid even for cc_attached.
|
||||
*/
|
||||
|
||||
pd_enable_timer(pd_port, PD_TIMER_SOURCE_START);
|
||||
}
|
||||
|
||||
void pe_src_discovery_entry(struct pd_port *pd_port)
|
||||
{
|
||||
/* The SourceCapabilitiesTimer continues to run during the states
|
||||
* defined in Source Startup Structured VDM Discover Identity State
|
||||
* Diagram
|
||||
*/
|
||||
|
||||
pd_port->pe_data.pd_connected = false;
|
||||
|
||||
pd_enable_timer(pd_port, PD_TIMER_SOURCE_CAPABILITY);
|
||||
|
||||
#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
|
||||
if (pd_is_discover_cable(pd_port))
|
||||
pd_enable_timer(pd_port, PD_TIMER_DISCOVER_ID);
|
||||
#endif
|
||||
}
|
||||
|
||||
void pe_src_send_capabilities_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG_HRESET_IF_TOUT(pd_port);
|
||||
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_SEND_WAIT_CAP);
|
||||
|
||||
pd_dpm_send_source_caps(pd_port);
|
||||
pd_port->pe_data.cap_counter++;
|
||||
}
|
||||
|
||||
void pe_src_negotiate_capabilities_entry(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
pd_handle_first_pd_command(pd_port);
|
||||
pd_dpm_src_evaluate_request(pd_port);
|
||||
}
|
||||
|
||||
void pe_src_transition_supply_entry(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t msg = PD_CTRL_ACCEPT;
|
||||
struct pd_event *pd_event = pd_get_curr_pd_event(pd_port);
|
||||
|
||||
/* goto-min */
|
||||
if (pd_event->event_type == PD_EVT_TCP_MSG) {
|
||||
msg = PD_CTRL_GOTO_MIN;
|
||||
pd_port->request_i_new = pd_port->request_i_op;
|
||||
}
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, msg);
|
||||
}
|
||||
|
||||
void pe_src_transition_supply2_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_PS_RDY);
|
||||
}
|
||||
|
||||
void pe_src_ready_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_notify_pe_src_explicit_contract(pd_port);
|
||||
pe_power_ready_entry(pd_port);
|
||||
}
|
||||
|
||||
void pe_src_disabled_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_notify_pe_hard_reset_completed(pd_port);
|
||||
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_DISABLE);
|
||||
pd_update_connect_state(pd_port, PD_CONNECT_TYPEC_ONLY_SRC);
|
||||
pd_dpm_dynamic_disable_vconn(pd_port);
|
||||
}
|
||||
|
||||
void pe_src_capability_response_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_reply_wait_reject_msg_no_resp(pd_port);
|
||||
}
|
||||
|
||||
void pe_src_hard_reset_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_hard_reset(pd_port);
|
||||
pd_enable_timer(pd_port, PD_TIMER_PS_HARD_RESET);
|
||||
}
|
||||
|
||||
void pe_src_hard_reset_received_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_enable_timer(pd_port, PD_TIMER_PS_HARD_RESET);
|
||||
}
|
||||
|
||||
void pe_src_transition_to_default_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_reset_local_hw(pd_port);
|
||||
pd_dpm_src_hard_reset(pd_port);
|
||||
}
|
||||
|
||||
void pe_src_transition_to_default_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_set_vconn(pd_port, PD_ROLE_VCONN_ON);
|
||||
pd_enable_timer(pd_port, PD_TIMER_NO_RESPONSE);
|
||||
}
|
||||
|
||||
void pe_src_get_sink_cap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_SINK_CAP);
|
||||
}
|
||||
|
||||
void pe_src_get_sink_cap_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_dr_inform_sink_cap(pd_port);
|
||||
}
|
||||
|
||||
void pe_src_wait_new_capabilities_entry(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
/* Wait for new Source Capabilities */
|
||||
}
|
||||
|
||||
void pe_src_send_soft_reset_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_soft_reset(pd_port);
|
||||
}
|
||||
|
||||
void pe_src_soft_reset_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_handle_soft_reset(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-81
|
||||
Source Startup Structured VDM Discover Identity State Diagram (TODO)
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
|
||||
|
||||
#ifdef CONFIG_PD_SRC_RESET_CABLE
|
||||
void pe_src_cbl_send_soft_reset_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_RESPONSE(pd_port);
|
||||
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_DISCOVER_CABLE);
|
||||
|
||||
pd_send_cable_soft_reset(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_PD_SRC_RESET_CABLE */
|
||||
|
||||
void pe_src_vdm_identity_request_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_DISCOVER_CABLE);
|
||||
|
||||
pd_port->pe_data.discover_id_counter++;
|
||||
pd_send_vdm_discover_id(pd_port, TCPC_TX_SOP_PRIME);
|
||||
}
|
||||
|
||||
void pe_src_vdm_identity_acked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_cable_id(pd_port, true);
|
||||
}
|
||||
|
||||
void pe_src_vdm_identity_naked_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_cable_id(pd_port, true);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
|
||||
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
/*
|
||||
* [PD3.0] Source Port Not Supported Message State Diagram
|
||||
*/
|
||||
|
||||
void pe_src_send_not_supported_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
void pe_src_not_supported_received_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_DPM_INFORMED(pd_port);
|
||||
|
||||
pd_dpm_inform_not_support(pd_port);
|
||||
}
|
||||
|
||||
void pe_src_chunk_received_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_enable_timer(pd_port, PD_TIMER_CK_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-73 Source Port Source Alert State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
void pe_src_send_source_alert_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
pd_dpm_send_alert(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-76 Source Port Sink Alert State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
void pe_src_sink_alert_received_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_DPM_INFORMED(pd_port);
|
||||
|
||||
pd_dpm_inform_alert(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-78 Source Give Source Capabilities Extended State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
void pe_src_give_source_cap_ext_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_source_cap_ext(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-80 Source Give Source Status State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
void pe_src_give_source_status_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
pd_dpm_send_status(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-81 Source Port Get Sink Status State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
void pe_src_get_sink_status_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_MSG(pd_port);
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_GET_STATUS);
|
||||
}
|
||||
|
||||
void pe_src_get_sink_status_exit(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_inform_status(pd_port);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
|
||||
/*
|
||||
* [PD3.0] Figure 8-84 Source Give Source PPS Status State Diagram
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SOURCE
|
||||
void pe_src_give_pps_status_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
|
||||
/* TODO */
|
||||
PD_BUG_ON(1);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SOURCE */
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
118
drivers/usb/typec/mmi_tcpc/pd_policy_engine_ufp.c
Normal file
118
drivers/usb/typec/mmi_tcpc/pd_policy_engine_ufp.c
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for UFP
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-58 UFP Structured VDM Discover Identity State Diagram
|
||||
*/
|
||||
|
||||
void pe_ufp_vdm_get_identity_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_ufp_request_id_info(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-59 UFP Structured VDM Discover SVIDs State Diagram
|
||||
*/
|
||||
|
||||
void pe_ufp_vdm_get_svids_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_ufp_request_svid_info(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-60 UFP Structured VDM Discover Modes State Diagram
|
||||
*/
|
||||
|
||||
void pe_ufp_vdm_get_modes_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_ufp_request_mode_info(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-61 UFP Structured VDM Enter Mode State Diagram
|
||||
*/
|
||||
|
||||
void pe_ufp_vdm_evaluate_mode_entry_entry(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_ufp_request_enter_mode(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-62 UFP Structured VDM Exit Mode State Diagram
|
||||
*/
|
||||
|
||||
void pe_ufp_vdm_mode_exit_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_ufp_request_exit_mode(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-63 UFP VDM Attention State Diagram
|
||||
*/
|
||||
|
||||
void pe_ufp_vdm_attention_request_entry(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
VDM_STATE_NORESP_CMD(pd_port);
|
||||
|
||||
switch (pd_port->mode_svid) {
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
case USB_SID_DISPLAYPORT:
|
||||
pd_dpm_ufp_send_dp_attention(pd_port);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
pd_send_vdm_attention(pd_port,
|
||||
TCPC_TX_SOP, pd_port->mode_svid, pd_port->mode_obj_pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ALT Mode
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
|
||||
void pe_ufp_vdm_dp_status_update_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_ufp_request_dp_status(pd_port);
|
||||
}
|
||||
|
||||
void pe_ufp_vdm_dp_configure_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_ufp_request_dp_config(pd_port);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
/*
|
||||
* SVMD/UVDM
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
|
||||
void pe_ufp_uvdm_recv_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_ufp_recv_uvdm(pd_port);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
71
drivers/usb/typec/mmi_tcpc/pd_policy_engine_vcs.c
Normal file
71
drivers/usb/typec/mmi_tcpc/pd_policy_engine_vcs.c
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for VCS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/pd_policy_engine.h"
|
||||
|
||||
/*
|
||||
* [PD2.0] Figure 8-57 VCONN Swap State Diagram
|
||||
*/
|
||||
|
||||
void pe_vcs_send_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pe_send_swap_request_entry(pd_port, PD_CTRL_VCONN_SWAP);
|
||||
}
|
||||
|
||||
void pe_vcs_evaluate_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_dpm_vcs_evaluate_swap(pd_port);
|
||||
}
|
||||
|
||||
void pe_vcs_accept_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_ACCEPT);
|
||||
}
|
||||
|
||||
void pe_vcs_reject_vconn_swap_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_reply_wait_reject_msg(pd_port);
|
||||
}
|
||||
|
||||
void pe_vcs_wait_for_vconn_entry(struct pd_port *pd_port)
|
||||
{
|
||||
pd_enable_pe_state_timer(pd_port, PD_TIMER_VCONN_ON);
|
||||
}
|
||||
|
||||
void pe_vcs_turn_off_vconn_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_DPM_ACK(pd_port);
|
||||
pd_dpm_vcs_enable_vconn(pd_port, PD_ROLE_VCONN_OFF);
|
||||
}
|
||||
|
||||
void pe_vcs_turn_on_vconn_entry(struct pd_port *pd_port)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_RESET_CABLE
|
||||
dpm_reaction_set(pd_port, DPM_REACTION_CAP_RESET_CABLE);
|
||||
#endif /* CONFIG_USB_PD_RESET_CABLE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
pd_dpm_vcs_enable_vconn(pd_port, PD_ROLE_VCONN_DYNAMIC_ON);
|
||||
}
|
||||
|
||||
void pe_vcs_send_ps_rdy_entry(struct pd_port *pd_port)
|
||||
{
|
||||
PE_STATE_WAIT_TX_SUCCESS(pd_port);
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_PS_RDY);
|
||||
}
|
||||
837
drivers/usb/typec/mmi_tcpc/pd_process_evt.c
Normal file
837
drivers/usb/typec/mmi_tcpc/pd_process_evt.c
Normal file
|
|
@ -0,0 +1,837 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Process Event
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
|
||||
/*
|
||||
* [BLOCK] print event
|
||||
*/
|
||||
|
||||
#if PE_EVENT_DBG_ENABLE
|
||||
static const char * const pd_ctrl_msg_name[] = {
|
||||
"ctrl0",
|
||||
"good_crc",
|
||||
"goto_min",
|
||||
"accept",
|
||||
"reject",
|
||||
"ping",
|
||||
"ps_rdy",
|
||||
"get_src_cap",
|
||||
"get_snk_cap",
|
||||
"dr_swap",
|
||||
"pr_swap",
|
||||
"vs_swap",
|
||||
"wait",
|
||||
"soft_reset",
|
||||
"ctrlE",
|
||||
"ctrlF",
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
"no_support",
|
||||
"get_src_cap_ex",
|
||||
"get_status",
|
||||
"fr_swap",
|
||||
"get_pps",
|
||||
"get_cc",
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
};
|
||||
|
||||
static inline void print_ctrl_msg_event(struct tcpc_device *tcpc, uint8_t msg)
|
||||
{
|
||||
if (msg < PD_CTRL_MSG_NR)
|
||||
PE_EVT_INFO("%s\n", pd_ctrl_msg_name[msg]);
|
||||
}
|
||||
|
||||
static const char * const pd_data_msg_name[] = {
|
||||
"data0",
|
||||
"src_cap",
|
||||
"request",
|
||||
"bist",
|
||||
"sink_cap",
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
"bat_status",
|
||||
"alert",
|
||||
"get_ci",
|
||||
#else
|
||||
"data5",
|
||||
"data6",
|
||||
"data7",
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
"data8",
|
||||
"data9",
|
||||
"dataA",
|
||||
"dataB",
|
||||
"dataC",
|
||||
"dataD",
|
||||
"dataE",
|
||||
"vdm",
|
||||
};
|
||||
|
||||
static inline void print_data_msg_event(struct tcpc_device *tcpc, uint8_t msg)
|
||||
{
|
||||
if (msg < PD_DATA_MSG_NR)
|
||||
PE_EVT_INFO("%s\n", pd_data_msg_name[msg]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
static const char *const pd_ext_msg_name[] = {
|
||||
"ext0",
|
||||
"src_cap_ex",
|
||||
"status",
|
||||
"get_bat_cap",
|
||||
"get_bat_status",
|
||||
"bat_cap",
|
||||
"get_mfr_info",
|
||||
"mfr_info",
|
||||
"sec_req",
|
||||
"sec_resp",
|
||||
"fw_update_req",
|
||||
"fw_update_res",
|
||||
"pps_status",
|
||||
"ci",
|
||||
"cc",
|
||||
};
|
||||
|
||||
static inline void print_ext_msg_event(struct tcpc_device *tcpc, uint8_t msg)
|
||||
{
|
||||
if (msg < PD_EXT_MSG_NR)
|
||||
PE_EVT_INFO("%s\n", pd_ext_msg_name[msg]);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
static const char *const pd_hw_msg_name[] = {
|
||||
"Detached",
|
||||
"Attached",
|
||||
"hard_reset",
|
||||
"vbus_high",
|
||||
"vbus_low",
|
||||
"vbus_0v",
|
||||
"vbus_stable",
|
||||
"tx_err",
|
||||
"discard",
|
||||
"retry_vdm",
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
"sink_tx_change",
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
};
|
||||
|
||||
static inline void print_hw_msg_event(struct tcpc_device *tcpc, uint8_t msg)
|
||||
{
|
||||
if (msg < PD_HW_MSG_NR)
|
||||
PE_EVT_INFO("%s\n", pd_hw_msg_name[msg]);
|
||||
}
|
||||
|
||||
static const char *const pd_pe_msg_name[] = {
|
||||
"reset_prl_done",
|
||||
"pr_at_dft",
|
||||
"hard_reset_done",
|
||||
"pe_idle",
|
||||
"vdm_reset",
|
||||
"vdm_not_support",
|
||||
};
|
||||
|
||||
static inline void print_pe_msg_event(struct tcpc_device *tcpc, uint8_t msg)
|
||||
{
|
||||
if (msg < PD_PE_MSG_NR)
|
||||
PE_EVT_INFO("%s\n", pd_pe_msg_name[msg]);
|
||||
}
|
||||
|
||||
static const char * const pd_dpm_msg_name[] = {
|
||||
"ack",
|
||||
"nak",
|
||||
"cap_change",
|
||||
"not_support",
|
||||
};
|
||||
|
||||
static inline void print_dpm_msg_event(struct tcpc_device *tcpc, uint8_t msg)
|
||||
{
|
||||
if (msg < PD_DPM_MSG_NR)
|
||||
PE_EVT_INFO("dpm_%s\n", pd_dpm_msg_name[msg]);
|
||||
}
|
||||
|
||||
static const char *const tcp_dpm_evt_name[] = {
|
||||
/* TCP_DPM_EVT_UNKONW */
|
||||
"unknown",
|
||||
|
||||
/* TCP_DPM_EVT_PD_COMMAND */
|
||||
"pr_swap_snk",
|
||||
"pr_swap_src",
|
||||
"dr_swap_ufp",
|
||||
"dr_swap_dfp",
|
||||
"vc_swap_off",
|
||||
"vc_swap_on",
|
||||
"goto_min",
|
||||
"soft_reset",
|
||||
"cable_soft_reset",
|
||||
"get_src_cap",
|
||||
"get_snk_cap",
|
||||
"request",
|
||||
"request_ex",
|
||||
"request_again",
|
||||
"bist_cm2",
|
||||
"dummy",
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
"get_src_cap_ext",
|
||||
"get_status",
|
||||
"fr_swap_snk",
|
||||
"fr_swap_src",
|
||||
"get_cc",
|
||||
"get_pps",
|
||||
|
||||
"alert",
|
||||
"get_ci",
|
||||
"get_bat_cap",
|
||||
"get_bat_status",
|
||||
"get_mfrs_info",
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
/* TCP_DPM_EVT_VDM_COMMAND */
|
||||
"disc_cable",
|
||||
"disc_id",
|
||||
"disc_svid",
|
||||
"disc_mode",
|
||||
"enter_mode",
|
||||
"exit_mode",
|
||||
"attention",
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
"dp_atten",
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
"dp_status",
|
||||
"dp_config",
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
"uvdm",
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
/* TCP_DPM_EVT_IMMEDIATELY */
|
||||
"hard_reset",
|
||||
"error_recovery",
|
||||
};
|
||||
|
||||
static inline void print_tcp_event(struct tcpc_device *tcpc, uint8_t msg)
|
||||
{
|
||||
if (msg < TCP_DPM_EVT_NR)
|
||||
PE_EVT_INFO("tcp_event(%s), %d\n",
|
||||
tcp_dpm_evt_name[msg], msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void print_event(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#if PE_EVENT_DBG_ENABLE
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
switch (pd_event->event_type) {
|
||||
case PD_EVT_CTRL_MSG:
|
||||
print_ctrl_msg_event(tcpc, pd_event->msg);
|
||||
break;
|
||||
|
||||
case PD_EVT_DATA_MSG:
|
||||
print_data_msg_event(tcpc, pd_event->msg);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_EVT_EXT_MSG:
|
||||
print_ext_msg_event(tcpc, pd_event->msg);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
case PD_EVT_DPM_MSG:
|
||||
print_dpm_msg_event(tcpc, pd_event->msg);
|
||||
break;
|
||||
|
||||
case PD_EVT_HW_MSG:
|
||||
print_hw_msg_event(tcpc, pd_event->msg);
|
||||
break;
|
||||
|
||||
case PD_EVT_PE_MSG:
|
||||
print_pe_msg_event(tcpc, pd_event->msg);
|
||||
break;
|
||||
|
||||
case PD_EVT_TIMER_MSG:
|
||||
PE_EVT_INFO("timer\n");
|
||||
break;
|
||||
|
||||
case PD_EVT_TCP_MSG:
|
||||
print_tcp_event(tcpc, pd_event->msg);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
bool pd_make_pe_state_transit(struct pd_port *pd_port,
|
||||
uint8_t curr_state, const struct pe_state_reaction *state_reaction)
|
||||
{
|
||||
int i;
|
||||
const struct pe_state_transition *state_transition =
|
||||
state_reaction->state_transition;
|
||||
|
||||
for (i = 0; i < state_reaction->nr_transition; i++) {
|
||||
if (state_transition[i].curr_state == curr_state) {
|
||||
PE_TRANSIT_STATE(pd_port,
|
||||
state_transition[i].next_state);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
static inline bool pd30_process_ready_protocol_error(struct pd_port *pd_port)
|
||||
{
|
||||
bool multi_chunk;
|
||||
|
||||
if (!pd_check_rev30(pd_port))
|
||||
return false;
|
||||
|
||||
if (!pd_port->curr_unsupported_msg) {
|
||||
pe_transit_soft_reset_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
multi_chunk = pd_is_multi_chunk_msg(pd_port);
|
||||
|
||||
if (pd_port->power_role == PD_ROLE_SINK) {
|
||||
PE_TRANSIT_STATE(pd_port, multi_chunk ?
|
||||
PE_SNK_CHUNK_RECEIVED : PE_SNK_SEND_NOT_SUPPORTED);
|
||||
return true;
|
||||
}
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, multi_chunk ?
|
||||
PE_SRC_CHUNK_RECEIVED : PE_SRC_SEND_NOT_SUPPORTED);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
|
||||
bool pd_process_protocol_error(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool power_change = false;
|
||||
#if PE_INFO_ENABLE
|
||||
uint8_t event_type = pd_event->event_type;
|
||||
uint8_t msg_id = pd_get_msg_hdr_id(pd_port);
|
||||
uint8_t msg_type = pd_event->msg;
|
||||
#endif
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SNK_TRANSITION_SINK:
|
||||
/* fall through */
|
||||
case PE_SRC_TRANSITION_SUPPLY: /* never recv ping for Source =.=*/
|
||||
/* fall through */
|
||||
case PE_SRC_TRANSITION_SUPPLY2:
|
||||
power_change = true;
|
||||
if (pd_event_msg_match(pd_event,
|
||||
PD_EVT_CTRL_MSG, PD_CTRL_PING)) {
|
||||
PE_DBG("Ignore Ping\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
if (pd_event_msg_match(pd_event,
|
||||
PD_EVT_CTRL_MSG, PD_CTRL_PING)) {
|
||||
PE_DBG("Ignore Ping\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PE_SNK_READY:
|
||||
case PE_SRC_READY:
|
||||
if (pd30_process_ready_protocol_error(pd_port))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
};
|
||||
|
||||
if (pd_port->pe_data.pe_state_flags &
|
||||
PE_STATE_FLAG_IGNORE_UNKNOWN_EVENT) {
|
||||
PE_DBG("Ignore Unknown Event\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pd_check_pe_during_hard_reset(pd_port)) {
|
||||
PE_DBG("Ignore Event during HReset\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* msg_type: PD_EVT_CTRL_MSG (1), PD_EVT_DATA_MSG (2)
|
||||
*/
|
||||
|
||||
PE_INFO("PRL_ERR: %d-%d-%d\n", event_type, msg_type, msg_id);
|
||||
|
||||
if (pd_port->pe_data.during_swap) {
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP_ERROR_RECOVERY
|
||||
PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
|
||||
#else
|
||||
pe_transit_hard_reset_state(pd_port);
|
||||
#endif
|
||||
} else if (power_change)
|
||||
pe_transit_hard_reset_state(pd_port);
|
||||
else
|
||||
pe_transit_soft_reset_state(pd_port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pd_process_tx_failed(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_check_pe_state_ready(pd_port) ||
|
||||
pd_check_pe_during_hard_reset(pd_port)) {
|
||||
PE_DBG("Ignore tx_failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pe_transit_soft_reset_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_RESET_CABLE
|
||||
static inline bool pd_process_cable_ctrl_msg_accept(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_port->pe_state_curr) {
|
||||
#ifdef CONFIG_PD_SRC_RESET_CABLE
|
||||
case PE_SRC_CBL_SEND_SOFT_RESET:
|
||||
vdm_put_dpm_discover_cable_event(pd_port);
|
||||
return false;
|
||||
#endif /* CONFIG_PD_SRC_RESET_CABLE */
|
||||
|
||||
#ifdef CONFIG_PD_DFP_RESET_CABLE
|
||||
case PE_DFP_CBL_SEND_SOFT_RESET:
|
||||
pe_transit_ready_state(pd_port);
|
||||
return true;
|
||||
#endif /* CONFIG_PD_DFP_RESET_CABLE */
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_RESET_CABLE */
|
||||
|
||||
static inline bool pd_process_event_cable(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool ret = false;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
#ifdef CONFIG_USB_PD_RESET_CABLE
|
||||
if (pd_event->msg == PD_CTRL_ACCEPT)
|
||||
ret = pd_process_cable_ctrl_msg_accept(pd_port, pd_event);
|
||||
#endif /* CONFIG_USB_PD_RESET_CABLE */
|
||||
|
||||
if (!ret)
|
||||
PE_DBG("Ignore not SOP Ctrl Msg\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static void pd_copy_msg_data(struct pd_port *pd_port,
|
||||
uint8_t *payload, uint16_t count, uint8_t unit_sz)
|
||||
{
|
||||
pd_port->pd_msg_data_size = count * unit_sz;
|
||||
pd_port->pd_msg_data_count = count;
|
||||
pd_port->pd_msg_data_payload = payload;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
static inline void pd_copy_msg_data_from_ext_evt(
|
||||
struct pd_port *pd_port, struct pd_msg *pd_msg)
|
||||
{
|
||||
uint32_t *payload = pd_msg->payload;
|
||||
|
||||
uint16_t *ext_hdr = (uint16_t *) payload;
|
||||
uint8_t *ext_data = (uint8_t *) (ext_hdr+1);
|
||||
|
||||
uint16_t size = PD_EXT_HEADER_DATA_SIZE(*ext_hdr);
|
||||
|
||||
pd_copy_msg_data(pd_port, ext_data, size, 1);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
static inline void pd_copy_msg_data_from_evt(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
struct pd_msg *pd_msg = pd_event->pd_msg;
|
||||
|
||||
switch (pd_event->event_type) {
|
||||
case PD_EVT_DATA_MSG:
|
||||
PD_BUG_ON(pd_msg == NULL);
|
||||
pd_copy_msg_data(pd_port, (uint8_t *)pd_msg->payload,
|
||||
pd_get_msg_hdr_cnt(pd_port), sizeof(uint32_t));
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_EVT_EXT_MSG:
|
||||
PD_BUG_ON(pd_msg == NULL);
|
||||
pd_copy_msg_data_from_ext_evt(pd_port, pd_msg);
|
||||
return;
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
default:
|
||||
pd_copy_msg_data(pd_port, NULL, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
*
|
||||
* @ true : valid message
|
||||
* @ false : invalid message, pe should drop the message
|
||||
*/
|
||||
|
||||
static inline bool pe_is_valid_pd_msg_id(struct pd_port *pd_port,
|
||||
struct pd_event *pd_event, struct pd_msg *pd_msg)
|
||||
{
|
||||
uint8_t sop_type = pd_msg->frame_type;
|
||||
uint8_t msg_id = pd_get_msg_hdr_id(pd_port);
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_port->pe_state_curr == PE_BIST_TEST_DATA)
|
||||
return false;
|
||||
|
||||
if (pd_event->event_type == PD_EVT_CTRL_MSG) {
|
||||
switch (pd_event->msg) {
|
||||
/* SofReset always has a MessageID value of zero */
|
||||
case PD_CTRL_SOFT_RESET:
|
||||
if (msg_id != 0) {
|
||||
PE_INFO("Repeat soft_reset\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case PD_CTRL_GOOD_CRC:
|
||||
PE_DBG("Discard_CRC\n");
|
||||
return true;
|
||||
|
||||
#ifdef CONFIG_USB_PD_IGNORE_PS_RDY_AFTER_PR_SWAP
|
||||
case PD_CTRL_PS_RDY:
|
||||
if (pd_port->msg_id_pr_swap_last == msg_id) {
|
||||
PE_INFO("Repeat ps_rdy\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_IGNORE_PS_RDY_AFTER_PR_SWAP */
|
||||
}
|
||||
}
|
||||
|
||||
if (pd_port->pe_data.msg_id_rx[sop_type] == msg_id) {
|
||||
PE_INFO("Repeat msg: %c:%d:%d\n",
|
||||
(pd_event->event_type == PD_EVT_CTRL_MSG) ? 'C' : 'D',
|
||||
pd_event->msg, msg_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
pd_port->pe_data.msg_id_rx[sop_type] = msg_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pe_is_valid_pd_msg_role(struct pd_port *pd_port,
|
||||
struct pd_event *pd_event, struct pd_msg *pd_msg)
|
||||
{
|
||||
bool ret = true;
|
||||
uint8_t msg_pr, msg_dr;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_msg == NULL) /* Good-CRC */
|
||||
return true;
|
||||
|
||||
if (pd_msg->frame_type != TCPC_TX_SOP)
|
||||
return true;
|
||||
|
||||
msg_pr = PD_HEADER_PR(pd_msg->msg_hdr);
|
||||
msg_dr = PD_HEADER_DR(pd_msg->msg_hdr);
|
||||
|
||||
/*
|
||||
* The Port Power Role field of a received Message shall not be verified
|
||||
* by the receiver and no error recovery action shall be
|
||||
* taken if it is incorrect.
|
||||
*/
|
||||
|
||||
if (msg_pr == pd_port->power_role)
|
||||
PE_DBG("Wrong PR:%d\n", msg_pr);
|
||||
|
||||
/*
|
||||
* Should a Type-C Port receive a Message with the Port Data Role field
|
||||
* set to the same Data Role as its current Data Role,
|
||||
* except for the GoodCRC Message,
|
||||
* Type-C error recovery actions as defined
|
||||
* in [USBType-C 1.0] shall be performed.
|
||||
*/
|
||||
|
||||
if (msg_dr == pd_port->data_role) {
|
||||
#ifdef CONFIG_USB_PD_CHECK_DATA_ROLE
|
||||
ret = false;
|
||||
#endif
|
||||
PE_INFO("Wrong DR:%d\n", msg_dr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void pe_translate_pd_msg_event(struct pd_port *pd_port,
|
||||
struct pd_event *pd_event, struct pd_msg *pd_msg)
|
||||
{
|
||||
uint16_t msg_hdr;
|
||||
|
||||
PD_BUG_ON(pd_msg == NULL);
|
||||
|
||||
msg_hdr = pd_msg->msg_hdr;
|
||||
pd_port->curr_msg_hdr = msg_hdr;
|
||||
pd_event->msg = PD_HEADER_TYPE(msg_hdr);
|
||||
|
||||
if (PD_HEADER_CNT(msg_hdr))
|
||||
pd_event->event_type = PD_EVT_DATA_MSG;
|
||||
else
|
||||
pd_event->event_type = PD_EVT_CTRL_MSG;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
if (PD_HEADER_EXT(msg_hdr))
|
||||
pd_event->event_type = PD_EVT_EXT_MSG;
|
||||
|
||||
if (pd_msg->frame_type == TCPC_TX_SOP_PRIME) {
|
||||
pd_sync_sop_prime_spec_revision(
|
||||
pd_port, PD_HEADER_REV(msg_hdr));
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
}
|
||||
|
||||
static inline uint8_t pe_get_startup_state(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool act_as_sink = true;
|
||||
uint8_t startup_state = 0xff;
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
|
||||
pd_port->custom_dbgacc = false;
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
|
||||
switch (pd_event->msg_sec) {
|
||||
case TYPEC_ATTACHED_DBGACC_SNK:
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
|
||||
pd_port->custom_dbgacc = true;
|
||||
startup_state = PE_DBG_READY;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
case TYPEC_ATTACHED_SNK:
|
||||
startup_state = PE_SNK_STARTUP;
|
||||
break;
|
||||
|
||||
case TYPEC_ATTACHED_SRC:
|
||||
act_as_sink = false;
|
||||
startup_state = PE_SRC_STARTUP;
|
||||
break;
|
||||
}
|
||||
|
||||
/* At least > 2 for Ellisys VNDI PR_SWAP */
|
||||
#ifdef CONFIG_USB_PD_ERROR_RECOVERY_ONCE
|
||||
if (pd_port->error_recovery_once > 2)
|
||||
startup_state = PE_ERROR_RECOVERY_ONCE;
|
||||
#endif /* CONFIG_USB_PD_ERROR_RECOVERY_ONCE */
|
||||
|
||||
pd_init_message_hdr(pd_port, act_as_sink);
|
||||
return startup_state;
|
||||
}
|
||||
|
||||
static inline bool pe_transit_startup_state(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
uint8_t startup_state =
|
||||
pe_get_startup_state(pd_port, pd_event);
|
||||
|
||||
if (startup_state == 0xff)
|
||||
return false;
|
||||
|
||||
pd_dpm_notify_pe_startup(pd_port);
|
||||
PE_TRANSIT_STATE(pd_port, startup_state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum {
|
||||
TII_TRAP_IN_IDLE = 0,
|
||||
TII_TRANSIT_STATE = 1,
|
||||
TII_PE_RUNNING = 2,
|
||||
};
|
||||
|
||||
static inline uint8_t pe_check_trap_in_idle_state(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
switch (pd_port->pe_pd_state) {
|
||||
case PE_IDLE1:
|
||||
case PE_ERROR_RECOVERY:
|
||||
if (pd_event_pe_msg_match(pd_event, PD_PE_IDLE)) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_IDLE2);
|
||||
return TII_TRANSIT_STATE;
|
||||
}
|
||||
|
||||
pd_try_put_pe_idle_event(pd_port);
|
||||
break;
|
||||
|
||||
case PE_IDLE2:
|
||||
if (pd_event_hw_msg_match(pd_event, PD_HW_CC_ATTACHED)) {
|
||||
if (pe_transit_startup_state(pd_port, pd_event))
|
||||
return TII_TRANSIT_STATE;
|
||||
}
|
||||
|
||||
/* The original IDLE2 may trigger by PE_IDLE_TOUT */
|
||||
if (pd_event_hw_msg_match(pd_event, PD_HW_CC_DETACHED))
|
||||
pd_notify_pe_idle(pd_port);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (pd_event_hw_msg_match(pd_event, PD_HW_CC_DETACHED)) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_IDLE1);
|
||||
return TII_TRANSIT_STATE;
|
||||
}
|
||||
return TII_PE_RUNNING;
|
||||
}
|
||||
|
||||
PE_DBG("Trap in idle state, Ignore All MSG (%d:%d)\n",
|
||||
pd_event->event_type, pd_event->msg);
|
||||
return TII_TRAP_IN_IDLE;
|
||||
}
|
||||
|
||||
static inline void pe_init_curr_state(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->power_role == PD_ROLE_SINK) {
|
||||
pd_port->curr_ready_state = PE_SNK_READY;
|
||||
pd_port->curr_hreset_state = PE_SNK_HARD_RESET;
|
||||
pd_port->curr_sreset_state = PE_SNK_SEND_SOFT_RESET;
|
||||
} else {
|
||||
pd_port->curr_ready_state = PE_SRC_READY;
|
||||
pd_port->curr_hreset_state = PE_SRC_HARD_RESET;
|
||||
pd_port->curr_sreset_state = PE_SRC_SEND_SOFT_RESET;
|
||||
}
|
||||
|
||||
pd_port->curr_unsupported_msg = false;
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
|
||||
if (pd_port->custom_dbgacc)
|
||||
pd_port->curr_ready_state = PE_DBG_READY;
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
}
|
||||
|
||||
bool pd_process_event(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool ret = false;
|
||||
struct pd_msg *pd_msg = pd_event->pd_msg;
|
||||
uint8_t tii = pe_check_trap_in_idle_state(pd_port, pd_event);
|
||||
|
||||
if (tii < TII_PE_RUNNING)
|
||||
return tii;
|
||||
|
||||
pe_init_curr_state(pd_port);
|
||||
|
||||
if (pd_event->event_type == PD_EVT_PD_MSG)
|
||||
pe_translate_pd_msg_event(pd_port, pd_event, pd_msg);
|
||||
|
||||
#if PE_EVT_INFO_VDM_DIS
|
||||
if (!pd_curr_is_vdm_evt(pd_port))
|
||||
#endif
|
||||
print_event(pd_port, pd_event);
|
||||
|
||||
if ((pd_event->event_type < PD_EVT_PD_MSG_END) && (pd_msg != NULL)) {
|
||||
|
||||
if (!pe_is_valid_pd_msg_id(pd_port, pd_event, pd_msg))
|
||||
return false;
|
||||
|
||||
if (!pe_is_valid_pd_msg_role(pd_port, pd_event, pd_msg)) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pd_copy_msg_data_from_evt(pd_port, pd_event);
|
||||
|
||||
if (pd_curr_is_vdm_evt(pd_port))
|
||||
return pd_process_event_vdm(pd_port, pd_event);
|
||||
|
||||
if (pd_event->event_type == PD_EVT_TCP_MSG)
|
||||
return pd_process_event_tcp(pd_port, pd_event);
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
|
||||
if (pd_port->custom_dbgacc)
|
||||
return pd_process_event_dbg(pd_port, pd_event);
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
|
||||
if ((pd_event->event_type == PD_EVT_CTRL_MSG) &&
|
||||
(pd_event->msg != PD_CTRL_GOOD_CRC) &&
|
||||
(pd_msg != NULL) && (pd_msg->frame_type != TCPC_TX_SOP))
|
||||
return pd_process_event_cable(pd_port, pd_event);
|
||||
|
||||
if (pd_process_event_com(pd_port, pd_event))
|
||||
return true;
|
||||
|
||||
switch (pd_port->state_machine) {
|
||||
#ifdef CONFIG_USB_PD_DR_SWAP
|
||||
case PE_STATE_MACHINE_DR_SWAP:
|
||||
ret = pd_process_event_drs(pd_port, pd_event);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_DR_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
case PE_STATE_MACHINE_PR_SWAP:
|
||||
ret = pd_process_event_prs(pd_port, pd_event);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_VCONN_SWAP
|
||||
case PE_STATE_MACHINE_VCONN_SWAP:
|
||||
ret = pd_process_event_vcs(pd_port, pd_event);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_VCONN_SWAP */
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return true;
|
||||
|
||||
if (pd_port->power_role == PD_ROLE_SINK)
|
||||
ret = pd_process_event_snk(pd_port, pd_event);
|
||||
else
|
||||
ret = pd_process_event_src(pd_port, pd_event);
|
||||
|
||||
return ret;
|
||||
}
|
||||
665
drivers/usb/typec/mmi_tcpc/pd_process_evt_com.c
Normal file
665
drivers/usb/typec/mmi_tcpc/pd_process_evt_com.c
Normal file
|
|
@ -0,0 +1,665 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Policy Engine for Common
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
|
||||
/*
|
||||
* [BLOCK] DRP (dr_swap, pr_swap, vconn_swap)
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_DR_SWAP
|
||||
static inline bool pd_evaluate_reject_dr_swap(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_DATA) {
|
||||
if (pd_port->power_role == PD_ROLE_DFP)
|
||||
return pd_port->dpm_caps &
|
||||
DPM_CAP_DR_SWAP_REJECT_AS_UFP;
|
||||
return pd_port->dpm_caps & DPM_CAP_DR_SWAP_REJECT_AS_DFP;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DR_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
static inline bool pd_evaluate_reject_pr_swap(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
|
||||
if (pd_port->power_role == PD_ROLE_SOURCE)
|
||||
return pd_port->dpm_caps &
|
||||
DPM_CAP_PR_SWAP_REJECT_AS_SNK;
|
||||
return pd_port->dpm_caps & DPM_CAP_PR_SWAP_REJECT_AS_SRC;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_VCONN_SWAP
|
||||
static inline bool pd_evaluate_accept_vconn_swap(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->dpm_caps & DPM_CAP_LOCAL_VCONN_SUPPLY)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_VCONN_SWAP */
|
||||
|
||||
static inline bool pd_process_ctrl_msg_dr_swap(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
if (pd_port->pe_data.modal_operation) {
|
||||
pe_transit_hard_reset_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_DR_SWAP
|
||||
if (!pd_check_pe_state_ready(pd_port))
|
||||
return false;
|
||||
|
||||
if (!pd_evaluate_reject_dr_swap(pd_port)) {
|
||||
pd_port->pe_data.during_swap = false;
|
||||
pd_port->state_machine = PE_STATE_MACHINE_DR_SWAP;
|
||||
|
||||
PE_TRANSIT_DATA_STATE(pd_port,
|
||||
PE_DRS_UFP_DFP_EVALUATE_DR_SWAP,
|
||||
PE_DRS_DFP_UFP_EVALUATE_DR_SWAP);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DR_SWAP */
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, PE_REJECT);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pd_process_ctrl_msg_pr_swap(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
if (!pd_evaluate_reject_pr_swap(pd_port)) {
|
||||
pd_port->pe_data.during_swap = false;
|
||||
pd_port->state_machine = PE_STATE_MACHINE_PR_SWAP;
|
||||
pe_transit_evaluate_pr_swap_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, PE_REJECT);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pd_process_ctrl_msg_vconn_swap(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_VCONN_SWAP
|
||||
if (!pd_check_pe_state_ready(pd_port))
|
||||
return false;
|
||||
|
||||
if (pd_evaluate_accept_vconn_swap(pd_port)) {
|
||||
pd_port->state_machine = PE_STATE_MACHINE_VCONN_SWAP;
|
||||
PE_TRANSIT_STATE(pd_port, PE_VCS_EVALUATE_SWAP);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_VCONN_SWAP */
|
||||
|
||||
if (!pd_check_rev30(pd_port)) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_REJECT);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] BIST
|
||||
*/
|
||||
|
||||
static inline bool pd_process_data_msg_bist(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_port->request_v > 5000) {
|
||||
PE_INFO("bist_not_vsafe5v\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (BDO_MODE(pd_event->pd_msg->payload[0])) {
|
||||
case BDO_MODE_TEST_DATA:
|
||||
PE_DBG("bist_test\n");
|
||||
PE_TRANSIT_STATE(pd_port, PE_BIST_TEST_DATA);
|
||||
pd_noitfy_pe_bist_mode(pd_port, PD_BIST_MODE_TEST_DATA);
|
||||
return true;
|
||||
|
||||
case BDO_MODE_CARRIER2:
|
||||
PE_DBG("bist_cm2\n");
|
||||
PE_TRANSIT_STATE(pd_port, PE_BIST_CARRIER_MODE_2);
|
||||
pd_noitfy_pe_bist_mode(pd_port, PD_BIST_MODE_DISABLE);
|
||||
return true;
|
||||
|
||||
default:
|
||||
#if 0
|
||||
case BDO_MODE_RECV:
|
||||
case BDO_MODE_TRANSMIT:
|
||||
case BDO_MODE_COUNTERS:
|
||||
case BDO_MODE_CARRIER0:
|
||||
case BDO_MODE_CARRIER1:
|
||||
case BDO_MODE_CARRIER3:
|
||||
case BDO_MODE_EYE:
|
||||
#endif
|
||||
PE_DBG("Unsupport BIST\n");
|
||||
pd_noitfy_pe_bist_mode(pd_port, PD_BIST_MODE_DISABLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Ctrl MSG
|
||||
*/
|
||||
|
||||
static void pd_cancel_dpm_reaction(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->pe_data.dpm_reaction_id < DPM_REACTION_REJECT_CANCEL)
|
||||
dpm_reaction_clear(pd_port, pd_port->pe_data.dpm_reaction_id);
|
||||
}
|
||||
|
||||
static bool pd_process_ctrl_msg_wait_reject(struct pd_port *pd_port)
|
||||
{
|
||||
pd_cancel_dpm_reaction(pd_port);
|
||||
|
||||
if (pd_port->state_machine == PE_STATE_MACHINE_PR_SWAP)
|
||||
pd_notify_pe_cancel_pr_swap(pd_port);
|
||||
|
||||
pe_transit_ready_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pd_process_ctrl_msg_wait(struct pd_port *pd_port)
|
||||
{
|
||||
|
||||
return pd_process_ctrl_msg_wait_reject(pd_port);
|
||||
}
|
||||
|
||||
static inline bool pd_process_ctrl_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
if (!pd_check_rev30(pd_port) &&
|
||||
pd_event->msg >= PD_CTRL_PD30_START) {
|
||||
pd_event->msg = PD_CTRL_MSG_NR;
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
switch (pd_event->msg) {
|
||||
case PD_CTRL_GOOD_CRC:
|
||||
if (pd_port->pe_data.pe_state_flags &
|
||||
PE_STATE_FLAG_ENABLE_SENDER_RESPONSE_TIMER)
|
||||
pd_enable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
|
||||
|
||||
if (pd_port->pe_data.pe_state_flags2 &
|
||||
PE_STATE_FLAG_BACK_READY_IF_RECV_GOOD_CRC) {
|
||||
pe_transit_ready_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case PD_CTRL_REJECT:
|
||||
pd_notify_tcp_event_2nd_result(pd_port, TCP_DPM_RET_REJECT);
|
||||
|
||||
if (pd_port->pe_data.pe_state_flags &
|
||||
PE_STATE_FLAG_BACK_READY_IF_RECV_REJECT) {
|
||||
return pd_process_ctrl_msg_wait_reject(pd_port);
|
||||
}
|
||||
break;
|
||||
case PD_CTRL_WAIT:
|
||||
pd_notify_tcp_event_2nd_result(pd_port, TCP_DPM_RET_WAIT);
|
||||
|
||||
if (pd_port->pe_data.pe_state_flags &
|
||||
PE_STATE_FLAG_BACK_READY_IF_RECV_WAIT) {
|
||||
return pd_process_ctrl_msg_wait(pd_port);
|
||||
}
|
||||
break;
|
||||
|
||||
case PD_CTRL_SOFT_RESET:
|
||||
if (!pd_port->pe_data.during_swap &&
|
||||
!pd_check_pe_during_hard_reset(pd_port)) {
|
||||
pe_transit_soft_reset_recv_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Swap */
|
||||
case PD_CTRL_DR_SWAP:
|
||||
ret = pd_process_ctrl_msg_dr_swap(pd_port, pd_event);
|
||||
break;
|
||||
|
||||
case PD_CTRL_PR_SWAP:
|
||||
ret = pd_process_ctrl_msg_pr_swap(pd_port, pd_event);
|
||||
break;
|
||||
|
||||
case PD_CTRL_VCONN_SWAP:
|
||||
ret = pd_process_ctrl_msg_vconn_swap(pd_port, pd_event);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL
|
||||
case PD_CTRL_GET_COUNTRY_CODE:
|
||||
if (pd_port->country_nr) {
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
pe_get_curr_ready_state(pd_port),
|
||||
PE_GIVE_COUNTRY_CODES);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL */
|
||||
|
||||
case PD_CTRL_NOT_SUPPORTED:
|
||||
pd_cancel_dpm_reaction(pd_port);
|
||||
pd_notify_tcp_event_2nd_result(
|
||||
pd_port, TCP_DPM_RET_NOT_SUPPORT);
|
||||
|
||||
if (pd_port->pe_data.pe_state_flags &
|
||||
PE_STATE_FLAG_BACK_READY_IF_SR_TIMER_TOUT) {
|
||||
pe_transit_ready_state(pd_port);
|
||||
return true;
|
||||
} else if (pd_port->pe_data.vdm_state_timer) {
|
||||
vdm_put_pe_event(
|
||||
pd_port->tcpc, PD_PE_VDM_NOT_SUPPORT);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Data MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_data_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool ret = false;
|
||||
uint8_t ready_state = pe_get_curr_ready_state(pd_port);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
if (!pd_check_rev30(pd_port) &&
|
||||
pd_event->msg >= PD_DATA_PD30_START) {
|
||||
pd_event->msg = PD_DATA_MSG_NR;
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
switch (pd_event->msg) {
|
||||
case PD_DATA_BIST:
|
||||
if (pd_port->pe_state_curr == ready_state)
|
||||
ret = pd_process_data_msg_bist(pd_port, pd_event);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE
|
||||
case PD_DATA_BAT_STATUS:
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_GET_BATTERY_STATUS, ready_state);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL
|
||||
case PD_DATA_GET_COUNTRY_INFO:
|
||||
if (pd_port->country_nr) {
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
ready_state, PE_GIVE_COUNTRY_INFO);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_LOCAL */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Extend MSG
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
static inline bool pd_process_ext_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool ret = false;
|
||||
uint8_t ready_state = pe_get_curr_ready_state(pd_port);
|
||||
|
||||
if (!pd_check_rev30(pd_port)) {
|
||||
pd_event->msg = PD_DATA_MSG_NR;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USB_PD_REV30_CHUNKING_BY_PE
|
||||
if (pd_port->pe_state_curr == ready_state &&
|
||||
pd_is_multi_chunk_msg(pd_port)) {
|
||||
pd_port->curr_unsupported_msg = true;
|
||||
return pd_process_protocol_error(pd_port, pd_event);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_CHUNKING_BY_PE */
|
||||
|
||||
switch (pd_event->msg) {
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_LOCAL
|
||||
case PD_EXT_GET_BAT_CAP:
|
||||
if (pd_port->bat_nr) {
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
ready_state, PE_GIVE_BATTERY_CAP);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL
|
||||
case PD_EXT_GET_BAT_STATUS:
|
||||
if (pd_port->bat_nr) {
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
ready_state, PE_GIVE_BATTERY_STATUS);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_REMOTE
|
||||
case PD_EXT_BAT_CAP:
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_GET_BATTERY_CAP, ready_state);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL
|
||||
case PD_EXT_GET_MFR_INFO:
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
ready_state, PE_GIVE_MANUFACTURER_INFO);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE
|
||||
case PD_EXT_MFR_INFO:
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_GET_MANUFACTURER_INFO, ready_state);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE
|
||||
case PD_EXT_COUNTRY_INFO:
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_GET_COUNTRY_INFO, ready_state);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE
|
||||
case PD_EXT_COUNTRY_CODES:
|
||||
ret = PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_GET_COUNTRY_CODES, ready_state);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess DPM MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_dpm_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
switch (pd_event->msg) {
|
||||
case PD_DPM_ACK:
|
||||
if (pd_port->pe_data.pe_state_flags2 &
|
||||
PE_STATE_FLAG_BACK_READY_IF_DPM_ACK) {
|
||||
pe_transit_ready_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_DPM_NOT_SUPPORT:
|
||||
if (pd_check_rev30(pd_port)) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_VDM_NOT_SUPPORTED);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess HW MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_recv_hard_reset(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_RECV_HRESET_COUNTER
|
||||
if (pd_port->pe_data.recv_hard_reset_count > PD_HARD_RESET_COUNT) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_OVER_RECV_HRESET_LIMIT);
|
||||
return true;
|
||||
}
|
||||
|
||||
pd_port->pe_data.recv_hard_reset_count++;
|
||||
#endif /* CONFIG_USB_PD_RECV_HRESET_COUNTER */
|
||||
|
||||
#ifdef CONFIG_USB_PD_RENEGOTIATION_COUNTER
|
||||
if (pd_check_pe_during_hard_reset(pd_port))
|
||||
pd_port->pe_data.renegotiation_count++;
|
||||
#endif /* CONFIG_USB_PD_RENEGOTIATION_COUNTER */
|
||||
|
||||
pe_transit_hard_reset_recv_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pd_process_hw_msg_tx_failed(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_RENEGOTIATION_COUNTER
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_port->pe_data.renegotiation_count > PD_HARD_RESET_COUNT) {
|
||||
PE_INFO("renegotiation failed\n");
|
||||
PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_RENEGOTIATION_COUNTER */
|
||||
|
||||
if (pd_port->pe_data.pe_state_flags &
|
||||
PE_STATE_FLAG_BACK_READY_IF_TX_FAILED) {
|
||||
pd_notify_tcp_event_2nd_result(
|
||||
pd_port, TCP_DPM_RET_NO_RESPONSE);
|
||||
pe_transit_ready_state(pd_port);
|
||||
return true;
|
||||
} else if (pd_port->pe_data.pe_state_flags &
|
||||
PE_STATE_FLAG_HRESET_IF_TX_FAILED) {
|
||||
pe_transit_hard_reset_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool pd_process_hw_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_HW_RECV_HARD_RESET:
|
||||
return pd_process_recv_hard_reset(pd_port, pd_event);
|
||||
|
||||
case PD_HW_TX_FAILED:
|
||||
return pd_process_hw_msg_tx_failed(pd_port, pd_event);
|
||||
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Timer MSG
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_CHECK_RX_PENDING_IF_SRTOUT
|
||||
static inline bool pd_check_rx_pending(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t alert;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (tcpci_get_alert_status(tcpc, &alert))
|
||||
return false;
|
||||
|
||||
if (alert & TCPC_REG_ALERT_RX_STATUS) {
|
||||
PE_INFO("rx_pending\n");
|
||||
#ifndef CONFIG_USB_PD_ONLY_PRINT_SYSTEM_BUSY
|
||||
pd_enable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_CHECK_RX_PENDING_IF_SRTOUT */
|
||||
|
||||
static inline bool pd_process_timer_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
uint8_t ready_state = pe_get_curr_ready_state(pd_port);
|
||||
|
||||
switch (pd_event->msg) {
|
||||
#ifndef CONFIG_USB_PD_DBG_IGRONE_TIMEOUT
|
||||
case PD_TIMER_SENDER_RESPONSE:
|
||||
|
||||
#ifdef CONFIG_USB_PD_CHECK_RX_PENDING_IF_SRTOUT
|
||||
#ifndef CONFIG_USB_PD_ONLY_PRINT_SYSTEM_BUSY
|
||||
if (pd_check_rx_pending(pd_port))
|
||||
return false;
|
||||
#else
|
||||
pd_check_rx_pending(pd_port);
|
||||
#endif /* CONFIG_USB_PD_PRINT_SYSTEM_BUSY */
|
||||
#endif /* CONFIG_USB_PD_CHECK_RX_PENDING_IF_SRTOUT */
|
||||
|
||||
|
||||
pd_cancel_dpm_reaction(pd_port);
|
||||
pd_notify_pe_cancel_pr_swap(pd_port);
|
||||
pd_notify_tcp_event_2nd_result(pd_port, TCP_DPM_RET_TIMEOUT);
|
||||
if (pd_port->pe_data.pe_state_flags &
|
||||
PE_STATE_FLAG_BACK_READY_IF_SR_TIMER_TOUT) {
|
||||
PE_TRANSIT_STATE(pd_port, ready_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pd_port->pe_data.pe_state_flags &
|
||||
PE_STATE_FLAG_HRESET_IF_SR_TIMEOUT) {
|
||||
pe_transit_hard_reset_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_DBG_IGRONE_TIMEOUT */
|
||||
case PD_TIMER_BIST_CONT_MODE:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_BIST_CARRIER_MODE_2, ready_state))
|
||||
return true;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_DFP_FLOW_DELAY
|
||||
case PD_TIMER_DFP_FLOW_DELAY:
|
||||
if (pd_port->pe_state_curr == ready_state &&
|
||||
pd_port->data_role == PD_ROLE_DFP) {
|
||||
dpm_reaction_set_clear(pd_port,
|
||||
DPM_REACTION_CAP_READY_ONCE,
|
||||
DPM_REACTION_DFP_FLOW_DELAY);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_DFP_FLOW_DELAY */
|
||||
|
||||
#ifdef CONFIG_USB_PD_UFP_FLOW_DELAY
|
||||
case PD_TIMER_UFP_FLOW_DELAY:
|
||||
if (pd_port->pe_state_curr == ready_state &&
|
||||
pd_port->data_role == PD_ROLE_UFP) {
|
||||
dpm_reaction_set_clear(pd_port,
|
||||
DPM_REACTION_CAP_READY_ONCE,
|
||||
DPM_REACTION_UFP_FLOW_DELAY);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_UFP_FLOW_DELAY */
|
||||
|
||||
#ifdef CONFIG_USB_PD_VCONN_STABLE_DELAY
|
||||
case PD_TIMER_VCONN_STABLE:
|
||||
if (pd_port->vconn_role == PD_ROLE_VCONN_DYNAMIC_ON) {
|
||||
pd_set_vconn(pd_port, PD_ROLE_VCONN_ON);
|
||||
dpm_reaction_set_clear(pd_port,
|
||||
DPM_REACTION_CAP_READY_ONCE,
|
||||
DPM_REACTION_VCONN_STABLE_DELAY);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_VCONN_STABLE_DELAY */
|
||||
|
||||
#if defined(CONFIG_USB_PD_REV30) && defined(CONFIG_USB_PD_REV30_COLLISION_AVOID)
|
||||
case PD_TIMER_DEFERRED_EVT:
|
||||
pd_notify_tcp_event_buf_reset(
|
||||
pd_port, TCP_DPM_RET_DROP_PE_BUSY);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pd_process_event_com(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->event_type) {
|
||||
case PD_EVT_CTRL_MSG:
|
||||
return pd_process_ctrl_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_DATA_MSG:
|
||||
return pd_process_data_msg(pd_port, pd_event);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_EVT_EXT_MSG:
|
||||
return pd_process_ext_msg(pd_port, pd_event);
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
case PD_EVT_DPM_MSG:
|
||||
return pd_process_dpm_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_HW_MSG:
|
||||
return pd_process_hw_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_TIMER_MSG:
|
||||
return pd_process_timer_msg(pd_port, pd_event);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
28
drivers/usb/typec/mmi_tcpc/pd_process_evt_dbg.c
Normal file
28
drivers/usb/typec/mmi_tcpc/pd_process_evt_dbg.c
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Process Event For DBGACC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
|
||||
|
||||
bool pd_process_event_dbg(struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
/* Don't need to handle any PD message, Keep VBUS 5V, and using VDM */
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
|
||||
102
drivers/usb/typec/mmi_tcpc/pd_process_evt_drs.c
Normal file
102
drivers/usb/typec/mmi_tcpc/pd_process_evt_drs.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Process Event For DRS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
|
||||
/* PD Control MSG reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_GOOD_CRC) = {
|
||||
{ PE_DRS_DFP_UFP_ACCEPT_DR_SWAP, PE_DRS_DFP_UFP_CHANGE_TO_UFP },
|
||||
{ PE_DRS_UFP_DFP_ACCEPT_DR_SWAP, PE_DRS_UFP_DFP_CHANGE_TO_DFP },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_CTRL_MSG_GOOD_CRC);
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_ACCEPT) = {
|
||||
{ PE_DRS_DFP_UFP_SEND_DR_SWAP, PE_DRS_DFP_UFP_CHANGE_TO_UFP },
|
||||
{ PE_DRS_UFP_DFP_SEND_DR_SWAP, PE_DRS_UFP_DFP_CHANGE_TO_DFP },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_CTRL_MSG_ACCEPT);
|
||||
|
||||
/* DPM Event reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
|
||||
{ PE_DRS_DFP_UFP_EVALUATE_DR_SWAP, PE_DRS_DFP_UFP_ACCEPT_DR_SWAP },
|
||||
{ PE_DRS_UFP_DFP_EVALUATE_DR_SWAP, PE_DRS_UFP_DFP_ACCEPT_DR_SWAP },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_DPM_MSG_NAK) = {
|
||||
{ PE_DRS_DFP_UFP_EVALUATE_DR_SWAP, PE_DRS_DFP_UFP_REJECT_DR_SWAP },
|
||||
{ PE_DRS_UFP_DFP_EVALUATE_DR_SWAP, PE_DRS_UFP_DFP_REJECT_DR_SWAP },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DPM_MSG_NAK);
|
||||
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess PD Ctrl MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_ctrl_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_CTRL_GOOD_CRC:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_GOOD_CRC);
|
||||
|
||||
case PD_CTRL_ACCEPT:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_ACCEPT);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess DPM MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_dpm_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_DPM_ACK:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_ACK);
|
||||
|
||||
case PD_DPM_NAK:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_NAK);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Process Policy Engine's DRS Message
|
||||
*/
|
||||
|
||||
bool pd_process_event_drs(struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->event_type) {
|
||||
case PD_EVT_CTRL_MSG:
|
||||
return pd_process_ctrl_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_DPM_MSG:
|
||||
return pd_process_dpm_msg(pd_port, pd_event);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
242
drivers/usb/typec/mmi_tcpc/pd_process_evt_prs.c
Normal file
242
drivers/usb/typec/mmi_tcpc/pd_process_evt_prs.c
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Process Event For PRS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP_ERROR_RECOVERY
|
||||
#define PE_PRS_SNK_HARD_RESET PE_ERROR_RECOVERY
|
||||
#define PE_PRS_SRC_HARD_RESET PE_ERROR_RECOVERY
|
||||
#else
|
||||
#define PE_PRS_SNK_HARD_RESET PE_SNK_HARD_RESET
|
||||
#define PE_PRS_SRC_HARD_RESET PE_SRC_HARD_RESET
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP_ERROR_RECOVERY */
|
||||
|
||||
/* PD Control MSG reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_GOOD_CRC) = {
|
||||
{ PE_PRS_SRC_SNK_ACCEPT_PR_SWAP, PE_PRS_SRC_SNK_TRANSITION_TO_OFF },
|
||||
{ PE_PRS_SNK_SRC_ACCEPT_PR_SWAP, PE_PRS_SNK_SRC_TRANSITION_TO_OFF },
|
||||
|
||||
/* VBUS-ON & PS_RDY SENT */
|
||||
{ PE_PRS_SNK_SRC_SOURCE_ON, PE_SRC_STARTUP },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_CTRL_MSG_GOOD_CRC);
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_ACCEPT) = {
|
||||
{ PE_PRS_SRC_SNK_SEND_SWAP, PE_PRS_SRC_SNK_TRANSITION_TO_OFF },
|
||||
{ PE_PRS_SNK_SRC_SEND_SWAP, PE_PRS_SNK_SRC_TRANSITION_TO_OFF },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_CTRL_MSG_ACCEPT);
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_PS_RDY) = {
|
||||
{ PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_SNK_STARTUP },
|
||||
{ PE_PRS_SNK_SRC_TRANSITION_TO_OFF, PE_PRS_SNK_SRC_ASSERT_RP },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_CTRL_MSG_PS_RDY);
|
||||
|
||||
/* DPM Event reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
|
||||
{ PE_PRS_SRC_SNK_EVALUATE_PR_SWAP, PE_PRS_SRC_SNK_ACCEPT_PR_SWAP },
|
||||
{ PE_PRS_SNK_SRC_EVALUATE_PR_SWAP, PE_PRS_SNK_SRC_ACCEPT_PR_SWAP },
|
||||
|
||||
{ PE_PRS_SRC_SNK_ASSERT_RD, PE_PRS_SRC_SNK_WAIT_SOURCE_ON },
|
||||
{ PE_PRS_SNK_SRC_ASSERT_RP, PE_PRS_SNK_SRC_SOURCE_ON },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_DPM_MSG_NAK) = {
|
||||
{ PE_PRS_SRC_SNK_EVALUATE_PR_SWAP, PE_PRS_SRC_SNK_REJECT_PR_SWAP },
|
||||
{ PE_PRS_SNK_SRC_EVALUATE_PR_SWAP, PE_PRS_SNK_SRC_REJECT_SWAP },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DPM_MSG_NAK);
|
||||
|
||||
/* HW Event reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_HW_VBUS_PRESENT) = {
|
||||
#ifdef CONFIG_USB_PD_VBUS_DETECTION_DURING_PR_SWAP
|
||||
{ PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_SNK_STARTUP },
|
||||
#endif /* CONFIG_USB_PD_VBUS_DETECTION_DURING_PR_SWAP */
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_HW_VBUS_PRESENT);
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP_ERROR_RECOVERY
|
||||
DECL_PE_STATE_TRANSITION(PD_HW_TX_FAILED) = {
|
||||
{ PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_ERROR_RECOVERY },
|
||||
{ PE_PRS_SNK_SRC_SOURCE_ON, PE_ERROR_RECOVERY },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_HW_TX_FAILED);
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP_ERROR_RECOVERY */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_HW_VBUS_SAFE0V) = {
|
||||
{ PE_PRS_SRC_SNK_TRANSITION_TO_OFF, PE_PRS_SRC_SNK_ASSERT_RD },
|
||||
#ifdef CONFIG_USB_PD_VBUS_DETECTION_DURING_PR_SWAP
|
||||
{ PE_PRS_SNK_SRC_TRANSITION_TO_OFF, PE_PRS_SNK_SRC_ASSERT_RP },
|
||||
#endif /* CONFIG_USB_PD_VBUS_DETECTION_DURING_PR_SWAP */
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_HW_VBUS_SAFE0V);
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess PD Ctrl MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_ctrl_msg_good_crc(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
|
||||
pd_enable_pe_state_timer(pd_port, PD_TIMER_PS_SOURCE_ON);
|
||||
pd_unlock_msg_output(pd_port); /* for tSRCTransition */
|
||||
return false;
|
||||
|
||||
default:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_GOOD_CRC);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool pd_process_ctrl_msg_ps_rdy(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_port->pe_state_curr) {
|
||||
#ifdef CONFIG_USB_PD_VBUS_DETECTION_DURING_PR_SWAP
|
||||
case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
|
||||
pd_enable_vbus_valid_detection(pd_port, true);
|
||||
return false;
|
||||
|
||||
case PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
|
||||
pd_enable_vbus_safe0v_detection(pd_port);
|
||||
return false;
|
||||
|
||||
#endif /* CONFIG_USB_PD_VBUS_DETECTION_DURING_PR_SWAP */
|
||||
default:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_PS_RDY);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool pd_process_ctrl_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_CTRL_GOOD_CRC:
|
||||
return pd_process_ctrl_msg_good_crc(pd_port, pd_event);
|
||||
|
||||
case PD_CTRL_ACCEPT:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_ACCEPT);
|
||||
|
||||
case PD_CTRL_PS_RDY:
|
||||
return pd_process_ctrl_msg_ps_rdy(pd_port, pd_event);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess DPM MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_dpm_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_DPM_ACK:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_ACK);
|
||||
|
||||
case PD_DPM_NAK:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_NAK);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess HW MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_hw_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_HW_VBUS_PRESENT:
|
||||
if (pd_port->pe_state_curr == PE_PRS_SNK_SRC_SOURCE_ON)
|
||||
pd_send_sop_ctrl_msg(pd_port, PD_CTRL_PS_RDY);
|
||||
|
||||
return PE_MAKE_STATE_TRANSIT(PD_HW_VBUS_PRESENT);
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP_ERROR_RECOVERY
|
||||
case PD_HW_TX_FAILED:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_HW_TX_FAILED);
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP_ERROR_RECOVERY */
|
||||
|
||||
case PD_HW_VBUS_SAFE0V:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_HW_VBUS_SAFE0V);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Timer MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_timer_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_TIMER_PS_SOURCE_ON:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_PRS_SNK_HARD_RESET);
|
||||
|
||||
case PD_TIMER_PS_SOURCE_OFF:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_PRS_SNK_SRC_TRANSITION_TO_OFF,
|
||||
PE_PRS_SNK_HARD_RESET);
|
||||
|
||||
case PD_TIMER_SOURCE_TRANSITION:
|
||||
pd_dpm_prs_enable_power_source(pd_port, false);
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Process Policy Engine's PRS Message
|
||||
*/
|
||||
|
||||
bool pd_process_event_prs(struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->event_type) {
|
||||
case PD_EVT_CTRL_MSG:
|
||||
return pd_process_ctrl_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_DPM_MSG:
|
||||
return pd_process_dpm_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_HW_MSG:
|
||||
return pd_process_hw_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_TIMER_MSG:
|
||||
return pd_process_timer_msg(pd_port, pd_event);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
498
drivers/usb/typec/mmi_tcpc/pd_process_evt_snk.c
Normal file
498
drivers/usb/typec/mmi_tcpc/pd_process_evt_snk.c
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Process Event For SNK
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
#include "inc/tcpci_typec.h"
|
||||
|
||||
/* PD Control MSG reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_ACCEPT) = {
|
||||
{ PE_SNK_SELECT_CAPABILITY, PE_SNK_TRANSITION_SINK },
|
||||
{ PE_SNK_SEND_SOFT_RESET, PE_SNK_WAIT_FOR_CAPABILITIES },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_CTRL_MSG_ACCEPT);
|
||||
|
||||
/* PD Data MSG reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_DATA_MSG_SOURCE_CAP) = {
|
||||
{ PE_SNK_WAIT_FOR_CAPABILITIES, PE_SNK_EVALUATE_CAPABILITY },
|
||||
{ PE_SNK_READY, PE_SNK_EVALUATE_CAPABILITY },
|
||||
|
||||
/* PR-Swap issue (Check it later) */
|
||||
{ PE_SNK_STARTUP, PE_SNK_EVALUATE_CAPABILITY },
|
||||
{ PE_SNK_DISCOVERY, PE_SNK_EVALUATE_CAPABILITY },
|
||||
|
||||
#ifdef CONFIG_USB_PD_TCPM_CB_2ND
|
||||
{ PE_SNK_GET_SOURCE_CAP, PE_SNK_EVALUATE_CAPABILITY },
|
||||
#endif /* CONFIG_USB_PD_TCPM_CB_2ND */
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DATA_MSG_SOURCE_CAP);
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Ctrl MSG
|
||||
*/
|
||||
|
||||
static bool pd_process_ctrl_msg_get_source_cap(
|
||||
struct pd_port *pd_port, uint8_t next)
|
||||
{
|
||||
if (pd_port->pe_state_curr != PE_SNK_READY)
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
|
||||
PE_TRANSIT_STATE(pd_port, next);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
if (!pd_check_rev30(pd_port)) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_REJECT);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool pd_process_ctrl_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_PARTNER_CTRL_MSG_FIRST
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SNK_GET_SOURCE_CAP:
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
case PE_DR_SNK_GET_SINK_CAP:
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
if (pd_event->msg >= PD_CTRL_GET_SOURCE_CAP &&
|
||||
pd_event->msg <= PD_CTRL_VCONN_SWAP) {
|
||||
PE_DBG("Port Partner Request First\n");
|
||||
pd_port->pe_state_curr = PE_SNK_READY;
|
||||
pd_disable_timer(
|
||||
pd_port, PD_TIMER_SENDER_RESPONSE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PARTNER_CTRL_MSG_FIRST */
|
||||
|
||||
switch (pd_event->msg) {
|
||||
case PD_CTRL_GOOD_CRC:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_SOFT_RESET, PE_SNK_WAIT_FOR_CAPABILITIES);
|
||||
|
||||
case PD_CTRL_GOTO_MIN:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_READY, PE_SNK_TRANSITION_SINK))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case PD_CTRL_ACCEPT:
|
||||
if (PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_ACCEPT))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case PD_CTRL_PS_RDY:
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SNK_TRANSITION_SINK:
|
||||
pd_dpm_snk_transition_power(pd_port);
|
||||
PE_TRANSIT_STATE(pd_port, PE_SNK_READY);
|
||||
return true;
|
||||
|
||||
#ifdef CONFIG_USB_PD_VBUS_DETECTION_DURING_PR_SWAP
|
||||
case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
|
||||
case PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
|
||||
return false;
|
||||
#endif /* CONFIG_USB_PD_VBUS_DETECTION_DURING_PR_SWAP */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PD_CTRL_GET_SOURCE_CAP:
|
||||
if (pd_process_ctrl_msg_get_source_cap(
|
||||
pd_port, PE_DR_SNK_GIVE_SOURCE_CAP))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case PD_CTRL_GET_SINK_CAP:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_READY, PE_SNK_GIVE_SINK_CAP))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case PD_CTRL_REJECT:
|
||||
case PD_CTRL_WAIT:
|
||||
if (pd_port->pe_state_curr == PE_SNK_SELECT_CAPABILITY) {
|
||||
if (pd_port->pe_data.explicit_contract)
|
||||
PE_TRANSIT_STATE(pd_port, PE_SNK_READY);
|
||||
else {
|
||||
PE_TRANSIT_STATE(pd_port,
|
||||
PE_SNK_WAIT_FOR_CAPABILITIES);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_CTRL_NOT_SUPPORTED:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_READY, PE_SNK_NOT_SUPPORTED_RECEIVED))
|
||||
return true;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
case PD_CTRL_GET_SOURCE_CAP_EXT:
|
||||
if (pd_process_ctrl_msg_get_source_cap(
|
||||
pd_port, PE_DR_SNK_GIVE_SOURCE_CAP_EXT))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
case PD_CTRL_GET_STATUS:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_READY, PE_SNK_GIVE_SINK_STATUS))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
default:
|
||||
pd_port->curr_unsupported_msg = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return pd_process_protocol_error(pd_port, pd_event);
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Data MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_data_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_DATA_SOURCE_CAP:
|
||||
#ifdef CONFIG_USB_PD_IGNORE_PS_RDY_AFTER_PR_SWAP
|
||||
pd_port->msg_id_pr_swap_last = 0xff;
|
||||
#endif /* CONFIG_USB_PD_IGNORE_PS_RDY_AFTER_PR_SWAP */
|
||||
if (PE_MAKE_STATE_TRANSIT(PD_DATA_MSG_SOURCE_CAP))
|
||||
return true;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
case PD_DATA_SINK_CAP:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_DR_SNK_GET_SINK_CAP, PE_SNK_READY))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
case PD_DATA_ALERT:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_READY, PE_SNK_SOURCE_ALERT_RECEIVED))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
default:
|
||||
pd_port->curr_unsupported_msg = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return pd_process_protocol_error(pd_port, pd_event);
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Extend MSG
|
||||
*/
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
static inline bool pd_process_ext_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
case PD_EXT_SOURCE_CAP_EXT:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_GET_SOURCE_CAP_EXT, PE_SNK_READY))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
case PD_EXT_STATUS:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_GET_SOURCE_STATUS, PE_SNK_READY))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
case PD_EXT_PPS_STATUS:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_GET_PPS_STATUS, PE_SNK_READY))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
default:
|
||||
pd_port->curr_unsupported_msg = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return pd_process_protocol_error(pd_port, pd_event);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess DPM MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_dpm_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_DPM_ACK:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_EVALUATE_CAPABILITY, PE_SNK_SELECT_CAPABILITY);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess HW MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_hw_msg_sink_tx_change(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
struct pe_data *pe_data = &pd_port->pe_data;
|
||||
uint8_t pd_traffic;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SNK_FLOW_DELAY_STARTUP
|
||||
if (pe_data->pd_traffic_control == PD_SINK_TX_START)
|
||||
return false;
|
||||
#endif /* CONFIG_USB_PD_REV30_SNK_FLOW_DELAY_STARTUP */
|
||||
|
||||
if (!pd_check_rev30(pd_port))
|
||||
return false;
|
||||
|
||||
pd_traffic = pd_event->msg_sec ?
|
||||
PD_SINK_TX_OK : PD_SINK_TX_NG;
|
||||
|
||||
if (pe_data->pd_traffic_control == pd_traffic)
|
||||
return false;
|
||||
|
||||
pe_data->pd_traffic_control = pd_traffic;
|
||||
dpm_reaction_set_ready_once(pd_port);
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool pd_process_vbus_absent(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->pe_state_curr != PE_SNK_DISCOVERY)
|
||||
return false;
|
||||
#ifdef CONFIG_USB_PD_SNK_HRESET_KEEP_DRAW
|
||||
/* iSafe0mA: Maximum current a Sink
|
||||
* is allowed to draw when VBUS is driven to vSafe0V
|
||||
*/
|
||||
pd_dpm_sink_vbus(pd_port, false);
|
||||
#endif /* CONFIG_USB_PD_SNK_HRESET_KEEP_DRAW */
|
||||
pd_disable_pe_state_timer(pd_port);
|
||||
pd_enable_vbus_valid_detection(pd_port, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool pd_process_hw_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_HW_VBUS_PRESENT:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_DISCOVERY, PE_SNK_WAIT_FOR_CAPABILITIES);
|
||||
|
||||
case PD_HW_VBUS_ABSENT:
|
||||
return pd_process_vbus_absent(pd_port);
|
||||
|
||||
case PD_HW_TX_FAILED:
|
||||
return pd_process_tx_failed(pd_port);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
case PD_HW_SINK_TX_CHANGE:
|
||||
return pd_process_hw_msg_sink_tx_change(pd_port, pd_event);
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess PE MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_pe_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_PE_RESET_PRL_COMPLETED:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_STARTUP, PE_SNK_DISCOVERY);
|
||||
|
||||
case PD_PE_HARD_RESET_COMPLETED:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_HARD_RESET, PE_SNK_TRANSITION_TO_DEFAULT);
|
||||
|
||||
case PD_PE_POWER_ROLE_AT_DEFAULT:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_TRANSITION_TO_DEFAULT, PE_SNK_STARTUP);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Timer MSG
|
||||
*/
|
||||
|
||||
static inline void pd_report_typec_only_charger(struct pd_port *pd_port)
|
||||
{
|
||||
uint8_t state;
|
||||
struct tcpc_device *tcpc = pd_port->tcpc;
|
||||
|
||||
if (tcpc->typec_remote_rp_level == TYPEC_CC_VOLT_SNK_DFT)
|
||||
state = PD_CONNECT_TYPEC_ONLY_SNK_DFT;
|
||||
else
|
||||
state = PD_CONNECT_TYPEC_ONLY_SNK;
|
||||
|
||||
PE_INFO("TYPE-C Only Charger!\n");
|
||||
pd_dpm_sink_vbus(pd_port, true);
|
||||
pd_set_rx_enable(pd_port, PD_RX_CAP_PE_IDLE);
|
||||
pd_notify_pe_hard_reset_completed(pd_port);
|
||||
pd_update_connect_state(pd_port, state);
|
||||
}
|
||||
|
||||
static inline bool pd_process_timer_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#ifndef CONFIG_USB_PD_DBG_IGRONE_TIMEOUT
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
#endif /* CONFIG_USB_PD_DBG_IGRONE_TIMEOUT */
|
||||
struct pe_data __maybe_unused *pe_data = &pd_port->pe_data;
|
||||
|
||||
switch (pd_event->msg) {
|
||||
case PD_TIMER_SINK_REQUEST:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_READY, PE_SNK_SELECT_CAPABILITY);
|
||||
|
||||
#ifndef CONFIG_USB_PD_DBG_IGRONE_TIMEOUT
|
||||
case PD_TIMER_SINK_WAIT_CAP:
|
||||
case PD_TIMER_PS_TRANSITION:
|
||||
if ((pd_port->pe_state_curr != PE_SNK_DISCOVERY) &&
|
||||
(pe_data->hard_reset_counter <= PD_HARD_RESET_COUNT)) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_SNK_HARD_RESET);
|
||||
return true;
|
||||
}
|
||||
|
||||
PE_INFO("SRC NoResp\n");
|
||||
if (pd_port->request_v == TCPC_VBUS_SINK_5V) {
|
||||
pd_report_typec_only_charger(pd_port);
|
||||
} else {
|
||||
PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_DBG_IGRONE_TIMEOUT */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
|
||||
case PD_TIMER_DISCOVER_ID:
|
||||
vdm_put_dpm_discover_cable_event(pd_port);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
|
||||
/* fall through */
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_TIMER_CK_NOT_SUPPORTED:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SNK_CHUNK_RECEIVED, PE_SNK_SEND_NOT_SUPPORTED))
|
||||
return true;
|
||||
/* fall through */
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
#ifdef CONFIG_USB_PD_REV30_SNK_FLOW_DELAY_STARTUP
|
||||
case PD_TIMER_SNK_FLOW_DELAY:
|
||||
if (pe_data->pd_traffic_control == PD_SINK_TX_START) {
|
||||
if (typec_get_cc_res() == TYPEC_CC_VOLT_SNK_3_0)
|
||||
pe_data->pd_traffic_control = PD_SINK_TX_OK;
|
||||
else
|
||||
pe_data->pd_traffic_control = PD_SINK_TX_NG;
|
||||
if (pd_check_rev30(pd_port))
|
||||
dpm_reaction_set_ready_once(pd_port);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_SNK_FLOW_DELAY_STARTUP */
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Process Policy Engine's SNK Message
|
||||
*/
|
||||
|
||||
bool pd_process_event_snk(struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->event_type) {
|
||||
case PD_EVT_CTRL_MSG:
|
||||
return pd_process_ctrl_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_DATA_MSG:
|
||||
return pd_process_data_msg(pd_port, pd_event);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_EVT_EXT_MSG:
|
||||
return pd_process_ext_msg(pd_port, pd_event);
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
case PD_EVT_DPM_MSG:
|
||||
return pd_process_dpm_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_HW_MSG:
|
||||
return pd_process_hw_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_PE_MSG:
|
||||
return pd_process_pe_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_TIMER_MSG:
|
||||
return pd_process_timer_msg(pd_port, pd_event);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
550
drivers/usb/typec/mmi_tcpc/pd_process_evt_src.c
Normal file
550
drivers/usb/typec/mmi_tcpc/pd_process_evt_src.c
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Process Event For SRC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
|
||||
|
||||
/* PD Data MSG reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_DATA_MSG_REQUEST) = {
|
||||
{ PE_SRC_SEND_CAPABILITIES, PE_SRC_NEGOTIATE_CAPABILITIES },
|
||||
{ PE_SRC_READY, PE_SRC_NEGOTIATE_CAPABILITIES },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DATA_MSG_REQUEST);
|
||||
|
||||
/* DPM Event reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
|
||||
{ PE_SRC_NEGOTIATE_CAPABILITIES, PE_SRC_TRANSITION_SUPPLY },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_DPM_MSG_CAP_CHANGED) = {
|
||||
{ PE_SRC_READY, PE_SRC_SEND_CAPABILITIES },
|
||||
{ PE_SRC_WAIT_NEW_CAPABILITIES, PE_SRC_SEND_CAPABILITIES },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DPM_MSG_CAP_CHANGED);
|
||||
|
||||
/* Timer Event reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_TIMER_PS_HARD_RESET) = {
|
||||
{ PE_SRC_HARD_RESET, PE_SRC_TRANSITION_TO_DEFAULT },
|
||||
{ PE_SRC_HARD_RESET_RECEIVED, PE_SRC_TRANSITION_TO_DEFAULT },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_TIMER_PS_HARD_RESET);
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Ctrl MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_ctrl_msg_good_crc(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
|
||||
{
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SRC_SEND_CAPABILITIES:
|
||||
pd_port->pe_data.cap_counter = 0;
|
||||
pd_handle_hard_reset_recovery(pd_port);
|
||||
return false;
|
||||
|
||||
case PE_SRC_TRANSITION_SUPPLY:
|
||||
pd_enable_pe_state_timer(pd_port, PD_TIMER_SOURCE_TRANSITION);
|
||||
return false;
|
||||
|
||||
case PE_SRC_CAPABILITY_RESPONSE:
|
||||
if (!pd_port->pe_data.explicit_contract)
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_WAIT_NEW_CAPABILITIES);
|
||||
else if (pd_port->pe_data.invalid_contract)
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_HARD_RESET);
|
||||
else
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_READY);
|
||||
return true;
|
||||
|
||||
case PE_SRC_SOFT_RESET:
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_SEND_CAPABILITIES);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool pd_process_ctrl_msg_get_sink_cap(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
if (pd_port->pe_state_curr != PE_SRC_READY)
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_DR_SRC_GIVE_SINK_CAP);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
if (!pd_check_rev30(pd_port)) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_REJECT);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool pd_process_ctrl_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_PARTNER_CTRL_MSG_FIRST
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SRC_GET_SINK_CAP:
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
case PE_DR_SRC_GET_SOURCE_CAP:
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
if (pd_event->msg >= PD_CTRL_GET_SOURCE_CAP &&
|
||||
pd_event->msg <= PD_CTRL_VCONN_SWAP) {
|
||||
PE_DBG("Port Partner Request First\n");
|
||||
pd_port->pe_state_curr = PE_SRC_READY;
|
||||
pd_disable_timer(
|
||||
pd_port, PD_TIMER_SENDER_RESPONSE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PARTNER_CTRL_MSG_FIRST */
|
||||
|
||||
switch (pd_event->msg) {
|
||||
case PD_CTRL_GOOD_CRC:
|
||||
return pd_process_ctrl_msg_good_crc(pd_port, pd_event);
|
||||
|
||||
case PD_CTRL_ACCEPT:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_SEND_SOFT_RESET, PE_SRC_SEND_CAPABILITIES))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case PD_CTRL_GET_SOURCE_CAP:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_READY, PE_SRC_SEND_CAPABILITIES))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case PD_CTRL_GET_SINK_CAP:
|
||||
if (pd_process_ctrl_msg_get_sink_cap(pd_port, pd_event))
|
||||
return true;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_CTRL_NOT_SUPPORTED:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_READY, PE_SRC_NOT_SUPPORTED_RECEIVED))
|
||||
return true;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL
|
||||
case PD_CTRL_GET_SOURCE_CAP_EXT:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_READY, PE_SRC_GIVE_SOURCE_CAP_EXT))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
case PD_CTRL_GET_STATUS:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_READY, PE_SRC_GIVE_SOURCE_STATUS))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SOURCE
|
||||
case PD_CTRL_GET_PPS_STATUS:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_READY, PE_SRC_GIVE_PPS_STATUS))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SOURCE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
default:
|
||||
pd_port->curr_unsupported_msg = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return pd_process_protocol_error(pd_port, pd_event);
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Data MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_data_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
case PD_DATA_SOURCE_CAP:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_DR_SRC_GET_SOURCE_CAP, PE_SRC_READY))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
case PD_DATA_SINK_CAP:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_GET_SINK_CAP, PE_SRC_READY))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case PD_DATA_REQUEST:
|
||||
if (PE_MAKE_STATE_TRANSIT(PD_DATA_MSG_REQUEST))
|
||||
return true;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
case PD_DATA_ALERT:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_READY, PE_SRC_SINK_ALERT_RECEIVED))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
default:
|
||||
pd_port->curr_unsupported_msg = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return pd_process_protocol_error(pd_port, pd_event);
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Extend MSG
|
||||
*/
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
static inline bool pd_process_ext_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
case PD_EXT_SOURCE_CAP_EXT:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_DR_SRC_GET_SOURCE_CAP_EXT, PE_SRC_READY))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_LOCAL
|
||||
case PD_EXT_STATUS:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_GET_SINK_STATUS, PE_SRC_READY))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_LOCAL */
|
||||
|
||||
default:
|
||||
pd_port->curr_unsupported_msg = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return pd_process_protocol_error(pd_port, pd_event);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess DPM MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_dpm_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_DPM_ACK:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_ACK);
|
||||
|
||||
case PD_DPM_NAK:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_NEGOTIATE_CAPABILITIES,
|
||||
PE_SRC_CAPABILITY_RESPONSE);
|
||||
|
||||
case PD_DPM_CAP_CHANGED:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_CAP_CHANGED);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess HW MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_hw_msg_vbus_present(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SRC_STARTUP:
|
||||
pd_enable_timer(pd_port, PD_TIMER_SOURCE_START);
|
||||
break;
|
||||
|
||||
case PE_SRC_TRANSITION_TO_DEFAULT:
|
||||
pd_put_pe_event(pd_port, PD_PE_POWER_ROLE_AT_DEFAULT);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool pd_process_hw_msg_tx_failed(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
struct pe_data *pe_data = &pd_port->pe_data;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_port->pe_state_curr == PE_SRC_SEND_CAPABILITIES) {
|
||||
if (pe_data->pd_connected) {
|
||||
if (!pe_data->explicit_contract) {
|
||||
PE_DBG("PR_SWAP NoResp\n");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_DISCOVERY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PD_SRC_RESET_CABLE
|
||||
if (pd_port->pe_state_curr == PE_SRC_CBL_SEND_SOFT_RESET) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_SEND_CAPABILITIES);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_PD_SRC_RESET_CABLE */
|
||||
|
||||
return pd_process_tx_failed(pd_port);
|
||||
}
|
||||
|
||||
static inline bool pd_process_hw_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_HW_VBUS_PRESENT:
|
||||
return pd_process_hw_msg_vbus_present(pd_port, pd_event);
|
||||
|
||||
case PD_HW_VBUS_SAFE0V:
|
||||
pd_enable_timer(pd_port, PD_TIMER_SRC_RECOVER);
|
||||
return false;
|
||||
|
||||
case PD_HW_VBUS_STABLE:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_TRANSITION_SUPPLY, PE_SRC_TRANSITION_SUPPLY2);
|
||||
|
||||
case PD_HW_TX_FAILED:
|
||||
return pd_process_hw_msg_tx_failed(pd_port, pd_event);
|
||||
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess PE MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_pe_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_PE_RESET_PRL_COMPLETED:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_STARTUP, PE_SRC_SEND_CAPABILITIES);
|
||||
|
||||
case PD_PE_POWER_ROLE_AT_DEFAULT:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_TRANSITION_TO_DEFAULT, PE_SRC_STARTUP);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Timer MSG
|
||||
*/
|
||||
static inline bool pd_process_timer_msg_source_start(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
|
||||
if (pd_is_discover_cable(pd_port) &&
|
||||
pd_port->pe_data.msg_id_tx[TCPC_TX_SOP_PRIME] == 0) {
|
||||
|
||||
#ifdef CONFIG_PD_SRC_RESET_CABLE
|
||||
if (pd_is_reset_cable(pd_port)) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_CBL_SEND_SOFT_RESET);
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_PD_SRC_RESET_CABLE */
|
||||
|
||||
if (vdm_put_dpm_discover_cable_event(pd_port))
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
|
||||
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SRC_STARTUP:
|
||||
#ifdef CONFIG_PD_SRC_RESET_CABLE
|
||||
case PE_SRC_CBL_SEND_SOFT_RESET:
|
||||
#endif /* CONFIG_PD_SRC_RESET_CABLE */
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_SEND_CAPABILITIES);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
static inline bool pd_process_timer_msg_source_cap(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
if (pd_port->pe_state_curr != PE_SRC_DISCOVERY)
|
||||
return false;
|
||||
|
||||
if (pd_port->pe_data.cap_counter <= PD_CAPS_COUNT)
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_SEND_CAPABILITIES);
|
||||
else /* in this state, PD always not connected */
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_DISABLED);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pd_process_timer_msg_no_response(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
if (pd_port->pe_data.hard_reset_counter <= PD_HARD_RESET_COUNT)
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_HARD_RESET);
|
||||
else if (pd_port->pe_data.pd_prev_connected)
|
||||
PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
|
||||
else
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_DISABLED);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pd_process_timer_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_TIMER_SOURCE_CAPABILITY:
|
||||
return pd_process_timer_msg_source_cap(pd_port, pd_event);
|
||||
|
||||
#ifndef CONFIG_USB_PD_DBG_IGRONE_TIMEOUT
|
||||
#ifdef CONFIG_PD_SRC_RESET_CABLE
|
||||
case PD_TIMER_SENDER_RESPONSE:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_CBL_SEND_SOFT_RESET, PE_SRC_SEND_CAPABILITIES);
|
||||
#endif /* CONFIG_PD_SRC_RESET_CABLE */
|
||||
#endif
|
||||
|
||||
case PD_TIMER_PS_HARD_RESET:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_TIMER_PS_HARD_RESET);
|
||||
|
||||
case PD_TIMER_SOURCE_START:
|
||||
return pd_process_timer_msg_source_start(pd_port, pd_event);
|
||||
|
||||
#ifndef CONFIG_USB_PD_DBG_IGRONE_TIMEOUT
|
||||
case PD_TIMER_NO_RESPONSE:
|
||||
return pd_process_timer_msg_no_response(pd_port, pd_event);
|
||||
#endif
|
||||
|
||||
case PD_TIMER_SOURCE_TRANSITION:
|
||||
if (pd_port->state_machine != PE_STATE_MACHINE_PR_SWAP)
|
||||
pd_dpm_src_transition_power(pd_port);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_PD_DISCOVER_CABLE_ID
|
||||
case PD_TIMER_DISCOVER_ID:
|
||||
vdm_put_dpm_discover_cable_event(pd_port);
|
||||
break;
|
||||
#endif /* CONFIG_PD_DISCOVER_CABLE_ID */
|
||||
|
||||
case PD_TIMER_SRC_RECOVER:
|
||||
pd_dpm_source_vbus(pd_port, true);
|
||||
pd_enable_vbus_valid_detection(pd_port, true);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COLLISION_AVOID
|
||||
case PD_TIMER_SINK_TX:
|
||||
if (pd_port->pe_data.pd_traffic_control == PD_SINK_TX_NG)
|
||||
pd_port->pe_data.pd_traffic_control = PD_SOURCE_TX_OK;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_FLOW_DELAY_STARTUP
|
||||
if (pd_port->pe_data.pd_traffic_control == PD_SOURCE_TX_START)
|
||||
pd_port->pe_data.pd_traffic_control = PD_SINK_TX_OK;
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_FLOW_DELAY_STARTUP */
|
||||
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_COLLISION_AVOID */
|
||||
/* fall through */
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_TIMER_CK_NOT_SUPPORTED:
|
||||
return PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_SRC_CHUNK_RECEIVED, PE_SRC_SEND_NOT_SUPPORTED);
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Process Policy Engine's SRC Message
|
||||
*/
|
||||
|
||||
bool pd_process_event_src(struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->event_type) {
|
||||
case PD_EVT_CTRL_MSG:
|
||||
return pd_process_ctrl_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_DATA_MSG:
|
||||
return pd_process_data_msg(pd_port, pd_event);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
case PD_EVT_EXT_MSG:
|
||||
return pd_process_ext_msg(pd_port, pd_event);
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
case PD_EVT_DPM_MSG:
|
||||
return pd_process_dpm_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_HW_MSG:
|
||||
return pd_process_hw_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_PE_MSG:
|
||||
return pd_process_pe_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_TIMER_MSG:
|
||||
return pd_process_timer_msg(pd_port, pd_event);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
470
drivers/usb/typec/mmi_tcpc/pd_process_evt_tcp.c
Normal file
470
drivers/usb/typec/mmi_tcpc/pd_process_evt_tcp.c
Normal file
|
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Process Event for TCP
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
static inline int pd_handle_tcp_event_pr_swap(
|
||||
struct pd_port *pd_port, uint8_t new_role)
|
||||
{
|
||||
if (pd_port->power_role == new_role)
|
||||
return TCP_DPM_RET_DENIED_SAME_ROLE;
|
||||
|
||||
if (!(pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER))
|
||||
return TCP_DPM_RET_DENIED_LOCAL_CAP;
|
||||
|
||||
if (!pd_check_pe_state_ready(pd_port))
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
pd_port->pe_data.during_swap = false;
|
||||
pd_port->state_machine = PE_STATE_MACHINE_PR_SWAP;
|
||||
|
||||
pe_transit_send_pr_swap_state(pd_port);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DR_SWAP
|
||||
static inline int pd_handle_tcp_event_dr_swap(
|
||||
struct pd_port *pd_port, uint8_t new_role)
|
||||
{
|
||||
if (pd_port->data_role == new_role)
|
||||
return TCP_DPM_RET_DENIED_SAME_ROLE;
|
||||
|
||||
if (!(pd_port->dpm_caps & DPM_CAP_LOCAL_DR_DATA))
|
||||
return TCP_DPM_RET_DENIED_LOCAL_CAP;
|
||||
|
||||
if (!pd_check_pe_state_ready(pd_port))
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
pd_port->pe_data.during_swap = false;
|
||||
pd_port->state_machine = PE_STATE_MACHINE_DR_SWAP;
|
||||
|
||||
PE_TRANSIT_DATA_STATE(pd_port,
|
||||
PE_DRS_UFP_DFP_SEND_DR_SWAP,
|
||||
PE_DRS_DFP_UFP_SEND_DR_SWAP);
|
||||
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DR_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_VCONN_SWAP
|
||||
static inline int pd_handle_tcp_event_vconn_swap(
|
||||
struct pd_port *pd_port, uint8_t new_role)
|
||||
{
|
||||
uint8_t old_role = pd_port->vconn_role ? 1 : 0;
|
||||
|
||||
if (old_role == new_role)
|
||||
return TCP_DPM_RET_DENIED_SAME_ROLE;
|
||||
|
||||
if ((!pd_port->vconn_role) &&
|
||||
(!(pd_port->dpm_caps & DPM_CAP_LOCAL_VCONN_SUPPLY)))
|
||||
return TCP_DPM_RET_DENIED_LOCAL_CAP;
|
||||
|
||||
if (!pd_check_pe_state_ready(pd_port))
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
pd_port->state_machine = PE_STATE_MACHINE_VCONN_SWAP;
|
||||
PE_TRANSIT_STATE(pd_port, PE_VCS_SEND_SWAP);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_VCONN_SWAP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_PE_SOURCE
|
||||
static inline int pd_handle_tcp_event_gotomin(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->pe_state_curr != PE_SRC_READY)
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
if (!(pd_port->pe_data.dpm_flags & DPM_FLAGS_PARTNER_GIVE_BACK))
|
||||
return TCP_DPM_RET_DENIED_PARTNER_CAP;
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_TRANSITION_SUPPLY);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PE_SOURCE */
|
||||
|
||||
static inline int pd_handle_tcp_event_softreset(struct pd_port *pd_port)
|
||||
{
|
||||
if (!pd_check_pe_state_ready(pd_port))
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
pe_transit_soft_reset_state(pd_port);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PD_DFP_RESET_CABLE
|
||||
static inline int pd_handle_tcp_event_cable_softreset(struct pd_port *pd_port)
|
||||
{
|
||||
bool role_check;
|
||||
|
||||
if (!pd_check_pe_state_ready(pd_port))
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
role_check = pd_port->data_role == PD_ROLE_DFP;
|
||||
|
||||
if (pd_check_rev30(pd_port))
|
||||
role_check = pd_port->vconn_role;
|
||||
|
||||
if (!role_check)
|
||||
return TCP_DPM_RET_DENIED_WRONG_DATA_ROLE;
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, PE_DFP_CBL_SEND_SOFT_RESET);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_PD_DFP_RESET_CABLE */
|
||||
|
||||
static inline int pd_handle_tcp_event_get_source_cap(struct pd_port *pd_port)
|
||||
{
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SNK_READY:
|
||||
PE_TRANSIT_STATE(pd_port, PE_SNK_GET_SOURCE_CAP);
|
||||
return TCP_DPM_RET_SENT;
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
case PE_SRC_READY:
|
||||
if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_DR_SRC_GET_SOURCE_CAP);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
return TCP_DPM_RET_DENIED_LOCAL_CAP;
|
||||
}
|
||||
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
}
|
||||
|
||||
static inline int pd_handle_tcp_event_get_sink_cap(struct pd_port *pd_port)
|
||||
{
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SRC_READY:
|
||||
PE_TRANSIT_STATE(pd_port, PE_SRC_GET_SINK_CAP);
|
||||
return TCP_DPM_RET_SENT;
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
case PE_SNK_READY:
|
||||
if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_DR_SNK_GET_SINK_CAP);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
|
||||
return TCP_DPM_RET_DENIED_LOCAL_CAP;
|
||||
}
|
||||
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_PE_SINK
|
||||
static inline int pd_handle_tcp_event_request(struct pd_port *pd_port)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tcp_dpm_event *tcp_event = &pd_port->tcp_event;
|
||||
|
||||
if (pd_port->pe_state_curr != PE_SNK_READY)
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
switch (pd_get_curr_pd_event(pd_port)->msg) {
|
||||
case TCP_DPM_EVT_REQUEST:
|
||||
ret = pd_dpm_update_tcp_request(
|
||||
pd_port, &tcp_event->tcp_dpm_data.pd_req);
|
||||
break;
|
||||
case TCP_DPM_EVT_REQUEST_EX:
|
||||
ret = pd_dpm_update_tcp_request_ex(
|
||||
pd_port, &tcp_event->tcp_dpm_data.pd_req_ex);
|
||||
break;
|
||||
case TCP_DPM_EVT_REQUEST_AGAIN:
|
||||
ret = pd_dpm_update_tcp_request_again(pd_port);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != TCP_DPM_RET_SUCCESS)
|
||||
return ret;
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, PE_SNK_SELECT_CAPABILITY);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PE_SINK */
|
||||
|
||||
static inline int pd_handle_tcp_event_bist_cm2(struct pd_port *pd_port)
|
||||
{
|
||||
uint32_t bist = BDO_MODE_CARRIER2;
|
||||
|
||||
if (!pd_check_pe_state_ready(pd_port))
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
pd_send_sop_data_msg(pd_port, PD_DATA_BIST, 1, &bist);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
static inline int pd_handle_tcp_event_get_source_cap_ext(
|
||||
struct pd_port *pd_port)
|
||||
{
|
||||
switch (pd_port->pe_state_curr) {
|
||||
case PE_SNK_READY:
|
||||
PE_TRANSIT_STATE(pd_port, PE_SNK_GET_SOURCE_CAP_EXT);
|
||||
return TCP_DPM_RET_SENT;
|
||||
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
case PE_SRC_READY:
|
||||
if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
|
||||
PE_TRANSIT_STATE(pd_port,
|
||||
PE_DR_SRC_GET_SOURCE_CAP_EXT);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
return TCP_DPM_RET_DENIED_LOCAL_CAP;
|
||||
}
|
||||
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
static inline int pd_handle_tcp_event_get_pps_status(struct pd_port *pd_port)
|
||||
{
|
||||
if (pd_port->pe_state_curr != PE_SNK_READY)
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, PE_SNK_GET_PPS_STATUS);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
static inline int pd_make_tcp_event_transit_ready(
|
||||
struct pd_port *pd_port, uint8_t state)
|
||||
{
|
||||
if (!pd_check_pe_state_ready(pd_port))
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, state);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
|
||||
static inline int pd_make_tcp_event_transit_ready2(
|
||||
struct pd_port *pd_port, uint8_t snk_state, uint8_t src_state)
|
||||
{
|
||||
switch (pd_port->pe_state_curr) {
|
||||
|
||||
#ifdef CONFIG_USB_PD_PE_SINK
|
||||
case PE_SNK_READY:
|
||||
PE_TRANSIT_STATE(pd_port, snk_state);
|
||||
return TCP_DPM_RET_SENT;
|
||||
#endif /* CONFIG_USB_PD_PE_SINK */
|
||||
|
||||
#ifdef CONFIG_USB_PD_PE_SOURCE
|
||||
case PE_SRC_READY:
|
||||
PE_TRANSIT_STATE(pd_port, src_state);
|
||||
return TCP_DPM_RET_SENT;
|
||||
#endif /* CONFIG_USB_PD_PE_SOURCE */
|
||||
}
|
||||
|
||||
return TCP_DPM_RET_DENIED_NOT_READY;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
static inline int pd_handle_tcp_event_alert(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcp_dpm_event *tcp_event = &pd_port->tcp_event;
|
||||
|
||||
if (pd_get_curr_pd_event(pd_port)->msg_sec == PD_TCP_FROM_TCPM)
|
||||
pd_port->pe_data.local_alert |= tcp_event->tcp_dpm_data.index;
|
||||
|
||||
return pd_make_tcp_event_transit_ready2(pd_port,
|
||||
PE_SNK_SEND_SINK_ALERT, PE_SRC_SEND_SOURCE_ALERT);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_LOCAL */
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
static inline int pd_handle_tcp_event_hardreset(struct pd_port *pd_port)
|
||||
{
|
||||
pe_transit_hard_reset_state(pd_port);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
|
||||
static inline int pd_handle_tcp_event_error_recovery(struct pd_port *pd_port)
|
||||
{
|
||||
PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
|
||||
return TCP_DPM_RET_SENT;
|
||||
}
|
||||
|
||||
static inline int pd_handle_tcp_dpm_event(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
int ret = TCP_DPM_RET_DENIED_UNKNOWN;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
if (pd_event->msg >= TCP_DPM_EVT_PD30_COMMAND
|
||||
&& pd_event->msg < TCP_DPM_EVT_VDM_COMMAND) {
|
||||
if (!pd_check_rev30(pd_port))
|
||||
return TCP_DPM_RET_DENIED_PD_REV;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
switch (pd_event->msg) {
|
||||
default:
|
||||
break;
|
||||
case TCP_DPM_EVT_PR_SWAP_AS_SNK:
|
||||
case TCP_DPM_EVT_PR_SWAP_AS_SRC:
|
||||
#ifdef CONFIG_USB_PD_PR_SWAP
|
||||
ret = pd_handle_tcp_event_pr_swap(pd_port,
|
||||
pd_event->msg - TCP_DPM_EVT_PR_SWAP_AS_SNK);
|
||||
#endif /* CONFIG_USB_PD_PR_SWAP */
|
||||
break;
|
||||
|
||||
case TCP_DPM_EVT_DR_SWAP_AS_UFP:
|
||||
case TCP_DPM_EVT_DR_SWAP_AS_DFP:
|
||||
#ifdef CONFIG_USB_PD_DR_SWAP
|
||||
ret = pd_handle_tcp_event_dr_swap(pd_port,
|
||||
pd_event->msg - TCP_DPM_EVT_DR_SWAP_AS_UFP);
|
||||
#endif /* CONFIG_USB_PD_DR_SWAP */
|
||||
break;
|
||||
|
||||
case TCP_DPM_EVT_VCONN_SWAP_OFF:
|
||||
case TCP_DPM_EVT_VCONN_SWAP_ON:
|
||||
#ifdef CONFIG_USB_PD_VCONN_SWAP
|
||||
ret = pd_handle_tcp_event_vconn_swap(pd_port,
|
||||
pd_event->msg - TCP_DPM_EVT_VCONN_SWAP_OFF);
|
||||
#endif /* CONFIG_USB_PD_VCONN_SWAP */
|
||||
break;
|
||||
|
||||
case TCP_DPM_EVT_GOTOMIN:
|
||||
#ifdef CONFIG_USB_PD_PE_SOURCE
|
||||
ret = pd_handle_tcp_event_gotomin(pd_port);
|
||||
#endif /* CONFIG_USB_PD_PE_SOURCE */
|
||||
break;
|
||||
case TCP_DPM_EVT_SOFTRESET:
|
||||
ret = pd_handle_tcp_event_softreset(pd_port);
|
||||
break;
|
||||
|
||||
case TCP_DPM_EVT_CABLE_SOFTRESET:
|
||||
#ifdef CONFIG_PD_DFP_RESET_CABLE
|
||||
ret = pd_handle_tcp_event_cable_softreset(pd_port);
|
||||
#endif /* CONFIG_PD_DFP_RESET_CABLE */
|
||||
break;
|
||||
|
||||
case TCP_DPM_EVT_GET_SOURCE_CAP:
|
||||
ret = pd_handle_tcp_event_get_source_cap(pd_port);
|
||||
break;
|
||||
|
||||
case TCP_DPM_EVT_GET_SINK_CAP:
|
||||
ret = pd_handle_tcp_event_get_sink_cap(pd_port);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_PE_SINK
|
||||
case TCP_DPM_EVT_REQUEST:
|
||||
ret = pd_handle_tcp_event_request(pd_port);
|
||||
break;
|
||||
case TCP_DPM_EVT_REQUEST_EX:
|
||||
ret = pd_handle_tcp_event_request(pd_port);
|
||||
break;
|
||||
case TCP_DPM_EVT_REQUEST_AGAIN:
|
||||
ret = pd_handle_tcp_event_request(pd_port);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_PE_SINK */
|
||||
|
||||
case TCP_DPM_EVT_BIST_CM2:
|
||||
ret = pd_handle_tcp_event_bist_cm2(pd_port);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
#ifdef CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE
|
||||
case TCP_DPM_EVT_GET_SOURCE_CAP_EXT:
|
||||
ret = pd_handle_tcp_event_get_source_cap_ext(pd_port);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_SRC_CAP_EXT_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
case TCP_DPM_EVT_GET_STATUS:
|
||||
ret = pd_make_tcp_event_transit_ready2(pd_port,
|
||||
PE_SNK_GET_SOURCE_STATUS, PE_SRC_GET_SINK_STATUS);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE
|
||||
case TCP_DPM_EVT_GET_COUNTRY_CODE:
|
||||
ret = pd_make_tcp_event_transit_ready(
|
||||
pd_port, PE_GET_COUNTRY_CODES);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_CODE_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_PPS_SINK
|
||||
case TCP_DPM_EVT_GET_PPS_STATUS:
|
||||
ret = pd_handle_tcp_event_get_pps_status(pd_port);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_PPS_SINK */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_LOCAL
|
||||
case TCP_DPM_EVT_ALERT:
|
||||
ret = pd_handle_tcp_event_alert(pd_port);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_LOCAL */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE
|
||||
case TCP_DPM_EVT_GET_COUNTRY_INFO:
|
||||
ret = pd_make_tcp_event_transit_ready(
|
||||
pd_port, PE_GET_COUNTRY_INFO);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_COUNTRY_INFO_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_CAP_REMOTE
|
||||
case TCP_DPM_EVT_GET_BAT_CAP:
|
||||
ret = pd_make_tcp_event_transit_ready(
|
||||
pd_port, PE_GET_BATTERY_CAP);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_CAP_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE
|
||||
case TCP_DPM_EVT_GET_BAT_STATUS:
|
||||
ret = pd_make_tcp_event_transit_ready(
|
||||
pd_port, PE_GET_BATTERY_STATUS);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_STATUS_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE
|
||||
case TCP_DPM_EVT_GET_MFRS_INFO:
|
||||
ret = pd_make_tcp_event_transit_ready(
|
||||
pd_port, PE_GET_MANUFACTURER_INFO);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_REV30_MFRS_INFO_REMOTE */
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
case TCP_DPM_EVT_HARD_RESET:
|
||||
ret = pd_handle_tcp_event_hardreset(pd_port);
|
||||
break;
|
||||
|
||||
case TCP_DPM_EVT_ERROR_RECOVERY:
|
||||
ret = pd_handle_tcp_event_error_recovery(pd_port);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool pd_process_event_tcp(struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
int ret = pd_handle_tcp_dpm_event(pd_port, pd_event);
|
||||
|
||||
pd_notify_tcp_event_1st_result(pd_port, ret);
|
||||
return ret == TCP_DPM_RET_SENT;
|
||||
}
|
||||
126
drivers/usb/typec/mmi_tcpc/pd_process_evt_vcs.c
Normal file
126
drivers/usb/typec/mmi_tcpc/pd_process_evt_vcs.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Process Event For VCS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
|
||||
#ifdef CONFIG_USB_PD_VCONN_SWAP
|
||||
/* DPM Event reactions */
|
||||
|
||||
DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
|
||||
{ PE_VCS_EVALUATE_SWAP, PE_VCS_ACCEPT_SWAP },
|
||||
{ PE_VCS_TURN_ON_VCONN, PE_VCS_SEND_PS_RDY },
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess PD Ctrl MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_ctrl_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
uint8_t vconn_state = pd_port->vconn_role ?
|
||||
PE_VCS_WAIT_FOR_VCONN : PE_VCS_TURN_ON_VCONN;
|
||||
|
||||
switch (pd_event->msg) {
|
||||
case PD_CTRL_GOOD_CRC:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_VCS_ACCEPT_SWAP, vconn_state))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case PD_CTRL_ACCEPT:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_VCS_SEND_SWAP, vconn_state))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case PD_CTRL_PS_RDY:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_VCS_WAIT_FOR_VCONN, PE_VCS_TURN_OFF_VCONN))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess DPM MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_dpm_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_DPM_ACK:
|
||||
return PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_ACK);
|
||||
|
||||
case PD_DPM_NAK:
|
||||
if (PE_MAKE_STATE_TRANSIT_SINGLE(
|
||||
PE_VCS_EVALUATE_SWAP, PE_VCS_REJECT_VCONN_SWAP))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Timer MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_timer_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_TIMER_VCONN_ON:
|
||||
if (PE_MAKE_STATE_TRANSIT_TO_HRESET(PE_VCS_WAIT_FOR_VCONN))
|
||||
return true;
|
||||
break;
|
||||
|
||||
#if CONFIG_USB_PD_VCONN_READY_TOUT != 0
|
||||
case PD_TIMER_VCONN_READY:
|
||||
PE_STATE_DPM_ACK_IMMEDIATELY(pd_port);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Process Policy Engine's VCS Message
|
||||
*/
|
||||
|
||||
bool pd_process_event_vcs(struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->event_type) {
|
||||
case PD_EVT_CTRL_MSG:
|
||||
return pd_process_ctrl_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_DPM_MSG:
|
||||
return pd_process_dpm_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_TIMER_MSG:
|
||||
return pd_process_timer_msg(pd_port, pd_event);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_VCONN_SWAP */
|
||||
966
drivers/usb/typec/mmi_tcpc/pd_process_evt_vdm.c
Normal file
966
drivers/usb/typec/mmi_tcpc/pd_process_evt_vdm.c
Normal file
|
|
@ -0,0 +1,966 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Power Delivery Process Event For VDM
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/pd_core.h"
|
||||
#include "inc/tcpci_event.h"
|
||||
#include "inc/pd_process_evt.h"
|
||||
#include "inc/pd_dpm_core.h"
|
||||
|
||||
/* VDM reactions */
|
||||
|
||||
#define VDM_CMD_FLAG_CABLE_CMD (1<<0)
|
||||
#define VDM_CMD_FLAG_SEND_BY_UFP (1<<1)
|
||||
#define VDM_CMD_FLAG_SEND_BY_DFP (1<<2)
|
||||
#define VDM_CMD_FLAG_RECV_BY_UFP (1<<3)
|
||||
#define VDM_CMD_FLAG_RECV_BY_DFP (1<<4)
|
||||
#define VDM_CMD_FLAG_PD30_DUPLEX (1<<5)
|
||||
|
||||
struct vdm_state_transition {
|
||||
uint8_t vdm_cmd;
|
||||
uint8_t vdm_init_state;
|
||||
uint8_t vdm_request_state;
|
||||
uint8_t vdm_cmd_flags;
|
||||
};
|
||||
|
||||
#define VDM_CMD_REACTION(cmd, init, req, flags) { \
|
||||
.vdm_cmd = cmd, \
|
||||
.vdm_init_state = init, \
|
||||
.vdm_request_state = req, \
|
||||
.vdm_cmd_flags = flags, \
|
||||
}
|
||||
|
||||
#define VDM_DFP_CMD_REACTION(cmd, init, req) \
|
||||
VDM_CMD_REACTION(cmd, init, req, \
|
||||
VDM_CMD_FLAG_SEND_BY_DFP | VDM_CMD_FLAG_RECV_BY_UFP)
|
||||
|
||||
#define VDM_UFP_CMD_REACTION(cmd, init, req) \
|
||||
VDM_CMD_REACTION(cmd, init, req, \
|
||||
VDM_CMD_FLAG_SEND_BY_UFP | VDM_CMD_FLAG_RECV_BY_DFP)
|
||||
|
||||
#define VDM_CABLE_CMD_REACTION(cmd, init, req) \
|
||||
VDM_CMD_REACTION(cmd, init, req, \
|
||||
VDM_CMD_FLAG_SEND_BY_UFP | VDM_CMD_FLAG_SEND_BY_DFP \
|
||||
| VDM_CMD_FLAG_CABLE_CMD)
|
||||
|
||||
#define VDM_DFP_CMD_REACTION_PD30(cmd, init, req) \
|
||||
VDM_CMD_REACTION(cmd, init, req, \
|
||||
VDM_CMD_FLAG_SEND_BY_DFP | VDM_CMD_FLAG_RECV_BY_UFP | \
|
||||
VDM_CMD_FLAG_PD30_DUPLEX)
|
||||
|
||||
#define VDM_UFP_CMD_REACTION_PD30(cmd, init, req) \
|
||||
VDM_CMD_REACTION(cmd, init, req, \
|
||||
VDM_CMD_FLAG_SEND_BY_UFP | VDM_CMD_FLAG_RECV_BY_DFP | \
|
||||
VDM_CMD_FLAG_PD30_DUPLEX)
|
||||
|
||||
static const struct vdm_state_transition pe_vdm_state_reactions[] = {
|
||||
|
||||
VDM_DFP_CMD_REACTION_PD30(CMD_DISCOVER_IDENT,
|
||||
PE_UFP_VDM_GET_IDENTITY,
|
||||
PE_DFP_UFP_VDM_IDENTITY_REQUEST
|
||||
),
|
||||
|
||||
VDM_DFP_CMD_REACTION_PD30(CMD_DISCOVER_SVID,
|
||||
PE_UFP_VDM_GET_SVIDS,
|
||||
PE_DFP_VDM_SVIDS_REQUEST
|
||||
),
|
||||
|
||||
VDM_DFP_CMD_REACTION_PD30(CMD_DISCOVER_MODES,
|
||||
PE_UFP_VDM_GET_MODES,
|
||||
PE_DFP_VDM_MODES_REQUEST
|
||||
),
|
||||
|
||||
VDM_DFP_CMD_REACTION(CMD_ENTER_MODE,
|
||||
PE_UFP_VDM_EVALUATE_MODE_ENTRY,
|
||||
PE_DFP_VDM_MODE_ENTRY_REQUEST
|
||||
),
|
||||
|
||||
VDM_DFP_CMD_REACTION(CMD_EXIT_MODE,
|
||||
PE_UFP_VDM_MODE_EXIT,
|
||||
PE_DFP_VDM_MODE_EXIT_REQUEST
|
||||
),
|
||||
|
||||
VDM_UFP_CMD_REACTION_PD30(CMD_ATTENTION,
|
||||
PE_DFP_VDM_ATTENTION_REQUEST,
|
||||
PE_UFP_VDM_ATTENTION_REQUEST
|
||||
),
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
VDM_DFP_CMD_REACTION(CMD_DP_STATUS,
|
||||
PE_UFP_VDM_DP_STATUS_UPDATE,
|
||||
PE_DFP_VDM_DP_STATUS_UPDATE_REQUEST
|
||||
),
|
||||
|
||||
VDM_DFP_CMD_REACTION(CMD_DP_CONFIG,
|
||||
PE_UFP_VDM_DP_CONFIGURE,
|
||||
PE_DFP_VDM_DP_CONFIGURATION_REQUEST
|
||||
),
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
/* Only handle Timeout Case */
|
||||
VDM_DFP_CMD_REACTION_PD30(0,
|
||||
PE_UFP_UVDM_RECV,
|
||||
PE_DFP_UVDM_SEND
|
||||
),
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
|
||||
VDM_CABLE_CMD_REACTION(CMD_DISCOVER_IDENT,
|
||||
0,
|
||||
PE_SRC_VDM_IDENTITY_REQUEST
|
||||
),
|
||||
#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
|
||||
VDM_CABLE_CMD_REACTION(CMD_DISCOVER_IDENT,
|
||||
0,
|
||||
PE_DFP_CBL_VDM_IDENTITY_REQUEST
|
||||
),
|
||||
#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
|
||||
};
|
||||
|
||||
static inline bool pd_vdm_state_transit_rx(struct pd_port *pd_port,
|
||||
const struct vdm_state_transition *state_transition)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (!pd_check_pe_state_ready(pd_port)) {
|
||||
PE_DBG("670 : invalid, current status\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, state_transition->vdm_init_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pd_vdm_state_transit_tx(struct pd_port *pd_port,
|
||||
uint8_t vdm_cmdt, const struct vdm_state_transition *state_transition)
|
||||
{
|
||||
int ret_code = TCP_DPM_RET_VDM_NAK;
|
||||
uint8_t curr_state = state_transition->vdm_request_state;
|
||||
uint8_t next_state = curr_state + 1;
|
||||
|
||||
switch (vdm_cmdt) {
|
||||
|
||||
case CMDT_RSP_NAK:
|
||||
if (curr_state != PE_DFP_VDM_MODE_EXIT_REQUEST)
|
||||
next_state = curr_state+2;
|
||||
break;
|
||||
|
||||
case CMDT_RSP_BUSY:
|
||||
if (curr_state == PE_DFP_VDM_MODE_EXIT_REQUEST)
|
||||
next_state = pe_get_curr_hard_reset_state(pd_port);
|
||||
else
|
||||
next_state = curr_state+2;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret_code = TCP_DPM_RET_VDM_ACK;
|
||||
break;
|
||||
}
|
||||
|
||||
pd_notify_tcp_vdm_event_2nd_result(pd_port, ret_code);
|
||||
PE_TRANSIT_STATE(pd_port, next_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vdm_is_state_transition_available(struct pd_port *pd_port,
|
||||
bool recv, const struct vdm_state_transition *state_transition)
|
||||
{
|
||||
uint8_t shift = 1;
|
||||
uint8_t vdm_cmd_flags = state_transition->vdm_cmd_flags;
|
||||
|
||||
if (pd_check_rev30(pd_port) &&
|
||||
(vdm_cmd_flags & VDM_CMD_FLAG_PD30_DUPLEX)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pd_port->data_role == PD_ROLE_DFP)
|
||||
shift += 1;
|
||||
|
||||
if (recv)
|
||||
shift += 2;
|
||||
|
||||
return vdm_cmd_flags & (1 << shift);
|
||||
}
|
||||
|
||||
static bool pd_vdm_state_transit(
|
||||
struct pd_port *pd_port, uint8_t vdm_cmdt,
|
||||
const struct vdm_state_transition *state_transition)
|
||||
{
|
||||
uint8_t curr_state;
|
||||
|
||||
curr_state = pd_port->pe_state_curr;
|
||||
|
||||
if (curr_state == PE_UFP_VDM_ATTENTION_REQUEST) {
|
||||
VDM_STATE_DPM_INFORMED(pd_port);
|
||||
pd_notify_tcp_vdm_event_2nd_result(
|
||||
pd_port, TCP_DPM_RET_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vdm_cmdt == CMDT_INIT) { /* Recv */
|
||||
if (!vdm_is_state_transition_available(
|
||||
pd_port, true, state_transition))
|
||||
return false;
|
||||
|
||||
return pd_vdm_state_transit_rx(pd_port, state_transition);
|
||||
}
|
||||
|
||||
/* Send */
|
||||
if (!vdm_is_state_transition_available(
|
||||
pd_port, false, state_transition))
|
||||
return false;
|
||||
|
||||
if (curr_state != state_transition->vdm_request_state)
|
||||
return false;
|
||||
|
||||
return pd_vdm_state_transit_tx(
|
||||
pd_port, vdm_cmdt, state_transition);
|
||||
}
|
||||
|
||||
enum {
|
||||
VDM_STATE_TRANSIT_SOP_CMD = 0,
|
||||
VDM_STATE_TRANSIT_SOP_PRIME_CMD = VDM_CMD_FLAG_CABLE_CMD,
|
||||
VDM_STATE_TRANSIT_NAK = 2,
|
||||
|
||||
VDM_STATE_TRANSIT_CHECK_TX = 3,
|
||||
};
|
||||
|
||||
static bool pe_check_vdm_state_transit_valid(
|
||||
struct pd_port *pd_port, uint8_t transit_type, uint8_t *vdm_cmdt,
|
||||
const struct vdm_state_transition *state_transition)
|
||||
{
|
||||
uint8_t curr_state;
|
||||
uint8_t vdm_cmd;
|
||||
uint8_t cable_cmd;
|
||||
uint8_t vdm_cmd_flags;
|
||||
uint32_t curr_vdm_hdr;
|
||||
|
||||
curr_state = pd_port->pe_state_curr;
|
||||
|
||||
if (transit_type == VDM_STATE_TRANSIT_NAK) {
|
||||
if (curr_state != state_transition->vdm_request_state)
|
||||
return false;
|
||||
|
||||
*vdm_cmdt = CMDT_RSP_BUSY;
|
||||
return true;
|
||||
} else if (transit_type >= VDM_STATE_TRANSIT_CHECK_TX) {
|
||||
return state_transition->vdm_request_state == transit_type;
|
||||
}
|
||||
|
||||
curr_vdm_hdr = pd_port->curr_vdm_hdr;
|
||||
|
||||
vdm_cmd = PD_VDO_CMD(curr_vdm_hdr);
|
||||
*vdm_cmdt = PD_VDO_CMDT(curr_vdm_hdr);
|
||||
|
||||
if (state_transition->vdm_cmd != vdm_cmd)
|
||||
return false;
|
||||
|
||||
vdm_cmd_flags = state_transition->vdm_cmd_flags;
|
||||
cable_cmd = vdm_cmd_flags & VDM_CMD_FLAG_CABLE_CMD;
|
||||
|
||||
if (cable_cmd != transit_type)
|
||||
return false;
|
||||
|
||||
if (cable_cmd && curr_state != state_transition->vdm_request_state)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool pd_make_vdm_state_transit(
|
||||
struct pd_port *pd_port, uint8_t transit_type)
|
||||
{
|
||||
int i;
|
||||
bool check_tx;
|
||||
uint8_t vdm_cmdt;
|
||||
const struct vdm_state_transition *state_transition;
|
||||
|
||||
uint8_t nr_transition = ARRAY_SIZE(pe_vdm_state_reactions);
|
||||
const struct vdm_state_transition *state_reaction =
|
||||
pe_vdm_state_reactions;
|
||||
|
||||
check_tx = transit_type >= VDM_STATE_TRANSIT_CHECK_TX;
|
||||
|
||||
for (i = 0; i < nr_transition; i++) {
|
||||
state_transition = &state_reaction[i];
|
||||
|
||||
if (!pe_check_vdm_state_transit_valid(
|
||||
pd_port, transit_type, &vdm_cmdt, state_transition))
|
||||
continue;
|
||||
|
||||
if (check_tx) {
|
||||
return vdm_is_state_transition_available(
|
||||
pd_port, false, state_transition);
|
||||
} else {
|
||||
return pd_vdm_state_transit(
|
||||
pd_port, vdm_cmdt, state_transition);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool pd_make_vdm_state_transit_sop(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_make_vdm_state_transit(
|
||||
pd_port, VDM_STATE_TRANSIT_SOP_CMD);
|
||||
}
|
||||
|
||||
static inline bool pd_make_vdm_state_transit_cable(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_make_vdm_state_transit(
|
||||
pd_port, VDM_STATE_TRANSIT_SOP_PRIME_CMD);
|
||||
}
|
||||
|
||||
static inline bool pd_make_vdm_state_transit_nak(struct pd_port *pd_port)
|
||||
{
|
||||
return pd_make_vdm_state_transit(
|
||||
pd_port, VDM_STATE_TRANSIT_NAK);
|
||||
}
|
||||
|
||||
/* Discover Cable ID */
|
||||
|
||||
#ifdef CONFIG_PD_DISCOVER_CABLE_ID
|
||||
DECL_PE_STATE_TRANSITION(PD_DPM_MSG_DISCOVER_CABLE) = {
|
||||
#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
|
||||
{ PE_SRC_STARTUP, PE_SRC_VDM_IDENTITY_REQUEST},
|
||||
{ PE_SRC_DISCOVERY, PE_SRC_VDM_IDENTITY_REQUEST},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
|
||||
{ PE_SRC_READY, PE_DFP_CBL_VDM_IDENTITY_REQUEST},
|
||||
{ PE_SNK_READY, PE_DFP_CBL_VDM_IDENTITY_REQUEST},
|
||||
#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
|
||||
|
||||
#ifdef CONFIG_PD_SRC_RESET_CABLE
|
||||
{ PE_SRC_CBL_SEND_SOFT_RESET, PE_SRC_VDM_IDENTITY_REQUEST},
|
||||
#endif /* CONFIG_PD_SRC_RESET_CABLE */
|
||||
};
|
||||
DECL_PE_STATE_REACTION(PD_DPM_MSG_DISCOVER_CABLE);
|
||||
#endif /* CONFIG_PD_DISCOVER_CABLE_ID */
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Ctrl MSG
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
#ifdef CONFIG_USB_PD_DBG_DP_UFP_U_AUTO_ATTENTION
|
||||
static inline bool pd_ufp_u_auto_send_attention(struct pd_port *pd_port)
|
||||
{
|
||||
struct dp_data *dp_data = pd_get_dp_data(pd_port);
|
||||
|
||||
if (dp_data->local_config != 0) {
|
||||
PE_TRANSIT_STATE(pd_port,
|
||||
PE_UFP_VDM_ATTENTION_REQUEST);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DBG_DP_UFP_U_AUTO_ATTENTION */
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
static inline bool pd_process_ctrl_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
struct pe_data *pe_data = &pd_port->pe_data;
|
||||
|
||||
/* VDM Only handle CtrlMsg = GoodCRC */
|
||||
|
||||
if (pd_event->msg != PD_CTRL_GOOD_CRC)
|
||||
return false;
|
||||
|
||||
if (pe_data->vdm_state_flags &
|
||||
VDM_STATE_FLAG_ENABLE_VDM_RESPONSE_TIMER)
|
||||
pd_enable_timer(pd_port, pe_data->vdm_state_timer);
|
||||
|
||||
switch (pd_port->pe_state_curr) {
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
#ifdef CONFIG_USB_PD_DBG_DP_UFP_U_AUTO_ATTENTION
|
||||
case PE_UFP_VDM_DP_CONFIGURE:
|
||||
if (pd_ufp_u_auto_send_attention(pd_port))
|
||||
return true;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_DBG_DP_UFP_U_AUTO_ATTENTION */
|
||||
|
||||
case PE_UFP_VDM_ATTENTION_REQUEST:
|
||||
pd_notify_tcp_vdm_event_2nd_result(
|
||||
pd_port, TCP_DPM_RET_VDM_ACK);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
|
||||
case PE_SRC_VDM_IDENTITY_REQUEST:
|
||||
pe_data->power_cable_present = true;
|
||||
return false;
|
||||
#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
|
||||
|
||||
#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
|
||||
case PE_DFP_CBL_VDM_IDENTITY_REQUEST:
|
||||
pe_data->power_cable_present = true;
|
||||
return false;
|
||||
#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
case PE_DFP_UVDM_SEND:
|
||||
if (!pd_port->uvdm_wait_resp) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_DFP_UVDM_ACKED);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
}
|
||||
|
||||
if (pe_data->vdm_state_flags
|
||||
& VDM_STATE_FLAG_BACK_READY_IF_RECV_GOOD_CRC) {
|
||||
pe_transit_ready_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Custom MSG (SVDM/UVDM)
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
|
||||
bool pd_process_custom_vdm(struct pd_port *pd_port, bool svdm)
|
||||
{
|
||||
bool recv = false;
|
||||
|
||||
if (pd_port->data_role == PD_ROLE_UFP)
|
||||
recv = true;
|
||||
|
||||
if (pd_check_rev30(pd_port) && svdm)
|
||||
recv = true;
|
||||
|
||||
if (pd_check_pe_state_ready(pd_port)) {
|
||||
if (recv) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_UFP_UVDM_RECV);
|
||||
return true;
|
||||
}
|
||||
} else if (pd_port->pe_state_curr == PE_DFP_UVDM_SEND) {
|
||||
PE_TRANSIT_STATE(pd_port, PE_DFP_UVDM_ACKED);
|
||||
return true;
|
||||
}
|
||||
|
||||
pd_put_dpm_event(pd_port, PD_DPM_NOT_SUPPORT);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
static inline bool pd_process_uvdm(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
#ifdef CONFIG_USB_PD_UVDM
|
||||
/* support sop only */
|
||||
if (pd_event->pd_msg->frame_type != TCPC_TX_SOP)
|
||||
return false;
|
||||
|
||||
if (pd_process_custom_vdm(pd_port, false))
|
||||
return true;
|
||||
#else
|
||||
pd_put_dpm_event(pd_port, PD_DPM_NOT_SUPPORT);
|
||||
#endif /* CONFIG_USB_PD_UVDM */
|
||||
|
||||
/* TODO: Reply Not_Supported Message*/
|
||||
PE_DBG("659 : Invalid UVDM\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Data MSG (VDM)
|
||||
*/
|
||||
|
||||
#if (PE_EVT_INFO_VDM_DIS == 0)
|
||||
static const char * const pe_vdm_cmd_name[] = {
|
||||
"DiscoverID",
|
||||
"DiscoverSVID",
|
||||
"DiscoverMode",
|
||||
"EnterMode",
|
||||
"ExitMode",
|
||||
"Attention",
|
||||
};
|
||||
|
||||
#if PE_INFO_ENABLE
|
||||
static const char *const pe_vdm_cmd_type_name[] = {
|
||||
"INIT",
|
||||
"ACK",
|
||||
"NACK",
|
||||
"BUSY",
|
||||
};
|
||||
#endif /* PE_INFO_ENABLE */
|
||||
|
||||
static inline const char *assign_vdm_cmd_name(uint8_t cmd)
|
||||
{
|
||||
if (cmd <= ARRAY_SIZE(pe_vdm_cmd_name) && cmd != 0) {
|
||||
cmd -= 1;
|
||||
return pe_vdm_cmd_name[cmd];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
static const char *const pe_vdm_dp_cmd_name[] = {
|
||||
"DPStatus",
|
||||
"DPConfig",
|
||||
};
|
||||
|
||||
static inline const char *assign_vdm_dp_cmd_name(uint8_t cmd)
|
||||
{
|
||||
if (cmd >= CMD_DP_STATUS) {
|
||||
cmd -= CMD_DP_STATUS;
|
||||
if (cmd < ARRAY_SIZE(pe_vdm_dp_cmd_name))
|
||||
return pe_vdm_dp_cmd_name[cmd];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
#endif /* if (PE_EVT_INFO_VDM_DIS == 0) */
|
||||
|
||||
static inline void print_vdm_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
#if (PE_EVT_INFO_VDM_DIS == 0)
|
||||
uint8_t cmd;
|
||||
uint8_t cmd_type;
|
||||
uint16_t svid;
|
||||
const char *name = NULL;
|
||||
uint32_t vdm_hdr = pd_port->curr_vdm_hdr;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
cmd = PD_VDO_CMD(vdm_hdr);
|
||||
cmd_type = PD_VDO_CMDT(vdm_hdr);
|
||||
svid = PD_VDO_VID(vdm_hdr);
|
||||
|
||||
name = assign_vdm_cmd_name(cmd);
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
if (name == NULL && svid == USB_SID_DISPLAYPORT)
|
||||
name = assign_vdm_dp_cmd_name(cmd);
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
if (name == NULL)
|
||||
return;
|
||||
|
||||
#if PE_INFO_ENABLE
|
||||
if (cmd_type >= ARRAY_SIZE(pe_vdm_cmd_type_name))
|
||||
return;
|
||||
|
||||
PE_INFO("%s:%s\n", name, pe_vdm_cmd_type_name[cmd_type]);
|
||||
#endif /* PE_INFO_ENABLE */
|
||||
|
||||
#endif /* PE_EVT_INFO_VDM_DIS */
|
||||
}
|
||||
|
||||
static inline bool pd_process_sop_vdm(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_make_vdm_state_transit_sop(pd_port))
|
||||
return true;
|
||||
|
||||
#ifdef CONFIG_USB_PD_SVDM
|
||||
if (pd_process_custom_vdm(pd_port, true))
|
||||
return true;
|
||||
#endif /* CONFIG_USB_PD_SVDM */
|
||||
|
||||
PE_DBG("Unknown SVDM\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool pd_process_sop_prime_vdm(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
return pd_make_vdm_state_transit_cable(pd_port);
|
||||
}
|
||||
|
||||
static inline bool pd_process_data_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool ret = false;
|
||||
uint32_t vdm_hdr;
|
||||
struct pd_msg *pd_msg = pd_event->pd_msg;
|
||||
|
||||
if (pd_event->msg != PD_DATA_VENDOR_DEF)
|
||||
return ret;
|
||||
|
||||
vdm_hdr = pd_msg->payload[0];
|
||||
pd_port->curr_vdm_hdr = vdm_hdr;
|
||||
pd_port->curr_vdm_ops = PD_VDO_OPOS(vdm_hdr);
|
||||
pd_port->curr_vdm_svid = PD_VDO_VID(vdm_hdr);
|
||||
|
||||
if (!PD_VDO_SVDM(vdm_hdr))
|
||||
return pd_process_uvdm(pd_port, pd_event);
|
||||
|
||||
/* From Port Partner, copy curr_state from pd_state */
|
||||
if (PD_VDO_CMDT(vdm_hdr) == CMDT_INIT) {
|
||||
pd_port->pe_vdm_state = pd_port->pe_pd_state;
|
||||
pd_port->pe_state_curr = pd_port->pe_pd_state;
|
||||
|
||||
#if PE_DBG_RESET_VDM_DIS == 0
|
||||
PE_DBG("reset vdm_state\n");
|
||||
#endif /* if PE_DBG_RESET_VDM_DIS == 0 */
|
||||
}
|
||||
|
||||
print_vdm_msg(pd_port, pd_event);
|
||||
|
||||
if (pd_msg->frame_type == TCPC_TX_SOP_PRIME)
|
||||
ret = pd_process_sop_prime_vdm(pd_port, pd_event);
|
||||
else
|
||||
ret = pd_process_sop_vdm(pd_port, pd_event);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess PDM MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_dpm_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
if (pd_event->msg != PD_DPM_ACK)
|
||||
return false;
|
||||
|
||||
if (pd_port->pe_data.vdm_state_flags &
|
||||
VDM_STATE_FLAG_BACK_READY_IF_DPM_ACK) {
|
||||
pe_transit_ready_state(pd_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess HW MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_hw_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
struct pe_data *pe_data = &pd_port->pe_data;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_event->msg == PD_HW_TX_DISCARD &&
|
||||
(pe_data->vdm_discard_retry_count < 10)) {
|
||||
PE_INFO("vdm_discard_retry\n");
|
||||
pe_data->vdm_discard_retry_flag = true;
|
||||
pe_data->vdm_discard_retry_count++;
|
||||
}
|
||||
|
||||
switch (pd_event->msg) {
|
||||
case PD_HW_TX_FAILED:
|
||||
case PD_HW_TX_DISCARD:
|
||||
return pd_make_vdm_state_transit_nak(pd_port);
|
||||
|
||||
case PD_HW_RETRY_VDM:
|
||||
if (pd_port->pe_data.vdm_state_timer)
|
||||
return pd_make_vdm_state_transit_nak(pd_port);
|
||||
PE_DBG("RetryVDM\n");
|
||||
return pd_process_sop_vdm(pd_port, pd_event);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess PE MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_pe_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_PE_VDM_NOT_SUPPORT:
|
||||
break;
|
||||
|
||||
case PD_PE_VDM_RESET:
|
||||
pd_port->pe_data.reset_vdm_state = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return pd_make_vdm_state_transit_nak(pd_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess Timer MSG
|
||||
*/
|
||||
|
||||
static inline bool pd_process_timer_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
case PD_TIMER_VDM_MODE_ENTRY:
|
||||
case PD_TIMER_VDM_MODE_EXIT:
|
||||
case PD_TIMER_VDM_RESPONSE:
|
||||
case PD_TIMER_UVDM_RESPONSE:
|
||||
return pd_make_vdm_state_transit_nak(pd_port);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Porcess TCP MSG
|
||||
*/
|
||||
|
||||
const uint8_t tcp_vdm_evt_init_state[] = {
|
||||
PE_DFP_UFP_VDM_IDENTITY_REQUEST, /* TCP_DPM_EVT_DISCOVER_ID */
|
||||
PE_DFP_VDM_SVIDS_REQUEST, /* TCP_DPM_EVT_DISCOVER_SVIDS */
|
||||
PE_DFP_VDM_MODES_REQUEST, /* TCP_DPM_EVT_DISCOVER_MODES */
|
||||
PE_DFP_VDM_MODE_ENTRY_REQUEST, /* TCP_DPM_EVT_ENTER_MODE */
|
||||
PE_DFP_VDM_MODE_EXIT_REQUEST, /* TCP_DPM_EVT_EXIT_MODE */
|
||||
PE_UFP_VDM_ATTENTION_REQUEST, /* TCP_DPM_EVT_ATTENTION */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
PE_UFP_VDM_ATTENTION_REQUEST, /* TCP_DPM_EVT_DP_ATTENTION */
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
PE_DFP_VDM_DP_STATUS_UPDATE_REQUEST, /* TCP_DPM_EVT_DP_STATUS_UPDATE */
|
||||
PE_DFP_VDM_DP_CONFIGURATION_REQUEST, /* TCP_DPM_EVT_DP_CONFIG */
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
PE_DFP_UVDM_SEND, /* TCP_DPM_EVT_UVDM */
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
};
|
||||
|
||||
static inline bool pd_process_tcp_cable_event(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
bool ret;
|
||||
int tcp_ret;
|
||||
#ifdef CONFIG_PD_DISCOVER_CABLE_ID
|
||||
bool role_check = true;
|
||||
|
||||
if (pd_check_rev30(pd_port))
|
||||
role_check = pd_port->vconn_role;
|
||||
|
||||
if (role_check) {
|
||||
ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_DISCOVER_CABLE);
|
||||
tcp_ret = ret ? TCP_DPM_RET_SENT : TCP_DPM_RET_DENIED_NOT_READY;
|
||||
} else {
|
||||
ret = false;
|
||||
tcp_ret = TCP_DPM_RET_DENIED_WRONG_DATA_ROLE;
|
||||
}
|
||||
#else
|
||||
ret = false;
|
||||
tcp_ret = TCP_DPM_RET_DENIED_UNKNOWN;
|
||||
#endif /* CONFIG_PD_DISCOVER_CABLE_ID */
|
||||
|
||||
pd_notify_tcp_event_1st_result(pd_port, tcp_ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
|
||||
static inline uint32_t tcpc_update_bits(
|
||||
uint32_t var, uint32_t update, uint32_t mask)
|
||||
{
|
||||
return (var & (~mask)) | (update & mask);
|
||||
}
|
||||
|
||||
static inline void pd_parse_tcp_dpm_evt_svdm(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcp_dpm_svdm_data *svdm_data =
|
||||
&pd_port->tcp_event.tcp_dpm_data.svdm_data;
|
||||
|
||||
pd_port->mode_svid = svdm_data->svid;
|
||||
pd_port->mode_obj_pos = svdm_data->ops;
|
||||
}
|
||||
|
||||
static inline void pd_parse_tcp_dpm_evt_dp_status(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcp_dpm_dp_data *dp_data_tcp =
|
||||
&pd_port->tcp_event.tcp_dpm_data.dp_data;
|
||||
|
||||
struct dp_data *dp_data = pd_get_dp_data(pd_port);
|
||||
|
||||
pd_port->mode_svid = USB_SID_DISPLAYPORT;
|
||||
dp_data->local_status = tcpc_update_bits(
|
||||
dp_data->local_status,
|
||||
dp_data_tcp->val, dp_data_tcp->mask);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
|
||||
static inline void pd_parse_tcp_dpm_evt_dp_config(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcp_dpm_dp_data *dp_data_tcp =
|
||||
&pd_port->tcp_event.tcp_dpm_data.dp_data;
|
||||
struct dp_data *dp_data = pd_get_dp_data(pd_port);
|
||||
|
||||
pd_port->mode_svid = USB_SID_DISPLAYPORT;
|
||||
dp_data->local_config = tcpc_update_bits(
|
||||
dp_data->local_config, dp_data_tcp->val, dp_data_tcp->mask);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
static inline void pd_parse_tcp_dpm_evt_uvdm(struct pd_port *pd_port)
|
||||
{
|
||||
struct tcp_dpm_custom_vdm_data *vdm_data =
|
||||
&pd_port->tcp_event.tcp_dpm_data.vdm_data;
|
||||
|
||||
pd_port->uvdm_cnt = vdm_data->cnt;
|
||||
pd_port->uvdm_wait_resp = vdm_data->wait_resp;
|
||||
memcpy(pd_port->uvdm_data,
|
||||
vdm_data->vdos, sizeof(uint32_t) * vdm_data->cnt);
|
||||
|
||||
#ifdef CONFIG_USB_PD_SVDM
|
||||
if (pd_check_rev30(pd_port) &&
|
||||
(pd_port->uvdm_data[0] & VDO_SVDM_TYPE))
|
||||
pd_port->uvdm_data[0] |= VDO_SVDM_VERS(SVDM_REV20);
|
||||
#endif /* CONFIG_USB_PD_SVDM */
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
static inline void pd_parse_tcp_dpm_evt_from_tcpm(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
switch (pd_event->msg) {
|
||||
#ifdef CONFIG_USB_PD_KEEP_SVIDS
|
||||
case TCP_DPM_EVT_DISCOVER_SVIDS:
|
||||
pd_port->pe_data.remote_svid_list.cnt = 0;
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_KEEP_SVIDS */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
case TCP_DPM_EVT_DISCOVER_MODES:
|
||||
case TCP_DPM_EVT_ENTER_MODE:
|
||||
case TCP_DPM_EVT_EXIT_MODE:
|
||||
case TCP_DPM_EVT_ATTENTION:
|
||||
pd_parse_tcp_dpm_evt_svdm(pd_port);
|
||||
break;
|
||||
|
||||
case TCP_DPM_EVT_DP_ATTENTION:
|
||||
pd_parse_tcp_dpm_evt_dp_status(pd_port);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
|
||||
case TCP_DPM_EVT_DP_STATUS_UPDATE:
|
||||
pd_parse_tcp_dpm_evt_dp_status(pd_port);
|
||||
break;
|
||||
case TCP_DPM_EVT_DP_CONFIG:
|
||||
pd_parse_tcp_dpm_evt_dp_config(pd_port);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
case TCP_DPM_EVT_UVDM:
|
||||
pd_parse_tcp_dpm_evt_uvdm(pd_port);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool pd_check_tcp_msg_valid(
|
||||
struct pd_port *pd_port, uint8_t new_state)
|
||||
{
|
||||
return pd_make_vdm_state_transit(pd_port, new_state);
|
||||
}
|
||||
|
||||
static inline bool pd_process_tcp_msg(
|
||||
struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
uint8_t new_state;
|
||||
struct tcpc_device __maybe_unused *tcpc = pd_port->tcpc;
|
||||
|
||||
if (pd_event->msg == TCP_DPM_EVT_DISCOVER_CABLE)
|
||||
return pd_process_tcp_cable_event(pd_port, pd_event);
|
||||
|
||||
if (!pd_check_pe_state_ready(pd_port)) {
|
||||
pd_notify_tcp_event_1st_result(
|
||||
pd_port, TCP_DPM_RET_DENIED_NOT_READY);
|
||||
PE_DBG("skip vdm_request, not ready_state (%d)\n",
|
||||
pd_port->pe_state_curr);
|
||||
return false;
|
||||
}
|
||||
|
||||
new_state = pd_event->msg - TCP_DPM_EVT_DISCOVER_ID;
|
||||
if (new_state >= ARRAY_SIZE(tcp_vdm_evt_init_state)) {
|
||||
PD_BUG_ON(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
new_state = tcp_vdm_evt_init_state[new_state];
|
||||
|
||||
if (!pd_check_tcp_msg_valid(pd_port, new_state)) {
|
||||
pd_notify_tcp_event_1st_result(
|
||||
pd_port, TCP_DPM_RET_DENIED_WRONG_DATA_ROLE);
|
||||
PE_DBG("skip vdm_request, WRONG DATA ROLE\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pd_event->msg_sec == PD_TCP_FROM_TCPM)
|
||||
pd_parse_tcp_dpm_evt_from_tcpm(pd_port, pd_event);
|
||||
|
||||
PE_TRANSIT_STATE(pd_port, new_state);
|
||||
pd_notify_tcp_event_1st_result(pd_port, TCP_DPM_RET_SENT);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] Process Policy Engine's VDM Message
|
||||
*/
|
||||
|
||||
bool pd_process_event_vdm(struct pd_port *pd_port, struct pd_event *pd_event)
|
||||
{
|
||||
pd_port->pe_data.vdm_discard_retry_flag = false;
|
||||
|
||||
switch (pd_event->event_type) {
|
||||
case PD_EVT_CTRL_MSG:
|
||||
return pd_process_ctrl_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_DATA_MSG:
|
||||
return pd_process_data_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_DPM_MSG:
|
||||
return pd_process_dpm_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_HW_MSG:
|
||||
return pd_process_hw_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_PE_MSG:
|
||||
return pd_process_pe_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_TIMER_MSG:
|
||||
return pd_process_timer_msg(pd_port, pd_event);
|
||||
|
||||
case PD_EVT_TCP_MSG:
|
||||
return pd_process_tcp_msg(pd_port, pd_event);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
1641
drivers/usb/typec/mmi_tcpc/rt-regmap.c
Normal file
1641
drivers/usb/typec/mmi_tcpc/rt-regmap.c
Normal file
File diff suppressed because it is too large
Load diff
1208
drivers/usb/typec/mmi_tcpc/rt_pd_manager.c
Normal file
1208
drivers/usb/typec/mmi_tcpc/rt_pd_manager.c
Normal file
File diff suppressed because it is too large
Load diff
1812
drivers/usb/typec/mmi_tcpc/tcpc_rt1711h.c
Normal file
1812
drivers/usb/typec/mmi_tcpc/tcpc_rt1711h.c
Normal file
File diff suppressed because it is too large
Load diff
989
drivers/usb/typec/mmi_tcpc/tcpci.c
Normal file
989
drivers/usb/typec/mmi_tcpc/tcpci.c
Normal file
|
|
@ -0,0 +1,989 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "inc/tcpci.h"
|
||||
#include <linux/time.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define TCPC_NOTIFY_OVERTIME (20) /* ms */
|
||||
|
||||
#ifdef CONFIG_TCPC_NOTIFICATION_NON_BLOCKING
|
||||
struct tcp_notify_work {
|
||||
struct work_struct work;
|
||||
struct tcpc_device *tcpc;
|
||||
struct tcp_notify tcp_noti;
|
||||
uint8_t type;
|
||||
uint8_t state;
|
||||
};
|
||||
|
||||
static void tcp_notify_func(struct work_struct *work)
|
||||
{
|
||||
struct tcp_notify_work *tn_work =
|
||||
container_of(work, struct tcp_notify_work, work);
|
||||
struct tcpc_device *tcpc = tn_work->tcpc;
|
||||
struct tcp_notify *tcp_noti = &tn_work->tcp_noti;
|
||||
uint8_t type = tn_work->type;
|
||||
uint8_t state = tn_work->state;
|
||||
#ifdef CONFIG_PD_BEGUG_ON
|
||||
struct timeval begin, end;
|
||||
int timeval = 0;
|
||||
|
||||
do_gettimeofday(&begin);
|
||||
srcu_notifier_call_chain(&tcpc->evt_nh[type], state, tcp_noti);
|
||||
do_gettimeofday(&end);
|
||||
timeval = (timeval_to_ns(end) - timeval_to_ns(begin))/1000/1000;
|
||||
PD_BUG_ON(timeval > TCPC_NOTIFY_OVERTIME);
|
||||
#else
|
||||
srcu_notifier_call_chain(&tcpc->evt_nh[type], state, tcp_noti);
|
||||
#endif
|
||||
|
||||
kfree(tn_work);
|
||||
}
|
||||
|
||||
static int tcpc_check_notify_time(struct tcpc_device *tcpc,
|
||||
struct tcp_notify *tcp_noti, uint8_t type, uint8_t state)
|
||||
{
|
||||
struct tcp_notify_work *tn_work;
|
||||
|
||||
tn_work = kzalloc(sizeof(*tn_work), GFP_KERNEL);
|
||||
if (!tn_work)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&tn_work->work, tcp_notify_func);
|
||||
tn_work->tcpc = tcpc;
|
||||
tn_work->tcp_noti = *tcp_noti;
|
||||
tn_work->type = type;
|
||||
tn_work->state = state;
|
||||
|
||||
return queue_work(tcpc->evt_wq, &tn_work->work) ? 0 : -EAGAIN;
|
||||
}
|
||||
#else
|
||||
static int tcpc_check_notify_time(struct tcpc_device *tcpc,
|
||||
struct tcp_notify *tcp_noti, uint8_t type, uint8_t state)
|
||||
{
|
||||
int ret;
|
||||
#ifdef CONFIG_PD_BEGUG_ON
|
||||
struct timeval begin, end;
|
||||
int timeval = 0;
|
||||
|
||||
do_gettimeofday(&begin);
|
||||
ret = srcu_notifier_call_chain(&tcpc->evt_nh[type], state, tcp_noti);
|
||||
do_gettimeofday(&end);
|
||||
timeval = (timeval_to_ns(end) - timeval_to_ns(begin))/1000/1000;
|
||||
PD_BUG_ON(timeval > TCPC_NOTIFY_OVERTIME);
|
||||
#else
|
||||
ret = srcu_notifier_call_chain(&tcpc->evt_nh[type], state, tcp_noti);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_TCPC_NOTIFICATION_BLOCKING */
|
||||
|
||||
int tcpci_check_vbus_valid_from_ic(struct tcpc_device *tcpc)
|
||||
{
|
||||
uint16_t power_status;
|
||||
int vbus_level = tcpc->vbus_level;
|
||||
|
||||
if (tcpci_get_power_status(tcpc, &power_status) == 0) {
|
||||
if (vbus_level != tcpc->vbus_level) {
|
||||
TCPC_INFO("[Warning] ps_changed %d ->%d\n",
|
||||
vbus_level, tcpc->vbus_level);
|
||||
}
|
||||
}
|
||||
|
||||
return tcpci_check_vbus_valid(tcpc);
|
||||
}
|
||||
|
||||
int tcpci_check_vsafe0v(
|
||||
struct tcpc_device *tcpc, bool detect_en)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
ret = (tcpc->vbus_level == TCPC_VBUS_SAFE0V);
|
||||
#else
|
||||
ret = (tcpc->vbus_level == TCPC_VBUS_INVALID);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcpci_alert_status_clear(
|
||||
struct tcpc_device *tcpc, uint32_t mask)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->alert_status_clear == NULL);
|
||||
|
||||
return tcpc->ops->alert_status_clear(tcpc, mask);
|
||||
}
|
||||
EXPORT_SYMBOL(tcpci_alert_status_clear);
|
||||
|
||||
int tcpci_fault_status_clear(
|
||||
struct tcpc_device *tcpc, uint8_t status)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->fault_status_clear == NULL);
|
||||
|
||||
return tcpc->ops->fault_status_clear(tcpc, status);
|
||||
}
|
||||
|
||||
int tcpci_set_alert_mask(struct tcpc_device *tcpc, uint32_t mask)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (tcpc->ops->set_alert_mask)
|
||||
return tcpc->ops->set_alert_mask(tcpc, mask);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int tcpci_get_alert_mask(
|
||||
struct tcpc_device *tcpc, uint32_t *mask)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->get_alert_mask == NULL);
|
||||
|
||||
return tcpc->ops->get_alert_mask(tcpc, mask);
|
||||
}
|
||||
|
||||
int tcpci_get_alert_status(
|
||||
struct tcpc_device *tcpc, uint32_t *alert)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->get_alert_status == NULL);
|
||||
|
||||
return tcpc->ops->get_alert_status(tcpc, alert);
|
||||
}
|
||||
|
||||
int tcpci_get_fault_status(
|
||||
struct tcpc_device *tcpc, uint8_t *fault)
|
||||
{
|
||||
if (tcpc->ops->get_fault_status)
|
||||
return tcpc->ops->get_fault_status(tcpc, fault);
|
||||
|
||||
*fault = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_get_power_status(
|
||||
struct tcpc_device *tcpc, uint16_t *pw_status)
|
||||
{
|
||||
int ret;
|
||||
|
||||
PD_BUG_ON(tcpc->ops->get_power_status == NULL);
|
||||
|
||||
ret = tcpc->ops->get_power_status(tcpc, pw_status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tcpci_vbus_level_init(tcpc, *pw_status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_init(struct tcpc_device *tcpc, bool sw_reset)
|
||||
{
|
||||
int ret;
|
||||
uint16_t power_status;
|
||||
|
||||
PD_BUG_ON(tcpc->ops->init == NULL);
|
||||
|
||||
ret = tcpc->ops->init(tcpc, sw_reset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return tcpci_get_power_status(tcpc, &power_status);
|
||||
}
|
||||
|
||||
int tcpci_init_alert_mask(struct tcpc_device *tcpc)
|
||||
{
|
||||
if (tcpc->ops->init_alert_mask)
|
||||
return tcpc->ops->init_alert_mask(tcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_get_cc(struct tcpc_device *tcpc)
|
||||
{
|
||||
int ret;
|
||||
int cc1, cc2;
|
||||
|
||||
PD_BUG_ON(tcpc->ops->get_cc == NULL);
|
||||
|
||||
ret = tcpc->ops->get_cc(tcpc, &cc1, &cc2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if ((cc1 == tcpc->typec_remote_cc[0]) &&
|
||||
(cc2 == tcpc->typec_remote_cc[1])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tcpc->typec_remote_cc[0] = cc1;
|
||||
tcpc->typec_remote_cc[1] = cc2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tcpci_set_cc(struct tcpc_device *tcpc, int pull)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->set_cc == NULL);
|
||||
|
||||
#ifdef CONFIG_USB_PD_DBG_ALWAYS_LOCAL_RP
|
||||
if (pull == TYPEC_CC_RP)
|
||||
pull = tcpc->typec_local_rp_level;
|
||||
#endif /* CONFIG_USB_PD_DBG_ALWAYS_LOCAL_RP */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE
|
||||
if (pull == TYPEC_CC_DRP && tcpc->typec_legacy_cable) {
|
||||
#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE2
|
||||
if (tcpc->typec_legacy_cable == 2)
|
||||
pull = TYPEC_CC_RP;
|
||||
else if (tcpc->typec_legacy_retry_wk > 1)
|
||||
pull = TYPEC_CC_RP_3_0;
|
||||
else
|
||||
#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE2 */
|
||||
pull = TYPEC_CC_RP_1_5;
|
||||
TCPC_DBG2("LC->Toggling (%d)\n", pull);
|
||||
}
|
||||
#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE */
|
||||
|
||||
if (pull & TYPEC_CC_DRP) {
|
||||
tcpc->typec_remote_cc[0] =
|
||||
tcpc->typec_remote_cc[1] =
|
||||
TYPEC_CC_DRP_TOGGLING;
|
||||
}
|
||||
|
||||
tcpc->typec_local_cc = pull;
|
||||
return tcpc->ops->set_cc(tcpc, pull);
|
||||
}
|
||||
|
||||
int tcpci_set_polarity(struct tcpc_device *tcpc, int polarity)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->set_polarity == NULL);
|
||||
|
||||
return tcpc->ops->set_polarity(tcpc, polarity);
|
||||
}
|
||||
|
||||
int tcpci_set_low_rp_duty(struct tcpc_device *tcpc, bool low_rp)
|
||||
{
|
||||
#ifdef CONFIG_TYPEC_CAP_LOW_RP_DUTY
|
||||
if (low_rp)
|
||||
TCPC_INFO("low_rp_duty\n");
|
||||
|
||||
if (tcpc->ops->set_low_rp_duty)
|
||||
return tcpc->ops->set_low_rp_duty(tcpc, low_rp);
|
||||
#endif /* CONFIG_TYPEC_CAP_LOW_RP_DUTY */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_set_vconn(struct tcpc_device *tcpc, int enable)
|
||||
{
|
||||
#ifdef CONFIG_TCPC_SOURCE_VCONN
|
||||
struct tcp_notify tcp_noti;
|
||||
|
||||
if (tcpc->tcpc_source_vconn == enable)
|
||||
return 0;
|
||||
|
||||
tcpc->tcpc_source_vconn = enable;
|
||||
|
||||
tcp_noti.en_state.en = enable != 0;
|
||||
tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_VBUS, TCP_NOTIFY_SOURCE_VCONN);
|
||||
|
||||
if (tcpc->ops->set_vconn)
|
||||
return tcpc->ops->set_vconn(tcpc, enable);
|
||||
#endif /* CONFIG_TCPC_SOURCE_VCONN */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_is_low_power_mode(struct tcpc_device *tcpc)
|
||||
{
|
||||
int rv = 1;
|
||||
|
||||
#ifdef CONFIG_TCPC_LOW_POWER_MODE
|
||||
if (tcpc->ops->is_low_power_mode)
|
||||
rv = tcpc->ops->is_low_power_mode(tcpc);
|
||||
#endif /* CONFIG_TCPC_LOW_POWER_MODE */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int tcpci_set_low_power_mode(
|
||||
struct tcpc_device *tcpc, bool en, int pull)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
#ifdef CONFIG_TCPC_LOW_POWER_MODE
|
||||
if (tcpc->ops->set_low_power_mode)
|
||||
rv = tcpc->ops->set_low_power_mode(tcpc, en, pull);
|
||||
#endif /* CONFIG_TCPC_LOW_POWER_MODE */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int tcpci_set_watchdog(struct tcpc_device *tcpc, bool en)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (tcpc->tcpc_flags & TCPC_FLAGS_WATCHDOG_EN)
|
||||
if (tcpc->ops->set_watchdog)
|
||||
rv = tcpc->ops->set_watchdog(tcpc, en);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int tcpci_alert_vendor_defined_handler(struct tcpc_device *tcpc)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (tcpc->ops->alert_vendor_defined_handler)
|
||||
rv = tcpc->ops->alert_vendor_defined_handler(tcpc);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
int tcpci_is_vsafe0v(struct tcpc_device *tcpc)
|
||||
{
|
||||
int rv = -ENOTSUPP;
|
||||
|
||||
if (tcpc->ops->is_vsafe0v)
|
||||
rv = tcpc->ops->is_vsafe0v(tcpc);
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
|
||||
|
||||
#ifdef CONFIG_WATER_DETECTION
|
||||
int tcpci_is_water_detected(struct tcpc_device *tcpc)
|
||||
{
|
||||
if (tcpc->ops->is_water_detected)
|
||||
return tcpc->ops->is_water_detected(tcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_set_water_protection(struct tcpc_device *tcpc, bool en)
|
||||
{
|
||||
if (tcpc->ops->set_water_protection)
|
||||
return tcpc->ops->set_water_protection(tcpc, en);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_set_usbid_polling(struct tcpc_device *tcpc, bool en)
|
||||
{
|
||||
if (tcpc->ops->set_usbid_polling)
|
||||
return tcpc->ops->set_usbid_polling(tcpc, en);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_notify_wd_status(struct tcpc_device *tcpc, bool water_detected)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
|
||||
tcp_noti.wd_status.water_detected = water_detected;
|
||||
return tcpc_check_notify_time(tcpc, &tcp_noti, TCP_NOTIFY_IDX_MISC,
|
||||
TCP_NOTIFY_WD_STATUS);
|
||||
}
|
||||
#endif /* CONFIG_WATER_DETECTION */
|
||||
|
||||
#ifdef CONFIG_CABLE_TYPE_DETECTION
|
||||
int tcpci_notify_cable_type(struct tcpc_device *tcpc)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
|
||||
tcp_noti.cable_type.type = tcpc->typec_cable_type;
|
||||
return tcpc_check_notify_time(tcpc, &tcp_noti, TCP_NOTIFY_IDX_MISC,
|
||||
TCP_NOTIFY_CABLE_TYPE);
|
||||
}
|
||||
#endif /* CONFIG_CABLE_TYPE_DETECTION */
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
|
||||
int tcpci_set_msg_header(struct tcpc_device *tcpc,
|
||||
uint8_t power_role, uint8_t data_role)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->set_msg_header == NULL);
|
||||
|
||||
return tcpc->ops->set_msg_header(tcpc, power_role, data_role);
|
||||
}
|
||||
|
||||
int tcpci_set_rx_enable(struct tcpc_device *tcpc, uint8_t enable)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->set_rx_enable == NULL);
|
||||
|
||||
return tcpc->ops->set_rx_enable(tcpc, enable);
|
||||
}
|
||||
|
||||
int tcpci_protocol_reset(struct tcpc_device *tcpc)
|
||||
{
|
||||
if (tcpc->ops->protocol_reset)
|
||||
return tcpc->ops->protocol_reset(tcpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_get_message(struct tcpc_device *tcpc,
|
||||
uint32_t *payload, uint16_t *head, enum tcpm_transmit_type *type)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->get_message == NULL);
|
||||
|
||||
return tcpc->ops->get_message(tcpc, payload, head, type);
|
||||
}
|
||||
|
||||
int tcpci_transmit(struct tcpc_device *tcpc,
|
||||
enum tcpm_transmit_type type, uint16_t header, const uint32_t *data)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->transmit == NULL);
|
||||
|
||||
return tcpc->ops->transmit(tcpc, type, header, data);
|
||||
}
|
||||
|
||||
int tcpci_set_bist_test_mode(struct tcpc_device *tcpc, bool en)
|
||||
{
|
||||
if (tcpc->ops->set_bist_test_mode)
|
||||
return tcpc->ops->set_bist_test_mode(tcpc, en);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_set_bist_carrier_mode(struct tcpc_device *tcpc, uint8_t pattern)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->set_bist_carrier_mode == NULL);
|
||||
|
||||
if (pattern) /* wait for GoodCRC */
|
||||
udelay(240);
|
||||
|
||||
return tcpc->ops->set_bist_carrier_mode(tcpc, pattern);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
|
||||
int tcpci_retransmit(struct tcpc_device *tcpc)
|
||||
{
|
||||
PD_BUG_ON(tcpc->ops->retransmit == NULL);
|
||||
|
||||
return tcpc->ops->retransmit(tcpc);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_RETRY_CRC_DISCARD */
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
int tcpci_notify_typec_state(struct tcpc_device *tcpc)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
tcp_noti.typec_state.polarity = tcpc->typec_polarity;
|
||||
tcp_noti.typec_state.old_state = tcpc->typec_attach_old;
|
||||
tcp_noti.typec_state.new_state = tcpc->typec_attach_new;
|
||||
tcp_noti.typec_state.rp_level = tcpc->typec_remote_rp_level;
|
||||
tcp_noti.typec_state.local_rp_level = tcpc->typec_local_rp_level;
|
||||
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_USB, TCP_NOTIFY_TYPEC_STATE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcpci_notify_role_swap(
|
||||
struct tcpc_device *tcpc, uint8_t event, uint8_t role)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
tcp_noti.swap_state.new_role = role;
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MISC, event);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcpci_notify_pd_state(struct tcpc_device *tcpc, uint8_t connect)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
tcp_noti.pd_state.connected = connect;
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_USB, TCP_NOTIFY_PD_STATE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcpci_set_intrst(struct tcpc_device *tcpc, bool en)
|
||||
{
|
||||
#ifdef CONFIG_TCPC_INTRST_EN
|
||||
if (tcpc->ops->set_intrst)
|
||||
tcpc->ops->set_intrst(tcpc, en);
|
||||
#endif /* CONFIG_TCPC_INTRST_EN */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_enable_watchdog(struct tcpc_device *tcpc, bool en)
|
||||
{
|
||||
if (!(tcpc->tcpc_flags & TCPC_FLAGS_WATCHDOG_EN))
|
||||
return 0;
|
||||
|
||||
TCPC_DBG2("enable_WG: %d\n", en);
|
||||
|
||||
if (tcpc->typec_watchdog == en)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
tcpc->typec_watchdog = en;
|
||||
|
||||
if (tcpc->ops->set_watchdog)
|
||||
tcpc->ops->set_watchdog(tcpc, en);
|
||||
|
||||
#ifdef CONFIG_TCPC_INTRST_EN
|
||||
if (!en || tcpc->attach_wake_lock->active)
|
||||
tcpci_set_intrst(tcpc, en);
|
||||
#endif /* CONFIG_TCPC_INTRST_EN */
|
||||
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_source_vbus(
|
||||
struct tcpc_device *tcpc, uint8_t type, int mv, int ma)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
if (type >= TCP_VBUS_CTRL_PD &&
|
||||
tcpc->pd_port.pe_data.pd_prev_connected)
|
||||
type |= TCP_VBUS_CTRL_PD_DETECT;
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
if (ma < 0) {
|
||||
if (mv != 0) {
|
||||
switch (tcpc->typec_local_rp_level) {
|
||||
case TYPEC_CC_RP_1_5:
|
||||
ma = 1500;
|
||||
break;
|
||||
case TYPEC_CC_RP_3_0:
|
||||
ma = 3000;
|
||||
break;
|
||||
default:
|
||||
case TYPEC_CC_RP_DFT:
|
||||
ma = CONFIG_TYPEC_SRC_CURR_DFT;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
ma = 0;
|
||||
}
|
||||
|
||||
tcp_noti.vbus_state.ma = ma;
|
||||
tcp_noti.vbus_state.mv = mv;
|
||||
tcp_noti.vbus_state.type = type;
|
||||
|
||||
tcpci_enable_watchdog(tcpc, mv != 0);
|
||||
TCPC_DBG("source_vbus: %d mV, %d mA\n", mv, ma);
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_VBUS, TCP_NOTIFY_SOURCE_VBUS);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(tcpci_source_vbus);
|
||||
|
||||
int tcpci_sink_vbus(
|
||||
struct tcpc_device *tcpc, uint8_t type, int mv, int ma)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
if (type >= TCP_VBUS_CTRL_PD &&
|
||||
tcpc->pd_port.pe_data.pd_prev_connected)
|
||||
type |= TCP_VBUS_CTRL_PD_DETECT;
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
if (ma < 0) {
|
||||
if (mv != 0) {
|
||||
switch (tcpc->typec_remote_rp_level) {
|
||||
case TYPEC_CC_VOLT_SNK_1_5:
|
||||
ma = 1500;
|
||||
break;
|
||||
case TYPEC_CC_VOLT_SNK_3_0:
|
||||
ma = 3000;
|
||||
break;
|
||||
default:
|
||||
case TYPEC_CC_VOLT_SNK_DFT:
|
||||
ma = tcpc->typec_usb_sink_curr;
|
||||
break;
|
||||
}
|
||||
#if CONFIG_TYPEC_SNK_CURR_LIMIT > 0
|
||||
if (ma > CONFIG_TYPEC_SNK_CURR_LIMIT)
|
||||
ma = CONFIG_TYPEC_SNK_CURR_LIMIT;
|
||||
#endif /* CONFIG_TYPEC_SNK_CURR_LIMIT */
|
||||
} else
|
||||
ma = 0;
|
||||
}
|
||||
|
||||
tcp_noti.vbus_state.ma = ma;
|
||||
tcp_noti.vbus_state.mv = mv;
|
||||
tcp_noti.vbus_state.type = type;
|
||||
|
||||
TCPC_DBG("sink_vbus: %d mV, %d mA\n", mv, ma);
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_VBUS, TCP_NOTIFY_SINK_VBUS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcpci_disable_vbus_control(struct tcpc_device *tcpc)
|
||||
{
|
||||
#ifdef CONFIG_TYPEC_USE_DIS_VBUS_CTRL
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
TCPC_DBG("disable_vbus\n");
|
||||
tcpci_enable_watchdog(tcpc, false);
|
||||
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_VBUS, TCP_NOTIFY_DIS_VBUS_CTRL);
|
||||
return ret;
|
||||
#else
|
||||
tcpci_sink_vbus(tcpc, TCP_VBUS_CTRL_REMOVE, TCPC_VBUS_SINK_0V, 0);
|
||||
tcpci_source_vbus(tcpc, TCP_VBUS_CTRL_REMOVE, TCPC_VBUS_SOURCE_0V, 0);
|
||||
return 0;
|
||||
#endif /* CONFIG_TYPEC_USE_DIS_VBUS_CTRL */
|
||||
}
|
||||
|
||||
int tcpci_notify_attachwait_state(struct tcpc_device *tcpc, bool as_sink)
|
||||
{
|
||||
#ifdef CONFIG_TYPEC_NOTIFY_ATTACHWAIT
|
||||
uint8_t notify = 0;
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SNK
|
||||
if (as_sink)
|
||||
notify = TCP_NOTIFY_ATTACHWAIT_SNK;
|
||||
#endif /* CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SNK */
|
||||
|
||||
#ifdef CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SRC
|
||||
if (!as_sink)
|
||||
notify = TCP_NOTIFY_ATTACHWAIT_SRC;
|
||||
#endif /* CONFIG_TYPEC_NOTIFY_ATTACHWAIT_SRC */
|
||||
|
||||
if (notify == 0)
|
||||
return 0;
|
||||
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_VBUS, notify);
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif /* CONFIG_TYPEC_NOTIFY_ATTACHWAIT */
|
||||
|
||||
}
|
||||
|
||||
int tcpci_enable_auto_discharge(struct tcpc_device *tcpc, bool en)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_AUTO_DISCHARGE
|
||||
#ifdef CONFIG_TCPC_AUTO_DISCHARGE_IC
|
||||
if (tcpc->typec_auto_discharge != en) {
|
||||
tcpc->typec_auto_discharge = en;
|
||||
if (tcpc->ops->set_auto_discharge)
|
||||
ret = tcpc->ops->set_auto_discharge(tcpc, en);
|
||||
}
|
||||
#endif /* CONFIG_TCPC_AUTO_DISCHARGE_IC */
|
||||
#endif /* CONFIG_TYPEC_CAP_AUTO_DISCHARGE */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __tcpci_enable_force_discharge(
|
||||
struct tcpc_device *tcpc, bool en, int mv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_FORCE_DISCHARGE
|
||||
#ifdef CONFIG_TCPC_FORCE_DISCHARGE_IC
|
||||
if (tcpc->pd_force_discharge != en) {
|
||||
tcpc->pd_force_discharge = en;
|
||||
if (tcpc->ops->set_force_discharge)
|
||||
ret = tcpc->ops->set_force_discharge(tcpc, en, mv);
|
||||
}
|
||||
#endif /* CONFIG_TCPC_FORCE_DISCHARGE_IC */
|
||||
#endif /* CONFIG_TYPEC_CAP_FORCE_DISCHARGE */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __tcpci_enable_ext_discharge(struct tcpc_device *tcpc, bool en)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_TCPC_EXT_DISCHARGE
|
||||
struct tcp_notify tcp_noti;
|
||||
|
||||
if (tcpc->typec_ext_discharge != en) {
|
||||
tcpc->typec_ext_discharge = en;
|
||||
tcp_noti.en_state.en = en;
|
||||
TCPC_DBG("EXT-Discharge: %d\n", en);
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_VBUS, TCP_NOTIFY_EXT_DISCHARGE);
|
||||
}
|
||||
#endif /* CONFIG_TCPC_EXT_DISCHARGE */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcpci_enable_force_discharge(struct tcpc_device *tcpc, bool en, int mv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_FORCE_DISCHARGE
|
||||
ret = __tcpci_enable_force_discharge(tcpc, en, mv);
|
||||
#ifdef CONFIG_TCPC_FORCE_DISCHARGE_EXT
|
||||
ret = __tcpci_enable_ext_discharge(tcpc, en);
|
||||
#endif /* CONFIG_TCPC_FORCE_DISCHARGE_EXT */
|
||||
#endif /* CONFIG_TYPEC_CAP_FORCE_DISCHARGE */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
|
||||
int tcpci_notify_hard_reset_state(struct tcpc_device *tcpc, uint8_t state)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
tcp_noti.hreset_state.state = state;
|
||||
|
||||
if (state >= TCP_HRESET_SIGNAL_SEND)
|
||||
tcpc->pd_wait_hard_reset_complete = true;
|
||||
else if (tcpc->pd_wait_hard_reset_complete)
|
||||
tcpc->pd_wait_hard_reset_complete = false;
|
||||
else
|
||||
return 0;
|
||||
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MISC, TCP_NOTIFY_HARD_RESET_STATE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcpci_enter_mode(struct tcpc_device *tcpc,
|
||||
uint16_t svid, uint8_t ops, uint32_t mode)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
tcp_noti.mode_ctrl.svid = svid;
|
||||
tcp_noti.mode_ctrl.ops = ops;
|
||||
tcp_noti.mode_ctrl.mode = mode;
|
||||
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MODE, TCP_NOTIFY_ENTER_MODE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcpci_exit_mode(struct tcpc_device *tcpc, uint16_t svid)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
tcp_noti.mode_ctrl.svid = svid;
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MODE, TCP_NOTIFY_EXIT_MODE);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE
|
||||
|
||||
int tcpci_report_hpd_state(struct tcpc_device *tcpc, uint32_t dp_status)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
struct dp_data *dp_data = pd_get_dp_data(&tcpc->pd_port);
|
||||
|
||||
/* UFP_D to DFP_D only */
|
||||
|
||||
if (PD_DP_CFG_DFP_D(dp_data->local_config)) {
|
||||
tcp_noti.ama_dp_hpd_state.irq = PD_VDO_DPSTS_HPD_IRQ(dp_status);
|
||||
tcp_noti.ama_dp_hpd_state.state =
|
||||
PD_VDO_DPSTS_HPD_LVL(dp_status);
|
||||
tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MODE, TCP_NOTIFY_AMA_DP_HPD_STATE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_dp_status_update(struct tcpc_device *tcpc, uint32_t dp_status)
|
||||
{
|
||||
DP_INFO("Status0: 0x%x\n", dp_status);
|
||||
tcpci_report_hpd_state(tcpc, dp_status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_dp_configure(struct tcpc_device *tcpc, uint32_t dp_config)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
DP_INFO("LocalCFG: 0x%x\n", dp_config);
|
||||
|
||||
switch (dp_config & 0x03) {
|
||||
case 0:
|
||||
tcp_noti.ama_dp_state.sel_config = SW_USB;
|
||||
break;
|
||||
case MODE_DP_SNK:
|
||||
tcp_noti.ama_dp_state.sel_config = SW_DFP_D;
|
||||
tcp_noti.ama_dp_state.pin_assignment = (dp_config >> 8) & 0xff;
|
||||
break;
|
||||
case MODE_DP_SRC:
|
||||
tcp_noti.ama_dp_state.sel_config = SW_UFP_D;
|
||||
tcp_noti.ama_dp_state.pin_assignment = (dp_config >> 16) & 0xff;
|
||||
break;
|
||||
}
|
||||
if (tcp_noti.ama_dp_state.pin_assignment == 0)
|
||||
tcp_noti.ama_dp_state.pin_assignment = (dp_config >> 16) & 0xff;
|
||||
|
||||
DP_INFO("pin assignment: 0x%x\n",
|
||||
tcp_noti.ama_dp_state.pin_assignment);
|
||||
tcp_noti.ama_dp_state.signal = (dp_config >> 2) & 0x0f;
|
||||
tcp_noti.ama_dp_state.polarity = tcpc->typec_polarity;
|
||||
tcp_noti.ama_dp_state.active = 1;
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MODE, TCP_NOTIFY_AMA_DP_STATE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcpci_dp_attention(struct tcpc_device *tcpc, uint32_t dp_status)
|
||||
{
|
||||
/* DFP_U : Not call this function during internal flow */
|
||||
struct tcp_notify tcp_noti;
|
||||
|
||||
DP_INFO("Attention: 0x%x\n", dp_status);
|
||||
tcp_noti.ama_dp_attention.state = (uint8_t) dp_status;
|
||||
tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MODE, TCP_NOTIFY_AMA_DP_ATTENTION);
|
||||
return tcpci_report_hpd_state(tcpc, dp_status);
|
||||
}
|
||||
|
||||
int tcpci_dp_notify_status_update_done(
|
||||
struct tcpc_device *tcpc, uint32_t dp_status, bool ack)
|
||||
{
|
||||
/* DFP_U : Not call this function during internal flow */
|
||||
DP_INFO("Status1: 0x%x, ack=%d\n", dp_status, ack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_dp_notify_config_start(struct tcpc_device *tcpc)
|
||||
{
|
||||
/* DFP_U : Put signal & mux into the Safe State */
|
||||
struct tcp_notify tcp_noti;
|
||||
|
||||
DP_INFO("ConfigStart\n");
|
||||
tcp_noti.ama_dp_state.sel_config = SW_USB;
|
||||
tcp_noti.ama_dp_state.active = 0;
|
||||
tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MODE, TCP_NOTIFY_AMA_DP_STATE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_dp_notify_config_done(struct tcpc_device *tcpc,
|
||||
uint32_t local_cfg, uint32_t remote_cfg, bool ack)
|
||||
{
|
||||
/* DFP_U : If DP success,
|
||||
* internal flow will enter this function finally
|
||||
*/
|
||||
DP_INFO("ConfigDone, L:0x%x, R:0x%x, ack=%d\n",
|
||||
local_cfg, remote_cfg, ack);
|
||||
|
||||
if (ack)
|
||||
tcpci_dp_configure(tcpc, local_cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_CUSTOM_VDM
|
||||
int tcpci_notify_uvdm(struct tcpc_device *tcpc, bool ack)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
struct pd_port *pd_port = &tcpc->pd_port;
|
||||
|
||||
tcp_noti.uvdm_msg.ack = ack;
|
||||
|
||||
if (ack) {
|
||||
tcp_noti.uvdm_msg.uvdm_cnt = pd_port->uvdm_cnt;
|
||||
tcp_noti.uvdm_msg.uvdm_svid = pd_port->uvdm_svid;
|
||||
tcp_noti.uvdm_msg.uvdm_data = pd_port->uvdm_data;
|
||||
}
|
||||
|
||||
tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MODE, TCP_NOTIFY_UVDM);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_CUSTOM_VDM */
|
||||
|
||||
#ifdef CONFIG_USB_PD_ALT_MODE_RTDC
|
||||
int tcpci_dc_notify_en_unlock(struct tcpc_device *tcpc)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
DC_INFO("DirectCharge en_unlock\n");
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MODE, TCP_NOTIFY_DC_EN_UNLOCK);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_ALT_MODE_RTDC */
|
||||
|
||||
/* ---- Policy Engine (PD30) ---- */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_ALERT_REMOTE
|
||||
int tcpci_notify_alert(struct tcpc_device *tcpc, uint32_t ado)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
tcp_noti.alert_msg.ado = ado;
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MISC, TCP_NOTIFY_ALERT);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_ALERT_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_STATUS_REMOTE
|
||||
int tcpci_notify_status(struct tcpc_device *tcpc, struct pd_status *sdb)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
tcp_noti.status_msg.sdb = sdb;
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MISC, TCP_NOTIFY_STATUS);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_STATUS_REMOTE */
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30_BAT_INFO
|
||||
int tcpci_notify_request_bat_info(
|
||||
struct tcpc_device *tcpc, enum pd_battery_reference ref)
|
||||
{
|
||||
struct tcp_notify tcp_noti;
|
||||
int ret;
|
||||
|
||||
tcp_noti.request_bat.ref = ref;
|
||||
ret = tcpc_check_notify_time(tcpc, &tcp_noti,
|
||||
TCP_NOTIFY_IDX_MISC, TCP_NOTIFY_REQUEST_BAT_INFO);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30_BAT_INFO */
|
||||
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
689
drivers/usb/typec/mmi_tcpc/tcpci_alert.c
Normal file
689
drivers/usb/typec/mmi_tcpc/tcpci_alert.c
Normal file
|
|
@ -0,0 +1,689 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Richtek Inc.
|
||||
*
|
||||
* TCPC Interface for alert handler
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/tcpci_typec.h"
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
#include "inc/tcpci_event.h"
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#ifdef CONFIG_DUAL_ROLE_USB_INTF
|
||||
#include <linux/usb/class-dual-role.h>
|
||||
#endif /* CONFIG_DUAL_ROLE_USB_INTF */
|
||||
|
||||
/*
|
||||
* [BLOCK] TCPCI IRQ Handler
|
||||
*/
|
||||
|
||||
static int tcpci_alert_cc_changed(struct tcpc_device *tcpc)
|
||||
{
|
||||
return tcpc_typec_handle_cc_change(tcpc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
|
||||
static inline int tcpci_alert_vsafe0v(struct tcpc_device *tcpc)
|
||||
{
|
||||
tcpc_typec_handle_vsafe0v(tcpc);
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
#ifdef CONFIG_USB_PD_SAFE0V_DELAY
|
||||
tcpc_enable_timer(tcpc, PD_TIMER_VSAFE0V_DELAY);
|
||||
#else
|
||||
pd_put_vbus_safe0v_event(tcpc);
|
||||
#endif /* CONFIG_USB_PD_SAFE0V_DELAY */
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
|
||||
|
||||
static inline void tcpci_vbus_level_init_v10(
|
||||
struct tcpc_device *tcpc, uint16_t power_status)
|
||||
{
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
|
||||
tcpc->vbus_level =
|
||||
power_status & TCPC_REG_POWER_STATUS_VBUS_PRES ?
|
||||
TCPC_VBUS_VALID : TCPC_VBUS_INVALID;
|
||||
|
||||
#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
if (power_status & TCPC_REG_POWER_STATUS_EXT_VSAFE0V) {
|
||||
if (tcpc->vbus_level == TCPC_VBUS_INVALID)
|
||||
tcpc->vbus_level = TCPC_VBUS_SAFE0V;
|
||||
else
|
||||
TCPC_INFO("ps_confused: 0x%02x\n", power_status);
|
||||
}
|
||||
#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
|
||||
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
}
|
||||
|
||||
static inline void __tcpci_vbus_level_refresh(struct tcpc_device *tcpc)
|
||||
{
|
||||
tcpc->vbus_level = tcpc->vbus_present ? TCPC_VBUS_VALID :
|
||||
TCPC_VBUS_INVALID;
|
||||
|
||||
#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
if (tcpc->vbus_safe0v) {
|
||||
if (tcpc->vbus_level == TCPC_VBUS_INVALID)
|
||||
tcpc->vbus_level = TCPC_VBUS_SAFE0V;
|
||||
else
|
||||
TCPC_INFO("ps_confused: %d\n", tcpc->vbus_level);
|
||||
}
|
||||
#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
|
||||
}
|
||||
|
||||
static inline void tcpci_vbus_level_refresh(struct tcpc_device *tcpc)
|
||||
{
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
__tcpci_vbus_level_refresh(tcpc);
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
}
|
||||
|
||||
void tcpci_vbus_level_init(struct tcpc_device *tcpc, uint16_t status)
|
||||
{
|
||||
if (tcpc->tcpc_flags & TCPC_FLAGS_ALERT_V10) {
|
||||
tcpci_vbus_level_init_v10(tcpc, status);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
|
||||
tcpc->vbus_present = status & TCPC_REG_POWER_STATUS_VBUS_PRES ?
|
||||
true : false;
|
||||
__tcpci_vbus_level_refresh(tcpc);
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
}
|
||||
|
||||
static inline int tcpci_alert_power_status_changed_v10(struct tcpc_device *tcpc)
|
||||
{
|
||||
int rv = 0;
|
||||
bool show_msg = true;
|
||||
uint16_t power_status = 0;
|
||||
|
||||
rv = tcpci_get_power_status(tcpc, &power_status);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
#ifdef CONFIG_USB_PD_DIRECT_CHARGE
|
||||
if (tcpc->pd_during_direct_charge && tcpc->vbus_level != 0)
|
||||
show_msg = false;
|
||||
#endif /* CONFIG_USB_PD_DIRECT_CHARGE */
|
||||
|
||||
if (show_msg)
|
||||
TCPC_INFO("ps_change=%d\n", tcpc->vbus_level);
|
||||
|
||||
rv = tcpc_typec_handle_ps_change(tcpc, tcpc->vbus_level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
pd_put_vbus_changed_event(tcpc, true);
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
if (tcpc->vbus_level == TCPC_VBUS_SAFE0V)
|
||||
rv = tcpci_alert_vsafe0v(tcpc);
|
||||
#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline int tcpci_vbus_level_changed(struct tcpc_device *tcpc)
|
||||
{
|
||||
int rv = 0;
|
||||
bool show_msg = true;
|
||||
|
||||
#ifdef CONFIG_USB_PD_DIRECT_CHARGE
|
||||
if (tcpc->pd_during_direct_charge && tcpc->vbus_level != 0)
|
||||
show_msg = false;
|
||||
#endif /* CONFIG_USB_PD_DIRECT_CHARGE */
|
||||
|
||||
if (show_msg)
|
||||
TCPC_INFO("ps_change=%d\n", tcpc->vbus_level);
|
||||
|
||||
rv = tcpc_typec_handle_ps_change(tcpc, tcpc->vbus_level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
pd_put_vbus_changed_event(tcpc, true);
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
|
||||
if (tcpc->vbus_level == TCPC_VBUS_SAFE0V)
|
||||
rv = tcpci_alert_vsafe0v(tcpc);
|
||||
#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int tcpci_alert_power_status_changed(struct tcpc_device *tcpc)
|
||||
{
|
||||
int rv = 0;
|
||||
uint16_t status = 0;
|
||||
|
||||
if (tcpc->tcpc_flags & TCPC_FLAGS_ALERT_V10)
|
||||
return tcpci_alert_power_status_changed_v10(tcpc);
|
||||
|
||||
rv = tcpci_get_power_status(tcpc, &status);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
tcpc->vbus_present = (status & TCPC_REG_POWER_STATUS_VBUS_PRES) ?
|
||||
true : false;
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
static int tcpci_alert_tx_success(struct tcpc_device *tcpc)
|
||||
{
|
||||
uint8_t tx_state;
|
||||
|
||||
struct pd_event evt = {
|
||||
.event_type = PD_EVT_CTRL_MSG,
|
||||
.msg = PD_CTRL_GOOD_CRC,
|
||||
.pd_msg = NULL,
|
||||
};
|
||||
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
tx_state = tcpc->pd_transmit_state;
|
||||
tcpc->pd_transmit_state = PD_TX_STATE_GOOD_CRC;
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
|
||||
if (tx_state == PD_TX_STATE_WAIT_CRC_VDM)
|
||||
pd_put_vdm_event(tcpc, &evt, false);
|
||||
else
|
||||
pd_put_event(tcpc, &evt, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcpci_alert_tx_failed(struct tcpc_device *tcpc)
|
||||
{
|
||||
uint8_t tx_state;
|
||||
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
tx_state = tcpc->pd_transmit_state;
|
||||
tcpc->pd_transmit_state = PD_TX_STATE_NO_GOOD_CRC;
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
|
||||
if (tx_state == PD_TX_STATE_WAIT_CRC_VDM)
|
||||
vdm_put_hw_event(tcpc, PD_HW_TX_FAILED);
|
||||
else
|
||||
pd_put_hw_event(tcpc, PD_HW_TX_FAILED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcpci_alert_tx_discard(struct tcpc_device *tcpc)
|
||||
{
|
||||
uint8_t tx_state;
|
||||
bool retry_crc_discard = false;
|
||||
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
tx_state = tcpc->pd_transmit_state;
|
||||
tcpc->pd_transmit_state = PD_TX_STATE_DISCARD;
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
|
||||
TCPC_INFO("Discard\n");
|
||||
|
||||
if (tx_state == PD_TX_STATE_WAIT_CRC_VDM)
|
||||
pd_put_last_vdm_event(tcpc);
|
||||
else {
|
||||
retry_crc_discard =
|
||||
(tcpc->tcpc_flags &
|
||||
TCPC_FLAGS_RETRY_CRC_DISCARD) != 0;
|
||||
|
||||
if (retry_crc_discard) {
|
||||
#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
|
||||
tcpc->pd_discard_pending = true;
|
||||
tcpc_enable_timer(tcpc, PD_TIMER_DISCARD);
|
||||
#else
|
||||
TCPC_ERR("RETRY_CRC_DISCARD\n");
|
||||
#endif /* CONFIG_USB_PD_RETRY_CRC_DISCARD */
|
||||
} else {
|
||||
pd_put_hw_event(tcpc, PD_HW_TX_FAILED);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcpci_alert_recv_msg(struct tcpc_device *tcpc)
|
||||
{
|
||||
int retval;
|
||||
struct pd_msg *pd_msg;
|
||||
enum tcpm_transmit_type type;
|
||||
|
||||
pd_msg = pd_alloc_msg(tcpc);
|
||||
if (pd_msg == NULL) {
|
||||
tcpci_alert_status_clear(tcpc, TCPC_REG_ALERT_RX_MASK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
retval = tcpci_get_message(tcpc,
|
||||
pd_msg->payload, &pd_msg->msg_hdr, &type);
|
||||
if (retval < 0) {
|
||||
TCPC_INFO("recv_msg failed: %d\n", retval);
|
||||
pd_free_msg(tcpc, pd_msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
pd_msg->frame_type = (uint8_t) type;
|
||||
pd_put_pd_msg_event(tcpc, pd_msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcpci_alert_rx_overflow(struct tcpc_device *tcpc)
|
||||
{
|
||||
int rv;
|
||||
uint32_t alert_status;
|
||||
|
||||
TCPC_INFO("RX_OVERFLOW\n");
|
||||
|
||||
rv = tcpci_get_alert_status(tcpc, &alert_status);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
if (alert_status & TCPC_REG_ALERT_RX_STATUS)
|
||||
return tcpci_alert_recv_msg(tcpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcpci_alert_recv_hard_reset(struct tcpc_device *tcpc)
|
||||
{
|
||||
TCPC_INFO("HardResetAlert\n");
|
||||
pd_put_recv_hard_reset_event(tcpc);
|
||||
tcpci_init_alert_mask(tcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
static int tcpci_alert_vendor_defined(struct tcpc_device *tcpc)
|
||||
{
|
||||
tcpci_alert_vendor_defined_handler(tcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcpci_alert_fault(struct tcpc_device *tcpc)
|
||||
{
|
||||
uint8_t status = 0;
|
||||
|
||||
tcpci_get_fault_status(tcpc, &status);
|
||||
TCPC_INFO("FaultAlert=0x%x\n", status);
|
||||
tcpci_fault_status_clear(tcpc, status);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tcpci_alert);
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG
|
||||
static int tcpci_alert_wakeup(struct tcpc_device *tcpc)
|
||||
{
|
||||
if (tcpc->tcpc_flags & TCPC_FLAGS_LPM_WAKEUP_WATCHDOG) {
|
||||
TCPC_INFO("Wakeup\n");
|
||||
|
||||
if (tcpc->typec_remote_cc[0] == TYPEC_CC_DRP_TOGGLING)
|
||||
tcpc_enable_wakeup_timer(tcpc, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_RA_DETACH
|
||||
static int tcpci_alert_ra_detach(struct tcpc_device *tcpc)
|
||||
{
|
||||
if (tcpc->tcpc_flags & TCPC_FLAGS_CHECK_RA_DETACHE) {
|
||||
TCPC_DBG("RA_DETACH\n");
|
||||
|
||||
if (tcpc->typec_remote_cc[0] == TYPEC_CC_DRP_TOGGLING)
|
||||
tcpc_typec_enter_lpm_again(tcpc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_TYPEC_CAP_RA_DETACH */
|
||||
|
||||
struct tcpci_alert_handler {
|
||||
uint32_t bit_mask;
|
||||
int (*handler)(struct tcpc_device *tcpc);
|
||||
};
|
||||
|
||||
#define DECL_TCPCI_ALERT_HANDLER(xbit, xhandler) {\
|
||||
.bit_mask = 1 << xbit,\
|
||||
.handler = xhandler, \
|
||||
}
|
||||
|
||||
static const struct tcpci_alert_handler tcpci_alert_handlers[] = {
|
||||
DECL_TCPCI_ALERT_HANDLER(15, tcpci_alert_vendor_defined),
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
DECL_TCPCI_ALERT_HANDLER(4, tcpci_alert_tx_failed),
|
||||
DECL_TCPCI_ALERT_HANDLER(5, tcpci_alert_tx_discard),
|
||||
DECL_TCPCI_ALERT_HANDLER(6, tcpci_alert_tx_success),
|
||||
DECL_TCPCI_ALERT_HANDLER(2, tcpci_alert_recv_msg),
|
||||
DECL_TCPCI_ALERT_HANDLER(7, NULL),
|
||||
DECL_TCPCI_ALERT_HANDLER(8, NULL),
|
||||
DECL_TCPCI_ALERT_HANDLER(3, tcpci_alert_recv_hard_reset),
|
||||
DECL_TCPCI_ALERT_HANDLER(10, tcpci_alert_rx_overflow),
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG
|
||||
DECL_TCPCI_ALERT_HANDLER(16, tcpci_alert_wakeup),
|
||||
#endif /* CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG */
|
||||
|
||||
#ifdef CONFIG_TYPEC_CAP_RA_DETACH
|
||||
DECL_TCPCI_ALERT_HANDLER(21, tcpci_alert_ra_detach),
|
||||
#endif /* CONFIG_TYPEC_CAP_RA_DETACH */
|
||||
|
||||
DECL_TCPCI_ALERT_HANDLER(9, tcpci_alert_fault),
|
||||
DECL_TCPCI_ALERT_HANDLER(0, tcpci_alert_cc_changed),
|
||||
DECL_TCPCI_ALERT_HANDLER(1, tcpci_alert_power_status_changed),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
static inline bool tcpci_check_hard_reset_complete(
|
||||
struct tcpc_device *tcpc, uint32_t alert_status)
|
||||
{
|
||||
if ((alert_status & TCPC_REG_ALERT_HRESET_SUCCESS)
|
||||
== TCPC_REG_ALERT_HRESET_SUCCESS) {
|
||||
pd_put_sent_hard_reset_event(tcpc);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (alert_status & TCPC_REG_ALERT_TX_DISCARDED) {
|
||||
TCPC_INFO("HResetFailed\n");
|
||||
tcpci_transmit(tcpc, TCPC_TX_HARD_RESET, 0, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
int tcpci_alert(struct tcpc_device *tcpc)
|
||||
{
|
||||
int rv, i;
|
||||
uint32_t alert_status;
|
||||
uint32_t alert_mask;
|
||||
|
||||
rv = tcpci_get_alert_status(tcpc, &alert_status);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv = tcpci_get_alert_mask(tcpc, &alert_mask);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
/* mask all alert */
|
||||
rv = tcpci_set_alert_mask(tcpc, 0);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
#ifdef CONFIG_USB_PD_DBG_ALERT_STATUS
|
||||
if (alert_status != 0)
|
||||
TCPC_INFO("Alert:0x%04x, Mask:0x%04x\n",
|
||||
alert_status, alert_mask);
|
||||
#endif /* CONFIG_USB_PD_DBG_ALERT_STATUS */
|
||||
|
||||
alert_status &= alert_mask;
|
||||
|
||||
tcpci_alert_status_clear(tcpc,
|
||||
alert_status & (~TCPC_REG_ALERT_RX_MASK));
|
||||
|
||||
if (tcpc->typec_role == TYPEC_ROLE_UNKNOWN)
|
||||
return 0;
|
||||
|
||||
if ((tcpc->tcpc_flags & TCPC_FLAGS_ALERT_V10) &&
|
||||
(alert_status & TCPC_REG_ALERT_EXT_VBUS_80))
|
||||
alert_status |= TCPC_REG_ALERT_POWER_STATUS;
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
if (tcpc->pd_transmit_state == PD_TX_STATE_WAIT_HARD_RESET) {
|
||||
tcpci_check_hard_reset_complete(tcpc, alert_status);
|
||||
alert_status &= ~TCPC_REG_ALERT_TX_MASK;
|
||||
}
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#ifndef CONFIG_USB_PD_DBG_SKIP_ALERT_HANDLER
|
||||
for (i = 0; i < ARRAY_SIZE(tcpci_alert_handlers); i++) {
|
||||
if (tcpci_alert_handlers[i].bit_mask & alert_status) {
|
||||
if (tcpci_alert_handlers[i].handler != 0)
|
||||
tcpci_alert_handlers[i].handler(tcpc);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DBG_SKIP_ALERT_HANDLER */
|
||||
|
||||
/* unmask alert */
|
||||
rv = tcpci_set_alert_mask(tcpc, alert_mask);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
if (tcpc->tcpc_flags & TCPC_FLAGS_ALERT_V10)
|
||||
return 0;
|
||||
|
||||
tcpci_vbus_level_refresh(tcpc);
|
||||
tcpci_vbus_level_changed(tcpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* [BLOCK] TYPEC device changed
|
||||
*/
|
||||
|
||||
static inline void tcpci_attach_wake_lock(struct tcpc_device *tcpc)
|
||||
{
|
||||
#ifdef CONFIG_TCPC_ATTACH_WAKE_LOCK_TOUT
|
||||
__pm_wakeup_event(tcpc->attach_wake_lock,
|
||||
CONFIG_TCPC_ATTACH_WAKE_LOCK_TOUT);
|
||||
#else
|
||||
__pm_stay_awake(tcpc->attach_wake_lock);
|
||||
#endif /* CONFIG_TCPC_ATTACH_WAKE_LOCK_TOUT */
|
||||
}
|
||||
|
||||
int tcpci_set_wake_lock(
|
||||
struct tcpc_device *tcpc, bool pd_lock, bool user_lock)
|
||||
{
|
||||
bool ori_lock, new_lock;
|
||||
|
||||
if (tcpc->wake_lock_pd && tcpc->wake_lock_user)
|
||||
ori_lock = true;
|
||||
else
|
||||
ori_lock = false;
|
||||
|
||||
if (pd_lock && user_lock)
|
||||
new_lock = true;
|
||||
else
|
||||
new_lock = false;
|
||||
|
||||
if (new_lock != ori_lock) {
|
||||
if (new_lock) {
|
||||
TCPC_DBG("wake_lock=1\n");
|
||||
tcpci_attach_wake_lock(tcpc);
|
||||
if (tcpc->typec_watchdog)
|
||||
tcpci_set_intrst(tcpc, true);
|
||||
} else {
|
||||
TCPC_DBG("wake_lock=0\n");
|
||||
if (tcpc->typec_watchdog)
|
||||
tcpci_set_intrst(tcpc, false);
|
||||
__pm_relax(tcpc->attach_wake_lock);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tcpci_set_wake_lock_pd(
|
||||
struct tcpc_device *tcpc, bool pd_lock)
|
||||
{
|
||||
uint8_t wake_lock_pd;
|
||||
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
|
||||
wake_lock_pd = tcpc->wake_lock_pd;
|
||||
|
||||
if (pd_lock)
|
||||
wake_lock_pd++;
|
||||
else if (wake_lock_pd > 0)
|
||||
wake_lock_pd--;
|
||||
|
||||
if (wake_lock_pd == 0)
|
||||
__pm_wakeup_event(tcpc->detach_wake_lock, 5000);
|
||||
|
||||
tcpci_set_wake_lock(tcpc, wake_lock_pd, tcpc->wake_lock_user);
|
||||
|
||||
if (wake_lock_pd == 1)
|
||||
__pm_relax(tcpc->detach_wake_lock);
|
||||
|
||||
tcpc->wake_lock_pd = wake_lock_pd;
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tcpci_report_usb_port_attached(struct tcpc_device *tcpc)
|
||||
{
|
||||
TCPC_INFO("usb_port_attached\n");
|
||||
|
||||
#ifdef CONFIG_DUAL_ROLE_USB_INTF
|
||||
switch (tcpc->typec_attach_new) {
|
||||
case TYPEC_ATTACHED_SNK:
|
||||
case TYPEC_ATTACHED_CUSTOM_SRC:
|
||||
case TYPEC_ATTACHED_NORP_SRC:
|
||||
tcpc->dual_role_pr = DUAL_ROLE_PROP_PR_SNK;
|
||||
tcpc->dual_role_dr = DUAL_ROLE_PROP_DR_DEVICE;
|
||||
tcpc->dual_role_mode = DUAL_ROLE_PROP_MODE_UFP;
|
||||
tcpc->dual_role_vconn = DUAL_ROLE_PROP_VCONN_SUPPLY_NO;
|
||||
break;
|
||||
case TYPEC_ATTACHED_SRC:
|
||||
tcpc->dual_role_pr = DUAL_ROLE_PROP_PR_SRC;
|
||||
tcpc->dual_role_dr = DUAL_ROLE_PROP_DR_HOST;
|
||||
tcpc->dual_role_mode = DUAL_ROLE_PROP_MODE_DFP;
|
||||
tcpc->dual_role_vconn = DUAL_ROLE_PROP_VCONN_SUPPLY_YES;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
dual_role_instance_changed(tcpc->dr_usb);
|
||||
#endif /* CONFIG_DUAL_ROLE_USB_INTF */
|
||||
|
||||
tcpci_set_wake_lock_pd(tcpc, true);
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
|
||||
#ifdef CONFIG_USB_PD_DISABLE_PE
|
||||
if (tcpc->disable_pe)
|
||||
return 0;
|
||||
#endif /* CONFIG_USB_PD_DISABLE_PE */
|
||||
|
||||
if (tcpc->pd_inited_flag)
|
||||
pd_put_cc_attached_event(tcpc, tcpc->typec_attach_new);
|
||||
#endif /* CONFIG_USB_POWER_DLEIVERY */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tcpci_report_usb_port_detached(struct tcpc_device *tcpc)
|
||||
{
|
||||
TCPC_INFO("usb_port_detached\n");
|
||||
|
||||
#ifdef CONFIG_DUAL_ROLE_USB_INTF
|
||||
tcpc->dual_role_pr = DUAL_ROLE_PROP_PR_NONE;
|
||||
tcpc->dual_role_dr = DUAL_ROLE_PROP_DR_NONE;
|
||||
tcpc->dual_role_mode = DUAL_ROLE_PROP_MODE_NONE;
|
||||
tcpc->dual_role_vconn = DUAL_ROLE_PROP_VCONN_SUPPLY_NO;
|
||||
dual_role_instance_changed(tcpc->dr_usb);
|
||||
#endif /* CONFIG_DUAL_ROLE_USB_INTF */
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
if (tcpc->pd_inited_flag)
|
||||
pd_put_cc_detached_event(tcpc);
|
||||
else {
|
||||
pd_event_buf_reset(tcpc);
|
||||
tcpc_enable_timer(tcpc, TYPEC_RT_TIMER_PE_IDLE);
|
||||
}
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
tcpci_set_wake_lock_pd(tcpc, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_report_usb_port_changed(struct tcpc_device *tcpc)
|
||||
{
|
||||
tcpci_notify_typec_state(tcpc);
|
||||
|
||||
if (tcpc->typec_attach_old == TYPEC_UNATTACHED)
|
||||
tcpci_report_usb_port_attached(tcpc);
|
||||
else if (tcpc->typec_attach_new == TYPEC_UNATTACHED)
|
||||
tcpci_report_usb_port_detached(tcpc);
|
||||
else
|
||||
TCPC_DBG2("TCPC Attach Again\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tcpci_report_usb_port_changed);
|
||||
|
||||
/*
|
||||
* [BLOCK] TYPEC power control changed
|
||||
*/
|
||||
|
||||
static inline int tcpci_report_power_control_on(struct tcpc_device *tcpc)
|
||||
{
|
||||
tcpci_set_wake_lock_pd(tcpc, true);
|
||||
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
tcpc_disable_timer(tcpc, TYPEC_RT_TIMER_DISCHARGE);
|
||||
tcpci_enable_auto_discharge(tcpc, true);
|
||||
tcpci_enable_force_discharge(tcpc, false, 0);
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tcpci_report_power_control_off(struct tcpc_device *tcpc)
|
||||
{
|
||||
mutex_lock(&tcpc->access_lock);
|
||||
tcpci_enable_force_discharge(tcpc, true, 0);
|
||||
tcpc_enable_timer(tcpc, TYPEC_RT_TIMER_DISCHARGE);
|
||||
mutex_unlock(&tcpc->access_lock);
|
||||
|
||||
tcpci_set_wake_lock_pd(tcpc, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcpci_report_power_control(struct tcpc_device *tcpc, bool en)
|
||||
{
|
||||
if (tcpc->typec_power_ctrl == en)
|
||||
return 0;
|
||||
|
||||
tcpc->typec_power_ctrl = en;
|
||||
|
||||
if (en)
|
||||
tcpci_report_power_control_on(tcpc);
|
||||
else
|
||||
tcpci_report_power_control_off(tcpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
980
drivers/usb/typec/mmi_tcpc/tcpci_core.c
Normal file
980
drivers/usb/typec/mmi_tcpc/tcpci_core.c
Normal file
|
|
@ -0,0 +1,980 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* Richtek TypeC Port Control Interface Core Driver
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/tcpci_typec.h"
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
#include "pd_dpm_prv.h"
|
||||
#include "inc/tcpm.h"
|
||||
#ifdef CONFIG_RECV_BAT_ABSENT_NOTIFY
|
||||
#include "mtk_battery.h"
|
||||
#endif /* CONFIG_RECV_BAT_ABSENT_NOTIFY */
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
#include "inc/pd_dbg_info.h"
|
||||
#include "inc/rt-regmap.h"
|
||||
|
||||
#define TCPC_CORE_VERSION "2.0.14_G"
|
||||
|
||||
static ssize_t tcpc_show_property(struct device *dev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
static ssize_t tcpc_store_property(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
|
||||
#define TCPC_DEVICE_ATTR(_name, _mode) \
|
||||
{ \
|
||||
.attr = { .name = #_name, .mode = _mode }, \
|
||||
.show = tcpc_show_property, \
|
||||
.store = tcpc_store_property, \
|
||||
}
|
||||
|
||||
struct class *tcpc_class;
|
||||
EXPORT_SYMBOL_GPL(tcpc_class);
|
||||
|
||||
static struct device_type tcpc_dev_type;
|
||||
|
||||
static struct device_attribute tcpc_device_attributes[] = {
|
||||
TCPC_DEVICE_ATTR(role_def, 0444),
|
||||
TCPC_DEVICE_ATTR(rp_lvl, 0444),
|
||||
TCPC_DEVICE_ATTR(pd_test, 0664),
|
||||
TCPC_DEVICE_ATTR(info, 0444),
|
||||
TCPC_DEVICE_ATTR(timer, 0664),
|
||||
TCPC_DEVICE_ATTR(caps_info, 0444),
|
||||
TCPC_DEVICE_ATTR(pe_ready, 0444),
|
||||
};
|
||||
|
||||
enum {
|
||||
TCPC_DESC_ROLE_DEF = 0,
|
||||
TCPC_DESC_RP_LEVEL,
|
||||
TCPC_DESC_PD_TEST,
|
||||
TCPC_DESC_INFO,
|
||||
TCPC_DESC_TIMER,
|
||||
TCPC_DESC_CAP_INFO,
|
||||
TCPC_DESC_PE_READY,
|
||||
};
|
||||
|
||||
static struct attribute *__tcpc_attrs[ARRAY_SIZE(tcpc_device_attributes) + 1];
|
||||
static struct attribute_group tcpc_attr_group = {
|
||||
.attrs = __tcpc_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *tcpc_attr_groups[] = {
|
||||
&tcpc_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const role_text[] = {
|
||||
"SNK Only",
|
||||
"SRC Only",
|
||||
"DRP",
|
||||
"Try.SRC",
|
||||
"Try.SNK",
|
||||
};
|
||||
|
||||
static ssize_t tcpc_show_property(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tcpc_device *tcpc = to_tcpc_device(dev);
|
||||
const ptrdiff_t offset = attr - tcpc_device_attributes;
|
||||
int i = 0;
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
struct pe_data *pe_data;
|
||||
struct pd_port *pd_port;
|
||||
struct tcpm_power_cap_val cap;
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
switch (offset) {
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
case TCPC_DESC_CAP_INFO:
|
||||
pd_port = &tcpc->pd_port;
|
||||
pe_data = &pd_port->pe_data;
|
||||
snprintf(buf+strlen(buf), 256, "%s = %d\n%s = %d\n",
|
||||
"local_selected_cap",
|
||||
pe_data->local_selected_cap,
|
||||
"remote_selected_cap",
|
||||
pe_data->remote_selected_cap);
|
||||
|
||||
snprintf(buf+strlen(buf), 256, "%s\n",
|
||||
"local_src_cap(type, vmin, vmax, oper)");
|
||||
for (i = 0; i < pd_port->local_src_cap.nr; i++) {
|
||||
tcpm_extract_power_cap_val(
|
||||
pd_port->local_src_cap.pdos[i],
|
||||
&cap);
|
||||
snprintf(buf+strlen(buf), 256, "%d %d %d %d\n",
|
||||
cap.type, cap.min_mv, cap.max_mv, cap.ma);
|
||||
}
|
||||
snprintf(buf+strlen(buf), 256, "%s\n",
|
||||
"local_snk_cap(type, vmin, vmax, ioper)");
|
||||
for (i = 0; i < pd_port->local_snk_cap.nr; i++) {
|
||||
tcpm_extract_power_cap_val(
|
||||
pd_port->local_snk_cap.pdos[i],
|
||||
&cap);
|
||||
snprintf(buf+strlen(buf), 256, "%d %d %d %d\n",
|
||||
cap.type, cap.min_mv, cap.max_mv, cap.ma);
|
||||
}
|
||||
snprintf(buf+strlen(buf), 256, "%s\n",
|
||||
"remote_src_cap(type, vmin, vmax, ioper)");
|
||||
for (i = 0; i < pe_data->remote_src_cap.nr; i++) {
|
||||
tcpm_extract_power_cap_val(
|
||||
pe_data->remote_src_cap.pdos[i],
|
||||
&cap);
|
||||
snprintf(buf+strlen(buf), 256, "%d %d %d %d\n",
|
||||
cap.type, cap.min_mv, cap.max_mv, cap.ma);
|
||||
}
|
||||
snprintf(buf+strlen(buf), 256, "%s\n",
|
||||
"remote_snk_cap(type, vmin, vmax, ioper)");
|
||||
for (i = 0; i < pe_data->remote_snk_cap.nr; i++) {
|
||||
tcpm_extract_power_cap_val(
|
||||
pe_data->remote_snk_cap.pdos[i],
|
||||
&cap);
|
||||
snprintf(buf+strlen(buf), 256, "%d %d %d %d\n",
|
||||
cap.type, cap.min_mv, cap.max_mv, cap.ma);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
case TCPC_DESC_ROLE_DEF:
|
||||
snprintf(buf, 256, "%s\n", role_text[tcpc->desc.role_def]);
|
||||
break;
|
||||
case TCPC_DESC_RP_LEVEL:
|
||||
if (tcpc->typec_local_rp_level == TYPEC_CC_RP_DFT)
|
||||
snprintf(buf, 256, "%s\n", "Default");
|
||||
else if (tcpc->typec_local_rp_level == TYPEC_CC_RP_1_5)
|
||||
snprintf(buf, 256, "%s\n", "1.5");
|
||||
else if (tcpc->typec_local_rp_level == TYPEC_CC_RP_3_0)
|
||||
snprintf(buf, 256, "%s\n", "3.0");
|
||||
break;
|
||||
case TCPC_DESC_PD_TEST:
|
||||
snprintf(buf, 256, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
|
||||
"1: pr_swap", "2: dr_swap", "3: vconn_swap",
|
||||
"4: soft reset", "5: hard reset",
|
||||
"6: get_src_cap", "7: get_sink_cap",
|
||||
"8: discover_id", "9: discover_cable");
|
||||
break;
|
||||
case TCPC_DESC_INFO:
|
||||
i += snprintf(buf + i,
|
||||
256, "|^|==( %s info )==|^|\n", tcpc->desc.name);
|
||||
i += snprintf(buf + i,
|
||||
256, "role = %s\n", role_text[tcpc->desc.role_def]);
|
||||
if (tcpc->typec_local_rp_level == TYPEC_CC_RP_DFT)
|
||||
i += snprintf(buf + i, 256, "rplvl = %s\n", "Default");
|
||||
else if (tcpc->typec_local_rp_level == TYPEC_CC_RP_1_5)
|
||||
i += snprintf(buf + i, 256, "rplvl = %s\n", "1.5");
|
||||
else if (tcpc->typec_local_rp_level == TYPEC_CC_RP_3_0)
|
||||
i += snprintf(buf + i, 256, "rplvl = %s\n", "3.0");
|
||||
break;
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
case TCPC_DESC_PE_READY:
|
||||
pd_port = &tcpc->pd_port;
|
||||
if (pd_port->pe_data.pe_ready)
|
||||
snprintf(buf, 256, "%s\n", "yes");
|
||||
else
|
||||
snprintf(buf, 256, "%s\n", "no");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
static int get_parameters(char *buf, long int *param1, int num_of_par)
|
||||
{
|
||||
char *token;
|
||||
int base, cnt;
|
||||
|
||||
token = strsep(&buf, " ");
|
||||
|
||||
for (cnt = 0; cnt < num_of_par; cnt++) {
|
||||
if (token != NULL) {
|
||||
if ((token[1] == 'x') || (token[1] == 'X'))
|
||||
base = 16;
|
||||
else
|
||||
base = 10;
|
||||
|
||||
if (kstrtoul(token, base, ¶m1[cnt]) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
token = strsep(&buf, " ");
|
||||
}
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t tcpc_store_property(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
uint8_t role;
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
struct tcpc_device *tcpc = to_tcpc_device(dev);
|
||||
const ptrdiff_t offset = attr - tcpc_device_attributes;
|
||||
int ret;
|
||||
long int val;
|
||||
|
||||
switch (offset) {
|
||||
case TCPC_DESC_ROLE_DEF:
|
||||
ret = get_parameters((char *)buf, &val, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "get parameters fail\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tcpm_typec_change_role(tcpc, val);
|
||||
break;
|
||||
case TCPC_DESC_TIMER:
|
||||
ret = get_parameters((char *)buf, &val, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "get parameters fail\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
if (val > 0 && val <= PD_PE_TIMER_END_ID)
|
||||
pd_enable_timer(&tcpc->pd_port, val);
|
||||
else if (val > PD_PE_TIMER_END_ID && val < PD_TIMER_NR)
|
||||
tcpc_enable_timer(tcpc, val);
|
||||
#else
|
||||
if (val > 0 && val < PD_TIMER_NR)
|
||||
tcpc_enable_timer(tcpc, val);
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
break;
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
case TCPC_DESC_PD_TEST:
|
||||
ret = get_parameters((char *)buf, &val, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "get parameters fail\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (val) {
|
||||
case 1: /* Power Role Swap */
|
||||
role = tcpm_inquire_pd_power_role(tcpc);
|
||||
if (role == PD_ROLE_SINK)
|
||||
role = PD_ROLE_SOURCE;
|
||||
else
|
||||
role = PD_ROLE_SINK;
|
||||
tcpm_dpm_pd_power_swap(tcpc, role, NULL);
|
||||
break;
|
||||
case 2: /* Data Role Swap */
|
||||
role = tcpm_inquire_pd_data_role(tcpc);
|
||||
if (role == PD_ROLE_UFP)
|
||||
role = PD_ROLE_DFP;
|
||||
else
|
||||
role = PD_ROLE_UFP;
|
||||
tcpm_dpm_pd_data_swap(tcpc, role, NULL);
|
||||
break;
|
||||
case 3: /* Vconn Swap */
|
||||
role = tcpm_inquire_pd_vconn_role(tcpc);
|
||||
if (role == PD_ROLE_VCONN_OFF)
|
||||
role = PD_ROLE_VCONN_ON;
|
||||
else
|
||||
role = PD_ROLE_VCONN_OFF;
|
||||
tcpm_dpm_pd_vconn_swap(tcpc, role, NULL);
|
||||
break;
|
||||
case 4: /* Software Reset */
|
||||
tcpm_dpm_pd_soft_reset(tcpc, NULL);
|
||||
break;
|
||||
case 5: /* Hardware Reset */
|
||||
tcpm_dpm_pd_hard_reset(tcpc, NULL);
|
||||
break;
|
||||
case 6:
|
||||
tcpm_dpm_pd_get_source_cap(tcpc, NULL);
|
||||
break;
|
||||
case 7:
|
||||
tcpm_dpm_pd_get_sink_cap(tcpc, NULL);
|
||||
break;
|
||||
case 8:
|
||||
tcpm_dpm_vdm_discover_id(tcpc, NULL);
|
||||
break;
|
||||
case 9:
|
||||
tcpm_dpm_vdm_discover_cable(tcpc, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int tcpc_match_device_by_name(struct device *dev, const void *data)
|
||||
{
|
||||
const char *name = data;
|
||||
struct tcpc_device *tcpc = dev_get_drvdata(dev);
|
||||
|
||||
return strcmp(tcpc->desc.name, name) == 0;
|
||||
}
|
||||
|
||||
struct tcpc_device *tcpc_dev_get_by_name(const char *name)
|
||||
{
|
||||
struct device *dev = class_find_device(tcpc_class,
|
||||
NULL, (const void *)name, tcpc_match_device_by_name);
|
||||
return dev ? dev_get_drvdata(dev) : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(tcpc_dev_get_by_name);
|
||||
|
||||
static void tcpc_device_release(struct device *dev)
|
||||
{
|
||||
struct tcpc_device *tcpc = to_tcpc_device(dev);
|
||||
|
||||
pr_info("%s : %s device release\n", __func__, dev_name(dev));
|
||||
PD_BUG_ON(tcpc == NULL);
|
||||
/* Un-init pe thread */
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
tcpci_event_deinit(tcpc);
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
/* Un-init timer thread */
|
||||
tcpci_timer_deinit(tcpc);
|
||||
/* Un-init Mutex */
|
||||
/* Do initialization */
|
||||
}
|
||||
|
||||
static void tcpc_init_work(struct work_struct *work);
|
||||
static void tcpc_event_init_work(struct work_struct *work);
|
||||
|
||||
struct tcpc_device *tcpc_device_register(struct device *parent,
|
||||
struct tcpc_desc *tcpc_desc, struct tcpc_ops *ops, void *drv_data)
|
||||
{
|
||||
struct tcpc_device *tcpc;
|
||||
int ret = 0, i = 0;
|
||||
|
||||
pr_info("%s register tcpc device (%s)\n", __func__, tcpc_desc->name);
|
||||
tcpc = devm_kzalloc(parent, sizeof(*tcpc), GFP_KERNEL);
|
||||
if (!tcpc) {
|
||||
pr_err("%s : allocate tcpc memeory failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tcpc->evt_wq = alloc_ordered_workqueue("%s", 0, tcpc_desc->name);
|
||||
for (i = 0; i < TCP_NOTIFY_IDX_NR; i++)
|
||||
srcu_init_notifier_head(&tcpc->evt_nh[i]);
|
||||
|
||||
mutex_init(&tcpc->access_lock);
|
||||
mutex_init(&tcpc->typec_lock);
|
||||
mutex_init(&tcpc->timer_lock);
|
||||
mutex_init(&tcpc->mr_lock);
|
||||
sema_init(&tcpc->timer_enable_mask_lock, 1);
|
||||
spin_lock_init(&tcpc->timer_tick_lock);
|
||||
|
||||
tcpc->dev.class = tcpc_class;
|
||||
tcpc->dev.type = &tcpc_dev_type;
|
||||
tcpc->dev.parent = parent;
|
||||
tcpc->dev.release = tcpc_device_release;
|
||||
dev_set_drvdata(&tcpc->dev, tcpc);
|
||||
tcpc->drv_data = drv_data;
|
||||
dev_set_name(&tcpc->dev, "%s", tcpc_desc->name);
|
||||
tcpc->desc = *tcpc_desc;
|
||||
tcpc->ops = ops;
|
||||
tcpc->typec_local_rp_level = tcpc_desc->rp_lvl;
|
||||
|
||||
#ifdef CONFIG_TCPC_VCONN_SUPPLY_MODE
|
||||
tcpc->tcpc_vconn_supply = tcpc_desc->vconn_supply;
|
||||
#endif /* CONFIG_TCPC_VCONN_SUPPLY_MODE */
|
||||
|
||||
device_set_of_node_from_dev(&tcpc->dev, parent);
|
||||
|
||||
ret = device_register(&tcpc->dev);
|
||||
if (ret) {
|
||||
kfree(tcpc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&tcpc->init_work, tcpc_init_work);
|
||||
INIT_DELAYED_WORK(&tcpc->event_init_work, tcpc_event_init_work);
|
||||
|
||||
/* If system support "WAKE_LOCK_IDLE",
|
||||
* please use it instead of "WAKE_LOCK_SUSPEND"
|
||||
*/
|
||||
tcpc->attach_wake_lock =
|
||||
wakeup_source_register(&tcpc->dev, "tcpc_attach_wake_lock");
|
||||
tcpc->detach_wake_lock =
|
||||
wakeup_source_register(&tcpc->dev, "tcpc_detach_wake_lock");
|
||||
|
||||
tcpci_timer_init(tcpc);
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
pd_core_init(tcpc);
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
#ifdef CONFIG_DUAL_ROLE_USB_INTF
|
||||
ret = tcpc_dual_role_phy_init(tcpc);
|
||||
if (ret < 0)
|
||||
dev_err(&tcpc->dev, "dual role usb init fail\n");
|
||||
#endif /* CONFIG_DUAL_ROLE_USB_INTF */
|
||||
|
||||
return tcpc;
|
||||
}
|
||||
EXPORT_SYMBOL(tcpc_device_register);
|
||||
|
||||
int tcpc_device_irq_enable(struct tcpc_device *tcpc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!tcpc->ops->init) {
|
||||
pr_notice("%s Please implment tcpc ops init function\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tcpci_lock_typec(tcpc);
|
||||
ret = tcpci_init(tcpc, false);
|
||||
if (ret < 0) {
|
||||
tcpci_unlock_typec(tcpc);
|
||||
pr_err("%s tcpc init fail\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tcpc_typec_init(tcpc, tcpc->desc.role_def + 1);
|
||||
tcpci_unlock_typec(tcpc);
|
||||
if (ret < 0) {
|
||||
pr_err("%s : tcpc typec init fail\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
schedule_delayed_work(
|
||||
&tcpc->event_init_work, msecs_to_jiffies(10*1000));
|
||||
|
||||
pr_info("%s : tcpc irq enable OK!\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tcpc_device_irq_enable);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
static void bat_update_work_func(struct work_struct *work)
|
||||
{
|
||||
struct tcpc_device *tcpc = container_of(work,
|
||||
struct tcpc_device, bat_update_work.work);
|
||||
union power_supply_propval value;
|
||||
int ret;
|
||||
|
||||
ret = power_supply_get_property(
|
||||
tcpc->bat_psy, POWER_SUPPLY_PROP_CAPACITY, &value);
|
||||
if (ret == 0) {
|
||||
TCPC_INFO("%s battery update soc = %d\n",
|
||||
__func__, value.intval);
|
||||
tcpc->bat_soc = value.intval;
|
||||
} else
|
||||
TCPC_ERR("%s get battery capacity fail\n", __func__);
|
||||
|
||||
ret = power_supply_get_property(tcpc->bat_psy,
|
||||
POWER_SUPPLY_PROP_STATUS, &value);
|
||||
if (ret == 0) {
|
||||
if (value.intval == POWER_SUPPLY_STATUS_CHARGING) {
|
||||
TCPC_INFO("%s Battery Charging\n", __func__);
|
||||
tcpc->charging_status = BSDO_BAT_INFO_CHARGING;
|
||||
} else if (value.intval == POWER_SUPPLY_STATUS_DISCHARGING) {
|
||||
TCPC_INFO("%s Battery Discharging\n", __func__);
|
||||
tcpc->charging_status = BSDO_BAT_INFO_DISCHARGING;
|
||||
} else {
|
||||
TCPC_INFO("%s Battery Idle\n", __func__);
|
||||
tcpc->charging_status = BSDO_BAT_INFO_IDLE;
|
||||
}
|
||||
}
|
||||
if (ret < 0)
|
||||
TCPC_ERR("%s get battery charger now fail\n", __func__);
|
||||
|
||||
tcpm_update_bat_status_soc(tcpc,
|
||||
PD_BAT_REF_FIXED0, tcpc->charging_status, tcpc->bat_soc * 10);
|
||||
}
|
||||
|
||||
static int bat_nb_call_func(
|
||||
struct notifier_block *nb, unsigned long val, void *v)
|
||||
{
|
||||
struct tcpc_device *tcpc = container_of(nb, struct tcpc_device, bat_nb);
|
||||
struct power_supply *psy = (struct power_supply *)v;
|
||||
|
||||
if (!tcpc) {
|
||||
TCPC_ERR("%s tcpc is null\n", __func__);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
if (val == PSY_EVENT_PROP_CHANGED &&
|
||||
strcmp(psy->desc->name, "battery") == 0)
|
||||
schedule_delayed_work(&tcpc->bat_update_work, 0);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
static void tcpc_event_init_work(struct work_struct *work)
|
||||
{
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
struct tcpc_device *tcpc = container_of(
|
||||
work, struct tcpc_device, event_init_work.work);
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
int retval;
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
tcpci_lock_typec(tcpc);
|
||||
tcpci_event_init(tcpc);
|
||||
#ifdef CONFIG_USB_PD_WAIT_BC12
|
||||
tcpc->usb_psy = power_supply_get_by_name("usb");
|
||||
if (!tcpc->usb_psy) {
|
||||
tcpci_unlock_typec(tcpc);
|
||||
TCPC_ERR("%s get usb psy fail\n", __func__);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_WAIT_BC12 */
|
||||
tcpc->pd_inited_flag = 1;
|
||||
pr_info("%s typec attach new = %d\n",
|
||||
__func__, tcpc->typec_attach_new);
|
||||
if (tcpc->typec_attach_new)
|
||||
pd_put_cc_attached_event(tcpc, tcpc->typec_attach_new);
|
||||
tcpci_unlock_typec(tcpc);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
INIT_DELAYED_WORK(&tcpc->bat_update_work, bat_update_work_func);
|
||||
tcpc->bat_psy = power_supply_get_by_name("battery");
|
||||
if (!tcpc->bat_psy) {
|
||||
TCPC_ERR("%s get battery psy fail\n", __func__);
|
||||
return;
|
||||
}
|
||||
tcpc->charging_status = BSDO_BAT_INFO_IDLE;
|
||||
tcpc->bat_soc = 0;
|
||||
tcpc->bat_nb.notifier_call = bat_nb_call_func;
|
||||
tcpc->bat_nb.priority = 0;
|
||||
retval = power_supply_reg_notifier(&tcpc->bat_nb);
|
||||
if (retval < 0)
|
||||
pr_err("%s register power supply notifier fail\n", __func__);
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
}
|
||||
|
||||
static void tcpc_init_work(struct work_struct *work)
|
||||
{
|
||||
struct tcpc_device *tcpc = container_of(
|
||||
work, struct tcpc_device, init_work.work);
|
||||
|
||||
#ifndef CONFIG_TCPC_NOTIFIER_LATE_SYNC
|
||||
if (tcpc->desc.notifier_supply_num == 0)
|
||||
return;
|
||||
#endif
|
||||
pr_info("%s force start\n", __func__);
|
||||
|
||||
tcpc->desc.notifier_supply_num = 0;
|
||||
tcpc_device_irq_enable(tcpc);
|
||||
}
|
||||
|
||||
int tcpc_schedule_init_work(struct tcpc_device *tcpc)
|
||||
{
|
||||
#ifndef CONFIG_TCPC_NOTIFIER_LATE_SYNC
|
||||
if (tcpc->desc.notifier_supply_num == 0)
|
||||
return tcpc_device_irq_enable(tcpc);
|
||||
|
||||
pr_info("%s wait %d num\n", __func__, tcpc->desc.notifier_supply_num);
|
||||
|
||||
schedule_delayed_work(
|
||||
&tcpc->init_work, msecs_to_jiffies(30*1000));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tcpc_schedule_init_work);
|
||||
|
||||
struct tcp_notifier_block_wrapper {
|
||||
struct notifier_block stub_nb;
|
||||
struct notifier_block *action_nb;
|
||||
};
|
||||
|
||||
static int tcp_notifier_func_stub(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct tcp_notifier_block_wrapper *nb_wrapper =
|
||||
container_of(nb, struct tcp_notifier_block_wrapper, stub_nb);
|
||||
struct notifier_block *action_nb = nb_wrapper->action_nb;
|
||||
|
||||
return nb_wrapper->action_nb->notifier_call(action_nb, action, data);
|
||||
}
|
||||
|
||||
struct tcpc_managed_res {
|
||||
void *res;
|
||||
void *key;
|
||||
int prv_id;
|
||||
struct tcpc_managed_res *next;
|
||||
};
|
||||
|
||||
|
||||
static int __add_wrapper_to_managed_res_list(struct tcpc_device *tcp_dev,
|
||||
void *res, void *key, int prv_id)
|
||||
{
|
||||
struct tcpc_managed_res *tail;
|
||||
struct tcpc_managed_res *mres;
|
||||
|
||||
mres = devm_kzalloc(&tcp_dev->dev, sizeof(*mres), GFP_KERNEL);
|
||||
if (!mres)
|
||||
return -ENOMEM;
|
||||
mres->res = res;
|
||||
mres->key = key;
|
||||
mres->prv_id = prv_id;
|
||||
mutex_lock(&tcp_dev->mr_lock);
|
||||
tail = tcp_dev->mr_head;
|
||||
if (tail) {
|
||||
while (tail->next)
|
||||
tail = tail->next;
|
||||
tail->next = mres;
|
||||
} else
|
||||
tcp_dev->mr_head = mres;
|
||||
mutex_unlock(&tcp_dev->mr_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __register_tcp_dev_notifier(struct tcpc_device *tcp_dev,
|
||||
struct notifier_block *nb, uint8_t idx)
|
||||
{
|
||||
struct tcp_notifier_block_wrapper *nb_wrapper;
|
||||
int retval;
|
||||
|
||||
nb_wrapper = devm_kzalloc(
|
||||
&tcp_dev->dev, sizeof(*nb_wrapper), GFP_KERNEL);
|
||||
if (!nb_wrapper)
|
||||
return -ENOMEM;
|
||||
nb_wrapper->action_nb = nb;
|
||||
nb_wrapper->stub_nb.notifier_call = tcp_notifier_func_stub;
|
||||
retval = srcu_notifier_chain_register(
|
||||
tcp_dev->evt_nh + idx, &nb_wrapper->stub_nb);
|
||||
if (retval < 0) {
|
||||
devm_kfree(&tcp_dev->dev, nb_wrapper);
|
||||
return retval;
|
||||
}
|
||||
retval = __add_wrapper_to_managed_res_list(
|
||||
tcp_dev, nb_wrapper, nb, idx);
|
||||
if (retval < 0)
|
||||
dev_warn(&tcp_dev->dev,
|
||||
"Failed to add resource to manager(%d)\n", retval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool __is_mulit_bits_set(uint32_t flags)
|
||||
{
|
||||
if (flags) {
|
||||
flags &= (flags - 1);
|
||||
return flags ? true : false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int register_tcp_dev_notifier(struct tcpc_device *tcp_dev,
|
||||
struct notifier_block *nb, uint8_t flags)
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
|
||||
if (__is_mulit_bits_set(flags)) {
|
||||
for (i = 0; i < TCP_NOTIFY_IDX_NR; i++) {
|
||||
if (flags & (1 << i)) {
|
||||
ret = __register_tcp_dev_notifier(
|
||||
tcp_dev, nb, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else { /* single bit */
|
||||
for (i = 0; i < TCP_NOTIFY_IDX_NR; i++) {
|
||||
if (flags & (1 << i)) {
|
||||
ret = srcu_notifier_chain_register(
|
||||
&tcp_dev->evt_nh[i], nb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_TCPC_NOTIFIER_LATE_SYNC
|
||||
if (tcp_dev->desc.notifier_supply_num == 0) {
|
||||
pr_info("%s already started\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tcp_dev->desc.notifier_supply_num--;
|
||||
pr_info("%s supply_num = %d\n", __func__,
|
||||
tcp_dev->desc.notifier_supply_num);
|
||||
|
||||
if (tcp_dev->desc.notifier_supply_num == 0) {
|
||||
cancel_delayed_work(&tcp_dev->init_work);
|
||||
tcpc_device_irq_enable(tcp_dev);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(register_tcp_dev_notifier);
|
||||
|
||||
|
||||
static void *__remove_wrapper_from_managed_res_list(
|
||||
struct tcpc_device *tcp_dev, void *key, int prv_id)
|
||||
{
|
||||
void *retval = NULL;
|
||||
struct tcpc_managed_res *mres = tcp_dev->mr_head;
|
||||
struct tcpc_managed_res *prev = NULL;
|
||||
|
||||
mutex_lock(&tcp_dev->mr_lock);
|
||||
if (mres) {
|
||||
while (mres) {
|
||||
if (mres->key == key && mres->prv_id == prv_id) {
|
||||
retval = mres->res;
|
||||
if (prev)
|
||||
prev->next = mres->next;
|
||||
else
|
||||
tcp_dev->mr_head = NULL;
|
||||
devm_kfree(&tcp_dev->dev, mres);
|
||||
break;
|
||||
}
|
||||
prev = mres;
|
||||
mres = mres->next;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&tcp_dev->mr_lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int __unregister_tcp_dev_notifier(struct tcpc_device *tcp_dev,
|
||||
struct notifier_block *nb, uint8_t idx)
|
||||
{
|
||||
struct tcp_notifier_block_wrapper *nb_wrapper;
|
||||
int retval;
|
||||
|
||||
nb_wrapper = __remove_wrapper_from_managed_res_list(tcp_dev, nb, idx);
|
||||
if (nb_wrapper) {
|
||||
retval = srcu_notifier_chain_unregister(
|
||||
tcp_dev->evt_nh + idx, &nb_wrapper->stub_nb);
|
||||
devm_kfree(&tcp_dev->dev, nb_wrapper);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int unregister_tcp_dev_notifier(struct tcpc_device *tcp_dev,
|
||||
struct notifier_block *nb, uint8_t flags)
|
||||
{
|
||||
int i = 0, ret = 0;
|
||||
|
||||
for (i = 0; i < TCP_NOTIFY_IDX_NR; i++) {
|
||||
if (flags & (1 << i)) {
|
||||
ret = __unregister_tcp_dev_notifier(tcp_dev, nb, i);
|
||||
if (ret == -ENOENT)
|
||||
ret = srcu_notifier_chain_unregister(
|
||||
tcp_dev->evt_nh + i, nb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_tcp_dev_notifier);
|
||||
|
||||
|
||||
void tcpc_device_unregister(struct device *dev, struct tcpc_device *tcpc)
|
||||
{
|
||||
if (!tcpc)
|
||||
return;
|
||||
|
||||
tcpc_typec_deinit(tcpc);
|
||||
|
||||
#ifdef CONFIG_USB_PD_REV30
|
||||
wakeup_source_unregister(tcpc->pd_port.pps_request_wake_lock);
|
||||
#endif /* CONFIG_USB_PD_REV30 */
|
||||
wakeup_source_unregister(tcpc->detach_wake_lock);
|
||||
wakeup_source_unregister(tcpc->attach_wake_lock);
|
||||
|
||||
#ifdef CONFIG_DUAL_ROLE_USB_INTF
|
||||
devm_dual_role_instance_unregister(&tcpc->dev, tcpc->dr_usb);
|
||||
#endif /* CONFIG_DUAL_ROLE_USB_INTF */
|
||||
|
||||
device_unregister(&tcpc->dev);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(tcpc_device_unregister);
|
||||
|
||||
void *tcpc_get_dev_data(struct tcpc_device *tcpc)
|
||||
{
|
||||
return tcpc->drv_data;
|
||||
}
|
||||
EXPORT_SYMBOL(tcpc_get_dev_data);
|
||||
|
||||
void tcpci_lock_typec(struct tcpc_device *tcpc)
|
||||
{
|
||||
mutex_lock(&tcpc->typec_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(tcpci_lock_typec);
|
||||
|
||||
void tcpci_unlock_typec(struct tcpc_device *tcpc)
|
||||
{
|
||||
mutex_unlock(&tcpc->typec_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(tcpci_unlock_typec);
|
||||
|
||||
static void tcpc_init_attrs(struct device_type *dev_type)
|
||||
{
|
||||
int i;
|
||||
|
||||
dev_type->groups = tcpc_attr_groups;
|
||||
for (i = 0; i < ARRAY_SIZE(tcpc_device_attributes); i++)
|
||||
__tcpc_attrs[i] = &tcpc_device_attributes[i].attr;
|
||||
}
|
||||
|
||||
static int __init tcpc_class_init(void)
|
||||
{
|
||||
pr_info("%s (%s)\n", __func__, TCPC_CORE_VERSION);
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
dpm_check_supported_modes();
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
tcpc_class = class_create(THIS_MODULE, "tcpc");
|
||||
if (IS_ERR(tcpc_class)) {
|
||||
pr_info("Unable to create tcpc class; errno = %ld\n",
|
||||
PTR_ERR(tcpc_class));
|
||||
return PTR_ERR(tcpc_class);
|
||||
}
|
||||
tcpc_init_attrs(&tcpc_dev_type);
|
||||
|
||||
pd_dbg_info_init();
|
||||
regmap_plat_init();
|
||||
|
||||
pr_info("TCPC class init OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit tcpc_class_exit(void)
|
||||
{
|
||||
regmap_plat_exit();
|
||||
pd_dbg_info_exit();
|
||||
|
||||
class_destroy(tcpc_class);
|
||||
pr_info("TCPC class un-init OK\n");
|
||||
}
|
||||
|
||||
subsys_initcall(tcpc_class_init);
|
||||
module_exit(tcpc_class_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Richtek TypeC Port Control Core");
|
||||
MODULE_AUTHOR("Jeff Chang <jeff_chang@richtek.com>");
|
||||
MODULE_VERSION(TCPC_CORE_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Release Version
|
||||
* 2.0.14_G
|
||||
* (1) Move out typec_port registration and operation to rt_pd_manager.c
|
||||
* (2) Rename CONFIG_TYPEC_WAIT_BC12 to CONFIG_USB_PD_WAIT_BC12
|
||||
* (3) Not to set power/data/vconn role repeatedly
|
||||
* (4) Revise vconn highV protection
|
||||
* (5) Revise tcpc timer
|
||||
* (6) Decrease VBUS present threshold (VBUS_CAL) by 60mV (2LSBs) for RT171x
|
||||
* (7) Replace \r\n with \n for resolving logs without newlines
|
||||
* (8) Remove the member time_stamp from struct pd_msg
|
||||
* (9) Remove NoResponseTimer as Sink for new PD spec
|
||||
* (10) Revise responses of Reject and Not_Supported
|
||||
* (11) Revise the usages of pd_traffic_control and typec_power_ctrl
|
||||
* (12) Revise the usages of wait_event_*()
|
||||
* (13) Add PD capability for TYPEC_ATTACHED_DBGACC_SNK
|
||||
* (14) Utilize rt-regmap to reduce I2C accesses
|
||||
*
|
||||
* 2.0.13_G
|
||||
* (1) Add TCPC flags for VCONN_SAFE5V_ONLY
|
||||
* (2) Add boolean property attemp_discover_svid in dts/dtsi
|
||||
* (3) Add a TCPM API for postponing Type-C role change until unattached
|
||||
* (4) Update VDOs according new PD spec
|
||||
* (5) Add an option for enabling/disabling the support of DebugAccessory.SRC
|
||||
* (6) Add the workaround for delayed ps_change related to PS_RDY
|
||||
* during PR_SWAP
|
||||
* (7) Always Back to PE ready state in pd_dpm_dfp_inform_id() and
|
||||
* pd_dpm_dfp_inform_svids()
|
||||
* (8) Re-fetch triggered_timer and enable_mask after lock acquisition
|
||||
* (9) Leave low power mode only when CC is detached
|
||||
* (10) Revise code related to pd_check_rev30()
|
||||
* (11) Bypass BC1.2 for PR_SWAP from Source to Sink (MTK only)
|
||||
* (12) Support charging icon for AudioAccessory (MTK only)
|
||||
* (13) Replace tcpc_dev with tcpc
|
||||
* (14) TCPCI Alert V10 and V20 co-exist
|
||||
* (15) Resolve DP Source/Sink Both Connected when acting as DFP_U
|
||||
* (16) Change CONFIG_TYPEC_SNK_CURR_DFT from 150 to 100 (mA)
|
||||
* (17) Define CONFIG_USB_PD_PR_SWAP_ERROR_RECOVERY by default
|
||||
* (18) Add an option for TCPC log with port name
|
||||
* (19) USB-C states go from ErrorRecovery to Unattached.SRC with Try.SRC role
|
||||
* (20) Revise dts/dtsi value for DisplayPort Alternative Mode
|
||||
* (21) Mask vSafe0V IRQ before entering low power mode
|
||||
* (22) Disable auto idle mode before entering low power mode
|
||||
* (23) Reset Protocol FSM and clear RX alerts twice before clock gating
|
||||
*
|
||||
* 2.0.12_G
|
||||
* (1) Fix voltage/current steps of RDO for APDO
|
||||
* (2) Non-blocking TCPC notification by default
|
||||
* (3) Fix synchronization/locking problems
|
||||
* (4) Fix NoRp.SRC support
|
||||
*
|
||||
* 2.0.11_G
|
||||
* (1) Fix PD compliance failures of Ellisys and MQP
|
||||
* (2) Wait the result of BC1.2 before starting PD policy engine
|
||||
* (3) Fix compile warnings
|
||||
* (4) Fix NoRp.SRC support
|
||||
*
|
||||
* 2.0.10_G
|
||||
* (1) fix battery noitifier plug out cause recursive locking detected in
|
||||
* nh->srcu.
|
||||
*
|
||||
* 2.0.9_G
|
||||
* (1) fix 10k A-to-C legacy cable workaround side effect when
|
||||
* cable plug in at worakround flow.
|
||||
*
|
||||
* 2.0.8_G
|
||||
* (1) fix timeout thread flow for wakeup pd event thread
|
||||
* after disable timer first.
|
||||
*
|
||||
* 2.0.7_G
|
||||
* (1) add extract pd source capability pdo defined in
|
||||
* PD30 v1.1 ECN for pe40 get apdo profile.
|
||||
*
|
||||
* 2.0.6_G
|
||||
* (1) register battery notifier for battery plug out
|
||||
* avoid TA hardreset 3 times will show charing icon.
|
||||
*
|
||||
* 2.0.5_G
|
||||
* (1) add CONFIG_TYPEC_CAP_NORP_SRC to support
|
||||
* A-to-C No-Rp cable.
|
||||
* (2) add handler pd eint with eint mask
|
||||
*
|
||||
* 2.0.4_G
|
||||
* (1) add CONFIG_TCPC_NOTIFIER_LATE_SYNC to
|
||||
* move irq_enable to late_initcall_sync stage
|
||||
* to prevent from notifier_supply_num setting wrong.
|
||||
*
|
||||
* 2.0.3_G
|
||||
* (1) use local_irq_XXX to instead raw_local_irq_XXX
|
||||
* to fix lock prov WARNING
|
||||
* (2) Remove unnecessary charger detect flow. it does
|
||||
* not need to switch BC1-2 path on otg_en
|
||||
*
|
||||
* 2.0.2_G
|
||||
* (1) Fix Coverity and check patch issue
|
||||
* (2) Fix 32-bit project build error
|
||||
*
|
||||
* 2.0.1_G
|
||||
* First released PD3.0 Driver
|
||||
*/
|
||||
291
drivers/usb/typec/mmi_tcpc/tcpci_dual_role.c
Normal file
291
drivers/usb/typec/mmi_tcpc/tcpci_dual_role.c
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Richtek Inc.
|
||||
*
|
||||
* TCPC Interface for dual role
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include "inc/tcpci.h"
|
||||
#include "inc/tcpci_typec.h"
|
||||
|
||||
#ifdef CONFIG_DUAL_ROLE_USB_INTF
|
||||
static enum dual_role_property tcpc_dual_role_props[] = {
|
||||
DUAL_ROLE_PROP_SUPPORTED_MODES,
|
||||
DUAL_ROLE_PROP_MODE,
|
||||
DUAL_ROLE_PROP_PR,
|
||||
DUAL_ROLE_PROP_DR,
|
||||
DUAL_ROLE_PROP_VCONN_SUPPLY,
|
||||
};
|
||||
|
||||
static int tcpc_dual_role_get_prop(struct dual_role_phy_instance *dual_role,
|
||||
enum dual_role_property prop, unsigned int *val)
|
||||
{
|
||||
struct tcpc_device *tcpc = dev_get_drvdata(dual_role->dev.parent);
|
||||
int ret = 0;
|
||||
|
||||
switch (prop) {
|
||||
case DUAL_ROLE_PROP_SUPPORTED_MODES:
|
||||
*val = tcpc->dual_role_supported_modes;
|
||||
break;
|
||||
case DUAL_ROLE_PROP_MODE:
|
||||
*val = tcpc->dual_role_mode;
|
||||
break;
|
||||
case DUAL_ROLE_PROP_PR:
|
||||
*val = tcpc->dual_role_pr;
|
||||
break;
|
||||
case DUAL_ROLE_PROP_DR:
|
||||
*val = tcpc->dual_role_dr;
|
||||
break;
|
||||
case DUAL_ROLE_PROP_VCONN_SUPPLY:
|
||||
*val = tcpc->dual_role_vconn;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tcpc_dual_role_prop_is_writeable(
|
||||
struct dual_role_phy_instance *dual_role, enum dual_role_property prop)
|
||||
{
|
||||
int retval = -EINVAL;
|
||||
struct tcpc_device *tcpc = dev_get_drvdata(dual_role->dev.parent);
|
||||
|
||||
switch (prop) {
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
case DUAL_ROLE_PROP_PR:
|
||||
case DUAL_ROLE_PROP_DR:
|
||||
case DUAL_ROLE_PROP_VCONN_SUPPLY:
|
||||
#else
|
||||
case DUAL_ROLE_PROP_MODE:
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
if (tcpc->dual_role_supported_modes ==
|
||||
DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP)
|
||||
retval = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
|
||||
static int tcpc_dual_role_set_prop_pr(
|
||||
struct tcpc_device *tcpc, unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t role;
|
||||
|
||||
switch (val) {
|
||||
case DUAL_ROLE_PROP_PR_SRC:
|
||||
role = PD_ROLE_SOURCE;
|
||||
break;
|
||||
case DUAL_ROLE_PROP_PR_SNK:
|
||||
role = PD_ROLE_SINK;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val == tcpc->dual_role_pr) {
|
||||
pr_info("%s wrong role (%d->%d)\n",
|
||||
__func__, tcpc->dual_role_pr, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = tcpm_dpm_pd_power_swap(tcpc, role, NULL);
|
||||
pr_info("%s power role swap (%d->%d): %d\n",
|
||||
__func__, tcpc->dual_role_pr, val, ret);
|
||||
|
||||
if (ret == TCPM_ERROR_NO_PD_CONNECTED) {
|
||||
ret = tcpm_typec_role_swap(tcpc);
|
||||
pr_info("%s typec role swap (%d->%d): %d\n",
|
||||
__func__, tcpc->dual_role_pr, val, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tcpc_dual_role_set_prop_dr(
|
||||
struct tcpc_device *tcpc, unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t role;
|
||||
|
||||
switch (val) {
|
||||
case DUAL_ROLE_PROP_DR_HOST:
|
||||
role = PD_ROLE_DFP;
|
||||
break;
|
||||
case DUAL_ROLE_PROP_DR_DEVICE:
|
||||
role = PD_ROLE_UFP;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val == tcpc->dual_role_dr) {
|
||||
pr_info("%s wrong role (%d->%d)\n",
|
||||
__func__, tcpc->dual_role_dr, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = tcpm_dpm_pd_data_swap(tcpc, role, NULL);
|
||||
pr_info("%s data role swap (%d->%d): %d\n",
|
||||
__func__, tcpc->dual_role_dr, val, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tcpc_dual_role_set_prop_vconn(
|
||||
struct tcpc_device *tcpc, unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t role;
|
||||
|
||||
switch (val) {
|
||||
case DUAL_ROLE_PROP_VCONN_SUPPLY_NO:
|
||||
role = PD_ROLE_VCONN_OFF;
|
||||
break;
|
||||
case DUAL_ROLE_PROP_VCONN_SUPPLY_YES:
|
||||
role = PD_ROLE_VCONN_ON;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val == tcpc->dual_role_vconn) {
|
||||
pr_info("%s wrong role (%d->%d)\n",
|
||||
__func__, tcpc->dual_role_vconn, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = tcpm_dpm_pd_vconn_swap(tcpc, role, NULL);
|
||||
pr_info("%s vconn swap (%d->%d): %d\n",
|
||||
__func__, tcpc->dual_role_vconn, val, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* TypeC Only */
|
||||
|
||||
static int tcpc_dual_role_set_prop_mode(
|
||||
struct tcpc_device *tcpc, unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (val == tcpc->dual_role_mode) {
|
||||
pr_info("%s wrong role (%d->%d)\n",
|
||||
__func__, tcpc->dual_role_mode, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = tcpm_typec_role_swap(tcpc);
|
||||
pr_info("%s typec role swap (%d->%d): %d\n",
|
||||
__func__, tcpc->dual_role_mode, val, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
static int tcpc_dual_role_set_prop(struct dual_role_phy_instance *dual_role,
|
||||
enum dual_role_property prop, const unsigned int *val)
|
||||
{
|
||||
struct tcpc_device *tcpc = dev_get_drvdata(dual_role->dev.parent);
|
||||
|
||||
switch (prop) {
|
||||
#ifdef CONFIG_USB_POWER_DELIVERY
|
||||
case DUAL_ROLE_PROP_PR:
|
||||
tcpc_dual_role_set_prop_pr(tcpc, *val);
|
||||
break;
|
||||
case DUAL_ROLE_PROP_DR:
|
||||
tcpc_dual_role_set_prop_dr(tcpc, *val);
|
||||
break;
|
||||
case DUAL_ROLE_PROP_VCONN_SUPPLY:
|
||||
tcpc_dual_role_set_prop_vconn(tcpc, *val);
|
||||
break;
|
||||
#else /* TypeC Only */
|
||||
case DUAL_ROLE_PROP_MODE:
|
||||
tcpc_dual_role_set_prop_mode(tcpc, *val);
|
||||
break;
|
||||
#endif /* CONFIG_USB_POWER_DELIVERY */
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tcpc_get_dual_desc(struct tcpc_device *tcpc)
|
||||
{
|
||||
struct device_node *np = of_find_node_by_name(NULL, tcpc->desc.name);
|
||||
u32 val;
|
||||
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
if (of_property_read_u32(np, "tcpc-dual,supported_modes", &val) >= 0) {
|
||||
if (val > DUAL_ROLE_PROP_SUPPORTED_MODES_TOTAL)
|
||||
tcpc->dual_role_supported_modes =
|
||||
DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP;
|
||||
else
|
||||
tcpc->dual_role_supported_modes = val;
|
||||
}
|
||||
}
|
||||
|
||||
int tcpc_dual_role_phy_init(
|
||||
struct tcpc_device *tcpc)
|
||||
{
|
||||
struct dual_role_phy_desc *dual_desc;
|
||||
int len;
|
||||
char *str_name;
|
||||
|
||||
tcpc->dr_usb = devm_kzalloc(&tcpc->dev,
|
||||
sizeof(*tcpc->dr_usb), GFP_KERNEL);
|
||||
|
||||
dual_desc = devm_kzalloc(&tcpc->dev, sizeof(*dual_desc), GFP_KERNEL);
|
||||
if (!dual_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
tcpc_get_dual_desc(tcpc);
|
||||
|
||||
len = strlen(tcpc->desc.name);
|
||||
str_name = devm_kzalloc(&tcpc->dev, len+11, GFP_KERNEL);
|
||||
snprintf(str_name, PAGE_SIZE, "dual-role-%s", tcpc->desc.name);
|
||||
dual_desc->name = str_name;
|
||||
|
||||
dual_desc->properties = tcpc_dual_role_props;
|
||||
dual_desc->num_properties = ARRAY_SIZE(tcpc_dual_role_props);
|
||||
dual_desc->get_property = tcpc_dual_role_get_prop;
|
||||
dual_desc->set_property = tcpc_dual_role_set_prop;
|
||||
dual_desc->property_is_writeable = tcpc_dual_role_prop_is_writeable;
|
||||
|
||||
tcpc->dr_usb = devm_dual_role_instance_register(&tcpc->dev, dual_desc);
|
||||
if (IS_ERR(tcpc->dr_usb)) {
|
||||
dev_err(&tcpc->dev, "tcpc fail to register dual role usb\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* init dual role phy instance property */
|
||||
tcpc->dual_role_pr = DUAL_ROLE_PROP_PR_NONE;
|
||||
tcpc->dual_role_dr = DUAL_ROLE_PROP_DR_NONE;
|
||||
tcpc->dual_role_mode = DUAL_ROLE_PROP_MODE_NONE;
|
||||
tcpc->dual_role_vconn = DUAL_ROLE_PROP_VCONN_SUPPLY_NO;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DUAL_ROLE_USB_INTF */
|
||||
1345
drivers/usb/typec/mmi_tcpc/tcpci_event.c
Normal file
1345
drivers/usb/typec/mmi_tcpc/tcpci_event.c
Normal file
File diff suppressed because it is too large
Load diff
1388
drivers/usb/typec/mmi_tcpc/tcpci_timer.c
Normal file
1388
drivers/usb/typec/mmi_tcpc/tcpci_timer.c
Normal file
File diff suppressed because it is too large
Load diff
2935
drivers/usb/typec/mmi_tcpc/tcpci_typec.c
Normal file
2935
drivers/usb/typec/mmi_tcpc/tcpci_typec.c
Normal file
File diff suppressed because it is too large
Load diff
2046
drivers/usb/typec/mmi_tcpc/tcpm.c
Normal file
2046
drivers/usb/typec/mmi_tcpc/tcpm.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue