diff mbox

[net-next,2/3] can: mscan-mpc5xxx: add support for the MPC521x processor

Message ID 1262420274-16586-3-git-send-email-wg@grandegger.com (mailing list archive)
State Not Applicable
Headers show

Commit Message

Wolfgang Grandegger Jan. 2, 2010, 8:17 a.m. UTC
From: Wolfgang Grandegger <wg@denx.de>

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).

Signed-off-by: Wolfgang Grandegger <wg@denx.de>
---
 drivers/net/can/mscan/Kconfig       |    2 +-
 drivers/net/can/mscan/mpc5xxx_can.c |  234 +++++++++++++++++++++++++++++------
 drivers/net/can/mscan/mscan.c       |   41 +++++--
 drivers/net/can/mscan/mscan.h       |   81 ++++++------
 4 files changed, 271 insertions(+), 87 deletions(-)

Comments

Wolfram Sang Jan. 2, 2010, 1:57 p.m. UTC | #1
On Sat, Jan 02, 2010 at 09:17:53AM +0100, Wolfgang Grandegger wrote:
> From: Wolfgang Grandegger <wg@denx.de>
> 
> 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).
> 
> Signed-off-by: Wolfgang Grandegger <wg@denx.de>
> ---
>  drivers/net/can/mscan/Kconfig       |    2 +-
>  drivers/net/can/mscan/mpc5xxx_can.c |  234 +++++++++++++++++++++++++++++------
>  drivers/net/can/mscan/mscan.c       |   41 +++++--
>  drivers/net/can/mscan/mscan.h       |   81 ++++++------
>  4 files changed, 271 insertions(+), 87 deletions(-)
> 
> diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig
> index cd0f2d6..723d009 100644
> --- a/drivers/net/can/mscan/Kconfig
> +++ b/drivers/net/can/mscan/Kconfig
> @@ -11,7 +11,7 @@ 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.
> diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
> index 1de6f63..42c719b 100644
> --- a/drivers/net/can/mscan/mpc5xxx_can.c
> +++ b/drivers/net/can/mscan/mpc5xxx_can.c
> @@ -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>
>  
> @@ -36,22 +37,15 @@
>  
>  #define DRV_NAME "mpc5xxx_can"
>  
> +#ifdef CONFIG_PPC_MPC5200
>  static struct of_device_id mpc52xx_cdm_ids[] __devinitdata = {
>  	{ .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 +55,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 toa hardware bug (check errata).

s/toa/to a/

> +	 */
> +	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 +82,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,10 +90,157 @@ 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 */

Hmmm, I don't really like those empty functions. I once used the data-field of
struct of_device_id, which carried a function pointer to a specific
init-function for the matched device. What do you think about such an approach?

> +
> +#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 mpc512x_clock_ids[] __devinitdata = {
> +	{ .compatible = "fsl,mpc5121-clock", },
> +	{}
> +};
> +
> +static u32  __devinit mpc512x_can_get_clock(struct of_device *ofdev,
> +					    const char *clock_name,
> +					    int *mscan_clksrc,
> +					    ssize_t mscan_addr)
> +{
> +	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 */
> +	clockidx = (mscan_addr & 0x80) ? 1 : 0;
> +	if (mscan_addr & 0x2000)
> +		clockidx += 2;

The PSCs use 'cell-index', here we use mscan_addr to derive the index. This is
not consistent, but should be IMHO. Now, which is the preferred way? I think
I'd go for 'cell-index', as other processors might have mscan_addr shuffled.
Also, we could use 'of_iomap' again in the probe_routine.

> +
> +	/*
> +	 * Clock source and divider selection: 3 different clock sources
> +	 * can be selected: "ip", "ref" or "sys". For the latetr 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);
> +		/* Dnable clock */

Enable

> +		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,
> +					    ssize_t mscan_addr)
> +{
> +	return 0;
> +}
> +#endif /* CONFIG_PPC_MPC512x */
>  
>  static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
>  				       const struct of_device_id *id)
> @@ -95,15 +248,21 @@ static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
>  	struct device_node *np = ofdev->node;
>  	struct net_device *dev;
>  	struct mscan_priv *priv;
> +	struct resource res;
>  	void __iomem *base;
> -	const char *clk_src;
> -	int err, irq, clock_src;
> +	const char *clock_name = NULL;
> +	int irq, clock_src = 0;
> +	int err = -ENOMEM;
>  
> -	base = of_iomap(ofdev->node, 0);
> +	if (of_address_to_resource(np, 0, &res)) {
> +		dev_err(&ofdev->dev, "couldn't get resource address\n");
> +		return err;
> +	}
> +
> +	base = ioremap(res.start, resource_size(&res));
>  	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,31 +273,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);
> +
> +	if (of_device_is_compatible(np, "fsl,mpc5121-mscan")) {
> +		priv->type = MSCAN_TYPE_MPC5121;
> +		priv->can.clock.freq =
> +			mpc512x_can_get_clock(ofdev, clock_name, &clock_src,
> +					      res.start);
> +	} else {
> +		priv->type = MSCAN_TYPE_MPC5200;
> +		priv->can.clock.freq =
> +			mpc52xx_can_get_clock(ofdev, clock_name, &clock_src);
> +	}
>  	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;
>  	}
>  
> @@ -164,7 +319,7 @@ exit_dispose_irq:
>  	irq_dispose_mapping(irq);
>  exit_unmap_mem:
>  	iounmap(base);
> -exit_release_mem:
> +
>  	return err;
>  }
>  
> @@ -227,6 +382,7 @@ static int mpc5xxx_can_resume(struct of_device *ofdev)
>  
>  static struct of_device_id __devinitdata mpc5xxx_can_table[] = {
>  	{.compatible = "fsl,mpc5200-mscan"},
> +	{.compatible = "fsl,mpc5121-mscan"},
>  	{},
>  };
>  
> @@ -255,5 +411,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 MPC5200 and MPC521x CAN driver");

