2 * CAN bus driver for the Freescale MPC5xxx embedded CPU.
4 * Copyright (C) 2004-2005 Andrey Volkov <avolkov@varma-el.com>,
6 * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
7 * Copyright (C) 2009 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the version 2 of the GNU General Public License
11 * as published by the Free Software Foundation
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/interrupt.h>
26 #include <linux/platform_device.h>
27 #include <linux/netdevice.h>
28 #include <linux/can.h>
29 #include <linux/can/dev.h>
30 #include <linux/of_platform.h>
31 #include <sysdev/fsl_soc.h>
33 #include <asm/mpc52xx.h>
37 #define DRV_NAME "mpc5xxx_can"
39 static struct of_device_id mpc52xx_cdm_ids
[] __devinitdata
= {
40 { .compatible
= "fsl,mpc5200-cdm", },
45 * Get frequency of the MSCAN clock source
47 * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock (IP_CLK)
48 * can be selected. According to the MPC5200 user's manual, the oscillator
49 * clock is the better choice as it has less jitter but due to a hardware
50 * bug, it can not be selected for the old MPC5200 Rev. A chips.
53 static unsigned int __devinit
mpc52xx_can_clock_freq(struct of_device
*of
,
57 struct mpc52xx_cdm __iomem
*cdm
;
58 struct device_node
*np_cdm
;
62 pvr
= mfspr(SPRN_PVR
);
64 freq
= mpc5xxx_get_bus_frequency(of
->node
);
68 if (clock_src
== MSCAN_CLKSRC_BUS
|| pvr
== 0x80822011)
71 /* Determine SYS_XTAL_IN frequency from the clock domain settings */
72 np_cdm
= of_find_matching_node(NULL
, mpc52xx_cdm_ids
);
74 dev_err(&of
->dev
, "can't get clock node!\n");
77 cdm
= of_iomap(np_cdm
, 0);
80 if (in_8(&cdm
->ipb_clk_sel
) & 0x1)
82 val
= in_be32(&cdm
->rstcfg
);
84 freq
*= (val
& (1 << 5)) ? 8 : 4;
85 freq
/= (val
& (1 << 6)) ? 12 : 16;
92 static int __devinit
mpc5xxx_can_probe(struct of_device
*ofdev
,
93 const struct of_device_id
*id
)
95 struct device_node
*np
= ofdev
->node
;
96 struct net_device
*dev
;
97 struct mscan_priv
*priv
;
100 int err
, irq
, clock_src
;
102 base
= of_iomap(ofdev
->node
, 0);
104 dev_err(&ofdev
->dev
, "couldn't ioremap\n");
106 goto exit_release_mem
;
109 irq
= irq_of_parse_and_map(np
, 0);
111 dev_err(&ofdev
->dev
, "no irq found\n");
116 dev
= alloc_mscandev();
119 goto exit_dispose_irq
;
122 priv
= netdev_priv(dev
);
123 priv
->reg_base
= base
;
127 * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
128 * (IP_CLK) can be selected as MSCAN clock source. According to
129 * the MPC5200 user's manual, the oscillator clock is the better
130 * choice as it has less jitter. For this reason, it is selected
133 clk_src
= of_get_property(np
, "fsl,mscan-clock-source", NULL
);
134 if (clk_src
&& strcmp(clk_src
, "ip") == 0)
135 clock_src
= MSCAN_CLKSRC_BUS
;
137 clock_src
= MSCAN_CLKSRC_XTAL
;
138 priv
->can
.clock
.freq
= mpc52xx_can_clock_freq(ofdev
, clock_src
);
139 if (!priv
->can
.clock
.freq
) {
140 dev_err(&ofdev
->dev
, "couldn't get MSCAN clock frequency\n");
142 goto exit_free_mscan
;
145 SET_NETDEV_DEV(dev
, &ofdev
->dev
);
147 err
= register_mscandev(dev
, clock_src
);
149 dev_err(&ofdev
->dev
, "registering %s failed (err=%d)\n",
151 goto exit_free_mscan
;
154 dev_set_drvdata(&ofdev
->dev
, dev
);
156 dev_info(&ofdev
->dev
, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
157 priv
->reg_base
, dev
->irq
, priv
->can
.clock
.freq
);
164 irq_dispose_mapping(irq
);
171 static int __devexit
mpc5xxx_can_remove(struct of_device
*ofdev
)
173 struct net_device
*dev
= dev_get_drvdata(&ofdev
->dev
);
174 struct mscan_priv
*priv
= netdev_priv(dev
);
176 dev_set_drvdata(&ofdev
->dev
, NULL
);
178 unregister_mscandev(dev
);
179 iounmap(priv
->reg_base
);
180 irq_dispose_mapping(dev
->irq
);
187 static struct mscan_regs saved_regs
;
188 static int mpc5xxx_can_suspend(struct of_device
*ofdev
, pm_message_t state
)
190 struct net_device
*dev
= dev_get_drvdata(&ofdev
->dev
);
191 struct mscan_priv
*priv
= netdev_priv(dev
);
192 struct mscan_regs
*regs
= (struct mscan_regs
*)priv
->reg_base
;
194 _memcpy_fromio(&saved_regs
, regs
, sizeof(*regs
));
199 static int mpc5xxx_can_resume(struct of_device
*ofdev
)
201 struct net_device
*dev
= dev_get_drvdata(&ofdev
->dev
);
202 struct mscan_priv
*priv
= netdev_priv(dev
);
203 struct mscan_regs
*regs
= (struct mscan_regs
*)priv
->reg_base
;
205 regs
->canctl0
|= MSCAN_INITRQ
;
206 while (!(regs
->canctl1
& MSCAN_INITAK
))
209 regs
->canctl1
= saved_regs
.canctl1
;
210 regs
->canbtr0
= saved_regs
.canbtr0
;
211 regs
->canbtr1
= saved_regs
.canbtr1
;
212 regs
->canidac
= saved_regs
.canidac
;
214 /* restore masks, buffers etc. */
215 _memcpy_toio(®s
->canidar1_0
, (void *)&saved_regs
.canidar1_0
,
216 sizeof(*regs
) - offsetof(struct mscan_regs
, canidar1_0
));
218 regs
->canctl0
&= ~MSCAN_INITRQ
;
219 regs
->cantbsel
= saved_regs
.cantbsel
;
220 regs
->canrier
= saved_regs
.canrier
;
221 regs
->cantier
= saved_regs
.cantier
;
222 regs
->canctl0
= saved_regs
.canctl0
;
228 static struct of_device_id __devinitdata mpc5xxx_can_table
[] = {
229 {.compatible
= "fsl,mpc5200-mscan"},
233 static struct of_platform_driver mpc5xxx_can_driver
= {
234 .owner
= THIS_MODULE
,
235 .name
= "mpc5xxx_can",
236 .probe
= mpc5xxx_can_probe
,
237 .remove
= __devexit_p(mpc5xxx_can_remove
),
239 .suspend
= mpc5xxx_can_suspend
,
240 .resume
= mpc5xxx_can_resume
,
242 .match_table
= mpc5xxx_can_table
,
245 static int __init
mpc5xxx_can_init(void)
247 return of_register_platform_driver(&mpc5xxx_can_driver
);
249 module_init(mpc5xxx_can_init
);
251 static void __exit
mpc5xxx_can_exit(void)
253 return of_unregister_platform_driver(&mpc5xxx_can_driver
);
255 module_exit(mpc5xxx_can_exit
);
257 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
258 MODULE_DESCRIPTION("Freescale MPC5200 CAN driver");
259 MODULE_LICENSE("GPL v2");