drivers: can: sja1000: add CAN statistics support
Add support for CAN statistics to the SJA1000 CAN controller driver. The hardware does not support distinguishing between being unable to transmit dominant versus being unable to transmit recessive bits. Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
parent
40ad8c8711
commit
4737706794
|
@ -163,6 +163,7 @@ int can_sja1000_start(const struct device *dev)
|
|||
}
|
||||
|
||||
can_sja1000_clear_errors(dev);
|
||||
CAN_STATS_RESET(dev);
|
||||
|
||||
err = can_sja1000_leave_reset_mode(dev);
|
||||
if (err != 0) {
|
||||
|
@ -599,6 +600,59 @@ static void can_sja1000_handle_transmit_irq(const struct device *dev)
|
|||
can_sja1000_tx_done(dev, status);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CAN_STATS
|
||||
static void can_sja1000_handle_data_overrun_irq(const struct device *dev)
|
||||
{
|
||||
/* See NXP SJA1000 Application Note AN97076 (figure 18) for data overrun details */
|
||||
|
||||
CAN_STATS_RX_OVERRUN_INC(dev);
|
||||
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_CMR, CAN_SJA1000_CMR_CDO);
|
||||
}
|
||||
|
||||
static void can_sja1000_handle_bus_error_irq(const struct device *dev)
|
||||
{
|
||||
/* See NXP SJA1000 Application Note AN97076 (tables 6 and 7) for ECC details */
|
||||
uint8_t ecc;
|
||||
|
||||
/* Read the Error Code Capture register to re-activate it */
|
||||
ecc = can_sja1000_read_reg(dev, CAN_SJA1000_ECC);
|
||||
|
||||
if (ecc == (CAN_SJA1000_ECC_ERRC_OTHER_ERROR | CAN_SJA1000_ECC_DIR_TX |
|
||||
CAN_SJA1000_ECC_SEG_ACK_SLOT)) {
|
||||
/* Missing ACK is reported as a TX "other" error in the ACK slot */
|
||||
CAN_STATS_ACK_ERROR_INC(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ecc == (CAN_SJA1000_ECC_ERRC_FORM_ERROR | CAN_SJA1000_ECC_DIR_RX |
|
||||
CAN_SJA1000_ECC_SEG_ACK_DELIM)) {
|
||||
/* CRC error is reported as a RX "form" error in the ACK delimiter */
|
||||
CAN_STATS_CRC_ERROR_INC(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ecc & CAN_SJA1000_ECC_ERRC_MASK) {
|
||||
case CAN_SJA1000_ECC_ERRC_BIT_ERROR:
|
||||
CAN_STATS_BIT_ERROR_INC(dev);
|
||||
break;
|
||||
|
||||
case CAN_SJA1000_ECC_ERRC_FORM_ERROR:
|
||||
CAN_STATS_FORM_ERROR_INC(dev);
|
||||
break;
|
||||
case CAN_SJA1000_ECC_ERRC_STUFF_ERROR:
|
||||
CAN_STATS_STUFF_ERROR_INC(dev);
|
||||
break;
|
||||
|
||||
case CAN_SJA1000_ECC_ERRC_OTHER_ERROR:
|
||||
__fallthrough;
|
||||
default:
|
||||
/* Other error not currently reported in CAN statistics */
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_CAN_STATS */
|
||||
|
||||
static void can_sja1000_handle_error_warning_irq(const struct device *dev)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
|
@ -650,6 +704,16 @@ void can_sja1000_isr(const struct device *dev)
|
|||
can_sja1000_handle_receive_irq(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CAN_STATS
|
||||
if ((ir & CAN_SJA1000_IR_DOI) != 0) {
|
||||
can_sja1000_handle_data_overrun_irq(dev);
|
||||
}
|
||||
|
||||
if ((ir & CAN_SJA1000_IR_BEI) != 0) {
|
||||
can_sja1000_handle_bus_error_irq(dev);
|
||||
}
|
||||
#endif /* CONFIG_CAN_STATS */
|
||||
|
||||
if ((ir & CAN_SJA1000_IR_EI) != 0) {
|
||||
can_sja1000_handle_error_warning_irq(dev);
|
||||
}
|
||||
|
@ -754,6 +818,9 @@ int can_sja1000_init(const struct device *dev)
|
|||
|
||||
/* Enable interrupts */
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_IER,
|
||||
#ifdef CONFIG_CAN_STATS
|
||||
CAN_SJA1000_IER_BEIE | CAN_SJA1000_IER_DOIE |
|
||||
#endif /* CONFIG_CAN_STATS */
|
||||
CAN_SJA1000_IER_RIE | CAN_SJA1000_IER_TIE |
|
||||
CAN_SJA1000_IER_EIE | CAN_SJA1000_IER_EPIE);
|
||||
|
||||
|
|
|
@ -108,9 +108,37 @@
|
|||
|
||||
/* Error Code Capture register (ECC) bits */
|
||||
#define CAN_SJA1000_ECC_SEG_MASK GENMASK(4, 0)
|
||||
#define CAN_SJA1000_ECC_DIR BIT(5)
|
||||
#define CAN_SJA1000_ECC_DIR_MASK BIT(5)
|
||||
#define CAN_SJA1000_ECC_ERRC_MASK GENMASK(7, 6)
|
||||
|
||||
#define CAN_SJA1000_ECC_SEG_SOF FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 3U)
|
||||
#define CAN_SJA1000_ECC_SEG_ID28_TO_ID21 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 2U)
|
||||
#define CAN_SJA1000_ECC_SEG_ID20_TO_ID18 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 6U)
|
||||
#define CAN_SJA1000_ECC_SEG_SRTR FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 4U)
|
||||
#define CAN_SJA1000_ECC_SEG_IDE FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 5U)
|
||||
#define CAN_SJA1000_ECC_SEG_ID17_TO_ID13 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 7U)
|
||||
#define CAN_SJA1000_ECC_SEG_ID12_TO_ID5 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 15U)
|
||||
#define CAN_SJA1000_ECC_SEG_ID4_TO_ID0 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 14U)
|
||||
#define CAN_SJA1000_ECC_SEG_RTR FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 12U)
|
||||
#define CAN_SJA1000_ECC_SEG_RES1 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 13U)
|
||||
#define CAN_SJA1000_ECC_SEG_RES0 FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 9U)
|
||||
#define CAN_SJA1000_ECC_SEG_DLC FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 11U)
|
||||
#define CAN_SJA1000_ECC_SEG_DATA FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 10U)
|
||||
#define CAN_SJA1000_ECC_SEG_CRC_SEQ FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 8U)
|
||||
#define CAN_SJA1000_ECC_SEG_CRC_DELIM FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 24U)
|
||||
#define CAN_SJA1000_ECC_SEG_ACK_SLOT FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 25U)
|
||||
#define CAN_SJA1000_ECC_SEG_ACK_DELIM FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 27U)
|
||||
#define CAN_SJA1000_ECC_SEG_EOF FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 26U)
|
||||
#define CAN_SJA1000_ECC_SEG_INTERMISSION FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 18U)
|
||||
#define CAN_SJA1000_ECC_SEG_ACTIVE_ERROR_FLAG FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 17U)
|
||||
#define CAN_SJA1000_ECC_SEG_PASSIVE_ERROR_FLAG FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 22U)
|
||||
#define CAN_SJA1000_ECC_SEG_TOLERATE_DOM_BITS FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 19U)
|
||||
#define CAN_SJA1000_ECC_SEG_ERROR_DELIM FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 23U)
|
||||
#define CAN_SJA1000_ECC_SEG_OVERLOAD_FLAG FIELD_PREP(CAN_SJA1000_ECC_SEG_MASK, 28U)
|
||||
|
||||
#define CAN_SJA1000_ECC_DIR_TX FIELD_PREP(CAN_SJA1000_ECC_DIR_MASK, 0U)
|
||||
#define CAN_SJA1000_ECC_DIR_RX FIELD_PREP(CAN_SJA1000_ECC_DIR_MASK, 1U)
|
||||
|
||||
#define CAN_SJA1000_ECC_ERRC_BIT_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 0U)
|
||||
#define CAN_SJA1000_ECC_ERRC_FORM_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 1U)
|
||||
#define CAN_SJA1000_ECC_ERRC_STUFF_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 2U)
|
||||
|
|
Loading…
Reference in a new issue