simply 5xxx?

>  MODULE_LICENSE("GPL v2");
> diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
> index abdf5e8..9812aa0 100644
> --- a/drivers/net/can/mscan/mscan.c
> +++ b/drivers/net/can/mscan/mscan.c
> @@ -169,6 +169,27 @@ static int mscan_start(struct net_device *dev)
>  	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;
> +		if (!(in_8(&regs->canmisc) & MSCAN_BOHOLD))
> +			dev_err(dev->dev.parent, "Oops, not bus-off");

I think this error-message could be improved :)

> +		else
> +			out_8(&regs->canmisc, MSCAN_BOHOLD);
> +	} else {
> +		if (priv->can.state <= CAN_STATE_BUS_OFF)
> +			mscan_set_mode(dev, MSCAN_INIT_MODE);
> +		return mscan_start(dev);
> +	}
> +
> +	return 0;
> +}
> +
>  static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
>  {
>  	struct can_frame *frame = (struct can_frame *)skb->data;
> @@ -364,9 +385,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:
> @@ -496,9 +520,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))
> @@ -597,18 +619,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);
> diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
> index 00fc4aa..2114942 100644
> --- a/drivers/net/can/mscan/mscan.h
> +++ b/drivers/net/can/mscan/mscan.h
> @@ -39,17 +39,19 @@
>  #define MSCAN_LOOPB		0x20
>  #define MSCAN_LISTEN		0x10
>  #define MSCAN_WUPM		0x04
> +#define MSCAN_BORM		0x08

This should be one line up to keep the sorting intact.

>  #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
> @@ -136,7 +138,7 @@
>  #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_
> @@ -238,6 +239,12 @@ struct mscan_regs {
>  #define MSCAN_SET_MODE_RETRIES	255
>  #define MSCAN_ECHO_SKB_MAX	3
>  
> +/* MSCAN type variants */
> +enum {
> +	MSCAN_TYPE_MPC5200,
> +	MSCAN_TYPE_MPC5121
> +};
> +
>  #define BTR0_BRP_MASK		0x3f
>  #define BTR0_SJW_SHIFT		6
>  #define BTR0_SJW_MASK		(0x3 << BTR0_SJW_SHIFT)
> @@ -270,6 +277,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,11 +293,6 @@ 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);

