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 |
