can: mscan-mpc5xxx: add support for the MPC512x processor
authorWolfgang Grandegger <wg@denx.de>
Thu, 7 Jan 2010 09:43:07 +0000 (09:43 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 8 Jan 2010 09:02:18 +0000 (01:02 -0800)
The main differences compared to the MSCAN on the MPC5200 are:

- More flexibility in choosing the CAN source clock and frequency:

  Three different clock sources can be selected: "ip", "ref" or "sys".
  For the latter two, a clock divider can be defined as well. If the
  clock source is not specified by the device tree, we first try to
  find an optimal CAN source clock based on the system clock. If that
  is not possible, the reference clock will be used.

- The behavior of bus-off recovery is configurable:

  To comply with the usual handling of Socket-CAN bus-off recovery,
  "recovery on request" is selected (instead of automatic recovery).

Note that only MPC5121 Rev. 2 and later is supported.

Signed-off-by: Wolfgang Grandegger <wg@denx.de>
Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/can/mscan/Kconfig
drivers/net/can/mscan/mpc5xxx_can.c
drivers/net/can/mscan/mscan.c
drivers/net/can/mscan/mscan.h

index cd0f2d6f375d3e42e2384290251831c43308cb28..27d1d398e25e54c47c5f8ef4843575c43c338075 100644 (file)
@@ -11,12 +11,13 @@ if CAN_MSCAN
 
 config CAN_MPC5XXX
        tristate "Freescale MPC5xxx onboard CAN controller"
-       depends on PPC_MPC52xx
+       depends on (PPC_MPC52xx || PPC_MPC512x)
        ---help---
          If you say yes here you get support for Freescale's MPC5xxx
-         onboard CAN controller.
+         onboard CAN controller. Currently, the MPC5200, MPC5200B and
+         MPC5121 (Rev. 2 and later) are supported.
 
-         This driver can also be built as a module.  If so, the module
+         This driver can also be built as a module. If so, the module
          will be called mscan-mpc5xxx.ko.
 
 endif
index 1de6f6349b16c914c9ad01dcbe05fa99f5562872..f73487f723b8d6f1d4de8c74569429494c0a5c65 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/can/dev.h>
 #include <linux/of_platform.h>
 #include <sysdev/fsl_soc.h>
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <asm/mpc52xx.h>
 
 
 #define DRV_NAME "mpc5xxx_can"
 
-static struct of_device_id mpc52xx_cdm_ids[] __devinitdata = {
+struct mpc5xxx_can_data {
+       unsigned int type;
+       u32 (*get_clock)(struct of_device *ofdev, const char *clock_name,
+                        int *mscan_clksrc);
+};
+
+#ifdef CONFIG_PPC_MPC5200
+static struct of_device_id __devinitdata mpc52xx_cdm_ids[] = {
        { .compatible = "fsl,mpc5200-cdm", },
        {}
 };
 
-/*
- * Get frequency of the MSCAN clock source
- *
- * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock (IP_CLK)
- * can be selected. According to the MPC5200 user's manual, the oscillator
- * clock is the better choice as it has less jitter but due to a hardware
- * bug, it can not be selected for the old MPC5200 Rev. A chips.
- */
-
-static unsigned int  __devinit mpc52xx_can_clock_freq(struct of_device *of,
-                                                     int clock_src)
+static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
+                                          const char *clock_name,
+                                          int *mscan_clksrc)
 {
        unsigned int pvr;
        struct mpc52xx_cdm  __iomem *cdm;
@@ -61,11 +61,24 @@ static unsigned int  __devinit mpc52xx_can_clock_freq(struct of_device *of,
 
        pvr = mfspr(SPRN_PVR);
 
-       freq = mpc5xxx_get_bus_frequency(of->node);
+       /*
+        * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
+        * (IP_CLK) can be selected as MSCAN clock source. According to
+        * the MPC5200 user's manual, the oscillator clock is the better
+        * choice as it has less jitter. For this reason, it is selected
+        * by default. Unfortunately, it can not be selected for the old
+        * MPC5200 Rev. A chips due to a hardware bug (check errata).
+        */
+       if (clock_name && strcmp(clock_name, "ip") == 0)
+               *mscan_clksrc = MSCAN_CLKSRC_BUS;
+       else
+               *mscan_clksrc = MSCAN_CLKSRC_XTAL;
+
+       freq = mpc5xxx_get_bus_frequency(ofdev->node);
        if (!freq)
                return 0;
 
-       if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
+       if (*mscan_clksrc == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
                return freq;
 
        /* Determine SYS_XTAL_IN frequency from the clock domain settings */
@@ -75,7 +88,6 @@ static unsigned int  __devinit mpc52xx_can_clock_freq(struct of_device *of,
                return 0;
        }
        cdm = of_iomap(np_cdm, 0);
-       of_node_put(np_cdm);
 
        if (in_8(&cdm->ipb_clk_sel) & 0x1)
                freq *= 2;
@@ -84,26 +96,174 @@ static unsigned int  __devinit mpc52xx_can_clock_freq(struct of_device *of,
        freq *= (val & (1 << 5)) ? 8 : 4;
        freq /= (val & (1 << 6)) ? 12 : 16;
 
+       of_node_put(np_cdm);
        iounmap(cdm);
 
        return freq;
 }
+#else /* !CONFIG_PPC_MPC5200 */
+static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
+                                          const char *clock_name,
+                                          int *mscan_clksrc)
+{
+       return 0;
+}
+#endif /* CONFIG_PPC_MPC5200 */
+
+#ifdef CONFIG_PPC_MPC512x
+struct mpc512x_clockctl {
+       u32 spmr;               /* System PLL Mode Reg */
+       u32 sccr[2];            /* System Clk Ctrl Reg 1 & 2 */
+       u32 scfr1;              /* System Clk Freq Reg 1 */
+       u32 scfr2;              /* System Clk Freq Reg 2 */
+       u32 reserved;
+       u32 bcr;                /* Bread Crumb Reg */
+       u32 pccr[12];           /* PSC Clk Ctrl Reg 0-11 */
+       u32 spccr;              /* SPDIF Clk Ctrl Reg */
+       u32 cccr;               /* CFM Clk Ctrl Reg */
+       u32 dccr;               /* DIU Clk Cnfg Reg */
+       u32 mccr[4];            /* MSCAN Clk Ctrl Reg 1-3 */
+};
+
+static struct of_device_id __devinitdata mpc512x_clock_ids[] = {
+       { .compatible = "fsl,mpc5121-clock", },
+       {}
+};
+
+static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
+                                          const char *clock_name,
+                                          int *mscan_clksrc)
+{
+       struct mpc512x_clockctl __iomem *clockctl;
+       struct device_node *np_clock;
+       struct clk *sys_clk, *ref_clk;
+       int plen, clockidx, clocksrc = -1;
+       u32 sys_freq, val, clockdiv = 1, freq = 0;
+       const u32 *pval;
+
+       np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
+       if (!np_clock) {
+               dev_err(&ofdev->dev, "couldn't find clock node\n");
+               return -ENODEV;
+       }
+       clockctl = of_iomap(np_clock, 0);
+       if (!clockctl) {
+               dev_err(&ofdev->dev, "couldn't map clock registers\n");
+               return 0;
+       }
+
+       /* Determine the MSCAN device index from the physical address */
+       pval = of_get_property(ofdev->node, "reg", &plen);
+       BUG_ON(!pval || plen < sizeof(*pval));
+       clockidx = (*pval & 0x80) ? 1 : 0;
+       if (*pval & 0x2000)
+               clockidx += 2;
+
+       /*
+        * Clock source and divider selection: 3 different clock sources
+        * can be selected: "ip", "ref" or "sys". For the latter two, a
+        * clock divider can be defined as well. If the clock source is
+        * not specified by the device tree, we first try to find an
+        * optimal CAN source clock based on the system clock. If that
+        * is not posslible, the reference clock will be used.
+        */
+       if (clock_name && !strcmp(clock_name, "ip")) {
+               *mscan_clksrc = MSCAN_CLKSRC_IPS;
+               freq = mpc5xxx_get_bus_frequency(ofdev->node);
+       } else {
+               *mscan_clksrc = MSCAN_CLKSRC_BUS;
+
+               pval = of_get_property(ofdev->node,
+                                      "fsl,mscan-clock-divider", &plen);
+               if (pval && plen == sizeof(*pval))
+                       clockdiv = *pval;
+               if (!clockdiv)
+                       clockdiv = 1;
+
+               if (!clock_name || !strcmp(clock_name, "sys")) {
+                       sys_clk = clk_get(&ofdev->dev, "sys_clk");
+                       if (!sys_clk) {
+                               dev_err(&ofdev->dev, "couldn't get sys_clk\n");
+                               goto exit_unmap;
+                       }
+                       /* Get and round up/down sys clock rate */
+                       sys_freq = 1000000 *
+                               ((clk_get_rate(sys_clk) + 499999) / 1000000);
+
+                       if (!clock_name) {
+                               /* A multiple of 16 MHz would be optimal */
+                               if ((sys_freq % 16000000) == 0) {
+                                       clocksrc = 0;
+                                       clockdiv = sys_freq / 16000000;
+                                       freq = sys_freq / clockdiv;
+                               }
+                       } else {
+                               clocksrc = 0;
+                               freq = sys_freq / clockdiv;
+                       }
+               }
+
+               if (clocksrc < 0) {
+                       ref_clk = clk_get(&ofdev->dev, "ref_clk");
+                       if (!ref_clk) {
+                               dev_err(&ofdev->dev, "couldn't get ref_clk\n");
+                               goto exit_unmap;
+                       }
+                       clocksrc = 1;
+                       freq = clk_get_rate(ref_clk) / clockdiv;
+               }
+       }
+
+       /* Disable clock */
+       out_be32(&clockctl->mccr[clockidx], 0x0);
+       if (clocksrc >= 0) {
+               /* Set source and divider */
+               val = (clocksrc << 14) | ((clockdiv - 1) << 17);
+               out_be32(&clockctl->mccr[clockidx], val);
+               /* Enable clock */
+               out_be32(&clockctl->mccr[clockidx], val | 0x10000);
+       }
+
+       /* Enable MSCAN clock domain */
+       val = in_be32(&clockctl->sccr[1]);
+       if (!(val & (1 << 25)))
+               out_be32(&clockctl->sccr[1], val | (1 << 25));
+
+       dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
+               *mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
+               clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
+
+exit_unmap:
+       of_node_put(np_clock);
+       iounmap(clockctl);
+
+       return freq;
+}
+#else /* !CONFIG_PPC_MPC512x */
+static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
+                                          const char *clock_name,
+                                          int *mscan_clksrc)
+{
+       return 0;
+}
+#endif /* CONFIG_PPC_MPC512x */
 
 static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
                                       const struct of_device_id *id)
 {
+       struct mpc5xxx_can_data *data = (struct mpc5xxx_can_data *)id->data;
        struct device_node *np = ofdev->node;
        struct net_device *dev;
        struct mscan_priv *priv;
        void __iomem *base;
-       const char *clk_src;
-       int err, irq, clock_src;
+       const char *clock_name = NULL;
+       int irq, mscan_clksrc = 0;
+       int err = -ENOMEM;
 
-       base = of_iomap(ofdev->node, 0);
+       base = of_iomap(np, 0);
        if (!base) {
                dev_err(&ofdev->dev, "couldn't ioremap\n");
-               err = -ENOMEM;
-               goto exit_release_mem;
+               return err;
        }
 
        irq = irq_of_parse_and_map(np, 0);
@@ -114,37 +274,27 @@ static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
        }
 
        dev = alloc_mscandev();
-       if (!dev) {
-               err = -ENOMEM;
+       if (!dev)
                goto exit_dispose_irq;
-       }
 
        priv = netdev_priv(dev);
        priv->reg_base = base;
        dev->irq = irq;
 
-       /*
-        * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
-        * (IP_CLK) can be selected as MSCAN clock source. According to
-        * the MPC5200 user's manual, the oscillator clock is the better
-        * choice as it has less jitter. For this reason, it is selected
-        * by default.
-        */
-       clk_src = of_get_property(np, "fsl,mscan-clock-source", NULL);
-       if (clk_src && strcmp(clk_src, "ip") == 0)
-               clock_src = MSCAN_CLKSRC_BUS;
-       else
-               clock_src = MSCAN_CLKSRC_XTAL;
-       priv->can.clock.freq = mpc52xx_can_clock_freq(ofdev, clock_src);
+       clock_name = of_get_property(np, "fsl,mscan-clock-source", NULL);
+
+       BUG_ON(!data);
+       priv->type = data->type;
+       priv->can.clock.freq = data->get_clock(ofdev, clock_name,
+                                              &mscan_clksrc);
        if (!priv->can.clock.freq) {
-               dev_err(&ofdev->dev, "couldn't get MSCAN clock frequency\n");
-               err = -ENODEV;
+               dev_err(&ofdev->dev, "couldn't get MSCAN clock properties\n");
                goto exit_free_mscan;
        }
 
        SET_NETDEV_DEV(dev, &ofdev->dev);
 