s/clock_src/mscan_clksrc/

>  extern void unregister_mscandev(struct net_device *dev);
>  
> -- 
> 1.6.2.5
>
Wolfgang Grandegger Jan. 2, 2010, 4:08 p.m. UTC | #2
Wolfram Sang wrote:
> On Sat, Jan 02, 2010 at 09:17:53AM +0100, Wolfgang Grandegger wrote:
>> From: Wolfgang Grandegger <wg@denx.de>
>>
>> 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).
>>
>> Signed-off-by: Wolfgang Grandegger <wg@denx.de>
>> ---
>>  drivers/net/can/mscan/Kconfig       |    2 +-
>>  drivers/net/can/mscan/mpc5xxx_can.c |  234 +++++++++++++++++++++++++++++------
>>  drivers/net/can/mscan/mscan.c       |   41 +++++--
>>  drivers/net/can/mscan/mscan.h       |   81 ++++++------
>>  4 files changed, 271 insertions(+), 87 deletions(-)
>>
[snip]

>> +#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 */
> 
> Hmmm, I don't really like those empty functions. I once used the data-field of
> struct of_device_id, which carried a function pointer to a specific
> init-function for the matched device. What do you think about such an approach?

Often the problem is that the function will not compile on the other MPC
arch. This is not true here. So, the main reason for the #ifdefs is
space saving. Your approach will not help in both cases.

>> +
>> +#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 mpc512x_clock_ids[] __devinitdata = {
>> +	{ .compatible = "fsl,mpc5121-clock", },
>> +	{}
>> +};
>> +
>> +static u32  __devinit mpc512x_can_get_clock(struct of_device *ofdev,
>> +					    const char *clock_name,
>> +					    int *mscan_clksrc,
>> +					    ssize_t mscan_addr)
>> +{
>> +	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 */
>> +	clockidx = (mscan_addr & 0x80) ? 1 : 0;
>> +	if (mscan_addr & 0x2000)
>> +		clockidx += 2;
> 
> The PSCs use 'cell-index', here we use mscan_addr to derive the index. This is
> not consistent, but should be IMHO. Now, which is the preferred way? I think
> I'd go for 'cell-index', as other processors might have mscan_addr shuffled.
> Also, we could use 'of_iomap' again in the probe_routine.

I understood that "cell-index" is deprecated and it has been removed
from many nodes. That's why I used the address to derive the index.

I will fix all other issues.

Wolfgang.
Wolfgang Grandegger Jan. 4, 2010, 12:49 p.m. UTC | #3
Wolfgang Grandegger wrote:
> Wolfram Sang wrote:
>> On Sat, Jan 02, 2010 at 09:17:53AM +0100, Wolfgang Grandegger wrote:
>>> From: Wolfgang Grandegger <wg@denx.de>
>>>
>>> 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).
>>>
>>> Signed-off-by: Wolfgang Grandegger <wg@denx.de>
>>> ---
>>>  drivers/net/can/mscan/Kconfig       |    2 +-
>>>  drivers/net/can/mscan/mpc5xxx_can.c |  234 +++++++++++++++++++++++++++++------
>>>  drivers/net/can/mscan/mscan.c       |   41 +++++--
>>>  drivers/net/can/mscan/mscan.h       |   81 ++++++------
>>>  4 files changed, 271 insertions(+), 87 deletions(-)
>>>
> [snip]
> 
>>> +#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 */
>> Hmmm, I don't really like those empty functions. I once used the data-field of
>> struct of_device_id, which carried a function pointer to a specific
>> init-function for the matched device. What do you think about such an approach?
> 
> Often the problem is that the function will not compile on the other MPC
> arch. This is not true here. So, the main reason for the #ifdefs is
> space saving. Your approach will not help in both cases.
> 
>>> +
>>> +#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 mpc512x_clock_ids[] __devinitdata = {
>>> +	{ .compatible = "fsl,mpc5121-clock", },
>>> +	{}
>>> +};
>>> +
>>> +static u32  __devinit mpc512x_can_get_clock(struct of_device *ofdev,
>>> +					    const char *clock_name,
>>> +					    int *mscan_clksrc,
>>> +					    ssize_t mscan_addr)
>>> +{
>>> +	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 */
>>> +	clockidx = (mscan_addr & 0x80) ? 1 : 0;
>>> +	if (mscan_addr & 0x2000)
>>> +		clockidx += 2;
>> The PSCs use 'cell-index', here we use mscan_addr to derive the index. This is
>> not consistent, but should be IMHO. Now, which is the preferred way? I think
>> I'd go for 'cell-index', as other processors might have mscan_addr shuffled.
>> Also, we could use 'of_iomap' again in the probe_routine.
> 
> I understood that "cell-index" is deprecated and it has been removed
> from many nodes. That's why I used the address to derive the index.

So more thoughts: I still find inspecting the regs less error prune than
defining cell-index and it should work fine for "fsl,mpc5121_mscan".
Other processor variants might handle a different register layout with
another appropriate compatibility string. But I could retrieve the
"regs" property inside mpc512x_can_get_clock() to use of_iomap() as before.

Wolfgang.
Wolfram Sang Jan. 4, 2010, 4:24 p.m. UTC | #4
Hello Wolfgang,

first the good news: Your patches also work with our MPC5121-board.

> >> +#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 */
> > 
> > Hmmm, I don't really like those empty functions. I once used the data-field of
> > struct of_device_id, which carried a function pointer to a specific
> > init-function for the matched device. What do you think about such an approach?
> 
> Often the problem is that the function will not compile on the other MPC
> arch. This is not true here. So, the main reason for the #ifdefs is
> space saving. Your approach will not help in both cases.

My idea was: it might be nice to save both #else-branches and the if-clause in
probe() which calls this get_clock() or the other (and then another in case
there will be a new mpc5xyz-user in the future). And replace it with some
mpc5xxx_custom_init() which is taken from of_device_id->data. No big issue,
though; no show-stopper.

> >> +
> >> +#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 */
> >> +};

