Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

can: calc_bittiming: add PWM calculation

Perform the PWM calculation according to CiA recommendations.

Note that for databitrates greater than 5 MBPS, tqmin is less than
CAN_PWM_NS_MAX (which is defined to 200 nano seconds), consequently,
the result of the division:

DIV_ROUND_UP(xl_ns, CAN_PWM_NS_MAX)

is one and thus the for loop automatically stops on the first
iteration giving a single PWM symbol per bit as expected. Because of
that, there is no actual need for a separate conditional branch for
when the databitrate is greater than 5 MBPS.

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20251126-canxl-v8-10-e7e3eb74f889@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Vincent Mailhol and committed by
Marc Kleine-Budde
9892339c 8e2a2885

+46
+36
drivers/net/can/dev/calc_bittiming.c
··· 2 2 /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix 3 3 * Copyright (C) 2006 Andrey Volkov, Varma Electronics 4 4 * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> 5 + * Copyright (C) 2021-2025 Vincent Mailhol <mailhol@kernel.org> 5 6 */ 6 7 7 8 #include <linux/units.h> ··· 198 197 tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max); 199 198 *ctrlmode |= tdc_auto; 200 199 } 200 + } 201 + 202 + int can_calc_pwm(struct net_device *dev, struct netlink_ext_ack *extack) 203 + { 204 + struct can_priv *priv = netdev_priv(dev); 205 + const struct can_pwm_const *pwm_const = priv->xl.pwm_const; 206 + struct can_pwm *pwm = &priv->xl.pwm; 207 + u32 xl_tqmin = can_bit_time_tqmin(&priv->xl.data_bittiming); 208 + u32 xl_ns = can_tqmin_to_ns(xl_tqmin, priv->clock.freq); 209 + u32 nom_tqmin = can_bit_time_tqmin(&priv->bittiming); 210 + int pwm_per_bit_max = xl_tqmin / (pwm_const->pwms_min + pwm_const->pwml_min); 211 + int pwm_per_bit; 212 + u32 pwm_tqmin; 213 + 214 + /* For 5 MB/s databitrate or greater, xl_ns < CAN_PWM_NS_MAX 215 + * giving us a pwm_per_bit of 1 and the loop immediately breaks 216 + */ 217 + for (pwm_per_bit = DIV_ROUND_UP(xl_ns, CAN_PWM_NS_MAX); 218 + pwm_per_bit <= pwm_per_bit_max; pwm_per_bit++) 219 + if (xl_tqmin % pwm_per_bit == 0) 220 + break; 221 + 222 + if (pwm_per_bit > pwm_per_bit_max) { 223 + NL_SET_ERR_MSG_FMT(extack, 224 + "Can not divide the XL data phase's bit time: %u tqmin into multiple PWM symbols", 225 + xl_tqmin); 226 + return -EINVAL; 227 + } 228 + 229 + pwm_tqmin = xl_tqmin / pwm_per_bit; 230 + pwm->pwms = DIV_ROUND_UP_POW2(pwm_tqmin, 4); 231 + pwm->pwml = pwm_tqmin - pwm->pwms; 232 + pwm->pwmo = nom_tqmin % pwm_tqmin; 233 + 234 + return 0; 201 235 }
+10
include/linux/can/bittiming.h
··· 180 180 void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const, 181 181 const struct can_bittiming *dbt, 182 182 u32 tdc_mask, u32 *ctrlmode, u32 ctrlmode_supported); 183 + 184 + int can_calc_pwm(struct net_device *dev, struct netlink_ext_ack *extack); 183 185 #else /* !CONFIG_CAN_CALC_BITTIMING */ 184 186 static inline int 185 187 can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt, ··· 196 194 const struct can_bittiming *dbt, 197 195 u32 tdc_mask, u32 *ctrlmode, u32 ctrlmode_supported) 198 196 { 197 + } 198 + 199 + static inline int 200 + can_calc_pwm(struct net_device *dev, struct netlink_ext_ack *extack) 201 + { 202 + NL_SET_ERR_MSG(extack, 203 + "bit-timing calculation not available: manually provide PWML and PWMS\n"); 204 + return -EINVAL; 199 205 } 200 206 #endif /* CONFIG_CAN_CALC_BITTIMING */ 201 207