linux/drivers/usb/typec/tcpm/tcpm.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2015-2017 Google, Inc
 *
 * USB Power Delivery protocol stack.
 */

#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/hrtimer.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/power_supply.h>
#include <linux/proc_fs.h>
#include <linux/property.h>
#include <linux/sched/clock.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/usb/pd.h>
#include <linux/usb/pd_ado.h>
#include <linux/usb/pd_bdo.h>
#include <linux/usb/pd_ext_sdb.h>
#include <linux/usb/pd_vdo.h>
#include <linux/usb/role.h>
#include <linux/usb/tcpm.h>
#include <linux/usb/typec_altmode.h>

#include <uapi/linux/sched/types.h>

#define FOREACH_STATE(S)

#define FOREACH_AMS(S)

#define GENERATE_ENUM(e)
#define GENERATE_STRING(s)

enum tcpm_state {};

static const char * const tcpm_states[] =;

enum tcpm_ams {};

static const char * const tcpm_ams_str[] =;

enum vdm_states {};

enum pd_msg_request {};

enum adev_actions {};

/*
 * Initial current capability of the new source when vSafe5V is applied during PD3.0 Fast Role Swap.
 * Based on "Table 6-14 Fixed Supply PDO - Sink" of "USB Power Delivery Specification Revision 3.0,
 * Version 1.2"
 */
enum frs_typec_current {};

/* Events from low level driver */

#define TCPM_CC_EVENT
#define TCPM_VBUS_EVENT
#define TCPM_RESET_EVENT
#define TCPM_FRS_EVENT
#define TCPM_SOURCING_VBUS
#define TCPM_PORT_CLEAN
#define TCPM_PORT_ERROR

#define LOG_BUFFER_ENTRIES
#define LOG_BUFFER_ENTRY_SIZE

/* Alternate mode support */

#define SVID_DISCOVERY_MAX
#define ALTMODE_DISCOVERY_MAX

#define GET_SINK_CAP_RETRY_MS
#define SEND_DISCOVER_RETRY_MS

struct pd_mode_data {};

/*
 * @min_volt: Actual min voltage at the local port
 * @req_min_volt: Requested min voltage to the port partner
 * @max_volt: Actual max voltage at the local port
 * @req_max_volt: Requested max voltage to the port partner
 * @max_curr: Actual max current at the local port
 * @req_max_curr: Requested max current of the port partner
 * @req_out_volt: Requested output voltage to the port partner
 * @req_op_curr: Requested operating current to the port partner
 * @supported: Parter has at least one APDO hence supports PPS
 * @active: PPS mode is active
 */
struct pd_pps_data {};

struct pd_data {};

struct tcpm_port {};

struct pd_rx_event {};

static const char * const pd_rev[] =;

#define tcpm_cc_is_sink(cc)

/* As long as cc is pulled up, we can consider it as sink. */
#define tcpm_port_is_sink(port)

#define tcpm_cc_is_source(cc)
#define tcpm_cc_is_audio(cc)
#define tcpm_cc_is_open(cc)

#define tcpm_port_is_source(port)

#define tcpm_port_is_debug(port)

#define tcpm_port_is_audio(port)

#define tcpm_port_is_audio_detached(port)

#define tcpm_try_snk(port)

#define tcpm_try_src(port)

#define tcpm_data_role_for_source(port)

#define tcpm_data_role_for_sink(port)

#define tcpm_sink_tx_ok(port)

#define tcpm_wait_for_discharge(port)

static enum tcpm_state tcpm_default_state(struct tcpm_port *port)
{}

static bool tcpm_port_is_disconnected(struct tcpm_port *port)
{}

/*
 * Logging
 */

#ifdef CONFIG_DEBUG_FS

static bool tcpm_log_full(struct tcpm_port *port)
{}

__printf(2, 0)
static void _tcpm_log(struct tcpm_port *port, const char *fmt, va_list args)
{}

__printf(2, 3)
static void tcpm_log(struct tcpm_port *port, const char *fmt, ...)
{}

