aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMarc Kleine-Budde <mkl@pengutronix.de>2014-02-28 11:08:21 -0500
committerMarc Kleine-Budde <mkl@pengutronix.de>2014-03-03 06:41:46 -0500
commitb1aa1c7a2165b44ecce66286a3095cc6c7667d1c (patch)
tree88e163d51f28e04dbdca2b931b3bc76c0497af6f /drivers/net
parentf003698e23f6f56a791774f14d0ac35d04872490 (diff)
can: flexcan: fix transition from and to freeze mode in chip_{,un}freeze
This patch factors out freeze and unfreeze of the CAN core into seperate functions. Experiments have shown that the transition from and to freeze mode may take several microseconds, especially the time entering the freeze mode depends on the current bitrate. This patch adds a while loop which polls the Freeze Mode ACK bit (FRZ_ACK) that indicates a successfull mode change. If the function runs into a timeout a error value is returned. Cc: linux-stable <stable@vger.kernel.org> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/can/flexcan.c60
1 files changed, 49 insertions, 11 deletions
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 6b0fecd0a6ad..330b5b957a39 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -325,6 +325,44 @@ static int flexcan_chip_disable(struct flexcan_priv *priv)
325 return 0; 325 return 0;
326} 326}
327 327
328static int flexcan_chip_freeze(struct flexcan_priv *priv)
329{
330 struct flexcan_regs __iomem *regs = priv->base;
331 unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
332 u32 reg;
333
334 reg = flexcan_read(&regs->mcr);
335 reg |= FLEXCAN_MCR_HALT;
336 flexcan_write(reg, &regs->mcr);
337
338 while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
339 usleep_range(100, 200);
340
341 if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
342 return -ETIMEDOUT;
343
344 return 0;
345}
346
347static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
348{
349 struct flexcan_regs __iomem *regs = priv->base;
350 unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
351 u32 reg;
352
353 reg = flexcan_read(&regs->mcr);
354 reg &= ~FLEXCAN_MCR_HALT;
355 flexcan_write(reg, &regs->mcr);
356
357 while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
358 usleep_range(10, 20);
359
360 if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK)
361 return -ETIMEDOUT;
362
363 return 0;
364}
365
328static int flexcan_get_berr_counter(const struct net_device *dev, 366static int flexcan_get_berr_counter(const struct net_device *dev,
329 struct can_berr_counter *bec) 367 struct can_berr_counter *bec)
330{ 368{
@@ -756,7 +794,7 @@ static int flexcan_chip_start(struct net_device *dev)
756 netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n", 794 netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n",
757 reg_mcr); 795 reg_mcr);
758 err = -ENODEV; 796 err = -ENODEV;
759 goto out; 797 goto out_chip_disable;
760 } 798 }
761 799
762 flexcan_set_bittiming(dev); 800 flexcan_set_bittiming(dev);
@@ -826,12 +864,12 @@ static int flexcan_chip_start(struct net_device *dev)
826 864
827 err = flexcan_transceiver_enable(priv); 865 err = flexcan_transceiver_enable(priv);
828 if (err) 866 if (err)
829 goto out; 867 goto out_chip_disable;
830 868
831 /* synchronize with the can bus */ 869 /* synchronize with the can bus */
832 reg_mcr = flexcan_read(&regs->mcr); 870 err = flexcan_chip_unfreeze(priv);
833 reg_mcr &= ~FLEXCAN_MCR_HALT; 871 if (err)
834 flexcan_write(reg_mcr, &regs->mcr); 872 goto out_transceiver_disable;
835 873
836 priv->can.state = CAN_STATE_ERROR_ACTIVE; 874 priv->can.state = CAN_STATE_ERROR_ACTIVE;
837 875
@@ -844,7 +882,9 @@ static int flexcan_chip_start(struct net_device *dev)
844 882
845 return 0; 883 return 0;
846 884
847 out: 885 out_transceiver_disable:
886 flexcan_transceiver_disable(priv);
887 out_chip_disable:
848 flexcan_chip_disable(priv); 888 flexcan_chip_disable(priv);
849 return err; 889 return err;
850} 890}
@@ -859,12 +899,10 @@ static void flexcan_chip_stop(struct net_device *dev)
859{ 899{
860 struct flexcan_priv *priv = netdev_priv(dev); 900 struct flexcan_priv *priv = netdev_priv(dev);
861 struct flexcan_regs __iomem *regs = priv->base; 901 struct flexcan_regs __iomem *regs = priv->base;
862 u32 reg;
863 902
864 /* Disable + halt module */ 903 /* freeze + disable module */
865 reg = flexcan_read(&regs->mcr); 904 flexcan_chip_freeze(priv);
866 reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT; 905 flexcan_chip_disable(priv);
867 flexcan_write(reg, &regs->mcr);
868 906
869 /* Disable all interrupts */ 907 /* Disable all interrupts */
870 flexcan_write(0, &regs->imask1); 908 flexcan_write(0, &regs->imask1);