drivers: usb_c: tcpc: stm32: Add VCONN functionality

Add VCONN discharge functionality to TCPC and driver

Signed-off-by: Sam Hurst <sbh1187@gmail.com>
This commit is contained in:
Sam Hurst 2022-12-14 12:13:06 -08:00 committed by Carles Cufí
commit 77e1638c3c
4 changed files with 130 additions and 2 deletions

View file

@ -156,10 +156,15 @@ static uint32_t ucpd_get_cc_enable_mask(const struct device *dev)
const struct tcpc_config *const config = dev->config; const struct tcpc_config *const config = dev->config;
uint32_t mask = UCPD_CR_CCENABLE_Msk; uint32_t mask = UCPD_CR_CCENABLE_Msk;
/*
* When VCONN is enabled, it is supplied on the CC line that's
* not being used for Power Delivery messages.
*/
if (data->ucpd_vconn_enable) { if (data->ucpd_vconn_enable) {
uint32_t cr = LL_UCPD_ReadReg(config->ucpd_port, CR); uint32_t cr = LL_UCPD_ReadReg(config->ucpd_port, CR);
int pol = (cr & UCPD_CR_PHYCCSEL); int pol = (cr & UCPD_CR_PHYCCSEL);
/* Dissable CC line that's used for VCONN */
mask &= ~BIT(UCPD_CR_CCENABLE_Pos + !pol); mask &= ~BIT(UCPD_CR_CCENABLE_Pos + !pol);
} }
@ -281,12 +286,52 @@ static int ucpd_set_vconn(const struct device *dev, bool enable)
update_stm32g0x_cc_line(config->ucpd_port); update_stm32g0x_cc_line(config->ucpd_port);
#endif #endif
/* Get CC line that VCONN is active on */
data->ucpd_vconn_cc = (cr & UCPD_CR_CCENABLE_0) ?
TC_POLARITY_CC2 : TC_POLARITY_CC1;
/* Call user supplied callback to set vconn */ /* Call user supplied callback to set vconn */
ret = data->vconn_cb(dev, enable); ret = data->vconn_cb(dev, data->ucpd_vconn_cc, enable);
return ret; return ret;
} }
/**
* @brief Discharge VCONN
*
* @retval 0 on success
* @retval -EIO on failure
* @retval -ENOTSUP if not supported
*/
static int ucpd_vconn_discharge(const struct device *dev, bool enable)
{
struct tcpc_data *data = dev->data;
const struct tcpc_config *const config = dev->config;
/* VCONN should not be discharged while it's enabled */
if (data->ucpd_vconn_enable) {
return -EIO;
}
if (data->vconn_discharge_cb) {
/* Use DPM supplied VCONN Discharge */
return data->vconn_discharge_cb(dev, data->ucpd_vconn_cc, enable);
}
/* Use TCPC VCONN Discharge */
if (enable) {
LL_UCPD_VconnDischargeEnable(config->ucpd_port);
} else {
LL_UCPD_VconnDischargeDisable(config->ucpd_port);
}
#ifdef CONFIG_SOC_SERIES_STM32G0X
update_stm32g0x_cc_line(config->ucpd_port);
#endif
return 0;
}
/** /**
* @brief Sets the value of the CC pull up resistor used when operating as a Source * @brief Sets the value of the CC pull up resistor used when operating as a Source
* *
@ -1236,6 +1281,20 @@ static void ucpd_set_vconn_cb(const struct device *dev,
data->vconn_cb = vconn_cb; data->vconn_cb = vconn_cb;
} }
/**
* @brief Sets a callback that can discharge VCONN if the TCPC is
* unable to or the system is configured in a way that does not use
* the VCONN discharge capabilities of the TCPC
*
*/
static void ucpd_set_vconn_discharge_cb(const struct device *dev,
tcpc_vconn_discharge_cb_t cb)
{
struct tcpc_data *data = dev->data;
data->vconn_discharge_cb = cb;
}
/** /**
* @brief UCPD interrupt init * @brief UCPD interrupt init
*/ */
@ -1344,7 +1403,9 @@ static const struct tcpc_driver_api driver_api = {
.set_cc = ucpd_set_cc, .set_cc = ucpd_set_cc,
.set_roles = ucpd_set_roles, .set_roles = ucpd_set_roles,
.set_vconn_cb = ucpd_set_vconn_cb, .set_vconn_cb = ucpd_set_vconn_cb,
.set_vconn_discharge_cb = ucpd_set_vconn_discharge_cb,
.set_vconn = ucpd_set_vconn, .set_vconn = ucpd_set_vconn,
.vconn_discharge = ucpd_vconn_discharge,
.set_cc_polarity = ucpd_cc_set_polarity, .set_cc_polarity = ucpd_cc_set_polarity,
.dump_std_reg = ucpd_dump_std_reg, .dump_std_reg = ucpd_dump_std_reg,
.set_bist_test_mode = ucpd_set_bist_test_mode, .set_bist_test_mode = ucpd_set_bist_test_mode,

View file

@ -267,6 +267,8 @@ struct tcpc_config {
struct tcpc_data { struct tcpc_data {
/* VCONN callback function */ /* VCONN callback function */
tcpc_vconn_control_cb_t vconn_cb; tcpc_vconn_control_cb_t vconn_cb;
/* VCONN Discharge callback function */
tcpc_vconn_discharge_cb_t vconn_discharge_cb;
/* Alert information */ /* Alert information */
struct alert_info alert_info; struct alert_info alert_info;
@ -309,6 +311,8 @@ struct tcpc_data {
struct msg_header_info msg_header; struct msg_header_info msg_header;
/* Track VCONN on/off state */ /* Track VCONN on/off state */
bool ucpd_vconn_enable; bool ucpd_vconn_enable;
/* Track CC line that VCONN was active on */
enum tc_cc_polarity ucpd_vconn_cc;
/* Timer for amount of time to wait for receiving a GoodCRC */ /* Timer for amount of time to wait for receiving a GoodCRC */
struct k_timer goodcrc_rx_timer; struct k_timer goodcrc_rx_timer;

View file

@ -116,7 +116,10 @@ struct tcpc_chip_info {
}; };
}; };
typedef int (*tcpc_vconn_control_cb_t)(const struct device *dev, bool enable); typedef int (*tcpc_vconn_control_cb_t)(const struct device *dev,
enum tc_cc_polarity pol, bool enable);
typedef int (*tcpc_vconn_discharge_cb_t)(const struct device *dev,
enum tc_cc_polarity pol, bool enable);
typedef void (*tcpc_alert_handler_cb_t)(const struct device *dev, void *data, typedef void (*tcpc_alert_handler_cb_t)(const struct device *dev, void *data,
enum tcpc_alert alert); enum tcpc_alert alert);
@ -127,7 +130,9 @@ __subsystem struct tcpc_driver_api {
int (*select_rp_value)(const struct device *dev, enum tc_rp_value rp); int (*select_rp_value)(const struct device *dev, enum tc_rp_value rp);
int (*get_rp_value)(const struct device *dev, enum tc_rp_value *rp); int (*get_rp_value)(const struct device *dev, enum tc_rp_value *rp);
int (*set_cc)(const struct device *dev, enum tc_cc_pull pull); int (*set_cc)(const struct device *dev, enum tc_cc_pull pull);
void (*set_vconn_discharge_cb)(const struct device *dev, tcpc_vconn_discharge_cb_t cb);
void (*set_vconn_cb)(const struct device *dev, tcpc_vconn_control_cb_t vconn_cb); void (*set_vconn_cb)(const struct device *dev, tcpc_vconn_control_cb_t vconn_cb);
int (*vconn_discharge)(const struct device *dev, bool enable);
int (*set_vconn)(const struct device *dev, bool enable); int (*set_vconn)(const struct device *dev, bool enable);
int (*set_roles)(const struct device *dev, enum tc_power_role power_role, int (*set_roles)(const struct device *dev, enum tc_power_role power_role,
enum tc_data_role data_role); enum tc_data_role data_role);
@ -350,6 +355,53 @@ static inline void tcpc_set_vconn_cb(const struct device *dev,
return api->set_vconn_cb(dev, vconn_cb); return api->set_vconn_cb(dev, vconn_cb);
} }
/**
* @brief Sets a callback that can enable or discharge VCONN if the TCPC is
* unable to or the system is configured in a way that does not use
* the VCONN control capabilities of the TCPC
*
* The callback is called in the tcpc_vconn_discharge function if cb isn't NULL
*
* @param dev Runtime device structure
* @param cb pointer to the callback function that discharges vconn
*/
static inline void tcpc_set_vconn_discharge_cb(const struct device *dev,
tcpc_vconn_discharge_cb_t cb)
{
const struct tcpc_driver_api *api =
(const struct tcpc_driver_api *)dev->api;
__ASSERT(api->set_vconn_discharge_cb != NULL,
"Callback pointer should not be NULL");
return api->set_vconn_discharge_cb(dev, cb);
}
/**
* @brief Discharges VCONN
*
* This function uses the TCPC to discharge VCONN if possible or calls the
* callback function set by tcpc_set_vconn_cb
*
* @param dev Runtime device structure
* @param enable VCONN discharge is enabled when true, it's disabled
*
* @retval 0 on success
* @retval -EIO on failure
* @retval -ENOSYS if not implemented
*/
static inline int tcpc_vconn_discharge(const struct device *dev, bool enable)
{
const struct tcpc_driver_api *api =
(const struct tcpc_driver_api *)dev->api;
if (api->vconn_discharge == NULL) {
return -ENOSYS;
}
return api->vconn_discharge(dev, enable);
}
/** /**
* @brief Enables or disables VCONN * @brief Enables or disables VCONN
* *

View file

@ -123,6 +123,8 @@ enum usbc_policy_check_t {
CHECK_DATA_ROLE_SWAP_TO_UFP, CHECK_DATA_ROLE_SWAP_TO_UFP,
/** Check if Sink is at default level */ /** Check if Sink is at default level */
CHECK_SNK_AT_DEFAULT_LEVEL, CHECK_SNK_AT_DEFAULT_LEVEL,
/** Check if should control VCONN */
CHECK_VCONN_CONTROL,
}; };
/** /**
@ -213,6 +215,15 @@ void *usbc_get_dpm_data(const struct device *dev);
void usbc_set_vconn_control_cb(const struct device *dev, void usbc_set_vconn_control_cb(const struct device *dev,
const tcpc_vconn_control_cb_t cb); const tcpc_vconn_control_cb_t cb);
/**
* @brief Set the callback used to discharge VCONN
*
* @param dev Runtime device structure
* @param cb VCONN discharge callback
*/
void usbc_set_vconn_discharge_cb(const struct device *dev,
const tcpc_vconn_discharge_cb_t cb);
/** /**
* @brief Set the callback used to check a policy * @brief Set the callback used to check a policy
* *