__printf(2, 3)
static void tcpm_log_force(struct tcpm_port *port, const char *fmt, ...)
{}

static void tcpm_log_source_caps(struct tcpm_port *port)
{}

static int tcpm_debug_show(struct seq_file *s, void *v)
{}
DEFINE_SHOW_ATTRIBUTE();

static void tcpm_debugfs_init(struct tcpm_port *port)
{}

static void tcpm_debugfs_exit(struct tcpm_port *port)
{}

#else

__printf(2, 3)
static void tcpm_log(const struct tcpm_port *port, const char *fmt, ...) { }
__printf(2, 3)
static void tcpm_log_force(struct tcpm_port *port, const char *fmt, ...) { }
static void tcpm_log_source_caps(struct tcpm_port *port) { }
static void tcpm_debugfs_init(const struct tcpm_port *port) { }
static void tcpm_debugfs_exit(const struct tcpm_port *port) { }

#endif

static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
{}

static int tcpm_enable_auto_vbus_discharge(struct tcpm_port *port, bool enable)
{}

static void tcpm_apply_rc(struct tcpm_port *port)
{}

/*
 * Determine RP value to set based on maximum current supported
 * by a port if configured as source.
 * Returns CC value to report to link partner.
 */
static enum typec_cc_status tcpm_rp_cc(struct tcpm_port *port)
{}

static void tcpm_ams_finish(struct tcpm_port *port)
{}

static int tcpm_pd_transmit(struct tcpm_port *port,
			    enum tcpm_transmit_type tx_sop_type,
			    const struct pd_message *msg)
{}

void tcpm_pd_transmit_complete(struct tcpm_port *port,
			       enum tcpm_transmit_status status)
{}
EXPORT_SYMBOL_GPL();

static int tcpm_mux_set(struct tcpm_port *port, int state,
			enum usb_role usb_role,
			enum typec_orientation orientation)
{}

static int tcpm_set_polarity(struct tcpm_port *port,
			     enum typec_cc_polarity polarity)
{}

static int tcpm_set_vconn(struct tcpm_port *port, bool enable)
{}

static u32 tcpm_get_current_limit(struct tcpm_port *port)
{}

static int tcpm_set_current_limit(struct tcpm_port *port, u32 max_ma, u32 mv)
{}

static int tcpm_set_attached_state(struct tcpm_port *port, bool attached)
{}

static int tcpm_set_roles(struct tcpm_port *port, bool attached,
			  enum typec_role role, enum typec_data_role data)
{}

static int tcpm_set_pwr_role(struct tcpm_port *port, enum typec_role role)
{}

/*
 * Transform the PDO to be compliant to PD rev2.0.
 * Return 0 if the PDO type is not defined in PD rev2.0.
 * Otherwise, return the converted PDO.
 */
static u32 tcpm_forge_legacy_pdo(struct tcpm_port *port, u32 pdo, enum typec_role role)
{}

static int tcpm_pd_send_source_caps(struct tcpm_port *port)
{}

static int tcpm_pd_send_sink_caps(struct tcpm_port *port)
{}

static void mod_tcpm_delayed_work(struct tcpm_port *port, unsigned int delay_ms)
{}

static void mod_vdm_delayed_work(struct tcpm_port *port, unsigned int delay_ms)
{}

static void mod_enable_frs_delayed_work(struct tcpm_port *port, unsigned int delay_ms)
{}

static void mod_send_discover_delayed_work(struct tcpm_port *port, unsigned int delay_ms)
{}

static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state,
			   unsigned int delay_ms)
{}

static void tcpm_set_state_cond(struct tcpm_port *port, enum tcpm_state state,
				unsigned int delay_ms)
{}

static void tcpm_queue_message(struct tcpm_port *port,
			       enum pd_msg_request message)
{}

static bool tcpm_vdm_ams(struct tcpm_port *port)
{}

static bool tcpm_ams_interruptible(struct tcpm_port *port)
{}

static int tcpm_ams_start(struct tcpm_port *port, enum tcpm_ams ams)
{}

/*
 * VDM/VDO handling functions
 */
