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:
parent
a19cf99aa3
commit
77e1638c3c
4 changed files with 130 additions and 2 deletions
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue