drivers: can: check timing parameters

Check the requested CAN timing parameters against the min/max values
supported by the driver and return an error if they are out of range.

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
Henrik Brix Andersen 2023-03-17 11:21:26 +01:00 committed by Carles Cufí
commit d5672c9ee3
2 changed files with 62 additions and 27 deletions

View file

@ -250,6 +250,41 @@ static uint16_t sample_point_for_bitrate(uint32_t bitrate)
return sample_pnt;
}
static int check_timing_in_range(const struct can_timing *timing,
const struct can_timing *min,
const struct can_timing *max)
{
if (timing->sjw != CAN_SJW_NO_CHANGE &&
!IN_RANGE(timing->sjw, min->sjw, max->sjw)) {
return -ENOTSUP;
}
if (!IN_RANGE(timing->prop_seg, min->prop_seg, max->prop_seg) ||
!IN_RANGE(timing->phase_seg1, min->phase_seg1, max->phase_seg1) ||
!IN_RANGE(timing->phase_seg2, min->phase_seg2, max->phase_seg2) ||
!IN_RANGE(timing->prescaler, min->prescaler, max->prescaler)) {
return -ENOTSUP;
}
return 0;
}
int z_impl_can_set_timing(const struct device *dev,
const struct can_timing *timing)
{
const struct can_driver_api *api = (const struct can_driver_api *)dev->api;
const struct can_timing *min = can_get_timing_min(dev);
const struct can_timing *max = can_get_timing_max(dev);
int err;
err = check_timing_in_range(timing, min, max);
if (err != 0) {
return err;
}
return api->set_timing(dev, timing);
}
int z_impl_can_set_bitrate(const struct device *dev, uint32_t bitrate)
{
struct can_timing timing;
@ -285,6 +320,26 @@ int z_impl_can_set_bitrate(const struct device *dev, uint32_t bitrate)
}
#ifdef CONFIG_CAN_FD_MODE
int z_impl_can_set_timing_data(const struct device *dev,
const struct can_timing *timing_data)
{
const struct can_driver_api *api = (const struct can_driver_api *)dev->api;
const struct can_timing *min = can_get_timing_data_min(dev);
const struct can_timing *max = can_get_timing_data_max(dev);
int err;
if (api->set_timing_data == NULL) {
return -ENOSYS;
}
err = check_timing_in_range(timing_data, min, max);
if (err != 0) {
return err;
}
return api->set_timing_data(dev, timing_data);
}
int z_impl_can_set_bitrate_data(const struct device *dev, uint32_t bitrate_data)
{
struct can_timing timing_data;

View file

@ -234,6 +234,11 @@ struct can_bus_err_cnt {
uint8_t rx_err_cnt;
};
/** Synchronization Jump Width (SJW) value to indicate that the SJW should not
* be changed by the timing calculation.
*/
#define CAN_SJW_NO_CHANGE 0
/**
* @brief CAN bus timing structure
*
@ -868,25 +873,12 @@ __syscall int can_calc_timing_data(const struct device *dev, struct can_timing *
* @retval 0 If successful.
* @retval -EBUSY if the CAN controller is not in stopped state.
* @retval -EIO General input/output error, failed to configure device.
* @retval -ENOTSUP if the timing parameters are not supported by the driver.
* @retval -ENOSYS if CAN-FD support is not implemented by the driver.
*/
__syscall int can_set_timing_data(const struct device *dev,
const struct can_timing *timing_data);
#ifdef CONFIG_CAN_FD_MODE
static inline int z_impl_can_set_timing_data(const struct device *dev,
const struct can_timing *timing_data)
{
const struct can_driver_api *api = (const struct can_driver_api *)dev->api;
if (api->set_timing_data == NULL) {
return -ENOSYS;
}
return api->set_timing_data(dev, timing_data);
}
#endif /* CONFIG_CAN_FD_MODE */
/**
* @brief Set the bitrate for the data phase of the CAN-FD controller
*
@ -936,11 +928,6 @@ __syscall int can_set_bitrate_data(const struct device *dev, uint32_t bitrate_da
int can_calc_prescaler(const struct device *dev, struct can_timing *timing,
uint32_t bitrate);
/** Synchronization Jump Width (SJW) value to indicate that the SJW should not
* be changed by the timing calculation.
*/
#define CAN_SJW_NO_CHANGE 0
/**
* @brief Configure the bus timing of a CAN controller.
*
@ -953,19 +940,12 @@ int can_calc_prescaler(const struct device *dev, struct can_timing *timing,
*
* @retval 0 If successful.
* @retval -EBUSY if the CAN controller is not in stopped state.
* @retval -ENOTSUP if the timing parameters are not supported by the driver.
* @retval -EIO General input/output error, failed to configure device.
*/
__syscall int can_set_timing(const struct device *dev,
const struct can_timing *timing);
static inline int z_impl_can_set_timing(const struct device *dev,
const struct can_timing *timing)
{
const struct can_driver_api *api = (const struct can_driver_api *)dev->api;
return api->set_timing(dev, timing);
}
/**
* @brief Get the supported modes of the CAN controller
*