static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header,
			   const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type)
{}

static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header,
				    const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type)
{}

static void svdm_consume_identity(struct tcpm_port *port, const u32 *p, int cnt)
{}

static void svdm_consume_identity_sop_prime(struct tcpm_port *port, const u32 *p, int cnt)
{}

static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt,
			       enum tcpm_transmit_type rx_sop_type)
{}

static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt,
			       enum tcpm_transmit_type rx_sop_type)
{}

static void tcpm_register_partner_altmodes(struct tcpm_port *port)
{}

static void tcpm_register_plug_altmodes(struct tcpm_port *port)
{}

#define supports_modal(port)
#define supports_modal_cable(port)
#define supports_host(port)

/*
 * Helper to determine whether the port is capable of SOP' communication at the
 * current point in time.
 */
static bool tcpm_can_communicate_sop_prime(struct tcpm_port *port)
{}

static bool tcpm_attempt_vconn_swap_discovery(struct tcpm_port *port)
{}


static bool tcpm_cable_vdm_supported(struct tcpm_port *port)
{}

static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
			const u32 *p, int cnt, u32 *response,
			enum adev_actions *adev_action,
			enum tcpm_transmit_type rx_sop_type,
			enum tcpm_transmit_type *response_tx_sop_type)
{}

static void tcpm_pd_handle_msg(struct tcpm_port *port,
			       enum pd_msg_request message,
			       enum tcpm_ams ams);

static void tcpm_handle_vdm_request(struct tcpm_port *port,
				    const __le32 *payload, int cnt,
				    enum tcpm_transmit_type rx_sop_type)
{}

static void tcpm_send_vdm(struct tcpm_port *port, u32 vid, int cmd,
			  const u32 *data, int count, enum tcpm_transmit_type tx_sop_type)
{}

static unsigned int vdm_ready_timeout(u32 vdm_hdr)
{}

static void vdm_run_state_machine(struct tcpm_port *port)
{}

static void vdm_state_machine_work(struct kthread_work *work)
{}

enum pdo_err {};

static const char * const pdo_err_msg[] =;

static enum pdo_err tcpm_caps_err(struct tcpm_port *port, const u32 *pdo,
				  unsigned int nr_pdo)
{}

static int tcpm_validate_caps(struct tcpm_port *port, const u32 *pdo,
			      unsigned int nr_pdo)
{}

static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo)
{}

static int tcpm_altmode_exit(struct typec_altmode *altmode)
{}

static int tcpm_altmode_vdm(struct typec_altmode *altmode,
			    u32 header, const u32 *data, int count)
{}

static const struct typec_altmode_ops tcpm_altmode_ops =;


static int tcpm_cable_altmode_enter(struct typec_altmode *altmode, enum typec_plug_index sop,
				    u32 *vdo)
{}

static int tcpm_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop)
{}

static int tcpm_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop,
				  u32 header, const u32 *data, int count)
{}

static const struct typec_cable_ops tcpm_cable_ops =;

/*
 * PD (data, control) command handling functions
 */
static inline enum tcpm_state ready_state(struct tcpm_port *port)
{}

static int tcpm_pd_send_control(struct tcpm_port *port,
				enum pd_ctrl_msg_type type,
				enum tcpm_transmit_type tx_sop_type);

static void tcpm_handle_alert(struct tcpm_port *port, const __le32 *payload,
			      int cnt)
{}

static int tcpm_set_auto_vbus_discharge_threshold(struct tcpm_port *port,
						  enum typec_pwr_opmode mode, bool pps_active,
						  u32 requested_vbus_voltage)
{}

static void tcpm_pd_handle_state(struct tcpm_port *port,
				 enum tcpm_state state,
				 enum tcpm_ams ams,
				 unsigned int delay_ms)
{}

static void tcpm_pd_handle_msg(struct tcpm_port *port,
			       enum pd_msg_request message,
			       enum tcpm_ams ams)
{}

static int tcpm_register_source_caps(struct tcpm_port *port)
{}