I wonder if this (and the occurence in clock.c) should be factored out and
moved to asm/mpc5xxx.h?

> >> +
> >> +static struct of_device_id mpc512x_clock_ids[] __devinitdata = {
> >> +	{ .compatible = "fsl,mpc5121-clock", },
> >> +	{}
> >> +};
> >> +
> >> +static u32  __devinit mpc512x_can_get_clock(struct of_device *ofdev,
> >> +					    const char *clock_name,
> >> +					    int *mscan_clksrc,
> >> +					    ssize_t mscan_addr)
> >> +{
> >> +	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 */
> >> +	clockidx = (mscan_addr & 0x80) ? 1 : 0;
> >> +	if (mscan_addr & 0x2000)
> >> +		clockidx += 2;
> > 
> > The PSCs use 'cell-index', here we use mscan_addr to derive the index. This is
> > not consistent, but should be IMHO. Now, which is the preferred way? I think
> > I'd go for 'cell-index', as other processors might have mscan_addr shuffled.
> > Also, we could use 'of_iomap' again in the probe_routine.
> 
> I understood that "cell-index" is deprecated and it has been removed
> from many nodes. That's why I used the address to derive the index.

Well, the arguments in your other mail make sense to me, so keep it this way.
As not only the index-issue, but also the clock-handling is different for the
PSCs, it is at least consistently inconsistent :D

One further note: I couldn't spot any code handling Rev1 of the MPC5121? Do you
plan to add such code? If not, we should at least put a comment that it is
missing. The binding documentation should be updated as well, as you can't use
all options on such revisions.

Regards,

   Wolfram
Wolfgang Grandegger Jan. 4, 2010, 4:52 p.m. UTC | #5
Hi Wolfram,

Wolfram Sang wrote:
> Hello Wolfgang,
> 
> first the good news: Your patches also work with our MPC5121-board.

Nice. Just for curiosity, what clock and frequency does it select on
your board? It should be listed when the driver is loaded.

>>>> +#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 */
>>> Hmmm, I don't really like those empty functions. I once used the data-field of
>>> struct of_device_id, which carried a function pointer to a specific
>>> init-function for the matched device. What do you think about such an approach?
>> Often the problem is that the function will not compile on the other MPC
>> arch. This is not true here. So, the main reason for the #ifdefs is
>> space saving. Your approach will not help in both cases.
> 
> My idea was: it might be nice to save both #else-branches and the if-clause in
> probe() which calls this get_clock() or the other (and then another in case
> there will be a new mpc5xyz-user in the future). And replace it with some
> mpc5xxx_custom_init() which is taken from of_device_id->data. No big issue,
> though; no show-stopper.

You mean like in the i2c-mpc driver:

http://lxr.linux.no/#linux+v2.6.32/drivers/i2c/busses/i2c-mpc.c#L585

No problem, if I handle the regs property inside the mpc5121-specific
function. The #ifdef's are for *space saving*. If nobody else than me
cares, I will remove them.

>>>> +
>>>> +#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 */
>>>> +};
> 
> I wonder if this (and the occurence in clock.c) should be factored out and
> moved to asm/mpc5xxx.h?

