diff options
Diffstat (limited to 'drivers/net/can/flexcan.c')
-rw-r--r-- | drivers/net/can/flexcan.c | 91 |
1 files changed, 76 insertions, 15 deletions
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 13f0f219d8aa..a13a4896a8bd 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c | |||
@@ -182,22 +182,23 @@ | |||
182 | /* FLEXCAN hardware feature flags | 182 | /* FLEXCAN hardware feature flags |
183 | * | 183 | * |
184 | * Below is some version info we got: | 184 | * Below is some version info we got: |
185 | * SOC Version IP-Version Glitch- [TR]WRN_INT Memory err RTR re- | 185 | * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR re- |
186 | * Filter? connected? detection ception in MB | 186 | * Filter? connected? Passive detection ception in MB |
187 | * MX25 FlexCAN2 03.00.00.00 no no no no | 187 | * MX25 FlexCAN2 03.00.00.00 no no ? no no |
188 | * MX28 FlexCAN2 03.00.04.00 yes yes no no | 188 | * MX28 FlexCAN2 03.00.04.00 yes yes no no no |
189 | * MX35 FlexCAN2 03.00.00.00 no no no no | 189 | * MX35 FlexCAN2 03.00.00.00 no no ? no no |
190 | * MX53 FlexCAN2 03.00.00.00 yes no no no | 190 | * MX53 FlexCAN2 03.00.00.00 yes no no no no |
191 | * MX6s FlexCAN3 10.00.12.00 yes yes no yes | 191 | * MX6s FlexCAN3 10.00.12.00 yes yes no no yes |
192 | * VF610 FlexCAN3 ? no yes yes yes? | 192 | * VF610 FlexCAN3 ? no yes ? yes yes? |
193 | * | 193 | * |
194 | * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected. | 194 | * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected. |
195 | */ | 195 | */ |
196 | #define FLEXCAN_QUIRK_BROKEN_ERR_STATE BIT(1) /* [TR]WRN_INT not connected */ | 196 | #define FLEXCAN_QUIRK_BROKEN_WERR_STATE BIT(1) /* [TR]WRN_INT not connected */ |
197 | #define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */ | 197 | #define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */ |
198 | #define FLEXCAN_QUIRK_ENABLE_EACEN_RRS BIT(3) /* Enable EACEN and RRS bit in ctrl2 */ | 198 | #define FLEXCAN_QUIRK_ENABLE_EACEN_RRS BIT(3) /* Enable EACEN and RRS bit in ctrl2 */ |
199 | #define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) /* Disable Memory error detection */ | 199 | #define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) /* Disable Memory error detection */ |
200 | #define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) /* Use timestamp based offloading */ | 200 | #define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) /* Use timestamp based offloading */ |
201 | #define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) /* No interrupt for error passive */ | ||
201 | 202 | ||
202 | /* Structure of the message buffer */ | 203 | /* Structure of the message buffer */ |
203 | struct flexcan_mb { | 204 | struct flexcan_mb { |
@@ -281,14 +282,17 @@ struct flexcan_priv { | |||
281 | }; | 282 | }; |
282 | 283 | ||
283 | static const struct flexcan_devtype_data fsl_p1010_devtype_data = { | 284 | static const struct flexcan_devtype_data fsl_p1010_devtype_data = { |
284 | .quirks = FLEXCAN_QUIRK_BROKEN_ERR_STATE, | 285 | .quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE | |
286 | FLEXCAN_QUIRK_BROKEN_PERR_STATE, | ||
285 | }; | 287 | }; |
286 | 288 | ||
287 | static const struct flexcan_devtype_data fsl_imx28_devtype_data; | 289 | static const struct flexcan_devtype_data fsl_imx28_devtype_data = { |
290 | .quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE, | ||
291 | }; | ||
288 | 292 | ||
289 | static const struct flexcan_devtype_data fsl_imx6q_devtype_data = { | 293 | static const struct flexcan_devtype_data fsl_imx6q_devtype_data = { |
290 | .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | | 294 | .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | |
291 | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP, | 295 | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE, |
292 | }; | 296 | }; |
293 | 297 | ||
294 | static const struct flexcan_devtype_data fsl_vf610_devtype_data = { | 298 | static const struct flexcan_devtype_data fsl_vf610_devtype_data = { |
@@ -335,6 +339,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr) | |||
335 | } | 339 | } |
336 | #endif | 340 | #endif |
337 | 341 | ||
342 | static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv) | ||
343 | { | ||
344 | struct flexcan_regs __iomem *regs = priv->regs; | ||
345 | u32 reg_ctrl = (priv->reg_ctrl_default | FLEXCAN_CTRL_ERR_MSK); | ||
346 | |||
347 | flexcan_write(reg_ctrl, ®s->ctrl); | ||
348 | } | ||
349 | |||
350 | static inline void flexcan_error_irq_disable(const struct flexcan_priv *priv) | ||
351 | { | ||
352 | struct flexcan_regs __iomem *regs = priv->regs; | ||
353 | u32 reg_ctrl = (priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_MSK); | ||
354 | |||
355 | flexcan_write(reg_ctrl, ®s->ctrl); | ||
356 | } | ||
357 | |||
338 | static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv) | 358 | static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv) |
339 | { | 359 | { |
340 | if (!priv->reg_xceiver) | 360 | if (!priv->reg_xceiver) |
@@ -713,6 +733,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) | |||
713 | struct flexcan_regs __iomem *regs = priv->regs; | 733 | struct flexcan_regs __iomem *regs = priv->regs; |
714 | irqreturn_t handled = IRQ_NONE; | 734 | irqreturn_t handled = IRQ_NONE; |
715 | u32 reg_iflag1, reg_esr; | 735 | u32 reg_iflag1, reg_esr; |
736 | enum can_state last_state = priv->can.state; | ||
716 | 737 | ||
717 | reg_iflag1 = flexcan_read(®s->iflag1); | 738 | reg_iflag1 = flexcan_read(®s->iflag1); |
718 | 739 | ||
@@ -765,8 +786,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) | |||
765 | flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr); | 786 | flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr); |
766 | } | 787 | } |
767 | 788 | ||
768 | /* state change interrupt */ | 789 | /* state change interrupt or broken error state quirk fix is enabled */ |
769 | if (reg_esr & FLEXCAN_ESR_ERR_STATE) | 790 | if ((reg_esr & FLEXCAN_ESR_ERR_STATE) || |
791 | (priv->devtype_data->quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE | | ||
792 | FLEXCAN_QUIRK_BROKEN_PERR_STATE))) | ||
770 | flexcan_irq_state(dev, reg_esr); | 793 | flexcan_irq_state(dev, reg_esr); |
771 | 794 | ||
772 | /* bus error IRQ - handle if bus error reporting is activated */ | 795 | /* bus error IRQ - handle if bus error reporting is activated */ |
@@ -774,6 +797,44 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) | |||
774 | (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) | 797 | (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) |
775 | flexcan_irq_bus_err(dev, reg_esr); | 798 | flexcan_irq_bus_err(dev, reg_esr); |
776 | 799 | ||
800 | /* availability of error interrupt among state transitions in case | ||
801 | * bus error reporting is de-activated and | ||
802 | * FLEXCAN_QUIRK_BROKEN_PERR_STATE is enabled: | ||
803 | * +--------------------------------------------------------------+ | ||
804 | * | +----------------------------------------------+ [stopped / | | ||
805 | * | | | sleeping] -+ | ||
806 | * +-+-> active <-> warning <-> passive -> bus off -+ | ||
807 | * ___________^^^^^^^^^^^^_______________________________ | ||
808 | * disabled(1) enabled disabled | ||
809 | * | ||
810 | * (1): enabled if FLEXCAN_QUIRK_BROKEN_WERR_STATE is enabled | ||
811 | */ | ||
812 | if ((last_state != priv->can.state) && | ||
813 | (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_PERR_STATE) && | ||
814 | !(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) { | ||
815 | switch (priv->can.state) { | ||
816 | case CAN_STATE_ERROR_ACTIVE: | ||
817 | if (priv->devtype_data->quirks & | ||
818 | FLEXCAN_QUIRK_BROKEN_WERR_STATE) | ||
819 | flexcan_error_irq_enable(priv); | ||
820 | else | ||
821 | flexcan_error_irq_disable(priv); | ||
822 | break; | ||
823 | |||
824 | case CAN_STATE_ERROR_WARNING: | ||
825 | flexcan_error_irq_enable(priv); | ||
826 | break; | ||
827 | |||
828 | case CAN_STATE_ERROR_PASSIVE: | ||
829 | case CAN_STATE_BUS_OFF: | ||
830 | flexcan_error_irq_disable(priv); | ||
831 | break; | ||
832 | |||
833 | default: | ||
834 | break; | ||
835 | } | ||
836 | } | ||
837 | |||
777 | return handled; | 838 | return handled; |
778 | } | 839 | } |
779 | 840 | ||
@@ -887,7 +948,7 @@ static int flexcan_chip_start(struct net_device *dev) | |||
887 | * on most Flexcan cores, too. Otherwise we don't get | 948 | * on most Flexcan cores, too. Otherwise we don't get |
888 | * any error warning or passive interrupts. | 949 | * any error warning or passive interrupts. |
889 | */ | 950 | */ |
890 | if (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_ERR_STATE || | 951 | if (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_WERR_STATE || |
891 | priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) | 952 | priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) |
892 | reg_ctrl |= FLEXCAN_CTRL_ERR_MSK; | 953 | reg_ctrl |= FLEXCAN_CTRL_ERR_MSK; |
893 | else | 954 | else |