static int tcpm_register_sink_caps(struct tcpm_port *port)
{}

static void tcpm_pd_data_request(struct tcpm_port *port,
				 const struct pd_message *msg,
				 enum tcpm_transmit_type rx_sop_type)
{}

static void tcpm_pps_complete(struct tcpm_port *port, int result)
{}

static void tcpm_pd_ctrl_request(struct tcpm_port *port,
				 const struct pd_message *msg,
				 enum tcpm_transmit_type rx_sop_type)
{}

static void tcpm_pd_ext_msg_request(struct tcpm_port *port,
				    const struct pd_message *msg)
{}

static void tcpm_pd_rx_handler(struct kthread_work *work)
{}

void tcpm_pd_receive(struct tcpm_port *port, const struct pd_message *msg,
		     enum tcpm_transmit_type rx_sop_type)
{}
EXPORT_SYMBOL_GPL();

static int tcpm_pd_send_control(struct tcpm_port *port,
				enum pd_ctrl_msg_type type,
				enum tcpm_transmit_type tx_sop_type)
{}

/*
 * Send queued message without affecting state.
 * Return true if state machine should go back to sleep,
 * false otherwise.
 */
static bool tcpm_send_queued_message(struct tcpm_port *port)
{}

static int tcpm_pd_check_request(struct tcpm_port *port)
{}

#define min_power(x, y)
#define min_current(x, y)

static int tcpm_pd_select_pdo(struct tcpm_port *port, int *sink_pdo,
			      int *src_pdo)
{}

static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port)
{}

static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo)
{}

static int tcpm_pd_send_request(struct tcpm_port *port)
{}

static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo)
{}

static int tcpm_pd_send_pps_request(struct tcpm_port *port)
{}

static int tcpm_set_vbus(struct tcpm_port *port, bool enable)
{}

static int tcpm_set_charge(struct tcpm_port *port, bool charge)
{}

static bool tcpm_start_toggling(struct tcpm_port *port, enum typec_cc_status cc)
{}

static int tcpm_init_vbus(struct tcpm_port *port)
{}

static int tcpm_init_vconn(struct tcpm_port *port)
{}

static void tcpm_typec_connect(struct tcpm_port *port)
{}

static int tcpm_src_attach(struct tcpm_port *port)
{}

static void tcpm_typec_disconnect(struct tcpm_port *port)
{}

static void tcpm_unregister_altmodes(struct tcpm_port *port)
{}

static void tcpm_set_partner_usb_comm_capable(struct tcpm_port *port, bool capable)
{}

static void tcpm_reset_port(struct tcpm_port *port)
{}

static void tcpm_detach(struct tcpm_port *port)
{}

static void tcpm_src_detach(struct tcpm_port *port)
{}

static int tcpm_snk_attach(struct tcpm_port *port)
{}

static void tcpm_snk_detach(struct tcpm_port *port)
{}

static int tcpm_acc_attach(struct tcpm_port *port)
{}

static void tcpm_acc_detach(struct tcpm_port *port)
{}

static inline enum tcpm_state hard_reset_state(struct tcpm_port *port)
{}

static inline enum tcpm_state unattached_state(struct tcpm_port *port)
{}

static void tcpm_swap_complete(struct tcpm_port *port, int result)
{}

static enum typec_pwr_opmode tcpm_get_pwr_opmode(enum typec_cc_status cc)
{}

static enum typec_cc_status tcpm_pwr_opmode_to_rp(enum typec_pwr_opmode opmode)
{}

static void tcpm_set_initial_svdm_version(struct tcpm_port *port)
{}

static void run_state_machine(struct tcpm_port *port)
{}

static void tcpm_state_machine_work(struct kthread_work *work)
{}

static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
			    enum typec_cc_status cc2)
{}

static void _tcpm_pd_vbus_on(struct tcpm_port *port)
{}

static void _tcpm_pd_vbus_off(struct tcpm_port *port)
{}

static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
{}

static void _tcpm_pd_hard_reset(struct tcpm_port *port)
{}

static void tcpm_pd_event_handler(struct kthread_work *work)
{}