I was thinking about that as well but mpc5xxx.h seems not (yet) to be a
popular place to store mpc5xxx related definitions.

>>>> +
>>>> +static struct of_device_id mpc512x_clock_ids[] __devinitdata = {
>>>> +	{ .compatible = "fsl,mpc5121-clock", },
>>>> +	{}
>>>> +};
>>>> +
>>>> +static u32  __devinit mpc512x_can_get_clock(struct of_device *ofdev,
>>>> +					    const char *clock_name,
>>>> +					    int *mscan_clksrc,
>>>> +					    ssize_t mscan_addr)
>>>> +{
>>>> +	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 */
>>>> +	clockidx = (mscan_addr & 0x80) ? 1 : 0;
>>>> +	if (mscan_addr & 0x2000)
>>>> +		clockidx += 2;
>>> The PSCs use 'cell-index', here we use mscan_addr to derive the index. This is
>>> not consistent, but should be IMHO. Now, which is the preferred way? I think
>>> I'd go for 'cell-index', as other processors might have mscan_addr shuffled.
>>> Also, we could use 'of_iomap' again in the probe_routine.
>> I understood that "cell-index" is deprecated and it has been removed
>> from many nodes. That's why I used the address to derive the index.
> 
> Well, the arguments in your other mail make sense to me, so keep it this way.
> As not only the index-issue, but also the clock-handling is different for the
> PSCs, it is at least consistently inconsistent :D

OK.

> One further note: I couldn't spot any code handling Rev1 of the MPC5121? Do you
> plan to add such code? If not, we should at least put a comment that it is
> missing. The binding documentation should be updated as well, as you can't use
> all options on such revisions.

Do we have rev1 support in the mainline kernel? I also understood that
there are only a few devel boards out there with v1 CPUs. If necessary,
this could be fixed later on demand. But it should be documented, e.g.
in the KConfig and dts bindings doc, of course.

Did you have a chance to test bus-off recovery? I just realized one
issue if the device is stopped while in bus-off.

Will come up with a v2 patch soon...

Thanks,

Wolfgang.
Wolfram Sang Jan. 4, 2010, 5:22 p.m. UTC | #6
> Nice. Just for curiosity, what clock and frequency does it select on
> your board? It should be listed when the driver is loaded.

Using this simple dts-snipplet

                mscan@1300 {
                        compatible = "fsl,mpc5121-mscan";
                        cell-index = <0>;
                        interrupts = <12 8>;
                        interrupt-parent = < &ipic >;
                        reg = <0x1300 0x80>;
                };

I get this output:

mpc5xxx_can 80001300.mscan: using 'sys_clk' with frequency divider 25
mpc5xxx_can 80001300.mscan: MSCAN at 0xe1064300, irq 16, clock 16000000 Hz

mpc5xxx_can 80001380.mscan: using 'sys_clk' with frequency divider 25
mpc5xxx_can 80001380.mscan: MSCAN at 0xe106c380, irq 17, clock 16000000 Hz


> > My idea was: it might be nice to save both #else-branches and the if-clause in
> > probe() which calls this get_clock() or the other (and then another in case
> > there will be a new mpc5xyz-user in the future). And replace it with some
> > mpc5xxx_custom_init() which is taken from of_device_id->data. No big issue,
> > though; no show-stopper.
> 
> You mean like in the i2c-mpc driver:
> 
> http://lxr.linux.no/#linux+v2.6.32/drivers/i2c/busses/i2c-mpc.c#L585

Yes.

> No problem, if I handle the regs property inside the mpc5121-specific
> function. The #ifdef's are for *space saving*. If nobody else than me
> cares, I will remove them.

I'd be fine with keeping them.

> >>>> +
> >>>> +#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 */
> >>>> +};
> > 
> > I wonder if this (and the occurence in clock.c) should be factored out and
> > moved to asm/mpc5xxx.h?
> 
> I was thinking about that as well but mpc5xxx.h seems not (yet) to be a
> popular place to store mpc5xxx related definitions.

