From 0bae208778a658b016bb427e99e7e8683748583b Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 1 Mar 2022 12:45:21 +0100 Subject: [PATCH] drivers: can: add support for getting the maximum supported bitrate Add support for getting the maximum supported bitrate in bits/s for CAN controller/transceiver combination and check that a requested bitrate is within the supported range. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_handlers.c | 14 ++++++++--- include/drivers/can.h | 50 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/drivers/can/can_handlers.c b/drivers/can/can_handlers.c index 4fa1f47ef7f..a91505969f1 100644 --- a/drivers/can/can_handlers.c +++ b/drivers/can/can_handlers.c @@ -22,7 +22,6 @@ static inline int z_vrfy_can_set_timing(const struct device *dev, static inline int z_vrfy_can_get_core_clock(const struct device *dev, uint32_t *rate) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, get_core_clock)); Z_OOPS(Z_SYSCALL_MEMORY_WRITE(rate, sizeof(rate))); @@ -30,6 +29,16 @@ static inline int z_vrfy_can_get_core_clock(const struct device *dev, } #include +static inline int z_vrfy_can_get_max_bitrate(const struct device *dev, + uint32_t *max_bitrate) +{ + Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, get_max_bitrate)); + Z_OOPS(Z_SYSCALL_MEMORY_WRITE(max_bitrate, sizeof(*max_bitrate))); + + return z_impl_can_get_max_bitrate(dev, max_bitrate); +} +#include + static inline int z_vrfy_can_send(const struct device *dev, const struct zcan_frame *frame, k_timeout_t timeout, @@ -73,7 +82,6 @@ static inline int z_vrfy_can_add_rx_filter_msgq(const struct device *dev, static inline void z_vrfy_can_remove_rx_filter(const struct device *dev, int filter_id) { - Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, remove_rx_filter)); z_impl_can_remove_rx_filter((const struct device *)dev, (int)filter_id); @@ -84,7 +92,6 @@ static inline int z_vrfy_can_get_state(const struct device *dev, enum can_state *state, struct can_bus_err_cnt *err_cnt) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); if (state != NULL) { @@ -103,7 +110,6 @@ int z_vrfy_can_get_state(const struct device *dev, enum can_state *state, static inline int z_vrfy_can_recover(const struct device *dev, k_timeout_t timeout) { - Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); return z_impl_can_recover(dev, k_timeout_t timeout); diff --git a/include/drivers/can.h b/include/drivers/can.h index 535a9065684..8391c25b90a 100644 --- a/include/drivers/can.h +++ b/include/drivers/can.h @@ -371,6 +371,13 @@ typedef int (*can_get_core_clock_t)(const struct device *dev, uint32_t *rate); */ typedef int (*can_get_max_filters_t)(const struct device *dev, enum can_ide id_type); +/** + * @typedef can_get_max_bitrate_t + * @brief Callback API upon getting the maximum supported bitrate + * See @a can_get_max_bitrate() for argument description + */ +typedef int (*can_get_max_bitrate_t)(const struct device *dev, uint32_t *max_bitrate); + __subsystem struct can_driver_api { can_set_mode_t set_mode; can_set_timing_t set_timing; @@ -384,6 +391,7 @@ __subsystem struct can_driver_api { can_set_state_change_callback_t set_state_change_callback; can_get_core_clock_t get_core_clock; can_get_max_filters_t get_max_filters; + can_get_max_bitrate_t get_max_bitrate; /* Min values for the timing registers */ struct can_timing timing_min; /* Max values for the timing registers */ @@ -624,6 +632,30 @@ static inline int z_impl_can_get_core_clock(const struct device *dev, uint32_t * return api->get_core_clock(dev, rate); } +/** + * @brief Get maximum supported bitrate + * + * Get the maximum supported bitrate for the CAN controller/transceiver combination. + * + * @param dev Pointer to the device structure for the driver instance. + * @param[out] max_bitrate Maximum supported bitrate in bits/s + * + * @retval -EIO General input/output error. + * @retval -ENOSYS If this function is not implemented by the driver. + */ +__syscall int can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate); + +static inline int z_impl_can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) +{ + const struct can_driver_api *api = (const struct can_driver_api *)dev->api; + + if (api->get_max_bitrate == NULL) { + return -ENOSYS; + } + + return api->get_max_bitrate(dev, max_bitrate); +} + /** * @brief Calculate timing parameters from bitrate and sample point * @@ -755,6 +787,7 @@ static inline int z_impl_can_set_mode(const struct device *dev, enum can_mode mo * @param bitrate_data Desired data phase bitrate. * * @retval 0 If successful. + * @retval -ENOTSUP bitrate not supported by CAN controller/transceiver combination * @retval -EINVAL bitrate cannot be met. * @retval -EIO General input/output error, failed to set bitrate. */ @@ -766,8 +799,21 @@ static inline int can_set_bitrate(const struct device *dev, #ifdef CONFIG_CAN_FD_MODE struct can_timing timing_data; #endif + uint32_t max_bitrate; int ret; + ret = can_get_max_bitrate(dev, &max_bitrate); + if (ret == -ENOSYS) { + /* Maximum bitrate unknown */ + max_bitrate = 0; + } else if (ret < 0) { + return ret; + } + + if ((max_bitrate > 0) && (bitrate > max_bitrate)) { + return -ENOTSUP; + } + ret = can_calc_timing(dev, &timing, bitrate, 875); if (ret < 0) { return -EINVAL; @@ -776,6 +822,10 @@ static inline int can_set_bitrate(const struct device *dev, timing.sjw = CAN_SJW_NO_CHANGE; #ifdef CONFIG_CAN_FD_MODE + if ((max_bitrate > 0) && (bitrate_data > max_bitrate)) { + return -ENOTSUP; + } + ret = can_calc_timing_data(dev, &timing_data, bitrate_data, 875); if (ret < 0) { return -EINVAL;