void tcpm_cc_change(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

void tcpm_vbus_change(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

void tcpm_pd_hard_reset(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

void tcpm_sink_frs(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

void tcpm_sourcing_vbus(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

void tcpm_port_clean(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

bool tcpm_port_is_toggling(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

void tcpm_port_error_recovery(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

static void tcpm_enable_frs_work(struct kthread_work *work)
{}

static void tcpm_send_discover_work(struct kthread_work *work)
{}

static int tcpm_dr_set(struct typec_port *p, enum typec_data_role data)
{}

static int tcpm_pr_set(struct typec_port *p, enum typec_role role)
{}

static int tcpm_vconn_set(struct typec_port *p, enum typec_role role)
{}

static int tcpm_try_role(struct typec_port *p, int role)
{}

static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 req_op_curr)
{}

static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 req_out_volt)
{}

static int tcpm_pps_activate(struct tcpm_port *port, bool activate)
{}

static void tcpm_init(struct tcpm_port *port)
{}

static int tcpm_port_type_set(struct typec_port *p, enum typec_port_type type)
{}

static struct pd_data *tcpm_find_pd_data(struct tcpm_port *port, struct usb_power_delivery *pd)
{}

static struct usb_power_delivery **tcpm_pd_get(struct typec_port *p)
{}

static int tcpm_pd_set(struct typec_port *p, struct usb_power_delivery *pd)
{}

static const struct typec_operations tcpm_ops =;

void tcpm_tcpc_reset(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

static void tcpm_port_unregister_pd(struct tcpm_port *port)
{}

static int tcpm_port_register_pd(struct tcpm_port *port)
{}

static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode)
{}

static int tcpm_fw_get_snk_vdos(struct tcpm_port *port, struct fwnode_handle *fwnode)
{}

/* Power Supply access to expose source power information */
enum tcpm_psy_online_states {};

static enum power_supply_property tcpm_psy_props[] =;

static int tcpm_psy_get_online(struct tcpm_port *port,
			       union power_supply_propval *val)
{}

static int tcpm_psy_get_voltage_min(struct tcpm_port *port,
				    union power_supply_propval *val)
{}

static int tcpm_psy_get_voltage_max(struct tcpm_port *port,
				    union power_supply_propval *val)
{}

static int tcpm_psy_get_voltage_now(struct tcpm_port *port,
				    union power_supply_propval *val)
{}

static int tcpm_psy_get_current_max(struct tcpm_port *port,
				    union power_supply_propval *val)
{}

static int tcpm_psy_get_current_now(struct tcpm_port *port,
				    union power_supply_propval *val)
{}

static int tcpm_psy_get_input_power_limit(struct tcpm_port *port,
					  union power_supply_propval *val)
{}

static int tcpm_psy_get_prop(struct power_supply *psy,
			     enum power_supply_property psp,
			     union power_supply_propval *val)
{}

static int tcpm_psy_set_online(struct tcpm_port *port,
			       const union power_supply_propval *val)
{}

static int tcpm_psy_set_prop(struct power_supply *psy,
			     enum power_supply_property psp,
			     const union power_supply_propval *val)
{}

static int tcpm_psy_prop_writeable(struct power_supply *psy,
				   enum power_supply_property psp)
{}

static enum power_supply_usb_type tcpm_psy_usb_types[] =;

static const char *tcpm_psy_name_prefix =;

static int devm_tcpm_psy_register(struct tcpm_port *port)
{}

static enum hrtimer_restart state_machine_timer_handler(struct hrtimer *timer)
{}

static enum hrtimer_restart vdm_state_machine_timer_handler(struct hrtimer *timer)
{}

static enum hrtimer_restart enable_frs_timer_handler(struct hrtimer *timer)
{}

static enum hrtimer_restart send_discover_timer_handler(struct hrtimer *timer)
{}

struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
{}
EXPORT_SYMBOL_GPL();

void tcpm_unregister_port(struct tcpm_port *port)
{}
EXPORT_SYMBOL_GPL();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();