Probably because the mpc5121 is not very popular when it comes to mainline
activity. (BTW, I also wondered why it is not named mpc512x.h as I'd think
mpc5xxx is for common stuff between mpc5200 and mpc5121. But this is another
issue, not relevant here.)

> > One further note: I couldn't spot any code handling Rev1 of the MPC5121? Do you
> > plan to add such code? If not, we should at least put a comment that it is
> > missing. The binding documentation should be updated as well, as you can't use
> > all options on such revisions.
> 
> Do we have rev1 support in the mainline kernel? I also understood that
> there are only a few devel boards out there with v1 CPUs. If necessary,
> this could be fixed later on demand. But it should be documented, e.g.
> in the KConfig and dts bindings doc, of course.

Yup, documenting it will do.

> Did you have a chance to test bus-off recovery? I just realized one
> issue if the device is stopped while in bus-off.

Sorry, I just did basic transfer-tests as I am currently busy with other
projects.

> Will come up with a v2 patch soon...

Please do an s/latetr/latter/ before posting it :)

Regards,

   Wolfram
Wolfgang Grandegger Jan. 4, 2010, 5:35 p.m. UTC | #7
Wolfram Sang wrote:
>> Nice. Just for curiosity, what clock and frequency does it select on
>> your board? It should be listed when the driver is loaded.
> 
> Using this simple dts-snipplet
> 
>                 mscan@1300 {
>                         compatible = "fsl,mpc5121-mscan";
>                         cell-index = <0>;
>                         interrupts = <12 8>;
>                         interrupt-parent = < &ipic >;
>                         reg = <0x1300 0x80>;
>                 };
> 
> I get this output:
> 
> mpc5xxx_can 80001300.mscan: using 'sys_clk' with frequency divider 25
> mpc5xxx_can 80001300.mscan: MSCAN at 0xe1064300, irq 16, clock 16000000 Hz
> 
> mpc5xxx_can 80001380.mscan: using 'sys_clk' with frequency divider 25
> mpc5xxx_can 80001380.mscan: MSCAN at 0xe106c380, irq 17, clock 16000000 Hz

OK, the the board uses an oscillator clock of 33.333333 MHz. The "ref"
or "ip" clock would be a worse choice.

>>> My idea was: it might be nice to save both #else-branches and the if-clause in
>>> probe() which calls this get_clock() or the other (and then another in case
>>> there will be a new mpc5xyz-user in the future). And replace it with some
>>> mpc5xxx_custom_init() which is taken from of_device_id->data. No big issue,
>>> though; no show-stopper.
>> You mean like in the i2c-mpc driver:
>>
>> http://lxr.linux.no/#linux+v2.6.32/drivers/i2c/busses/i2c-mpc.c#L585
> 
> Yes.
> 
>> No problem, if I handle the regs property inside the mpc5121-specific
>> function. The #ifdef's are for *space saving*. If nobody else than me
>> cares, I will remove them.
> 
> I'd be fine with keeping them.

