can: enhance bit timing ioctl to set both nominal and data bit timing

This adds field type to canioc_bittiming_s structure that allows
to set/obtain bit timing for both CAN CC and CAN FD.
CANIOC_GET_BITTIMING is now bidirectional: user specifies type field
and gets other fields from the controller.

The commit also updates current CAN FD capable controllers using the
ioctl. The type is not checked for classical CAN only controllers
and nominal bit timing is returned regardless of type value.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
This commit is contained in:
Michal Lenc 2024-07-09 10:45:43 +02:00 committed by Alan Carvalho de Assis
parent 816b1b28a0
commit e16ee4dba3
4 changed files with 197 additions and 58 deletions

View File

@ -2652,18 +2652,39 @@ static int mcan_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg)
DEBUGASSERT(bt != NULL);
regval = mcan_getreg(priv, SAM_MCAN_BTP_OFFSET);
bt->bt_sjw = ((regval & MCAN_BTP_SJW_MASK) >>
MCAN_BTP_SJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & MCAN_BTP_TSEG1_MASK) >>
MCAN_BTP_TSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & MCAN_BTP_TSEG2_MASK) >>
MCAN_BTP_TSEG2_SHIFT) + 1;
#ifdef CONFIG_CAN_FD
if (bt->type == CAN_BITTIMING_DATA)
{
regval = mcan_getreg(priv, SAM_MCAN_FBTP_OFFSET);
bt->bt_sjw = ((regval & MCAN_FBTP_FSJW_MASK) >>
MCAN_FBTP_FSJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & MCAN_FBTP_FTSEG1_MASK) >>
MCAN_FBTP_FTSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & MCAN_FBTP_FTSEG2_MASK) >>
MCAN_FBTP_FTSEG2_SHIFT) + 1;
brp = ((regval & MCAN_FBTP_FBRP_MASK) >>
MCAN_FBTP_FBRP_SHIFT) + 1;
bt->bt_baud = SAMA5_MCANCLK_FREQUENCY / brp /
(bt->bt_tseg1 + bt->bt_tseg2 + 1);
}
else
#endif
{
regval = mcan_getreg(priv, SAM_MCAN_BTP_OFFSET);
bt->bt_sjw = ((regval & MCAN_BTP_SJW_MASK) >>
MCAN_BTP_SJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & MCAN_BTP_TSEG1_MASK) >>
MCAN_BTP_TSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & MCAN_BTP_TSEG2_MASK) >>
MCAN_BTP_TSEG2_SHIFT) + 1;
brp = ((regval & MCAN_BTP_BRP_MASK) >>
MCAN_BTP_BRP_SHIFT) + 1;
bt->bt_baud = SAMA5_MCANCLK_FREQUENCY / brp /
(bt->bt_tseg1 + bt->bt_tseg2 + 1);
}
brp = ((regval & MCAN_BTP_BRP_MASK) >>
MCAN_BTP_BRP_SHIFT) + 1;
bt->bt_baud = SAMA5_MCANCLK_FREQUENCY / brp /
(bt->bt_tseg1 + bt->bt_tseg2 + 1);
ret = OK;
}
break;
@ -2716,8 +2737,18 @@ static int mcan_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg)
/* Save the value of the new bit timing register */
flags = enter_critical_section();
priv->btp = MCAN_BTP_BRP(brp) | MCAN_BTP_TSEG1(tseg1) |
MCAN_BTP_TSEG2(tseg2) | MCAN_BTP_SJW(sjw);
#ifdef CONFIG_CAN_FD
if (bt->type == CAN_BITTIMING_DATA)
{
priv->fbtp = MCAN_FBTP_FBRP(brp) | MCAN_FBTP_FTSEG1(tseg1) |
MCAN_FBTP_FTSEG2(tseg2) | MCAN_FBTP_FSJW(sjw);
}
else
#endif
{
priv->btp = MCAN_BTP_BRP(brp) | MCAN_BTP_TSEG1(tseg1) |
MCAN_BTP_TSEG2(tseg2) | MCAN_BTP_SJW(sjw);
}
/* We need to reset to instantiate the new timing. Save
* current state information so that recover to this

View File

@ -144,10 +144,10 @@
(float)CONFIG_SAMV7_MCAN0_FBITRATE)) - 1))
# define MCAN0_DSJW (CONFIG_SAMV7_MCAN0_FFSJW - 1)
# if MCAN0_DTSEG1 > 15
# if MCAN0_DTSEG1 > 31
# error Invalid MCAN0 DTSEG1
# endif
# if MCAN0_DTSEG2 > 7
# if MCAN0_DTSEG2 > 15
# error Invalid MCAN0 DTSEG2
# endif
# if MCAN0_DSJW > 3
@ -429,10 +429,10 @@
(float)CONFIG_SAMV7_MCAN1_FBITRATE)) - 1))
# define MCAN1_DSJW (CONFIG_SAMV7_MCAN1_FFSJW - 1)
#if MCAN1_DTSEG1 > 15
#if MCAN1_DTSEG1 > 31
# error Invalid MCAN1 DTSEG1
#endif
#if MCAN1_DTSEG2 > 7
#if MCAN1_DTSEG2 > 15
# error Invalid MCAN1 DTSEG2
#endif
#if MCAN1_DSJW > 3
@ -2650,33 +2650,70 @@ static int mcan_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg)
DEBUGASSERT(bt != NULL);
regval = mcan_getreg(priv, SAM_MCAN_NBTP_OFFSET);
if (priv->rev == 0)
#ifdef CONFIG_CAN_FD
if (bt->type == CAN_BITTIMING_DATA)
{
/* Revision A */
if (priv->rev == 0)
{
/* Revision A */
bt->bt_sjw = ((regval & MCAN_REVA_BTP_SJW_MASK) >>
MCAN_REVA_BTP_SJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & MCAN_REVA_BTP_TSEG1_MASK) >>
MCAN_REVA_BTP_TSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & MCAN_REVA_BTP_TSEG2_MASK) >>
MCAN_REVA_BTP_TSEG2_SHIFT) + 1;
brp = ((regval & MCAN_REVA_BTP_BRP_MASK) >>
MCAN_REVA_BTP_BRP_SHIFT) + 1;
regval = mcan_getreg(priv,
SAM_MCAN_REVA_FBTP_OFFSET);
bt->bt_sjw = ((regval & MCAN_REVA_FBTP_FSJW_MASK) >>
MCAN_REVA_FBTP_FSJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & MCAN_REVA_FBTP_FTSEG1_MASK) >>
MCAN_REVA_FBTP_FTSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & MCAN_REVA_FBTP_FTSEG2_MASK) >>
MCAN_REVA_FBTP_FTSEG2_SHIFT) + 1;
brp = ((regval & MCAN_REVA_FBTP_FBRP_MASK) >>
MCAN_REVA_FBTP_FBRP_SHIFT) + 1;
}
else
{
/* Revision B */
regval = mcan_getreg(priv, SAM_MCAN_DBTP_OFFSET);
bt->bt_sjw = ((regval & MCAN_DBTP_DSJW_MASK) >>
MCAN_DBTP_DSJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & MCAN_DBTP_DTSEG1_MASK) >>
MCAN_DBTP_DTSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & MCAN_DBTP_DTSEG2_MASK) >>
MCAN_DBTP_DTSEG2_SHIFT) + 1;
brp = ((regval & MCAN_DBTP_DBRP_MASK) >>
MCAN_DBTP_DBRP_SHIFT) + 1;
}
}
else
#endif
{
/* Revision B */
if (priv->rev == 0)
{
/* Revision A */
bt->bt_sjw = ((regval & MCAN_NBTP_NSJW_MASK) >>
MCAN_NBTP_NSJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & MCAN_NBTP_NTSEG1_MASK) >>
MCAN_NBTP_NTSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & MCAN_NBTP_NTSEG2_MASK) >>
MCAN_NBTP_NTSEG2_SHIFT) + 1;
brp = ((regval & MCAN_NBTP_NBRP_MASK) >>
MCAN_NBTP_NBRP_SHIFT) + 1;
regval = mcan_getreg(priv, SAM_MCAN_REVA_BTP_OFFSET);
bt->bt_sjw = ((regval & MCAN_REVA_BTP_SJW_MASK) >>
MCAN_REVA_BTP_SJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & MCAN_REVA_BTP_TSEG1_MASK) >>
MCAN_REVA_BTP_TSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & MCAN_REVA_BTP_TSEG2_MASK) >>
MCAN_REVA_BTP_TSEG2_SHIFT) + 1;
brp = ((regval & MCAN_REVA_BTP_BRP_MASK) >>
MCAN_REVA_BTP_BRP_SHIFT) + 1;
}
else
{
/* Revision B */
regval = mcan_getreg(priv, SAM_MCAN_NBTP_OFFSET);
bt->bt_sjw = ((regval & MCAN_NBTP_NSJW_MASK) >>
MCAN_NBTP_NSJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & MCAN_NBTP_NTSEG1_MASK) >>
MCAN_NBTP_NTSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & MCAN_NBTP_NTSEG2_MASK) >>
MCAN_NBTP_NTSEG2_SHIFT) + 1;
brp = ((regval & MCAN_NBTP_NBRP_MASK) >>
MCAN_NBTP_NBRP_SHIFT) + 1;
}
}
bt->bt_baud = SAMV7_MCANCLK_FREQUENCY / brp /
@ -2733,17 +2770,41 @@ static int mcan_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg)
/* Save the value of the new bit timing register */
flags = enter_critical_section();
if (priv->rev == 0)
#ifdef CONFIG_CAN_FD
if (bt->type == CAN_BITTIMING_DATA)
{
priv->btp = MCAN_REVA_BTP_BRP(brp) |
MCAN_REVA_BTP_TSEG1(tseg1) |
MCAN_REVA_BTP_TSEG2(tseg2) |
MCAN_REVA_BTP_SJW(sjw);
if (priv->rev == 0)
{
priv->fbtp = MCAN_REVA_FBTP_FBRP(brp) |
MCAN_REVA_FBTP_FTSEG1(tseg1) |
MCAN_REVA_FBTP_FTSEG2(tseg2) |
MCAN_REVA_FBTP_FSJW(sjw);
}
else
{
priv->fbtp = MCAN_DBTP_DBRP(brp) |
MCAN_DBTP_DTSEG1(tseg1) |
MCAN_DBTP_DTSEG2(tseg2) |
MCAN_DBTP_DSJW(sjw);
}
}
else
#endif
{
priv->btp = MCAN_NBTP_NBRP(brp) | MCAN_NBTP_NTSEG1(tseg1) |
MCAN_NBTP_NTSEG2(tseg2) | MCAN_NBTP_NSJW(sjw);
if (priv->rev == 0)
{
priv->btp = MCAN_REVA_BTP_BRP(brp) |
MCAN_REVA_BTP_TSEG1(tseg1) |
MCAN_REVA_BTP_TSEG2(tseg2) |
MCAN_REVA_BTP_SJW(sjw);
}
else
{
priv->btp = MCAN_NBTP_NBRP(brp) |
MCAN_NBTP_NTSEG1(tseg1) |
MCAN_NBTP_NTSEG2(tseg2) |
MCAN_NBTP_NSJW(sjw);
}
}
/* We need to reset to instantiate the new timing. Save

View File

@ -2068,18 +2068,39 @@ static int fdcan_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg)
DEBUGASSERT(bt != NULL);
regval = fdcan_getreg(priv, STM32_FDCAN_NBTP_OFFSET);
bt->bt_sjw = ((regval & FDCAN_NBTP_NSJW_MASK) >>
FDCAN_NBTP_NSJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & FDCAN_NBTP_NTSEG1_MASK) >>
FDCAN_NBTP_NTSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & FDCAN_NBTP_NTSEG2_MASK) >>
FDCAN_NBTP_NTSEG2_SHIFT) + 1;
#ifdef CONFIG_CAN_FD
if (bt->type == CAN_BITTIMING_DATA)
{
regval = fdcan_getreg(priv, STM32_FDCAN_DBTP_OFFSET);
bt->bt_sjw = ((regval & FDCAN_DBTP_DSJW_MASK) >>
FDCAN_DBTP_DSJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & FDCAN_DBTP_DTSEG1_MASK) >>
FDCAN_DBTP_DTSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & FDCAN_DBTP_DTSEG2_MASK) >>
FDCAN_DBTP_DTSEG2_SHIFT) + 1;
nbrp = ((regval & FDCAN_DBTP_DBRP_MASK) >>
FDCAN_DBTP_DBRP_SHIFT) + 1;
bt->bt_baud = STM32_FDCANCLK_FREQUENCY / nbrp /
(bt->bt_tseg1 + bt->bt_tseg2 + 1);
}
else
#endif
{
regval = fdcan_getreg(priv, STM32_FDCAN_NBTP_OFFSET);
bt->bt_sjw = ((regval & FDCAN_NBTP_NSJW_MASK) >>
FDCAN_NBTP_NSJW_SHIFT) + 1;
bt->bt_tseg1 = ((regval & FDCAN_NBTP_NTSEG1_MASK) >>
FDCAN_NBTP_NTSEG1_SHIFT) + 1;
bt->bt_tseg2 = ((regval & FDCAN_NBTP_NTSEG2_MASK) >>
FDCAN_NBTP_NTSEG2_SHIFT) + 1;
nbrp = ((regval & FDCAN_NBTP_NBRP_MASK) >>
FDCAN_NBTP_NBRP_SHIFT) + 1;
bt->bt_baud = STM32_FDCANCLK_FREQUENCY / nbrp /
(bt->bt_tseg1 + bt->bt_tseg2 + 1);
}
nbrp = ((regval & FDCAN_NBTP_NBRP_MASK) >>
FDCAN_NBTP_NBRP_SHIFT) + 1;
bt->bt_baud = STM32_FDCANCLK_FREQUENCY / nbrp /
(bt->bt_tseg1 + bt->bt_tseg2 + 1);
ret = OK;
}
break;
@ -2130,8 +2151,22 @@ static int fdcan_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg)
/* Save the value of the new bit timing register */
priv->nbtp = FDCAN_NBTP_NBRP(nbrp) | FDCAN_NBTP_NTSEG1(ntseg1) |
FDCAN_NBTP_NTSEG2(ntseg2) | FDCAN_NBTP_NSJW(nsjw);
#ifdef CONFIG_CAN_FD
if (bt->type == CAN_BITTIMING_DATA)
{
priv->dbtp = FDCAN_NBTP_DBRP(nbrp) |
FDCAN_NBTP_DTSEG1(ntseg1) |
FDCAN_DBTP_DTSEG2(ntseg2) |
FDCAN_DBTP_DSJW(nsjw);
}
else
#endif
{
priv->nbtp = FDCAN_NBTP_NBRP(nbrp) |
FDCAN_NBTP_NTSEG1(ntseg1) |
FDCAN_NBTP_NTSEG2(ntseg2) |
FDCAN_NBTP_NSJW(nsjw);
}
/* We need to reset to instantiate the new timing. Save
* current state information so that recover to this

View File

@ -438,6 +438,11 @@
#define CAN_FILTER_DUAL 1 /* Dual address match */
#define CAN_FILTER_RANGE 2 /* Match a range of addresses */
/* CAN bit timing support ***************************************************/
#define CAN_BITTIMING_NOMINAL 0 /* Specifies nominal bittiming */
#define CAN_BITTIMING_DATA 1 /* Specifies data bittiming */
/****************************************************************************
* Public Types
****************************************************************************/
@ -713,6 +718,13 @@ struct canioc_rtr_s
struct canioc_bittiming_s
{
#ifdef CONFIG_CAN_FD
uint8_t type; /* Nominal/Data bit timing. This is
* used to specify which bit timing
* should be set/obtained. Applies
* only if CAN FD is configured.
*/
#endif
uint32_t bt_baud; /* Bit rate = 1 / bit time */
uint8_t bt_tseg1; /* TSEG1 in time quanta */
uint8_t bt_tseg2; /* TSEG2 in time quanta */