| /* Copyright 2023 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| /** |
| * @file drivers/pdc.h |
| * @brief Public APIs for Power Delivery Controller Chip drivers. |
| * |
| */ |
| #ifndef ZEPHYR_INCLUDE_DRIVERS_PDC_H_ |
| #define ZEPHYR_INCLUDE_DRIVERS_PDC_H_ |
| |
| #include "ec_commands.h" |
| #include "power.h" |
| #include "ucsi_v3.h" |
| #include "usb_pd.h" |
| #include "usbc/utils.h" |
| |
| #include <errno.h> |
| |
| #include <zephyr/device.h> |
| #include <zephyr/drivers/i2c.h> |
| #include <zephyr/sys/slist.h> |
| #include <zephyr/types.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #define PDC_VID_INVALID (0x0000) |
| #define PDC_PID_INVALID (0x0000) |
| |
| /** |
| * Compare PDC versions |
| */ |
| #define PDC_FWVER_AT_LEAST(ver_in, major, minor) \ |
| (PDC_FWVER_GET_MAJOR(ver_in) > (major) || \ |
| (PDC_FWVER_GET_MAJOR(ver_in) == (major) && \ |
| PDC_FWVER_GET_MINOR(ver_in) >= (minor))) |
| |
| /** |
| * Extract the major, minor, and patch elements from a 32-bit version in |
| * `struct pdc_info_t` |
| */ |
| #define PDC_FWVER_GET_MAJOR(fwver) (((fwver) >> 16) & 0xFF) |
| #define PDC_FWVER_GET_MINOR(fwver) (((fwver) >> 8) & 0xFF) |
| #define PDC_FWVER_GET_PATCH(fwver) ((fwver) & 0xFF) |
| |
| #define PDC_FWVER_INVALID (0xFFFFFFFF) |
| |
| #define NODE_MATCHES(node1, node2) IS_EQ(DT_DEP_ORD(node1), DT_DEP_ORD(node2)) |
| |
| #define COMPARE_PDC_ARRAY_MEMBER(usbc_id, prop, idx, target) \ |
| COND_CODE_1(NODE_MATCHES(DT_PROP_BY_IDX(usbc_id, prop, idx), target), \ |
| (USBC_PORT_NEW(usbc_id)), ()) |
| |
| #define GET_USBC_PORT_IF_PDC_IN_LIST(usbc_id, target) \ |
| DT_FOREACH_PROP_ELEM_VARGS(usbc_id, pdc, COMPARE_PDC_ARRAY_MEMBER, \ |
| target) |
| |
| /** |
| * @brief Given a devicetree node, return the USB-C port number that references |
| * the devicetree node. |
| * |
| * Usage: |
| * usbc_port0: port0@0 { |
| * compatible = "named-usbc-port"; |
| * reg = < 0x0 >; |
| * chg = < &charger >; |
| * pdc = < &pdc_power_p0 >; |
| * }; |
| * usbc_port1: port1@1 { |
| * compatible = "named-usbc-port"; |
| * reg = < 0x1 >; |
| * pdc = < &pdc_power_p1 >; |
| * }; |
| * &i2c{ |
| * pdc_power_p1: driver@88 { |
| * compatible = "my-driver"; |
| * } |
| * }; |
| * |
| * |
| * @param target Devicetree node to search for |
| * @param prop named-usbc-port property to check |
| * @returns USB-C port number |
| */ |
| #define USBC_PORT_FROM_PDC_DRIVER_NODE(target) \ |
| DT_FOREACH_STATUS_OKAY_VARGS(named_usbc_port, \ |
| GET_USBC_PORT_IF_PDC_IN_LIST, target) |
| |
| /** |
| * @brief Power Delivery Controller Information |
| */ |
| struct pdc_info_t { |
| /** Firmware version running on the PDC */ |
| uint32_t fw_version; |
| /** Power Delivery Revision supported by the PDC */ |
| uint16_t pd_revision; |
| /** Power Delivery Version supported by the PDC */ |
| uint16_t pd_version; |
| /** VID of the PDC (optional) */ |
| uint16_t vid; |
| /** PID of the PDC (optional) */ |
| uint16_t pid; |
| /** Set to 1 if running from flash code (optional) */ |
| uint8_t is_running_flash_code; |
| /** Set to the currently used flash bank (optional) */ |
| uint8_t running_in_flash_bank; |
| /** 12-byte program name string plus NUL terminator */ |
| char project_name[USB_PD_CHIP_INFO_PROJECT_NAME_LEN + 1]; |
| /** Compat string of driver */ |
| char driver_name[USB_PD_CHIP_INFO_DRIVER_NAME_LEN + 1]; |
| /** If true, do not apply PDC FW updates to this port */ |
| bool no_fw_update; |
| /** True if the PDC hardware supports FRS */ |
| bool frs_supported; |
| /** True if the USB-C port is capable of USB communication as a device |
| */ |
| bool usb_comm_capable_as_device; |
| /** Extra information (optional) */ |
| uint16_t extra; |
| }; |
| |
| /** |
| * Connector status changes that PDCs can report through vendor defined |
| * interfaces. These events are not supported by GET_CONNECTOR_STATUS. |
| */ |
| union vendor_status_change_bits_t { |
| struct { |
| /* Set to 1 when PDC reports receiving a PD Alert message */ |
| uint32_t alert_received : 1; |
| uint32_t reserved : 31; |
| }; |
| uint32_t raw_value; |
| }; |
| |
| /** |
| * The type of interface used to access the PDC |
| */ |
| enum pdc_bus_type { |
| PDC_BUS_TYPE_NONE = 0, |
| PDC_BUS_TYPE_I2C, |
| PDC_BUS_TYPE_MAX, |
| }; |
| |
| /** |
| * @brief Bus info for PDC chip. This gets exposed via host command to enable |
| * passthrough access to the PDC from AP during firmware updates. |
| */ |
| struct pdc_hw_config_t { |
| enum pdc_bus_type bus_type; |
| union { |
| struct i2c_dt_spec i2c; |
| }; |
| bool ccd; |
| }; |
| |
| /** |
| * @brief Used for building CMD_PDC_GET_PDOS |
| */ |
| struct get_pdo_t { |
| enum pdo_type_t pdo_type; |
| enum pdo_source_t pdo_source; |
| uint8_t num_pdos; |
| enum pdo_offset_t pdo_offset; |
| /** flag to indicate retrieving pdo from PDC */ |
| bool updating; |
| }; |
| |
| /** |
| * Used with pdc_get_sbu_mux_mode() / pdc_set_sbu_mux_mode() |
| */ |
| enum pdc_sbu_mux_mode { |
| /** SBU mux mode is invalid or unknown */ |
| PDC_SBU_MUX_MODE_INVALID = -1, |
| /** The SBU mux behaves normally (switches to debug path when a debug |
| * accessory is attached, or connected to AP for alternate modes) */ |
| PDC_SBU_MUX_MODE_NORMAL = 0, |
| /** The SBU mux is forced into the debug path unconditionally. Used when |
| * CCD must be kept alive. This is not cleared unless explicitly set |
| * back to PDC_SBU_MUX_MODE_NORMAL or the PDC reboots. */ |
| PDC_SBU_MUX_MODE_FORCE_DBG, |
| PDC_SBU_MUX_MODE_MAX, |
| }; |
| |
| /** |
| * Used with pdc_set_pdr to describe the desired power policy / behavior |
| */ |
| enum pdc_power_policy { |
| /** Transition to or remain in the sink role, and allow external power |
| role swap requests */ |
| PDC_POWER_POLICY_SINK_ALLOW_SWAP, |
| /** Transition to or remain in the sink role, and block external power |
| role swap requests */ |
| PDC_POWER_POLICY_SINK_DISALLOW_SWAP, |
| /** Transition to or remain in the source role, and allow external power |
| role swap requests */ |
| PDC_POWER_POLICY_SOURCE_ALLOW_SWAP, |
| /** Transition to or remain in the source role, and block external power |
| role swap requests */ |
| PDC_POWER_POLICY_SOURCE_DISALLOW_SWAP, |
| }; |
| |
| /** |
| * Used to define device maximum source PDP |
| */ |
| enum max_pdp_t { |
| MAX_PDP_7_5W, |
| MAX_PDP_15W, |
| }; |
| |
| /** Helper macro to set the policy to sink and allow or disallow external swaps |
| * based on a boolean argument. |
| */ |
| #define PDC_POWER_POLICY_SINK(external_swap) \ |
| ((external_swap) ? PDC_POWER_POLICY_SINK_ALLOW_SWAP : \ |
| PDC_POWER_POLICY_SINK_DISALLOW_SWAP) |
| |
| /** Helper macro to set the policy to source and allow or disallow external |
| * swaps based on a boolean argument. |
| */ |
| #define PDC_POWER_POLICY_SOURCE(external_swap) \ |
| ((external_swap) ? PDC_POWER_POLICY_SOURCE_ALLOW_SWAP : \ |
| PDC_POWER_POLICY_SOURCE_DISALLOW_SWAP) |
| |
| struct pdc_callback; |
| |
| /** |
| * @typedef |
| * @brief These are the API function types |
| */ |
| typedef void (*pdc_start_thread_t)(const struct device *dev); |
| typedef int (*pdc_get_ucsi_version_t)(const struct device *dev, |
| uint16_t *version); |
| typedef int (*pdc_reset_t)(const struct device *dev); |
| typedef int (*pdc_connector_reset_t)(const struct device *dev, |
| union connector_reset_t reset); |
| typedef int (*pdc_get_capability_t)(const struct device *dev, |
| struct capability_t *caps); |
| typedef int (*pdc_get_connector_capability_t)( |
| const struct device *dev, union connector_capability_t *caps); |
| typedef int (*pdc_set_ccom_t)(const struct device *dev, enum ccom_t ccom); |
| typedef int (*pdc_set_drp_mode_t)(const struct device *dev, enum drp_mode_t dm); |
| typedef int (*pdc_get_drp_mode_t)(const struct device *dev, |
| enum drp_mode_t *dm); |
| typedef int (*pdc_set_uor_t)(const struct device *dev, union uor_t uor); |
| typedef int (*pdc_set_pdr_t)(const struct device *dev, union pdr_t pdr); |
| typedef int (*pdc_set_sink_path_t)(const struct device *dev, bool en); |
| typedef int (*pdc_get_connector_status_t)( |
| const struct device *dev, union connector_status_t *connector_status); |
| typedef int (*pdc_get_error_status_t)(const struct device *dev, |
| union error_status_t *es); |
| typedef int (*pdc_set_handler_cb_t)(const struct device *dev, |
| struct pdc_callback *callback); |
| typedef void (*pdc_cci_cb_t)(const struct device *dev, |
| const struct pdc_callback *callback, |
| union cci_event_t cci_event); |
| typedef int (*pdc_get_vbus_t)(const struct device *dev, uint16_t *vbus); |
| typedef int (*pdc_get_pdos_t)(const struct device *dev, |
| enum pdo_type_t pdo_type, |
| enum pdo_offset_t pdo_offset, uint8_t num_pdos, |
| enum pdo_source_t source, uint32_t *pdos); |
| typedef int (*pdc_get_rdo_t)(const struct device *dev, uint32_t *rdo); |
| typedef int (*pdc_set_rdo_t)(const struct device *dev, uint32_t rdo); |
| typedef int (*pdc_get_info_t)(const struct device *dev, struct pdc_info_t *info, |
| bool live); |
| typedef int (*pdc_get_hw_config_t)(const struct device *dev, |
| struct pdc_hw_config_t *config); |
| typedef bool (*pdc_get_hw_frs_support_t)(const struct device *dev); |
| typedef int (*pdc_get_current_pdo_t)(const struct device *dev, uint32_t *pdo); |
| typedef int (*pdc_read_power_level_t)(const struct device *dev); |
| typedef int (*pdc_set_power_level_t)(const struct device *dev, |
| enum usb_typec_current_t tcc); |
| typedef int (*pdc_reconnect_t)(const struct device *dev); |
| typedef int (*pdc_update_retimer_fw_t)(const struct device *dev, bool enable); |
| typedef bool (*pdc_is_init_done_t)(const struct device *dev); |
| typedef int (*pdc_get_cable_property_t)(const struct device *dev, |
| union cable_property_t *cable_prop); |
| typedef int (*pdc_get_vdo_t)(const struct device *dev, union get_vdo_t req, |
| uint8_t *req_list, uint32_t *vdo); |
| typedef int (*pdc_get_identity_discovery_t)(const struct device *dev, |
| bool *disc_state); |
| typedef int (*pdc_set_comms_state_t)(const struct device *dev, bool active); |
| typedef int (*pdc_is_vconn_sourcing_t)(const struct device *dev, |
| bool *vconn_sourcing); |
| typedef int (*pdc_set_pdos_t)(const struct device *dev, enum pdo_type_t type, |
| uint32_t *pdo, int count); |
| typedef int (*pdc_get_pch_data_status_t)(const struct device *dev, |
| uint8_t port_num, uint8_t *status_reg); |
| typedef int (*pdc_execute_ucsi_cmd_t)(const struct device *dev, |
| uint8_t ucsi_command, uint8_t data_size, |
| uint8_t *command_specific, |
| uint8_t *lpm_data_out, |
| struct pdc_callback *callback); |
| typedef int (*pdc_manage_callback_t)(const struct device *dev, |
| struct pdc_callback *callback, bool set); |
| typedef int (*pdc_ack_cc_ci_t)(const struct device *dev, |
| union conn_status_change_bits_t ci, bool cc, |
| uint16_t vendor_defined); |
| typedef int (*pdc_get_lpm_ppm_info_t)(const struct device *dev, |
| struct lpm_ppm_info_t *info); |
| typedef int (*pdc_set_frs_t)(const struct device *dev, bool enable); |
| typedef int (*pdc_get_attention_vdo_t)(const struct device *dev, |
| union get_attention_vdo_t *vdo); |
| typedef int (*pdc_get_sbu_mux_mode_t)(const struct device *dev, |
| enum pdc_sbu_mux_mode *mode); |
| typedef int (*pdc_set_sbu_mux_mode_t)(const struct device *dev, |
| enum pdc_sbu_mux_mode mode); |
| typedef int (*pdc_set_ap_power_state_t)(const struct device *dev, |
| enum power_state state); |
| typedef int (*pdc_set_battery_capability_t)(const struct device *dev, |
| union battery_capability_t *bcap); |
| typedef int (*pdc_set_battery_status_t)(const struct device *dev, |
| union battery_status_t *bstat); |
| typedef int (*pdc_set_bbr_cts_t)(const struct device *dev, bool enable); |
| typedef int (*pdc_get_vendor_status_t)( |
| const struct device *dev, |
| union vendor_status_change_bits_t *vendor_status); |
| typedef int (*pdc_get_alert_t)(const struct device *dev, uint32_t *ado); |
| typedef int (*pdc_set_max_pdp_t)(const struct device *dev, |
| enum max_pdp_t max_pdp); |
| |
| /** |
| * @cond INTERNAL_HIDDEN |
| * |
| * These are for internal use only, so skip these in public documentation. |
| */ |
| __subsystem struct pdc_driver_api { |
| pdc_start_thread_t start_thread; |
| pdc_is_init_done_t is_init_done; |
| pdc_get_ucsi_version_t get_ucsi_version; |
| pdc_reset_t reset; |
| pdc_connector_reset_t connector_reset; |
| pdc_get_capability_t get_capability; |
| pdc_get_connector_capability_t get_connector_capability; |
| pdc_set_ccom_t set_ccom; |
| pdc_set_drp_mode_t set_drp_mode; |
| pdc_get_drp_mode_t get_drp_mode; |
| pdc_set_uor_t set_uor; |
| pdc_set_pdr_t set_pdr; |
| pdc_set_sink_path_t set_sink_path; |
| pdc_get_connector_status_t get_connector_status; |
| pdc_get_error_status_t get_error_status; |
| pdc_set_handler_cb_t set_handler_cb; |
| pdc_get_vbus_t get_vbus_voltage; |
| pdc_get_current_pdo_t get_current_pdo; |
| pdc_get_pdos_t get_pdos; |
| pdc_get_rdo_t get_rdo; |
| pdc_set_rdo_t set_rdo; |
| pdc_read_power_level_t read_power_level; |
| pdc_get_info_t get_info; |
| pdc_get_hw_config_t get_hw_config; |
| pdc_get_hw_frs_support_t get_hw_frs_support; |
| pdc_set_power_level_t set_power_level; |
| pdc_reconnect_t reconnect; |
| pdc_update_retimer_fw_t update_retimer; |
| pdc_get_cable_property_t get_cable_property; |
| pdc_get_vdo_t get_vdo; |
| pdc_get_identity_discovery_t get_identity_discovery; |
| pdc_set_comms_state_t set_comms_state; |
| pdc_is_vconn_sourcing_t is_vconn_sourcing; |
| pdc_set_pdos_t set_pdos; |
| pdc_get_pch_data_status_t get_pch_data_status; |
| pdc_execute_ucsi_cmd_t execute_ucsi_cmd; |
| pdc_manage_callback_t manage_callback; |
| pdc_ack_cc_ci_t ack_cc_ci; |
| pdc_get_lpm_ppm_info_t get_lpm_ppm_info; |
| pdc_set_frs_t set_frs; |
| pdc_get_attention_vdo_t get_attention_vdo; |
| pdc_get_sbu_mux_mode_t get_sbu_mux_mode; |
| pdc_set_sbu_mux_mode_t set_sbu_mux_mode; |
| pdc_set_ap_power_state_t set_ap_power_state; |
| pdc_set_battery_capability_t set_battery_capability; |
| pdc_set_battery_status_t set_battery_status; |
| pdc_set_bbr_cts_t set_bbr_cts; |
| pdc_get_vendor_status_t get_vendor_status; |
| pdc_get_alert_t get_alert; |
| pdc_set_max_pdp_t set_max_pdp; |
| }; |
| /** |
| * @endcond |
| */ |
| |
| /** |
| * @brief Starts the PDC driver thread |
| * |
| * @param dev PDC device structure pointer |
| */ |
| static inline void pdc_start_thread(const struct device *dev) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->start_thread != NULL, |
| "START_THREAD is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->start_thread(dev); |
| } |
| |
| /** |
| * @brief Tests if the PDC driver init process is complete |
| * |
| * @param dev PDC device structure pointer |
| * |
| * @retval true if PDC driver init process is complete, else false |
| */ |
| static inline bool pdc_is_init_done(const struct device *dev) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->is_init_done != NULL, |
| "IS_INIT_DONE is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->is_init_done(dev); |
| } |
| |
| /** |
| * @brief Trigger the PDC to read the power level when in Source mode. |
| * @note CCI Events set |
| * busy: If PDC is Busy |
| * error: If the connector is in Sink Mode or is disconnected |
| * command_completed: power level in source mode ready |
| * |
| * @param dev PDC device structure pointer |
| * |
| * @retval 0 on API call success |
| * @retval -EBUSY if not ready to execute the command |
| */ |
| static inline int pdc_read_power_level(const struct device *dev) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->read_power_level != NULL, |
| "READ_POWER_LEVEL is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->read_power_level(dev); |
| } |
| |
| /** |
| * @brief Read the version of the UCSI supported by the PDC. The version is |
| * read and cached during PDC initialization, so this call is |
| * synchronous and the version information is returned immediately |
| * to caller. |
| * @note CCI Events set |
| * <none> |
| * |
| * @param dev PDC device structure pointer |
| * |
| * @retval PDC Version number in BCD as an uint16. Format is JJMN, where (JJ – |
| * major version number, M – minor version number, N – sub-minor |
| * version number) |
| * @retval -EINVAL if caps is NULL |
| */ |
| static inline int pdc_get_ucsi_version(const struct device *dev, |
| uint16_t *version) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_ucsi_version != NULL, |
| "GET_UCSI_VERSION is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_ucsi_version(dev, version); |
| } |
| |
| /** |
| * @brief Resets the PDC |
| * @note CCI Events set |
| * reset_completed: PDC has been reset |
| * |
| * @param dev PDC device structure pointer |
| * |
| * @retval 0 on API call success |
| * @retval -EBUSY if not ready to execute the command |
| */ |
| static inline int pdc_reset(const struct device *dev) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->reset != NULL, |
| "RESET is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->reset(dev); |
| } |
| |
| /** |
| * @brief Resets a PDC connector |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: connector was reset |
| * |
| * @param dev PDC device structure pointer |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| */ |
| static inline int pdc_connector_reset(const struct device *dev, |
| union connector_reset_t reset) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->connector_reset != NULL, |
| "CONNECTOR_RESET is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->connector_reset(dev, reset); |
| } |
| |
| /** |
| * @brief Set the Sink FET state while in the Attached Sink State |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: sink path was set |
| * |
| * @param dev PDC device structure pointer |
| * @param en true to enable the Sink FET or false to disable it |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| */ |
| static inline int pdc_set_sink_path(const struct device *dev, bool en) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->set_sink_path != NULL, |
| "SET_SINK_PATH is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->set_sink_path(dev, en); |
| } |
| |
| /** |
| * @brief Gets the PDC device capabilities. |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: capability was retrieved |
| * |
| * @param dev PDC device structure pointer |
| * @param caps pointer where the device capabilities are stored. |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if caps is NULL |
| */ |
| static inline int pdc_get_capability(const struct device *dev, |
| struct capability_t *caps) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_capability != NULL, |
| "GET_CAPABILITY is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_capability(dev, caps); |
| } |
| |
| /** |
| * @brief Gets the PDC connector status. |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: connector status was retrieved |
| * @note cci_event.command_completed_indicator is set when the UCSI command |
| * completes. |
| * @note cci_event.error_indicator is set if the UCSI command was |
| * unsuccessful. |
| * |
| * @param dev PDC device structure pointer |
| * @param cs pointer where the connector status is stored. |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if cs is NULL |
| */ |
| static inline int |
| pdc_get_connector_status(const struct device *dev, |
| union connector_status_t *connector_status) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_connector_status != NULL, |
| "GET_CONNECTOR_STATUS is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_connector_status(dev, |
| connector_status); |
| } |
| |
| /** |
| * @brief Gets the details about an error, if the cci_event.error_indicator is |
| * set. |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: error status was retrieved |
| * |
| * @param dev PDC device structure pointer |
| * @param es pointer where the error status is stored. |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if es is NULL |
| */ |
| static inline int pdc_get_error_status(const struct device *dev, |
| union error_status_t *es) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_error_status != NULL, |
| "GET_ERROR_STATUS is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_error_status(dev, es); |
| } |
| |
| /** |
| * @brief Gets capabilities of a connector |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: connector caps were retrieved |
| * |
| * @param dev PDC device structure pointer |
| * @param caps pointer where the connector capabilities are stored. |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if caps is NULL |
| */ |
| static inline int |
| pdc_get_connector_capability(const struct device *dev, |
| union connector_capability_t *caps) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_connector_capability != NULL, |
| "GET_CONNECTOR_CAPABILITY is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_connector_capability(dev, caps); |
| } |
| |
| /** |
| * @brief Sets the CC operation mode of the PDC |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: CCOM was set |
| * |
| * @param dev PDC device structure pointer |
| * @param ccom CC operation mode |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -ENOSYS if not implemented |
| */ |
| static inline int pdc_set_ccom(const struct device *dev, enum ccom_t ccom) |
| { |
| /* This is an optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->set_ccom == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_ccom(dev, ccom); |
| } |
| |
| /** |
| * @brief Sets the DRP mode of the PDC |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: DRP mode was set |
| * |
| * @param dev PDC device structure pointer |
| * @param dm DRP mode |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -ENOSYS if not implemented |
| */ |
| static inline int pdc_set_drp_mode(const struct device *dev, enum drp_mode_t dm) |
| { |
| /* This is an optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->set_drp_mode == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_drp_mode(dev, dm); |
| } |
| |
| static inline int pdc_get_drp_mode(const struct device *dev, |
| enum drp_mode_t *dm) |
| { |
| /* This is an optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->get_drp_mode == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->get_drp_mode(dev, dm); |
| } |
| |
| /** |
| * @brief Sets the USB operation role of the PDC |
| * @note CCI Events set |
| * busy: if the PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: UOR was set |
| * |
| * @param dev PDC device structure pointer |
| * @param uor USB operation role |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| */ |
| static inline int pdc_set_uor(const struct device *dev, union uor_t uor) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->set_uor != NULL, |
| "SET_UOR is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->set_uor(dev, uor); |
| } |
| |
| /** |
| * @brief Sets the Power direction role of the PDC |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: command was unsuccessful |
| * command_commpleted: PDR was set |
| * |
| * @param dev PDC device structure pointer |
| * @param pdr Power direction role |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if \p policy is invalid |
| */ |
| static inline int pdc_set_pdr(const struct device *dev, |
| enum pdc_power_policy policy) |
| { |
| union pdr_t pdr = { 0 }; |
| |
| __ASSERT(DEVICE_API_GET(pdc, dev)->set_pdr != NULL, |
| "SET_PDR is not optional"); |
| |
| switch (policy) { |
| case PDC_POWER_POLICY_SINK_ALLOW_SWAP: |
| pdr.swap_to_src = 0; |
| pdr.swap_to_snk = 1; |
| pdr.accept_pr_swap = 1; |
| break; |
| case PDC_POWER_POLICY_SINK_DISALLOW_SWAP: |
| pdr.swap_to_src = 0; |
| pdr.swap_to_snk = 1; |
| pdr.accept_pr_swap = 0; |
| break; |
| case PDC_POWER_POLICY_SOURCE_ALLOW_SWAP: |
| pdr.swap_to_src = 1; |
| pdr.swap_to_snk = 0; |
| pdr.accept_pr_swap = 1; |
| break; |
| case PDC_POWER_POLICY_SOURCE_DISALLOW_SWAP: |
| pdr.swap_to_src = 1; |
| pdr.swap_to_snk = 0; |
| pdr.accept_pr_swap = 0; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_pdr(dev, pdr); |
| } |
| |
| /** |
| * @brief Sets the callback the driver uses to communicate CC events to the |
| * TCPM. |
| * @note CCI Events set |
| * <none> |
| * |
| * @param dev PDC device structure pointer |
| * @param callback Pointer to callback |
| */ |
| static inline void pdc_set_cc_callback(const struct device *dev, |
| struct pdc_callback *callback) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->set_handler_cb != NULL, |
| "SET_HANDLER_CB is not optional"); |
| |
| DEVICE_API_GET(pdc, dev)->set_handler_cb(dev, callback); |
| } |
| |
| /** |
| * @brief Reads the VBUS voltage |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: if port isn't connected |
| * command_commpleted: VBUS voltage was read |
| * |
| * @param dev PDC device structure pointer |
| * @param voltage pointer to where the voltage is stored |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if voltage pointer is NULL |
| */ |
| static inline int pdc_get_vbus_voltage(const struct device *dev, |
| uint16_t *voltage) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_vbus_voltage != NULL, |
| "GET_VBUS_VOLTAGE is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_vbus_voltage(dev, voltage); |
| } |
| |
| /** |
| * @brief Gets the Sink or Source PDOs associated with the connector |
| * @note CCI Events set |
| * busy: if the PDC is busy |
| * error: the Port is not PD connected |
| * command_commpleted: PDOs have been retrieved |
| * |
| * @param dev PDC device structure pointer |
| * @param pdo_type Whether to retrieve source or sink PDOs |
| * @param pdo_offset starting offset of the first PDO to be returned. Valid |
| * values are 0 to 7. |
| * @param num_pdos number of PDOs to return starting from the PDO offset. NOTE: |
| * the number of PDOs returned is num + 1. Max is UCSI_GET_PDOS_MAX_NUM. |
| * @param source Whether to retrieve the LPM's (PDC) or port partner's PDOs. |
| * @param pdos pointer to where the PDOs are outputted to. |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if pdos is NULL |
| * @retval -ENOSYS if not implemented |
| */ |
| static inline int pdc_get_pdos(const struct device *dev, |
| enum pdo_type_t pdo_type, |
| enum pdo_offset_t pdo_offset, uint8_t num_pdos, |
| enum pdo_source_t source, uint32_t *pdos) |
| { |
| /* This is an optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->get_pdos == NULL) { |
| return -ENOSYS; |
| } |
| |
| __ASSERT(num_pdos <= UCSI_GET_PDOS_MAX_NUM, |
| "GET_PDOS supports a maximum count of " STRINGIFY( |
| UCSI_GET_PDOS_MAX_NUM) " PDOs"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_pdos(dev, pdo_type, pdo_offset, |
| num_pdos, source, pdos); |
| } |
| |
| /** |
| * @brief Get information about the PDC |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: if the the info could not be retrieved |
| * command_completed: if the info was received |
| * |
| * @param dev PDC device structure pointer |
| * @param info pointer to where the PDC information is stored |
| * @param live If true, force a read from chip. Else used cached version. |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if fw_version pointers is NULL |
| */ |
| static inline int pdc_get_info(const struct device *dev, |
| struct pdc_info_t *info, bool live) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_info != NULL, |
| "GET_INFO is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_info(dev, info, live); |
| } |
| |
| /** |
| * @brief Get bus interface hw config about the PDC |
| * |
| * @param dev PDC device structure pointer |
| * @param config Output struct for hw config |
| * |
| * @retval 0 on success |
| * @retval -EINVAL if info pointer is NULL |
| */ |
| static inline int pdc_get_hw_config(const struct device *dev, |
| struct pdc_hw_config_t *config) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_hw_config != NULL, |
| "GET_HW_CONFIG is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_hw_config(dev, config); |
| } |
| |
| /** |
| * @brief Get the Requested Data Object sent to the Source |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: if the port partner is a Sink |
| * command_commpleted: if the RDO was retrieved |
| * |
| * @param dev PDC device structure pointer |
| * @param rdo pointer to where the RDO is stored |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if rdo pointer is NULL |
| */ |
| static inline int pdc_get_rdo(const struct device *dev, uint32_t *rdo) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_rdo != NULL, |
| "GET_RDO is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_rdo(dev, rdo); |
| } |
| |
| /** |
| * @brief Sends a Requested Data Object to the attached Source |
| * @note CCI Events set |
| * busy: if the PDC is busy |
| * error: if the port partner is a Sink |
| * command_commpleted: RDO was sent to port partner |
| * |
| * @param dev PDC device structure pointer |
| * @param rdo RDO to send to the Source |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| */ |
| static inline int pdc_set_rdo(const struct device *dev, uint32_t rdo) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->set_rdo != NULL, |
| "SET_RDO is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->set_rdo(dev, rdo); |
| } |
| |
| /** |
| * @brief Get the currently selected PDO that was requested from the Source |
| * @note CCI Events set |
| * busy: if the PDC is busy |
| * error: if the port isn't PD connected, or port partner is a Sink |
| * command_commpleted: PDO has been retrieved |
| * |
| * @param dev PDC device structure pointer |
| * @param pdo pointer to where the PDO is stored |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if pdo pointer is NULL |
| * @retval -ENOSYS if not implemented |
| */ |
| static inline int pdc_get_current_pdo(const struct device *dev, uint32_t *pdo) |
| { |
| /* This is an optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->get_current_pdo == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->get_current_pdo(dev, pdo); |
| } |
| |
| /** |
| * @brief Sets the TypeC Rp current resistor. |
| * @note This command isn't compliant with the UCSI spec |
| * @note CCI Events set |
| * busy: if the PDC is busy |
| * error: if the command couldn't be executed |
| * command_commpleted: the Rp was set |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if tcc is set to TC_CURRENT_PPM_DEFINED |
| * @retval -ENOSYS if not implemented |
| */ |
| static inline int pdc_set_power_level(const struct device *dev, |
| enum usb_typec_current_t tcc) |
| { |
| /* This is an optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->set_power_level == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_power_level(dev, tcc); |
| } |
| |
| /** |
| * @brief Perform a Type-C reconnect |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: if port isn't connected |
| * command_commpleted: if the port has reconnected |
| * |
| * @param dev PDC device structure pointer |
| * |
| * @retval 0 on API call success |
| * @retval -EIO on failure |
| * @retval -ENOSYS if not implemented |
| */ |
| static inline int pdc_reconnect(const struct device *dev) |
| { |
| /* This is an optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->reconnect == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->reconnect(dev); |
| } |
| |
| /** |
| * @brief Command PD chip to enter retimer firmware update mode. |
| * |
| * @param enable True->enter, False->exit retimer firmware update mode. |
| * |
| * @retval 0 if success or I2C error. |
| * @retval -EIO if input/output error. |
| * @retval -ENOSYS if API not implemented. |
| */ |
| static inline int pdc_update_retimer_fw(const struct device *dev, bool enable) |
| { |
| /* Temporarily optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->update_retimer == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->update_retimer(dev, enable); |
| } |
| |
| /** |
| * @brief Command to get the PDC PCH DATA STATUS REG value. |
| * |
| * @param enable True->enter, False->exit get pch data status. |
| * |
| * @retval 0 if success. |
| * @retval -EIO if input/output error. |
| * @retval -ENOSYS if API not implemented. |
| */ |
| static inline int pdc_get_pch_data_status(const struct device *dev, |
| uint8_t port_num, uint8_t *status_reg) |
| { |
| /* Temporarily optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->get_pch_data_status == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->get_pch_data_status(dev, port_num, |
| status_reg); |
| } |
| |
| /** |
| * @brief Gets the attached cable properties |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: treated as non-emarker cable |
| * command_commpleted: capability was retrieved |
| * |
| * @param dev PDC device structure pointer |
| * @param cable_prop pointer where the cable properties are stored |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if caps is NULL |
| */ |
| static inline int pdc_get_cable_property(const struct device *dev, |
| union cable_property_t *cable_prop) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_cable_property != NULL, |
| "GET_CABLE_PROPERTY is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_cable_property(dev, cable_prop); |
| } |
| |
| /** |
| * @brief Get the Requested VDO objects |
| * @note CCI Events set |
| * busy: if PDC is busy |
| * error: |
| * command_commpleted: if the VDOs were retrieved |
| * |
| * @param dev PDC device structure pointer |
| * @param vdo pointer to where the VDOs are stored |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -EINVAL if vdo pointer is NULL |
| */ |
| static inline int pdc_get_vdo(const struct device *dev, union get_vdo_t vdo_req, |
| uint8_t *vdo_list, uint32_t *vdo) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_vdo != NULL, |
| "GET_VDO is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_vdo(dev, vdo_req, vdo_list, vdo); |
| } |
| |
| /** |
| * @brief get the state of the discovery process |
| * |
| * @param dev PDC device structure pointer |
| * @param disc_state pointer where the discovery state is stored. True if |
| * discovery is complete, else False |
| * |
| * @retval 0 on success |
| * @retval -ENOSYS if not implemented |
| * @retval -EINVAL if disc_state is NULL |
| */ |
| static inline int pdc_get_identity_discovery(const struct device *dev, |
| bool *disc_state) |
| { |
| if (DEVICE_API_GET(pdc, dev)->get_identity_discovery == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->get_identity_discovery(dev, |
| disc_state); |
| } |
| |
| /** |
| * @brief Control if the driver can communicate with the PDC. |
| * |
| * @param dev PDC device structure pointer |
| * @param comms_active True to allow PDC communication, false to end |
| * communication |
| * |
| * @retval 0 if success |
| */ |
| static inline int pdc_set_comms_state(const struct device *dev, |
| bool comms_active) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->set_comms_state != NULL, |
| "set_comms_state is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->set_comms_state(dev, comms_active); |
| } |
| |
| /** |
| * @brief Sends a Power Data Object to the PDC |
| * @note CCI Events set |
| * busy: if the PDC is busy |
| * command_commpleted: PDO was sent to LPM or port partner |
| * |
| * @param dev PDC device structure pointer |
| * @param type SINK_PDO or SOURCE_PDO |
| * @param pdo Pointer to PDO array |
| * @param count Number of PDOs to send |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| * @retval -ERANGE if the count is not supported |
| * @retval -EINVAL if \p pdo is NULL |
| */ |
| static inline int pdc_set_pdos(const struct device *dev, enum pdo_type_t type, |
| uint32_t *pdo, int count) |
| { |
| if (DEVICE_API_GET(pdc, dev)->set_pdos == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_pdos(dev, type, pdo, count); |
| } |
| |
| /** |
| * @brief Checks if the port is sourcing VCONN |
| * |
| * @param dev PDC device structure pointer |
| * @param vconn_sourcing True if the port is sourcing VCONN, else false |
| * |
| * @retval 0 if success |
| * @retval -ENOSYS if not implemented |
| * @retval -EINVAL if vconn_sourcing is NULL |
| */ |
| static inline int pdc_is_vconn_sourcing(const struct device *dev, |
| bool *vconn_sourcing) |
| { |
| if (DEVICE_API_GET(pdc, dev)->is_vconn_sourcing == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->is_vconn_sourcing(dev, vconn_sourcing); |
| } |
| |
| /** |
| * @brief Acknowledge command complete (cc) or change indicator (ci) |
| * @note CCI Events set |
| * busy: if the PDC is busy |
| * error: if command fails |
| * command_commpleted: ack_cc_ci write successful |
| * |
| * @param dev PDC device structure pointer |
| * @param ci Change Indicator bits |
| * @param cc Complete complete bit |
| * @param vendor_defined Vendor specified change indicator bits |
| * |
| * @retval 0 on success |
| * @retval -EBUSY if not ready to execute the command |
| */ |
| static inline int pdc_ack_cc_ci(const struct device *dev, |
| union conn_status_change_bits_t ci, bool cc, |
| uint16_t vendor_defined) |
| { |
| if (DEVICE_API_GET(pdc, dev)->ack_cc_ci == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->ack_cc_ci(dev, ci, cc, vendor_defined); |
| } |
| |
| /** |
| * @brief PDC message type or chip type identifiers. These are 8-bit |
| * values. |
| */ |
| enum pdc_trace_chip_type { |
| PDC_TRACE_CHIP_TYPE_UNSPEC = 0, |
| PDC_TRACE_CHIP_TYPE_RTS54XX = 0x54, |
| }; |
| |
| /** |
| * @brief Log outgoing PDC message for tracing |
| * |
| * @param port Type-C port number |
| * @param msg_type Message type (hint how to interpret message) |
| * @param buf Message to log |
| * @param count Message length |
| * |
| * @retval true IFF pushed into FIFO |
| */ |
| bool pdc_trace_msg_req(int port, enum pdc_trace_chip_type msg_type, |
| const uint8_t *buf, const int count); |
| |
| /** |
| * @brief Log incoming PDC message for tracing |
| * |
| * @param port Type-C port number |
| * @param msg_type Message type (hint how to interpret message) |
| * @param buf Message to log |
| * @param count Message length |
| * |
| * @retval true IFF pushed into FIFO |
| */ |
| bool pdc_trace_msg_resp(int port, enum pdc_trace_chip_type msg_type, |
| const uint8_t *buf, const int count); |
| |
| /** |
| * @brief Execute UCSI command synchronously |
| * |
| * @param dev PDC device structure pointer |
| * @param ucsi_command UCSI command |
| * @param data_size Size of the command specific data. |
| * @param command_specific Command specific data to be sent |
| * @param lpm_data_out Buffer to receive data returned from a PDC |
| * |
| * @return 0 on success |
| * @return -EBUSY if PDC is busy with serving another request. |
| * @return -ECONNREFUSED if PDC is suspended. |
| * @retval -ENOSYS if not implemented |
| * @return -ETIMEDOUT if timer expires while waiting for write or read operation |
| * to finish. |
| */ |
| static inline int pdc_execute_ucsi_cmd(const struct device *dev, |
| uint8_t ucsi_command, uint8_t data_size, |
| uint8_t *command_specific, |
| uint8_t *lpm_data_out, |
| struct pdc_callback *callback) |
| { |
| if (DEVICE_API_GET(pdc, dev)->execute_ucsi_cmd == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->execute_ucsi_cmd( |
| dev, ucsi_command, data_size, command_specific, lpm_data_out, |
| callback); |
| } |
| |
| /** |
| * @brief Add callback for connector change events. |
| * |
| * @param dev PDC device structure pointer |
| * @param callback Callback handler and data |
| * |
| * @return 0 on success |
| * @return -ENOSYS if not implemented |
| * @return -EINVAL for other errors |
| */ |
| static inline int pdc_add_ci_callback(const struct device *dev, |
| struct pdc_callback *callback) |
| { |
| if (DEVICE_API_GET(pdc, dev)->manage_callback == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->manage_callback(dev, callback, true); |
| } |
| |
| /** |
| * @brief Query UCSI LPM PPM info |
| * |
| * @param dev PDC device structure pointer |
| * @param info Caller-provided output struct for received data |
| * |
| * @return 0 on success |
| * @return -ENOSYS if not implemented |
| * @return -EINVAL for other errors |
| */ |
| static inline int pdc_get_lpm_ppm_info(const struct device *dev, |
| struct lpm_ppm_info_t *info) |
| { |
| if (DEVICE_API_GET(pdc, dev)->get_lpm_ppm_info == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->get_lpm_ppm_info(dev, info); |
| } |
| |
| /** |
| * @typedef pdc_callback_handler_t |
| * @brief Define the application callback handler function signature |
| * |
| * @param port Device struct for the PDC device. |
| * @param cb Original struct pdc_callback owning this handler |
| * @param pins Mask of pins that triggers the callback handler |
| * |
| * Note: cb pointer can be used to retrieve private data through |
| * CONTAINER_OF() if original struct pdc_callback is stored in |
| * another private structure. |
| */ |
| typedef void (*pdc_callback_handler_t)(const struct device *port, |
| struct pdc_callback *cb, |
| union cci_event_t cci_event); |
| |
| /** |
| * @brief PDC callback structure |
| * |
| * Used to register a callback in the driver instance callback list. |
| * As many callbacks as needed can be added as long as each of them |
| * are unique pointers of struct pdc_callback. |
| * Beware such structure should not be allocated on stack. |
| */ |
| struct pdc_callback { |
| /** This is meant to be used in the driver and the user should not |
| * mess with it. |
| */ |
| sys_snode_t node; |
| |
| /** Actual callback function being called when relevant. */ |
| pdc_cci_cb_t handler; |
| }; |
| |
| /** |
| * @brief Generic function to append or remove a callback from a callback list |
| * @note This should only be called by PDC drivers and not the user. |
| * |
| * @param callbacks A pointer to the original list of callbacks (can be NULL) |
| * @param callback A pointer of the callback to append or remove from the list |
| * @param set A boolean indicating insertion or removal of the callback |
| * |
| * @return 0 on success, negative errno otherwise. |
| */ |
| static inline int pdc_manage_callbacks(sys_slist_t *callbacks, |
| struct pdc_callback *callback, bool set) |
| { |
| __ASSERT(callback, "No callback!"); |
| __ASSERT(callback->handler, "No callback handler!"); |
| |
| if (!sys_slist_is_empty(callbacks)) { |
| if (!sys_slist_find_and_remove(callbacks, &callback->node)) { |
| if (!set) { |
| return -EINVAL; |
| } |
| } |
| } else if (!set) { |
| return -EINVAL; |
| } |
| |
| if (set) { |
| sys_slist_append(callbacks, &callback->node); |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * @brief Generic function to go through and fire callback from a callback list |
| * @note This should only be called by PDC drivers and not the user. |
| * |
| * @param list A pointer on the gpio callback list |
| * @param dev A pointer to the PDC device instance |
| * @param cci_event The actual CCI event mask that triggered the interrupt |
| */ |
| static inline void pdc_fire_callbacks(sys_slist_t *list, |
| const struct device *dev, |
| union cci_event_t cci_event) |
| { |
| struct pdc_callback *cb, *tmp; |
| |
| SYS_SLIST_FOR_EACH_CONTAINER_SAFE(list, cb, tmp, node) |
| { |
| __ASSERT(cb->handler, "No callback handler!"); |
| cb->handler(dev, cb, cci_event); |
| } |
| } |
| |
| /** |
| * @brief Enable or disable fast role swap (FRS). |
| * |
| * @param dev Pointer to the PDC device instance |
| * @param enable Set to true to enable FRS, set to false to disable FRS |
| * @return 0 on success, negative errno otherwise |
| */ |
| static inline int pdc_set_frs(const struct device *dev, bool enable) |
| { |
| if (DEVICE_API_GET(pdc, dev)->set_frs == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_frs(dev, enable); |
| } |
| |
| /** |
| * @brief Get whether or not the PDC supports FRS. |
| * |
| * @param dev Pointer to the PDC device instance |
| * @param config Pointer to the PDC hardware configuration structure |
| * @return true if the PDC supports FRS, false otherwise. |
| */ |
| static inline bool pdc_get_frs_supported(const struct device *dev) |
| { |
| __ASSERT(DEVICE_API_GET(pdc, dev)->get_hw_frs_support != NULL, |
| "GET_FRS_SUPPORTED is not optional"); |
| |
| return DEVICE_API_GET(pdc, dev)->get_hw_frs_support(dev); |
| } |
| |
| /** |
| * @brief UCSI command to request an Attention VDO received from the partner |
| * @param dev PDC device structure pointer |
| * @param get_attention_vdo_t pointer where the GET_ATTENTION_VDO response is |
| * stored. |
| * @return 0 on success, negative errno otherwise |
| */ |
| static inline int pdc_get_attention_vdo(const struct device *dev, |
| union get_attention_vdo_t *vdo) |
| { |
| if (DEVICE_API_GET(pdc, dev)->get_attention_vdo == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->get_attention_vdo(dev, vdo); |
| } |
| |
| /** |
| * @brief Vendor command to query current SBU mux operational mode |
| * @param dev PDC device structure pointer |
| * @param mode Output pointer for current mode to be written to |
| * @return 0 on success, or negative error code |
| */ |
| static inline int pdc_get_sbu_mux_mode(const struct device *dev, |
| enum pdc_sbu_mux_mode *mode) |
| { |
| if (DEVICE_API_GET(pdc, dev)->get_sbu_mux_mode == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->get_sbu_mux_mode(dev, mode); |
| } |
| |
| /** |
| * @brief Vendor command to set the SBU mux operational mode |
| * @param dev PDC device structure pointer |
| * @param mode Mode to set the SBU mux to |
| * @return 0 on success, or negative error code |
| */ |
| static inline int pdc_set_sbu_mux_mode(const struct device *dev, |
| enum pdc_sbu_mux_mode mode) |
| { |
| if (mode < 0 || mode >= PDC_SBU_MUX_MODE_MAX) { |
| return -EINVAL; |
| } |
| |
| if (DEVICE_API_GET(pdc, dev)->set_sbu_mux_mode == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_sbu_mux_mode(dev, mode); |
| } |
| |
| /** |
| * @brief Notify the PDC of the current AP power state |
| * |
| * @param dev Pointer to the PDC device instance |
| * @param power_state New AP power state |
| * @return 0 on success, negative errno otherwise |
| */ |
| static inline int pdc_set_ap_power_state(const struct device *dev, |
| enum power_state state) |
| { |
| if (DEVICE_API_GET(pdc, dev)->set_ap_power_state == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_ap_power_state(dev, state); |
| } |
| |
| /** |
| * @brief Set the battery capability response on PDC. |
| * |
| * @param dev Pointer to the PDC device instance |
| * @param bcap Battery capability |
| * @return 0 on success, negative errno otherwise |
| */ |
| static inline int pdc_set_battery_capability(const struct device *dev, |
| union battery_capability_t *bcap) |
| { |
| if (DEVICE_API_GET(pdc, dev)->set_battery_capability == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_battery_capability(dev, bcap); |
| } |
| |
| /** |
| * @brief Set the battery status response on PDC. |
| * |
| * @param dev Pointer to the PDC device instance |
| * @param bstat Battery status |
| * @return 0 on success, negative errno otherwise |
| */ |
| static inline int pdc_set_battery_status(const struct device *dev, |
| union battery_status_t *bstat) |
| { |
| if (DEVICE_API_GET(pdc, dev)->set_battery_status == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_battery_status(dev, bstat); |
| } |
| |
| /** |
| * @brief Configure PDC for BBR compliance test |
| * |
| * @param dev PDC device structure pointer |
| * @param enable Enable or disable BBR test mode |
| * |
| * @retval 0 on success |
| * @retval -ENOSYS if not implemented |
| */ |
| static inline int pdc_set_bbr_cts(const struct device *dev, bool enable) |
| { |
| if (DEVICE_API_GET(pdc, dev)->set_bbr_cts == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->set_bbr_cts(dev, enable); |
| } |
| |
| static inline int |
| pdc_get_vendor_status(const struct device *dev, |
| union vendor_status_change_bits_t *vendor_status) |
| { |
| /* This is an optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->get_vendor_status == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->get_vendor_status(dev, vendor_status); |
| } |
| |
| static inline int pdc_get_alert(const struct device *dev, uint32_t *ado) |
| { |
| /* This is an optional feature, so it might not be implemented */ |
| if (DEVICE_API_GET(pdc, dev)->get_alert == NULL) { |
| return -ENOSYS; |
| } |
| |
| return DEVICE_API_GET(pdc, dev)->get_alert(dev, ado); |
| } |
| |
| static inline int pdc_set_max_pdp(const struct device *dev, |
| enum max_pdp_t max_pdp) |
| { |
| const struct pdc_driver_api *api = |
| (const struct pdc_driver_api *)dev->api; |
| |
| if (api->set_max_pdp == NULL) { |
| return -ENOSYS; |
| } |
| |
| return api->set_max_pdp(dev, max_pdp); |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| /** |
| * @} |
| */ |
| |
| #endif /* ZEPHYR_INCLUDE_DRIVERS_PDC_H_ */ |