OK.

>>>>>> +
>>>>>> +#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 */
>>>>>> +};
>>> I wonder if this (and the occurence in clock.c) should be factored out and
>>> moved to asm/mpc5xxx.h?
>> I was thinking about that as well but mpc5xxx.h seems not (yet) to be a
>> popular place to store mpc5xxx related definitions.
> 
> Probably because the mpc5121 is not very popular when it comes to mainline
> activity. (BTW, I also wondered why it is not named mpc512x.h as I'd think
> mpc5xxx is for common stuff between mpc5200 and mpc5121. But this is another
> issue, not relevant here.)

Well, yes. The mpc512x Socket-CAN mainline support is already in a much
better shape than the base port. I will keep it until the mpc512x port
has matured/settled.

>>> One further note: I couldn't spot any code handling Rev1 of the MPC5121? Do you
>>> plan to add such code? If not, we should at least put a comment that it is
>>> missing. The binding documentation should be updated as well, as you can't use
>>> all options on such revisions.
>> Do we have rev1 support in the mainline kernel? I also understood that
>> there are only a few devel boards out there with v1 CPUs. If necessary,
>> this could be fixed later on demand. But it should be documented, e.g.
>> in the KConfig and dts bindings doc, of course.
> 
> Yup, documenting it will do.
> 
>> Did you have a chance to test bus-off recovery? I just realized one
>> issue if the device is stopped while in bus-off.
> 
> Sorry, I just did basic transfer-tests as I am currently busy with other
> projects.

You are welcome.

>> Will come up with a v2 patch soon...
> 
> Please do an s/latetr/latter/ before posting it :)

OK.

Wolfgang.
Wolfgang Denk Jan. 4, 2010, 7:40 p.m. UTC | #8
Dear Wolfram,

in message <20100104162441.GA4665@pengutronix.de> you wrote:
> 
> One further note: I couldn't spot any code handling Rev1 of the MPC5121? Do you
> plan to add such code? If not, we should at least put a comment that it is
> missing. The binding documentation should be updated as well, as you can't use
> all options on such revisions.

We only support MPC512x Rev. 2 (and later). This is also true for
other parts of the mainline kernel code - see for example trhe NAND
driver.


Best regards,

Wolfgang Denk
Wolfram Sang Jan. 4, 2010, 8:23 p.m. UTC | #9
Hello Wolfgang,

> We only support MPC512x Rev. 2 (and later). This is also true for
> other parts of the mainline kernel code - see for example trhe NAND
> driver.

Okay, good to know there are differences in NAND as well. As said before, it
makes sense to me to skip V1. It just should be documented IMHO, and, if
possible, the bindings should allow V1 support in case anyone dares.

Regards,

   Wolfram
diff mbox

Patch

diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig
index cd0f2d6..723d009 100644
--- a/drivers/net/can/mscan/Kconfig
+++ b/drivers/net/can/mscan/Kconfig
@@ -11,7 +11,7 @@  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.
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 1de6f63..42c719b 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -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>
 
@@ -36,22 +37,15 @@ 
 
 #define DRV_NAME "mpc5xxx_can"
 
