diff options
| author | Vincent Mailhol <mailhol@kernel.org> | 2025-11-26 11:16:11 +0100 |
|---|---|---|
| committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2025-11-26 11:20:43 +0100 |
| commit | 9892339cf0348730e82383d4de9d9387b9d63925 (patch) | |
| tree | 32958516a8dd52008918e0457d760832b85c6bc7 /drivers/net/can/dev/calc_bittiming.c | |
| parent | 8e2a2885a2a6217190065d1aae98fe88a670cc28 (diff) | |
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>
Diffstat (limited to 'drivers/net/can/dev/calc_bittiming.c')
| -rw-r--r-- | drivers/net/can/dev/calc_bittiming.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/net/can/dev/calc_bittiming.c b/drivers/net/can/dev/calc_bittiming.c index 394d6974f481..268ec6fa7c49 100644 --- a/drivers/net/can/dev/calc_bittiming.c +++ b/drivers/net/can/dev/calc_bittiming.c @@ -2,6 +2,7 @@ /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix * Copyright (C) 2006 Andrey Volkov, Varma Electronics * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> + * Copyright (C) 2021-2025 Vincent Mailhol <mailhol@kernel.org> */ #include <linux/units.h> @@ -198,3 +199,38 @@ void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const, *ctrlmode |= tdc_auto; } } + +int can_calc_pwm(struct net_device *dev, struct netlink_ext_ack *extack) +{ + struct can_priv *priv = netdev_priv(dev); + const struct can_pwm_const *pwm_const = priv->xl.pwm_const; + struct can_pwm *pwm = &priv->xl.pwm; + u32 xl_tqmin = can_bit_time_tqmin(&priv->xl.data_bittiming); + u32 xl_ns = can_tqmin_to_ns(xl_tqmin, priv->clock.freq); + u32 nom_tqmin = can_bit_time_tqmin(&priv->bittiming); + int pwm_per_bit_max = xl_tqmin / (pwm_const->pwms_min + pwm_const->pwml_min); + int pwm_per_bit; + u32 pwm_tqmin; + + /* For 5 MB/s databitrate or greater, xl_ns < CAN_PWM_NS_MAX + * giving us a pwm_per_bit of 1 and the loop immediately breaks + */ + for (pwm_per_bit = DIV_ROUND_UP(xl_ns, CAN_PWM_NS_MAX); + pwm_per_bit <= pwm_per_bit_max; pwm_per_bit++) + if (xl_tqmin % pwm_per_bit == 0) + break; + + if (pwm_per_bit > pwm_per_bit_max) { + NL_SET_ERR_MSG_FMT(extack, + "Can not divide the XL data phase's bit time: %u tqmin into multiple PWM symbols", + xl_tqmin); + return -EINVAL; + } + + pwm_tqmin = xl_tqmin / pwm_per_bit; + pwm->pwms = DIV_ROUND_UP_POW2(pwm_tqmin, 4); + pwm->pwml = pwm_tqmin - pwm->pwms; + pwm->pwmo = nom_tqmin % pwm_tqmin; + + return 0; +} |