[PATCH net-next 2/3] can: mscan-mpc5xxx: add support for the MPC521x processor
Wolfram Sang
w.sang at pengutronix.de
Sun Jan 3 00:57:34 EST 2010
On Sat, Jan 02, 2010 at 09:17:53AM +0100, Wolfgang Grandegger wrote:
> From: Wolfgang Grandegger <wg at 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 at 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 at 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(®s->canmisc) & MSCAN_BOHOLD))
> + dev_err(dev->dev.parent, "Oops, not bus-off");
I think this error-message could be improved :)
> + else
> + out_8(®s->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(®s->cantier, 0);
> - out_8(®s->canrier, 0);
> - setbits8(®s->canctl0, MSCAN_SLPRQ | MSCAN_INITRQ);
> + if (priv->type != MSCAN_TYPE_MPC5121) {
> + out_8(®s->cantier, 0);
> + out_8(®s->canrier, 0);
> + setbits8(®s->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(®s->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(®s->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
>
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: Digital signature
URL: <http://lists.ozlabs.org/pipermail/devicetree-discuss/attachments/20100102/ecb49621/attachment-0001.pgp>
More information about the devicetree-discuss
mailing list