+#ifdef CONFIG_PPC_MPC5200
 static struct of_device_id mpc52xx_cdm_ids[] __devinitdata = {
 	{ .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 +55,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 toa 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 +82,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,10 +90,157 @@  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 mpc512x_clock_ids[] __devinitdata = {
+	{ .compatible = "fsl,mpc5121-clock", },
+	{}
+};
+
+static u32  __devinit mpc512x_can_get_clock(struct of_device *ofdev,
+					    const char *clock_name,
+					    int *mscan_clksrc,
+					    ssize_t mscan_addr)
+{
+	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 */
+	clockidx = (mscan_addr & 0x80) ? 1 : 0;
+	if (mscan_addr & 0x2000)
+		clockidx += 2;
+
+	/*
+	 * Clock source and divider selection: 3 different clock sources
+	 * can be selected: "ip", "ref" or "sys". For the latetr 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);
+		/* Dnable 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,
+					    ssize_t mscan_addr)
+{
+	return 0;
+}
+#endif /* CONFIG_PPC_MPC512x */
 
 static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
 				       const struct of_device_id *id)
@@ -95,15 +248,21 @@  static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
 	struct device_node *np = ofdev->node;
 	struct net_device *dev;
 	struct mscan_priv *priv;
+	struct resource res;
 	void __iomem *base;
-	const char *clk_src;
-	int err, irq, clock_src;
+	const char *clock_name = NULL;
+	int irq, clock_src = 0;
+	int err = -ENOMEM;
 
-	base = of_iomap(ofdev->node, 0);
+	if (of_address_to_resource(np, 0, &res)) {
+		dev_err(&ofdev->dev, "couldn't get resource address\n");
+		return err;
+	}
+
+	base = ioremap(res.start, resource_size(&res));
 	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,31 +273,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);
+
+	if (of_device_is_compatible(np, "fsl,mpc5121-mscan")) {
+		priv->type = MSCAN_TYPE_MPC5121;
+		priv->can.clock.freq =
+			mpc512x_can_get_clock(ofdev, clock_name, &clock_src,
+					      res.start);
+	} else {
+		priv->type = MSCAN_TYPE_MPC5200;
+		priv->can.clock.freq =
+			mpc52xx_can_get_clock(ofdev, clock_name, &clock_src);
+	}
 	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;
 	}
 
@@ -164,7 +319,7 @@  exit_dispose_irq:
 	irq_dispose_mapping(irq);
 exit_unmap_mem:
 	iounmap(base);
-exit_release_mem:
+
 	return err;
 }
 
@@ -227,6 +382,7 @@  static int mpc5xxx_can_resume(struct of_device *ofdev)
 
 static struct of_device_id __devinitdata mpc5xxx_can_table[] = {
 	{.compatible = "fsl,mpc5200-mscan"},
+	{.compatible = "fsl,mpc5121-mscan"},
 	{},
 };
 
@@ -255,5 +411,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 MPC5200 and MPC521x CAN driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index abdf5e8..9812aa0 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -169,6 +169,27 @@  static int mscan_start(struct net_device *dev)
 	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;
+		if (!(in_8(&regs->canmisc) & MSCAN_BOHOLD))
+			dev_err(dev->dev.parent, "Oops, not bus-off");
+		else
+			out_8(&regs->canmisc, MSCAN_BOHOLD);
+	} else {
+		if (priv->can.state <= CAN_STATE_BUS_OFF)
+			mscan_set_mode(dev, MSCAN_INIT_MODE);
+		return mscan_start(dev);
+	}
+
+	return 0;
+}
+
 static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct can_frame *frame = (struct can_frame *)skb->data;
@@ -364,9 +385,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:
@@ -496,9 +520,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))
@@ -597,18 +619,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);
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
index 00fc4aa..2114942 100644
--- a/drivers/net/can/mscan/mscan.h
+++ b/drivers/net/can/mscan/mscan.h
@@ -39,17 +39,19 @@ 
 #define MSCAN_LOOPB		0x20
 #define MSCAN_LISTEN		0x10
 #define MSCAN_WUPM		0x04
+#define MSCAN_BORM		0x08
 #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
@@ -136,7 +138,7 @@ 
 #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_
@@ -238,6 +239,12 @@  struct mscan_regs {
 #define MSCAN_SET_MODE_RETRIES	255
 #define MSCAN_ECHO_SKB_MAX	3
 
+/* MSCAN type variants */
+enum {
+	MSCAN_TYPE_MPC5200,
+	MSCAN_TYPE_MPC5121
+};
+
 #define BTR0_BRP_MASK		0x3f
 #define BTR0_SJW_SHIFT		6
 #define BTR0_SJW_MASK		(0x3 << BTR0_SJW_SHIFT)
@@ -270,6 +277,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,11 +293,6 @@  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 void unregister_mscandev(struct net_device *dev);