-       err = register_mscandev(dev, clock_src);
+       err = register_mscandev(dev, mscan_clksrc);
        if (err) {
                dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
                        DRV_NAME, err);
@@ -164,7 +314,7 @@ exit_dispose_irq:
        irq_dispose_mapping(irq);
 exit_unmap_mem:
        iounmap(base);
-exit_release_mem:
+
        return err;
 }
 
@@ -225,8 +375,20 @@ static int mpc5xxx_can_resume(struct of_device *ofdev)
 }
 #endif
 
+static struct mpc5xxx_can_data __devinitdata mpc5200_can_data = {
+       .type = MSCAN_TYPE_MPC5200,
+       .get_clock = mpc52xx_can_get_clock,
+};
+
+static struct mpc5xxx_can_data __devinitdata mpc5121_can_data = {
+       .type = MSCAN_TYPE_MPC5121,
+       .get_clock = mpc512x_can_get_clock,
+};
+
 static struct of_device_id __devinitdata mpc5xxx_can_table[] = {
-       {.compatible = "fsl,mpc5200-mscan"},
+       { .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, },
+       /* Note that only MPC5121 Rev. 2 (and later) is supported */
+       { .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, },
        {},
 };
 
@@ -255,5 +417,5 @@ static void __exit mpc5xxx_can_exit(void)
 module_exit(mpc5xxx_can_exit);
 
 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
