diff options
Diffstat (limited to 'drivers/net/can/flexcan.c')
-rw-r--r-- | drivers/net/can/flexcan.c | 179 |
1 files changed, 136 insertions, 43 deletions
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index aaed97bee471..61376abdab39 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c | |||
@@ -144,6 +144,8 @@ | |||
144 | 144 | ||
145 | #define FLEXCAN_MB_CODE_MASK (0xf0ffffff) | 145 | #define FLEXCAN_MB_CODE_MASK (0xf0ffffff) |
146 | 146 | ||
147 | #define FLEXCAN_TIMEOUT_US (50) | ||
148 | |||
147 | /* | 149 | /* |
148 | * FLEXCAN hardware feature flags | 150 | * FLEXCAN hardware feature flags |
149 | * | 151 | * |
@@ -235,9 +237,12 @@ static const struct can_bittiming_const flexcan_bittiming_const = { | |||
235 | }; | 237 | }; |
236 | 238 | ||
237 | /* | 239 | /* |
238 | * Abstract off the read/write for arm versus ppc. | 240 | * Abstract off the read/write for arm versus ppc. This |
241 | * assumes that PPC uses big-endian registers and everything | ||
242 | * else uses little-endian registers, independent of CPU | ||
243 | * endianess. | ||
239 | */ | 244 | */ |
240 | #if defined(__BIG_ENDIAN) | 245 | #if defined(CONFIG_PPC) |
241 | static inline u32 flexcan_read(void __iomem *addr) | 246 | static inline u32 flexcan_read(void __iomem *addr) |
242 | { | 247 | { |
243 | return in_be32(addr); | 248 | return in_be32(addr); |
@@ -259,6 +264,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr) | |||
259 | } | 264 | } |
260 | #endif | 265 | #endif |
261 | 266 | ||
267 | static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv) | ||
268 | { | ||
269 | if (!priv->reg_xceiver) | ||
270 | return 0; | ||
271 | |||
272 | return regulator_enable(priv->reg_xceiver); | ||
273 | } | ||
274 | |||
275 | static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv) | ||
276 | { | ||
277 | if (!priv->reg_xceiver) | ||
278 | return 0; | ||
279 | |||
280 | return regulator_disable(priv->reg_xceiver); | ||
281 | } | ||
282 | |||
262 | static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, | 283 | static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, |
263 | u32 reg_esr) | 284 | u32 reg_esr) |
264 | { | 285 | { |
@@ -266,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, | |||
266 | (reg_esr & FLEXCAN_ESR_ERR_BUS); | 287 | (reg_esr & FLEXCAN_ESR_ERR_BUS); |
267 | } | 288 | } |
268 | 289 | ||
269 | static inline void flexcan_chip_enable(struct flexcan_priv *priv) | 290 | static int flexcan_chip_enable(struct flexcan_priv *priv) |
270 | { | 291 | { |
271 | struct flexcan_regs __iomem *regs = priv->base; | 292 | struct flexcan_regs __iomem *regs = priv->base; |
293 | unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; | ||
272 | u32 reg; | 294 | u32 reg; |
273 | 295 | ||
274 | reg = flexcan_read(®s->mcr); | 296 | reg = flexcan_read(®s->mcr); |
275 | reg &= ~FLEXCAN_MCR_MDIS; | 297 | reg &= ~FLEXCAN_MCR_MDIS; |
276 | flexcan_write(reg, ®s->mcr); | 298 | flexcan_write(reg, ®s->mcr); |
277 | 299 | ||
278 | udelay(10); | 300 | while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) |
301 | usleep_range(10, 20); | ||
302 | |||
303 | if (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK) | ||
304 | return -ETIMEDOUT; | ||
305 | |||
306 | return 0; | ||
279 | } | 307 | } |
280 | 308 | ||
281 | static inline void flexcan_chip_disable(struct flexcan_priv *priv) | 309 | static int flexcan_chip_disable(struct flexcan_priv *priv) |
282 | { | 310 | { |
283 | struct flexcan_regs __iomem *regs = priv->base; | 311 | struct flexcan_regs __iomem *regs = priv->base; |
312 | unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; | ||
284 | u32 reg; | 313 | u32 reg; |
285 | 314 | ||
286 | reg = flexcan_read(®s->mcr); | 315 | reg = flexcan_read(®s->mcr); |
287 | reg |= FLEXCAN_MCR_MDIS; | 316 | reg |= FLEXCAN_MCR_MDIS; |
288 | flexcan_write(reg, ®s->mcr); | 317 | flexcan_write(reg, ®s->mcr); |
318 | |||
319 | while (timeout-- && !(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) | ||
320 | usleep_range(10, 20); | ||
321 | |||
322 | if (!(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) | ||
323 | return -ETIMEDOUT; | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static 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(®s->mcr); | ||
335 | reg |= FLEXCAN_MCR_HALT; | ||
336 | flexcan_write(reg, ®s->mcr); | ||
337 | |||
338 | while (timeout-- && !(flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) | ||
339 | usleep_range(100, 200); | ||
340 | |||
341 | if (!(flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) | ||
342 | return -ETIMEDOUT; | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static 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(®s->mcr); | ||
354 | reg &= ~FLEXCAN_MCR_HALT; | ||
355 | flexcan_write(reg, ®s->mcr); | ||
356 | |||
357 | while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) | ||
358 | usleep_range(10, 20); | ||
359 | |||
360 | if (flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK) | ||
361 | return -ETIMEDOUT; | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int flexcan_chip_softreset(struct flexcan_priv *priv) | ||
367 | { | ||
368 | struct flexcan_regs __iomem *regs = priv->base; | ||
369 | unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; | ||
370 | |||
371 | flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr); | ||
372 | while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_SOFTRST)) | ||
373 | usleep_range(10, 20); | ||
374 | |||
375 | if (flexcan_read(®s->mcr) & FLEXCAN_MCR_SOFTRST) | ||
376 | return -ETIMEDOUT; | ||
377 | |||
378 | return 0; | ||
289 | } | 379 | } |
290 | 380 | ||
291 | static int flexcan_get_berr_counter(const struct net_device *dev, | 381 | static int flexcan_get_berr_counter(const struct net_device *dev, |
@@ -706,19 +796,14 @@ static int flexcan_chip_start(struct net_device *dev) | |||
706 | u32 reg_mcr, reg_ctrl; | 796 | u32 reg_mcr, reg_ctrl; |
707 | 797 | ||
708 | /* enable module */ | 798 | /* enable module */ |
709 | flexcan_chip_enable(priv); | 799 | err = flexcan_chip_enable(priv); |
800 | if (err) | ||
801 | return err; | ||
710 | 802 | ||
711 | /* soft reset */ | 803 | /* soft reset */ |
712 | flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr); | 804 | err = flexcan_chip_softreset(priv); |
713 | udelay(10); | 805 | if (err) |
714 | 806 | goto out_chip_disable; | |
715 | reg_mcr = flexcan_read(®s->mcr); | ||
716 | if (reg_mcr & FLEXCAN_MCR_SOFTRST) { | ||
717 | netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n", | ||
718 | reg_mcr); | ||
719 | err = -ENODEV; | ||
720 | goto out; | ||
721 | } | ||
722 | 807 | ||
723 | flexcan_set_bittiming(dev); | 808 | flexcan_set_bittiming(dev); |
724 | 809 | ||
@@ -785,16 +870,14 @@ static int flexcan_chip_start(struct net_device *dev) | |||
785 | if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) | 870 | if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) |
786 | flexcan_write(0x0, ®s->rxfgmask); | 871 | flexcan_write(0x0, ®s->rxfgmask); |
787 | 872 | ||
788 | if (priv->reg_xceiver) { | 873 | err = flexcan_transceiver_enable(priv); |
789 | err = regulator_enable(priv->reg_xceiver); | 874 | if (err) |
790 | if (err) | 875 | goto out_chip_disable; |
791 | goto out; | ||
792 | } | ||
793 | 876 | ||
794 | /* synchronize with the can bus */ | 877 | /* synchronize with the can bus */ |
795 | reg_mcr = flexcan_read(®s->mcr); | 878 | err = flexcan_chip_unfreeze(priv); |
796 | reg_mcr &= ~FLEXCAN_MCR_HALT; | 879 | if (err) |
797 | flexcan_write(reg_mcr, ®s->mcr); | 880 | goto out_transceiver_disable; |
798 | 881 | ||
799 | priv->can.state = CAN_STATE_ERROR_ACTIVE; | 882 | priv->can.state = CAN_STATE_ERROR_ACTIVE; |
800 | 883 | ||
@@ -807,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev) | |||
807 | 890 | ||
808 | return 0; | 891 | return 0; |
809 | 892 | ||
810 | out: | 893 | out_transceiver_disable: |
894 | flexcan_transceiver_disable(priv); | ||
895 | out_chip_disable: | ||
811 | flexcan_chip_disable(priv); | 896 | flexcan_chip_disable(priv); |
812 | return err; | 897 | return err; |
813 | } | 898 | } |
@@ -822,18 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev) | |||
822 | { | 907 | { |
823 | struct flexcan_priv *priv = netdev_priv(dev); | 908 | struct flexcan_priv *priv = netdev_priv(dev); |
824 | struct flexcan_regs __iomem *regs = priv->base; | 909 | struct flexcan_regs __iomem *regs = priv->base; |
825 | u32 reg; | 910 | |
911 | /* freeze + disable module */ | ||
912 | flexcan_chip_freeze(priv); | ||
913 | flexcan_chip_disable(priv); | ||
826 | 914 | ||
827 | /* Disable all interrupts */ | 915 | /* Disable all interrupts */ |
828 | flexcan_write(0, ®s->imask1); | 916 | flexcan_write(0, ®s->imask1); |
917 | flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL, | ||
918 | ®s->ctrl); | ||
829 | 919 | ||
830 | /* Disable + halt module */ | 920 | flexcan_transceiver_disable(priv); |
831 | reg = flexcan_read(®s->mcr); | ||
832 | reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT; | ||
833 | flexcan_write(reg, ®s->mcr); | ||
834 | |||
835 | if (priv->reg_xceiver) | ||
836 | regulator_disable(priv->reg_xceiver); | ||
837 | priv->can.state = CAN_STATE_STOPPED; | 921 | priv->can.state = CAN_STATE_STOPPED; |
838 | 922 | ||
839 | return; | 923 | return; |
@@ -863,7 +947,7 @@ static int flexcan_open(struct net_device *dev) | |||
863 | /* start chip and queuing */ | 947 | /* start chip and queuing */ |
864 | err = flexcan_chip_start(dev); | 948 | err = flexcan_chip_start(dev); |
865 | if (err) | 949 | if (err) |
866 | goto out_close; | 950 | goto out_free_irq; |
867 | 951 | ||
868 | can_led_event(dev, CAN_LED_EVENT_OPEN); | 952 | can_led_event(dev, CAN_LED_EVENT_OPEN); |
869 | 953 | ||
@@ -872,6 +956,8 @@ static int flexcan_open(struct net_device *dev) | |||
872 | 956 | ||
873 | return 0; | 957 | return 0; |
874 | 958 | ||
959 | out_free_irq: | ||
960 | free_irq(dev->irq, dev); | ||
875 | out_close: | 961 | out_close: |
876 | close_candev(dev); | 962 | close_candev(dev); |
877 | out_disable_per: | 963 | out_disable_per: |
@@ -942,12 +1028,16 @@ static int register_flexcandev(struct net_device *dev) | |||
942 | goto out_disable_ipg; | 1028 | goto out_disable_ipg; |
943 | 1029 | ||
944 | /* select "bus clock", chip must be disabled */ | 1030 | /* select "bus clock", chip must be disabled */ |
945 | flexcan_chip_disable(priv); | 1031 | err = flexcan_chip_disable(priv); |
1032 | if (err) | ||
1033 | goto out_disable_per; | ||
946 | reg = flexcan_read(®s->ctrl); | 1034 | reg = flexcan_read(®s->ctrl); |
947 | reg |= FLEXCAN_CTRL_CLK_SRC; | 1035 | reg |= FLEXCAN_CTRL_CLK_SRC; |
948 | flexcan_write(reg, ®s->ctrl); | 1036 | flexcan_write(reg, ®s->ctrl); |
949 | 1037 | ||
950 | flexcan_chip_enable(priv); | 1038 | err = flexcan_chip_enable(priv); |
1039 | if (err) | ||
1040 | goto out_chip_disable; | ||
951 | 1041 | ||
952 | /* set freeze, halt and activate FIFO, restrict register access */ | 1042 | /* set freeze, halt and activate FIFO, restrict register access */ |
953 | reg = flexcan_read(®s->mcr); | 1043 | reg = flexcan_read(®s->mcr); |
@@ -964,14 +1054,15 @@ static int register_flexcandev(struct net_device *dev) | |||
964 | if (!(reg & FLEXCAN_MCR_FEN)) { | 1054 | if (!(reg & FLEXCAN_MCR_FEN)) { |
965 | netdev_err(dev, "Could not enable RX FIFO, unsupported core\n"); | 1055 | netdev_err(dev, "Could not enable RX FIFO, unsupported core\n"); |
966 | err = -ENODEV; | 1056 | err = -ENODEV; |
967 | goto out_disable_per; | 1057 | goto out_chip_disable; |
968 | } | 1058 | } |
969 | 1059 | ||
970 | err = register_candev(dev); | 1060 | err = register_candev(dev); |
971 | 1061 | ||
972 | out_disable_per: | ||
973 | /* disable core and turn off clocks */ | 1062 | /* disable core and turn off clocks */ |
1063 | out_chip_disable: | ||
974 | flexcan_chip_disable(priv); | 1064 | flexcan_chip_disable(priv); |
1065 | out_disable_per: | ||
975 | clk_disable_unprepare(priv->clk_per); | 1066 | clk_disable_unprepare(priv->clk_per); |
976 | out_disable_ipg: | 1067 | out_disable_ipg: |
977 | clk_disable_unprepare(priv->clk_ipg); | 1068 | clk_disable_unprepare(priv->clk_ipg); |
@@ -1101,9 +1192,10 @@ static int flexcan_probe(struct platform_device *pdev) | |||
1101 | static int flexcan_remove(struct platform_device *pdev) | 1192 | static int flexcan_remove(struct platform_device *pdev) |
1102 | { | 1193 | { |
1103 | struct net_device *dev = platform_get_drvdata(pdev); | 1194 | struct net_device *dev = platform_get_drvdata(pdev); |
1195 | struct flexcan_priv *priv = netdev_priv(dev); | ||
1104 | 1196 | ||
1105 | unregister_flexcandev(dev); | 1197 | unregister_flexcandev(dev); |
1106 | 1198 | netif_napi_del(&priv->napi); | |
1107 | free_candev(dev); | 1199 | free_candev(dev); |
1108 | 1200 | ||
1109 | return 0; | 1201 | return 0; |
@@ -1114,8 +1206,11 @@ static int flexcan_suspend(struct device *device) | |||
1114 | { | 1206 | { |
1115 | struct net_device *dev = dev_get_drvdata(device); | 1207 | struct net_device *dev = dev_get_drvdata(device); |
1116 | struct flexcan_priv *priv = netdev_priv(dev); | 1208 | struct flexcan_priv *priv = netdev_priv(dev); |
1209 | int err; | ||
1117 | 1210 | ||
1118 | flexcan_chip_disable(priv); | 1211 | err = flexcan_chip_disable(priv); |
1212 | if (err) | ||
1213 | return err; | ||
1119 | 1214 | ||
1120 | if (netif_running(dev)) { | 1215 | if (netif_running(dev)) { |
1121 | netif_stop_queue(dev); | 1216 | netif_stop_queue(dev); |
@@ -1136,9 +1231,7 @@ static int flexcan_resume(struct device *device) | |||
1136 | netif_device_attach(dev); | 1231 | netif_device_attach(dev); |
1137 | netif_start_queue(dev); | 1232 | netif_start_queue(dev); |
1138 | } | 1233 | } |
1139 | flexcan_chip_enable(priv); | 1234 | return flexcan_chip_enable(priv); |
1140 | |||
1141 | return 0; | ||
1142 | } | 1235 | } |
1143 | #endif /* CONFIG_PM_SLEEP */ | 1236 | #endif /* CONFIG_PM_SLEEP */ |
1144 | 1237 | ||