-MODULE_DESCRIPTION("Freescale MPC5200 CAN driver");
+MODULE_DESCRIPTION("Freescale MPC5xxx CAN driver");
 MODULE_LICENSE("GPL v2");
index 0dcbe8cfab648fa4ba3ec692db6d33d1d8757f83..500d18918bd574205fe822d3ead94a20f6771f46 100644 (file)
@@ -152,6 +152,12 @@ static int mscan_start(struct net_device *dev)
        priv->shadow_canrier = 0;
        priv->flags = 0;
 
+       if (priv->type == MSCAN_TYPE_MPC5121) {
+               /* Clear pending bus-off condition */
+               if (in_8(&regs->canmisc) & MSCAN_BOHOLD)
+                       out_8(&regs->canmisc, MSCAN_BOHOLD);
+       }
+
        err = mscan_set_mode(dev, MSCAN_NORMAL_MODE);
        if (err)
                return err;
@@ -163,8 +169,29 @@ static int mscan_start(struct net_device *dev)
        out_8(&regs->cantier, 0);
 
        /* Enable receive interrupts. */
-       out_8(&regs->canrier, MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE |
-             MSCAN_RSTATE1 | MSCAN_RSTATE0 | MSCAN_TSTATE1 | MSCAN_TSTATE0);
+       out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
+
+       return 0;
+}
+
+static int mscan_restart(struct net_device *dev)
+{
+       struct mscan_priv *priv = netdev_priv(dev);
+
+       if (priv->type == MSCAN_TYPE_MPC5121) {
+               struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
+               WARN(!(in_8(&regs->canmisc) & MSCAN_BOHOLD),
+                    "bus-off state expected");
+               out_8(&regs->canmisc, MSCAN_BOHOLD);
+               /* Re-enable receive interrupts. */
+               out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
+       } else {
+               if (priv->can.state <= CAN_STATE_BUS_OFF)
+                       mscan_set_mode(dev, MSCAN_INIT_MODE);
+               return mscan_start(dev);
+       }
 
        return 0;
 }
@@ -362,9 +389,12 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
                         * automatically. To avoid that we stop the chip doing
                         * a light-weight stop (we are in irq-context).
                         */
-                       out_8(&regs->cantier, 0);
-                       out_8(&regs->canrier, 0);
-                       setbits8(&regs->canctl0, MSCAN_SLPRQ | MSCAN_INITRQ);
+                       if (priv->type != MSCAN_TYPE_MPC5121) {
+                               out_8(&regs->cantier, 0);
+                               out_8(&regs->canrier, 0);
+                               setbits8(&regs->canctl0,
+                                        MSCAN_SLPRQ | MSCAN_INITRQ);
+                       }
                        can_bus_off(dev);
                        break;
                default:
@@ -494,9 +524,7 @@ static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)
 
        switch (mode) {
        case CAN_MODE_START:
-               if (priv->can.state <= CAN_STATE_BUS_OFF)
-                       mscan_set_mode(dev, MSCAN_INIT_MODE);
-               ret = mscan_start(dev);
+               ret = mscan_restart(dev);
                if (ret)
                        break;
                if (netif_queue_stopped(dev))
@@ -595,18 +623,21 @@ static const struct net_device_ops mscan_netdev_ops = {
        .ndo_start_xmit         = mscan_start_xmit,
 };
 
-int register_mscandev(struct net_device *dev, int clock_src)
+int register_mscandev(struct net_device *dev, int mscan_clksrc)
 {
        struct mscan_priv *priv = netdev_priv(dev);
        struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
        u8 ctl1;
 
        ctl1 = in_8(&regs->canctl1);
-       if (clock_src)
+       if (mscan_clksrc)
                ctl1 |= MSCAN_CLKSRC;
        else
                ctl1 &= ~MSCAN_CLKSRC;
 
+       if (priv->type == MSCAN_TYPE_MPC5121)
+               ctl1 |= MSCAN_BORM; /* bus-off recovery upon request */
+
        ctl1 |= MSCAN_CANE;
        out_8(&regs->canctl1, ctl1);
        udelay(100);
index 00fc4aaf1ed8ca04533203813322914f8832202f..4ff966473bc9596477431637923a8fa5c2e8c2ab 100644 (file)
 #define MSCAN_CLKSRC           0x40
 #define MSCAN_LOOPB            0x20
 #define MSCAN_LISTEN           0x10
+#define MSCAN_BORM             0x08
 #define MSCAN_WUPM             0x04
 #define MSCAN_SLPAK            0x02
 #define MSCAN_INITAK           0x01
 
-/* Use the MPC5200 MSCAN variant? */
+/* Use the MPC5XXX MSCAN variant? */
 #ifdef CONFIG_PPC
-#define MSCAN_FOR_MPC5200
+#define MSCAN_FOR_MPC5XXX
 #endif
 
-#ifdef MSCAN_FOR_MPC5200
+#ifdef MSCAN_FOR_MPC5XXX
 #define MSCAN_CLKSRC_BUS       0
 #define MSCAN_CLKSRC_XTAL      MSCAN_CLKSRC
+#define MSCAN_CLKSRC_IPS       MSCAN_CLKSRC
 #else
 #define MSCAN_CLKSRC_BUS       MSCAN_CLKSRC
 #define MSCAN_CLKSRC_XTAL      0
 #define MSCAN_EFF_RTR_SHIFT    0
 #define MSCAN_EFF_FLAGS                0x18    /* IDE + SRR */
 
-#ifdef MSCAN_FOR_MPC5200
+#ifdef MSCAN_FOR_MPC5XXX
 #define _MSCAN_RESERVED_(n, num) u8 _res##n[num]
 #define _MSCAN_RESERVED_DSR_SIZE       2
 #else
@@ -165,67 +167,66 @@ struct mscan_regs {
        u8 cantbsel;                            /* + 0x14     0x0a */
        u8 canidac;                             /* + 0x15     0x0b */
        u8 reserved;                            /* + 0x16     0x0c */
-       _MSCAN_RESERVED_(6, 5);                 /* + 0x17          */
-#ifndef MSCAN_FOR_MPC5200
-       u8 canmisc;                             /*            0x0d */
-#endif
+       _MSCAN_RESERVED_(6, 2);                 /* + 0x17          */
+       u8 canmisc;                             /* + 0x19     0x0d */
+       _MSCAN_RESERVED_(7, 2);                 /* + 0x1a          */
        u8 canrxerr;                            /* + 0x1c     0x0e */
        u8 cantxerr;                            /* + 0x1d     0x0f */
-       _MSCAN_RESERVED_(7, 2);                 /* + 0x1e          */
+       _MSCAN_RESERVED_(8, 2);                 /* + 0x1e          */
        u16 canidar1_0;                         /* + 0x20     0x10 */
-       _MSCAN_RESERVED_(8, 2);                 /* + 0x22          */
+       _MSCAN_RESERVED_(9, 2);                 /* + 0x22          */
        u16 canidar3_2;                         /* + 0x24     0x12 */
-       _MSCAN_RESERVED_(9, 2);                 /* + 0x26          */
+       _MSCAN_RESERVED_(10, 2);                /* + 0x26          */
        u16 canidmr1_0;                         /* + 0x28     0x14 */
-       _MSCAN_RESERVED_(10, 2);                /* + 0x2a          */
+       _MSCAN_RESERVED_(11, 2);                /* + 0x2a          */
        u16 canidmr3_2;                         /* + 0x2c     0x16 */
-       _MSCAN_RESERVED_(11, 2);                /* + 0x2e          */
+       _MSCAN_RESERVED_(12, 2);                /* + 0x2e          */
        u16 canidar5_4;                         /* + 0x30     0x18 */
-       _MSCAN_RESERVED_(12, 2);                /* + 0x32          */
+       _MSCAN_RESERVED_(13, 2);                /* + 0x32          */
        u16 canidar7_6;                         /* + 0x34     0x1a */
-       _MSCAN_RESERVED_(13, 2);                /* + 0x36          */
+       _MSCAN_RESERVED_(14, 2);                /* + 0x36          */
        u16 canidmr5_4;                         /* + 0x38     0x1c */
-       _MSCAN_RESERVED_(14, 2);                /* + 0x3a          */
+       _MSCAN_RESERVED_(15, 2);                /* + 0x3a          */
        u16 canidmr7_6;                         /* + 0x3c     0x1e */
-       _MSCAN_RESERVED_(15, 2);                /* + 0x3e          */
+       _MSCAN_RESERVED_(16, 2);                /* + 0x3e          */
        struct {
                u16 idr1_0;                     /* + 0x40     0x20 */
-                _MSCAN_RESERVED_(16, 2);       /* + 0x42          */
+               _MSCAN_RESERVED_(17, 2);        /* + 0x42          */
                u16 idr3_2;                     /* + 0x44     0x22 */
-                _MSCAN_RESERVED_(17, 2);       /* + 0x46          */
+               _MSCAN_RESERVED_(18, 2);        /* + 0x46          */
                u16 dsr1_0;                     /* + 0x48     0x24 */
-                _MSCAN_RESERVED_(18, 2);       /* + 0x4a          */
+               _MSCAN_RESERVED_(19, 2);        /* + 0x4a          */
                u16 dsr3_2;                     /* + 0x4c     0x26 */
-                _MSCAN_RESERVED_(19, 2);       /* + 0x4e          */
+               _MSCAN_RESERVED_(20, 2);        /* + 0x4e          */
                u16 dsr5_4;                     /* + 0x50     0x28 */
-                _MSCAN_RESERVED_(20, 2);       /* + 0x52          */
+               _MSCAN_RESERVED_(21, 2);        /* + 0x52          */
                u16 dsr7_6;                     /* + 0x54     0x2a */
-                _MSCAN_RESERVED_(21, 2);       /* + 0x56          */
+               _MSCAN_RESERVED_(22, 2);        /* + 0x56          */
                u8 dlr;                         /* + 0x58     0x2c */
-                u8:8;                          /* + 0x59     0x2d */
-                _MSCAN_RESERVED_(22, 2);       /* + 0x5a          */
+               u8 reserved;                    /* + 0x59     0x2d */
+               _MSCAN_RESERVED_(23, 2);        /* + 0x5a          */
                u16 time;                       /* + 0x5c     0x2e */
        } rx;
-        _MSCAN_RESERVED_(23, 2);               /* + 0x5e          */
+       _MSCAN_RESERVED_(24, 2);                /* + 0x5e          */
        struct {
                u16 idr1_0;                     /* + 0x60     0x30 */
-                _MSCAN_RESERVED_(24, 2);       /* + 0x62          */
+               _MSCAN_RESERVED_(25, 2);        /* + 0x62          */
                u16 idr3_2;                     /* + 0x64     0x32 */
-                _MSCAN_RESERVED_(25, 2);       /* + 0x66          */
+               _MSCAN_RESERVED_(26, 2);        /* + 0x66          */
                u16 dsr1_0;                     /* + 0x68     0x34 */
-                _MSCAN_RESERVED_(26, 2);       /* + 0x6a          */
+               _MSCAN_RESERVED_(27, 2);        /* + 0x6a          */
                u16 dsr3_2;                     /* + 0x6c     0x36 */
-                _MSCAN_RESERVED_(27, 2);       /* + 0x6e          */
+               _MSCAN_RESERVED_(28, 2);        /* + 0x6e          */
                u16 dsr5_4;                     /* + 0x70     0x38 */
-                _MSCAN_RESERVED_(28, 2);       /* + 0x72          */
+               _MSCAN_RESERVED_(29, 2);        /* + 0x72          */
                u16 dsr7_6;                     /* + 0x74     0x3a */
-                _MSCAN_RESERVED_(29, 2);       /* + 0x76          */
+               _MSCAN_RESERVED_(30, 2);        /* + 0x76          */
                u8 dlr;                         /* + 0x78     0x3c */
                u8 tbpr;                        /* + 0x79     0x3d */
-                _MSCAN_RESERVED_(30, 2);       /* + 0x7a          */
+               _MSCAN_RESERVED_(31, 2);        /* + 0x7a          */
                u16 time;                       /* + 0x7c     0x3e */
        } tx;
-        _MSCAN_RESERVED_(31, 2);               /* + 0x7e          */
+       _MSCAN_RESERVED_(32, 2);                /* + 0x7e          */
 } __attribute__ ((packed));
 
 #undef _MSCAN_RESERVED_
@@ -237,6 +238,15 @@ struct mscan_regs {
 #define MSCAN_POWEROFF_MODE    (MSCAN_CSWAI | MSCAN_SLPRQ)
 #define MSCAN_SET_MODE_RETRIES 255
 #define MSCAN_ECHO_SKB_MAX     3
+#define MSCAN_RX_INTS_ENABLE   (MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE | \
+                                MSCAN_RSTATE1 | MSCAN_RSTATE0 | \
+                                MSCAN_TSTATE1 | MSCAN_TSTATE0)
+
+/* MSCAN type variants */
+enum {
+       MSCAN_TYPE_MPC5200,
+       MSCAN_TYPE_MPC5121
+};
 
 #define BTR0_BRP_MASK          0x3f
 #define BTR0_SJW_SHIFT         6
@@ -270,6 +280,7 @@ struct tx_queue_entry {
 
 struct mscan_priv {
        struct can_priv can;    /* must be the first member */
+       unsigned int type;      /* MSCAN type variants */
        long open_time;
        unsigned long flags;
        void __iomem *reg_base; /* ioremap'ed address to registers */
@@ -285,12 +296,7 @@ struct mscan_priv {
 };
 
 extern struct net_device *alloc_mscandev(void);
-/*
- * clock_src:
- *     1 = The MSCAN clock source is the onchip Bus Clock.
- *     0 = The MSCAN clock source is the chip Oscillator Clock.
- */
-extern int register_mscandev(struct net_device *dev, int clock_src);
+extern int register_mscandev(struct net_device *dev, int mscan_clksrc);
 extern void unregister_mscandev(struct net_device *dev);
 
 #endif /* __MSCAN_H__ */