124cfbcbaSWolfram Sang /*
224cfbcbaSWolfram Sang  * CAN bus driver for the Freescale MPC5xxx embedded CPU.
324cfbcbaSWolfram Sang  *
424cfbcbaSWolfram Sang  * Copyright (C) 2004-2005 Andrey Volkov <avolkov@varma-el.com>,
524cfbcbaSWolfram Sang  *                         Varma Electronics Oy
624cfbcbaSWolfram Sang  * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
724cfbcbaSWolfram Sang  * Copyright (C) 2009 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
824cfbcbaSWolfram Sang  *
924cfbcbaSWolfram Sang  * This program is free software; you can redistribute it and/or modify
1024cfbcbaSWolfram Sang  * it under the terms of the version 2 of the GNU General Public License
1124cfbcbaSWolfram Sang  * as published by the Free Software Foundation
1224cfbcbaSWolfram Sang  *
1324cfbcbaSWolfram Sang  * This program is distributed in the hope that it will be useful, but
1424cfbcbaSWolfram Sang  * WITHOUT ANY WARRANTY; without even the implied warranty of
1524cfbcbaSWolfram Sang  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1624cfbcbaSWolfram Sang  * GNU General Public License for more details.
1724cfbcbaSWolfram Sang  *
1824cfbcbaSWolfram Sang  * You should have received a copy of the GNU General Public License
1924cfbcbaSWolfram Sang  * along with this program; if not, write to the Free Software
2024cfbcbaSWolfram Sang  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2124cfbcbaSWolfram Sang  */
2224cfbcbaSWolfram Sang 
2324cfbcbaSWolfram Sang #include <linux/kernel.h>
2424cfbcbaSWolfram Sang #include <linux/module.h>
2524cfbcbaSWolfram Sang #include <linux/interrupt.h>
2624cfbcbaSWolfram Sang #include <linux/platform_device.h>
2724cfbcbaSWolfram Sang #include <linux/netdevice.h>
2824cfbcbaSWolfram Sang #include <linux/can/dev.h>
2924cfbcbaSWolfram Sang #include <linux/of_platform.h>
3024cfbcbaSWolfram Sang #include <sysdev/fsl_soc.h>
31bf3af547SWolfgang Grandegger #include <linux/clk.h>
3224cfbcbaSWolfram Sang #include <linux/io.h>
3324cfbcbaSWolfram Sang #include <asm/mpc52xx.h>
3424cfbcbaSWolfram Sang 
3524cfbcbaSWolfram Sang #include "mscan.h"
3624cfbcbaSWolfram Sang 
3724cfbcbaSWolfram Sang #define DRV_NAME "mpc5xxx_can"
3824cfbcbaSWolfram Sang 
39bf3af547SWolfgang Grandegger struct mpc5xxx_can_data {
40bf3af547SWolfgang Grandegger 	unsigned int type;
41bf3af547SWolfgang Grandegger 	u32 (*get_clock)(struct of_device *ofdev, const char *clock_name,
42bf3af547SWolfgang Grandegger 			 int *mscan_clksrc);
43bf3af547SWolfgang Grandegger };
44bf3af547SWolfgang Grandegger 
45c5bab5e9SWolfgang Grandegger #ifdef CONFIG_PPC_MPC52xx
46bf3af547SWolfgang Grandegger static struct of_device_id __devinitdata mpc52xx_cdm_ids[] = {
4724cfbcbaSWolfram Sang 	{ .compatible = "fsl,mpc5200-cdm", },
4824cfbcbaSWolfram Sang 	{}
4924cfbcbaSWolfram Sang };
5024cfbcbaSWolfram Sang 
51bf3af547SWolfgang Grandegger static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
52bf3af547SWolfgang Grandegger 					   const char *clock_name,
53bf3af547SWolfgang Grandegger 					   int *mscan_clksrc)
5424cfbcbaSWolfram Sang {
5524cfbcbaSWolfram Sang 	unsigned int pvr;
5624cfbcbaSWolfram Sang 	struct mpc52xx_cdm  __iomem *cdm;
5724cfbcbaSWolfram Sang 	struct device_node *np_cdm;
5824cfbcbaSWolfram Sang 	unsigned int freq;
5924cfbcbaSWolfram Sang 	u32 val;
6024cfbcbaSWolfram Sang 
6124cfbcbaSWolfram Sang 	pvr = mfspr(SPRN_PVR);
6224cfbcbaSWolfram Sang 
63bf3af547SWolfgang Grandegger 	/*
64bf3af547SWolfgang Grandegger 	 * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
65bf3af547SWolfgang Grandegger 	 * (IP_CLK) can be selected as MSCAN clock source. According to
66bf3af547SWolfgang Grandegger 	 * the MPC5200 user's manual, the oscillator clock is the better
67bf3af547SWolfgang Grandegger 	 * choice as it has less jitter. For this reason, it is selected
68bf3af547SWolfgang Grandegger 	 * by default. Unfortunately, it can not be selected for the old
69bf3af547SWolfgang Grandegger 	 * MPC5200 Rev. A chips due to a hardware bug (check errata).
70bf3af547SWolfgang Grandegger 	 */
71bf3af547SWolfgang Grandegger 	if (clock_name && strcmp(clock_name, "ip") == 0)
72bf3af547SWolfgang Grandegger 		*mscan_clksrc = MSCAN_CLKSRC_BUS;
73bf3af547SWolfgang Grandegger 	else
74bf3af547SWolfgang Grandegger 		*mscan_clksrc = MSCAN_CLKSRC_XTAL;
75bf3af547SWolfgang Grandegger 
766bd17eb9SAnatolij Gustschin 	freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
7724cfbcbaSWolfram Sang 	if (!freq)
7824cfbcbaSWolfram Sang 		return 0;
7924cfbcbaSWolfram Sang 
80bf3af547SWolfgang Grandegger 	if (*mscan_clksrc == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
8124cfbcbaSWolfram Sang 		return freq;
8224cfbcbaSWolfram Sang 
8324cfbcbaSWolfram Sang 	/* Determine SYS_XTAL_IN frequency from the clock domain settings */
8424cfbcbaSWolfram Sang 	np_cdm = of_find_matching_node(NULL, mpc52xx_cdm_ids);
8524cfbcbaSWolfram Sang 	if (!np_cdm) {
86c5bab5e9SWolfgang Grandegger 		dev_err(&ofdev->dev, "can't get clock node!\n");
8724cfbcbaSWolfram Sang 		return 0;
8824cfbcbaSWolfram Sang 	}
8924cfbcbaSWolfram Sang 	cdm = of_iomap(np_cdm, 0);
9024cfbcbaSWolfram Sang 
9124cfbcbaSWolfram Sang 	if (in_8(&cdm->ipb_clk_sel) & 0x1)
9224cfbcbaSWolfram Sang 		freq *= 2;
9324cfbcbaSWolfram Sang 	val = in_be32(&cdm->rstcfg);
9424cfbcbaSWolfram Sang 
9524cfbcbaSWolfram Sang 	freq *= (val & (1 << 5)) ? 8 : 4;
9624cfbcbaSWolfram Sang 	freq /= (val & (1 << 6)) ? 12 : 16;
9724cfbcbaSWolfram Sang 
98bf3af547SWolfgang Grandegger 	of_node_put(np_cdm);
9924cfbcbaSWolfram Sang 	iounmap(cdm);
10024cfbcbaSWolfram Sang 
10124cfbcbaSWolfram Sang 	return freq;
10224cfbcbaSWolfram Sang }
103c5bab5e9SWolfgang Grandegger #else /* !CONFIG_PPC_MPC52xx */
104bf3af547SWolfgang Grandegger static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
105bf3af547SWolfgang Grandegger 					   const char *clock_name,
106bf3af547SWolfgang Grandegger 					   int *mscan_clksrc)
107bf3af547SWolfgang Grandegger {
108bf3af547SWolfgang Grandegger 	return 0;
109bf3af547SWolfgang Grandegger }
110c5bab5e9SWolfgang Grandegger #endif /* CONFIG_PPC_MPC52xx */
111bf3af547SWolfgang Grandegger 
112bf3af547SWolfgang Grandegger #ifdef CONFIG_PPC_MPC512x
113bf3af547SWolfgang Grandegger struct mpc512x_clockctl {
114bf3af547SWolfgang Grandegger 	u32 spmr;		/* System PLL Mode Reg */
115bf3af547SWolfgang Grandegger 	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */
116bf3af547SWolfgang Grandegger 	u32 scfr1;		/* System Clk Freq Reg 1 */
117bf3af547SWolfgang Grandegger 	u32 scfr2;		/* System Clk Freq Reg 2 */
118bf3af547SWolfgang Grandegger 	u32 reserved;
119bf3af547SWolfgang Grandegger 	u32 bcr;		/* Bread Crumb Reg */
120bf3af547SWolfgang Grandegger 	u32 pccr[12];		/* PSC Clk Ctrl Reg 0-11 */
121bf3af547SWolfgang Grandegger 	u32 spccr;		/* SPDIF Clk Ctrl Reg */
122bf3af547SWolfgang Grandegger 	u32 cccr;		/* CFM Clk Ctrl Reg */
123bf3af547SWolfgang Grandegger 	u32 dccr;		/* DIU Clk Cnfg Reg */
124bf3af547SWolfgang Grandegger 	u32 mccr[4];		/* MSCAN Clk Ctrl Reg 1-3 */
125bf3af547SWolfgang Grandegger };
126bf3af547SWolfgang Grandegger 
127bf3af547SWolfgang Grandegger static struct of_device_id __devinitdata mpc512x_clock_ids[] = {
128bf3af547SWolfgang Grandegger 	{ .compatible = "fsl,mpc5121-clock", },
129bf3af547SWolfgang Grandegger 	{}
130bf3af547SWolfgang Grandegger };
131bf3af547SWolfgang Grandegger 
132bf3af547SWolfgang Grandegger static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
133bf3af547SWolfgang Grandegger 					   const char *clock_name,
134bf3af547SWolfgang Grandegger 					   int *mscan_clksrc)
135bf3af547SWolfgang Grandegger {
136bf3af547SWolfgang Grandegger 	struct mpc512x_clockctl __iomem *clockctl;
137bf3af547SWolfgang Grandegger 	struct device_node *np_clock;
138bf3af547SWolfgang Grandegger 	struct clk *sys_clk, *ref_clk;
139bf3af547SWolfgang Grandegger 	int plen, clockidx, clocksrc = -1;
140bf3af547SWolfgang Grandegger 	u32 sys_freq, val, clockdiv = 1, freq = 0;
141bf3af547SWolfgang Grandegger 	const u32 *pval;
142bf3af547SWolfgang Grandegger 
143bf3af547SWolfgang Grandegger 	np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
144bf3af547SWolfgang Grandegger 	if (!np_clock) {
145bf3af547SWolfgang Grandegger 		dev_err(&ofdev->dev, "couldn't find clock node\n");
146bf3af547SWolfgang Grandegger 		return -ENODEV;
147bf3af547SWolfgang Grandegger 	}
148bf3af547SWolfgang Grandegger 	clockctl = of_iomap(np_clock, 0);
149bf3af547SWolfgang Grandegger 	if (!clockctl) {
150bf3af547SWolfgang Grandegger 		dev_err(&ofdev->dev, "couldn't map clock registers\n");
151bf3af547SWolfgang Grandegger 		return 0;
152bf3af547SWolfgang Grandegger 	}
153bf3af547SWolfgang Grandegger 
154bf3af547SWolfgang Grandegger 	/* Determine the MSCAN device index from the physical address */
1556bd17eb9SAnatolij Gustschin 	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
156bf3af547SWolfgang Grandegger 	BUG_ON(!pval || plen < sizeof(*pval));
157bf3af547SWolfgang Grandegger 	clockidx = (*pval & 0x80) ? 1 : 0;
158bf3af547SWolfgang Grandegger 	if (*pval & 0x2000)
159bf3af547SWolfgang Grandegger 		clockidx += 2;
160bf3af547SWolfgang Grandegger 
161bf3af547SWolfgang Grandegger 	/*
162bf3af547SWolfgang Grandegger 	 * Clock source and divider selection: 3 different clock sources
163bf3af547SWolfgang Grandegger 	 * can be selected: "ip", "ref" or "sys". For the latter two, a
164bf3af547SWolfgang Grandegger 	 * clock divider can be defined as well. If the clock source is
165bf3af547SWolfgang Grandegger 	 * not specified by the device tree, we first try to find an
166bf3af547SWolfgang Grandegger 	 * optimal CAN source clock based on the system clock. If that
167bf3af547SWolfgang Grandegger 	 * is not posslible, the reference clock will be used.
168bf3af547SWolfgang Grandegger 	 */
169bf3af547SWolfgang Grandegger 	if (clock_name && !strcmp(clock_name, "ip")) {
170bf3af547SWolfgang Grandegger 		*mscan_clksrc = MSCAN_CLKSRC_IPS;
1716bd17eb9SAnatolij Gustschin 		freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
172bf3af547SWolfgang Grandegger 	} else {
173bf3af547SWolfgang Grandegger 		*mscan_clksrc = MSCAN_CLKSRC_BUS;
174bf3af547SWolfgang Grandegger 
1756bd17eb9SAnatolij Gustschin 		pval = of_get_property(ofdev->dev.of_node,
176bf3af547SWolfgang Grandegger 				       "fsl,mscan-clock-divider", &plen);
177bf3af547SWolfgang Grandegger 		if (pval && plen == sizeof(*pval))
178bf3af547SWolfgang Grandegger 			clockdiv = *pval;
179bf3af547SWolfgang Grandegger 		if (!clockdiv)
180bf3af547SWolfgang Grandegger 			clockdiv = 1;
181bf3af547SWolfgang Grandegger 
182bf3af547SWolfgang Grandegger 		if (!clock_name || !strcmp(clock_name, "sys")) {
183bf3af547SWolfgang Grandegger 			sys_clk = clk_get(&ofdev->dev, "sys_clk");
184bf3af547SWolfgang Grandegger 			if (!sys_clk) {
185bf3af547SWolfgang Grandegger 				dev_err(&ofdev->dev, "couldn't get sys_clk\n");
186bf3af547SWolfgang Grandegger 				goto exit_unmap;
187bf3af547SWolfgang Grandegger 			}
188bf3af547SWolfgang Grandegger 			/* Get and round up/down sys clock rate */
189bf3af547SWolfgang Grandegger 			sys_freq = 1000000 *
190bf3af547SWolfgang Grandegger 				((clk_get_rate(sys_clk) + 499999) / 1000000);
191bf3af547SWolfgang Grandegger 
192bf3af547SWolfgang Grandegger 			if (!clock_name) {
193bf3af547SWolfgang Grandegger 				/* A multiple of 16 MHz would be optimal */
194bf3af547SWolfgang Grandegger 				if ((sys_freq % 16000000) == 0) {
195bf3af547SWolfgang Grandegger 					clocksrc = 0;
196bf3af547SWolfgang Grandegger 					clockdiv = sys_freq / 16000000;
197bf3af547SWolfgang Grandegger 					freq = sys_freq / clockdiv;
198bf3af547SWolfgang Grandegger 				}
199bf3af547SWolfgang Grandegger 			} else {
200bf3af547SWolfgang Grandegger 				clocksrc = 0;
201bf3af547SWolfgang Grandegger 				freq = sys_freq / clockdiv;
202bf3af547SWolfgang Grandegger 			}
203bf3af547SWolfgang Grandegger 		}
204bf3af547SWolfgang Grandegger 
205bf3af547SWolfgang Grandegger 		if (clocksrc < 0) {
206bf3af547SWolfgang Grandegger 			ref_clk = clk_get(&ofdev->dev, "ref_clk");
207bf3af547SWolfgang Grandegger 			if (!ref_clk) {
208bf3af547SWolfgang Grandegger 				dev_err(&ofdev->dev, "couldn't get ref_clk\n");
209bf3af547SWolfgang Grandegger 				goto exit_unmap;
210bf3af547SWolfgang Grandegger 			}
211bf3af547SWolfgang Grandegger 			clocksrc = 1;
212bf3af547SWolfgang Grandegger 			freq = clk_get_rate(ref_clk) / clockdiv;
213bf3af547SWolfgang Grandegger 		}
214bf3af547SWolfgang Grandegger 	}
215bf3af547SWolfgang Grandegger 
216bf3af547SWolfgang Grandegger 	/* Disable clock */
217bf3af547SWolfgang Grandegger 	out_be32(&clockctl->mccr[clockidx], 0x0);
218bf3af547SWolfgang Grandegger 	if (clocksrc >= 0) {
219bf3af547SWolfgang Grandegger 		/* Set source and divider */
220bf3af547SWolfgang Grandegger 		val = (clocksrc << 14) | ((clockdiv - 1) << 17);
221bf3af547SWolfgang Grandegger 		out_be32(&clockctl->mccr[clockidx], val);
222bf3af547SWolfgang Grandegger 		/* Enable clock */
223bf3af547SWolfgang Grandegger 		out_be32(&clockctl->mccr[clockidx], val | 0x10000);
224bf3af547SWolfgang Grandegger 	}
225bf3af547SWolfgang Grandegger 
226bf3af547SWolfgang Grandegger 	/* Enable MSCAN clock domain */
227bf3af547SWolfgang Grandegger 	val = in_be32(&clockctl->sccr[1]);
228bf3af547SWolfgang Grandegger 	if (!(val & (1 << 25)))
229bf3af547SWolfgang Grandegger 		out_be32(&clockctl->sccr[1], val | (1 << 25));
230bf3af547SWolfgang Grandegger 
231bf3af547SWolfgang Grandegger 	dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
232bf3af547SWolfgang Grandegger 		*mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
233bf3af547SWolfgang Grandegger 		clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
234bf3af547SWolfgang Grandegger 
235bf3af547SWolfgang Grandegger exit_unmap:
236bf3af547SWolfgang Grandegger 	of_node_put(np_clock);
237bf3af547SWolfgang Grandegger 	iounmap(clockctl);
238bf3af547SWolfgang Grandegger 
239bf3af547SWolfgang Grandegger 	return freq;
240bf3af547SWolfgang Grandegger }
241bf3af547SWolfgang Grandegger #else /* !CONFIG_PPC_MPC512x */
242bf3af547SWolfgang Grandegger static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
243bf3af547SWolfgang Grandegger 					   const char *clock_name,
244bf3af547SWolfgang Grandegger 					   int *mscan_clksrc)
245bf3af547SWolfgang Grandegger {
246bf3af547SWolfgang Grandegger 	return 0;
247bf3af547SWolfgang Grandegger }
248bf3af547SWolfgang Grandegger #endif /* CONFIG_PPC_MPC512x */
24924cfbcbaSWolfram Sang 
25024cfbcbaSWolfram Sang static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
25124cfbcbaSWolfram Sang 				       const struct of_device_id *id)
25224cfbcbaSWolfram Sang {
253bf3af547SWolfgang Grandegger 	struct mpc5xxx_can_data *data = (struct mpc5xxx_can_data *)id->data;
2546bd17eb9SAnatolij Gustschin 	struct device_node *np = ofdev->dev.of_node;
25524cfbcbaSWolfram Sang 	struct net_device *dev;
25624cfbcbaSWolfram Sang 	struct mscan_priv *priv;
25724cfbcbaSWolfram Sang 	void __iomem *base;
258bf3af547SWolfgang Grandegger 	const char *clock_name = NULL;
259bf3af547SWolfgang Grandegger 	int irq, mscan_clksrc = 0;
260bf3af547SWolfgang Grandegger 	int err = -ENOMEM;
26124cfbcbaSWolfram Sang 
262bf3af547SWolfgang Grandegger 	base = of_iomap(np, 0);
26324cfbcbaSWolfram Sang 	if (!base) {
26424cfbcbaSWolfram Sang 		dev_err(&ofdev->dev, "couldn't ioremap\n");
265bf3af547SWolfgang Grandegger 		return err;
26624cfbcbaSWolfram Sang 	}
26724cfbcbaSWolfram Sang 
26824cfbcbaSWolfram Sang 	irq = irq_of_parse_and_map(np, 0);
26924cfbcbaSWolfram Sang 	if (!irq) {
27024cfbcbaSWolfram Sang 		dev_err(&ofdev->dev, "no irq found\n");
27124cfbcbaSWolfram Sang 		err = -ENODEV;
27224cfbcbaSWolfram Sang 		goto exit_unmap_mem;
27324cfbcbaSWolfram Sang 	}
27424cfbcbaSWolfram Sang 
27524cfbcbaSWolfram Sang 	dev = alloc_mscandev();
276bf3af547SWolfgang Grandegger 	if (!dev)
27724cfbcbaSWolfram Sang 		goto exit_dispose_irq;
27824cfbcbaSWolfram Sang 
27924cfbcbaSWolfram Sang 	priv = netdev_priv(dev);
28024cfbcbaSWolfram Sang 	priv->reg_base = base;
28124cfbcbaSWolfram Sang 	dev->irq = irq;
28224cfbcbaSWolfram Sang 
283bf3af547SWolfgang Grandegger 	clock_name = of_get_property(np, "fsl,mscan-clock-source", NULL);
284bf3af547SWolfgang Grandegger 
285bf3af547SWolfgang Grandegger 	BUG_ON(!data);
286bf3af547SWolfgang Grandegger 	priv->type = data->type;
287bf3af547SWolfgang Grandegger 	priv->can.clock.freq = data->get_clock(ofdev, clock_name,
288bf3af547SWolfgang Grandegger 					       &mscan_clksrc);
28924cfbcbaSWolfram Sang 	if (!priv->can.clock.freq) {
290bf3af547SWolfgang Grandegger 		dev_err(&ofdev->dev, "couldn't get MSCAN clock properties\n");
29124cfbcbaSWolfram Sang 		goto exit_free_mscan;
29224cfbcbaSWolfram Sang 	}
29324cfbcbaSWolfram Sang 
29424cfbcbaSWolfram Sang 	SET_NETDEV_DEV(dev, &ofdev->dev);
29524cfbcbaSWolfram Sang 
296bf3af547SWolfgang Grandegger 	err = register_mscandev(dev, mscan_clksrc);
29724cfbcbaSWolfram Sang 	if (err) {
29824cfbcbaSWolfram Sang 		dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
29924cfbcbaSWolfram Sang 			DRV_NAME, err);
30024cfbcbaSWolfram Sang 		goto exit_free_mscan;
30124cfbcbaSWolfram Sang 	}
30224cfbcbaSWolfram Sang 
30324cfbcbaSWolfram Sang 	dev_set_drvdata(&ofdev->dev, dev);
30424cfbcbaSWolfram Sang 
30524cfbcbaSWolfram Sang 	dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
30624cfbcbaSWolfram Sang 		 priv->reg_base, dev->irq, priv->can.clock.freq);
30724cfbcbaSWolfram Sang 
30824cfbcbaSWolfram Sang 	return 0;
30924cfbcbaSWolfram Sang 
31024cfbcbaSWolfram Sang exit_free_mscan:
31124cfbcbaSWolfram Sang 	free_candev(dev);
31224cfbcbaSWolfram Sang exit_dispose_irq:
31324cfbcbaSWolfram Sang 	irq_dispose_mapping(irq);
31424cfbcbaSWolfram Sang exit_unmap_mem:
31524cfbcbaSWolfram Sang 	iounmap(base);
316bf3af547SWolfgang Grandegger 
31724cfbcbaSWolfram Sang 	return err;
31824cfbcbaSWolfram Sang }
31924cfbcbaSWolfram Sang 
32024cfbcbaSWolfram Sang static int __devexit mpc5xxx_can_remove(struct of_device *ofdev)
32124cfbcbaSWolfram Sang {
32224cfbcbaSWolfram Sang 	struct net_device *dev = dev_get_drvdata(&ofdev->dev);
32324cfbcbaSWolfram Sang 	struct mscan_priv *priv = netdev_priv(dev);
32424cfbcbaSWolfram Sang 
32524cfbcbaSWolfram Sang 	dev_set_drvdata(&ofdev->dev, NULL);
32624cfbcbaSWolfram Sang 
32724cfbcbaSWolfram Sang 	unregister_mscandev(dev);
32824cfbcbaSWolfram Sang 	iounmap(priv->reg_base);
32924cfbcbaSWolfram Sang 	irq_dispose_mapping(dev->irq);
33024cfbcbaSWolfram Sang 	free_candev(dev);
33124cfbcbaSWolfram Sang 
33224cfbcbaSWolfram Sang 	return 0;
33324cfbcbaSWolfram Sang }
33424cfbcbaSWolfram Sang 
33524cfbcbaSWolfram Sang #ifdef CONFIG_PM
33624cfbcbaSWolfram Sang static struct mscan_regs saved_regs;
33724cfbcbaSWolfram Sang static int mpc5xxx_can_suspend(struct of_device *ofdev, pm_message_t state)
33824cfbcbaSWolfram Sang {
33924cfbcbaSWolfram Sang 	struct net_device *dev = dev_get_drvdata(&ofdev->dev);
34024cfbcbaSWolfram Sang 	struct mscan_priv *priv = netdev_priv(dev);
34124cfbcbaSWolfram Sang 	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
34224cfbcbaSWolfram Sang 
34324cfbcbaSWolfram Sang 	_memcpy_fromio(&saved_regs, regs, sizeof(*regs));
34424cfbcbaSWolfram Sang 
34524cfbcbaSWolfram Sang 	return 0;
34624cfbcbaSWolfram Sang }
34724cfbcbaSWolfram Sang 
34824cfbcbaSWolfram Sang static int mpc5xxx_can_resume(struct of_device *ofdev)
34924cfbcbaSWolfram Sang {
35024cfbcbaSWolfram Sang 	struct net_device *dev = dev_get_drvdata(&ofdev->dev);
35124cfbcbaSWolfram Sang 	struct mscan_priv *priv = netdev_priv(dev);
35224cfbcbaSWolfram Sang 	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
35324cfbcbaSWolfram Sang 
35424cfbcbaSWolfram Sang 	regs->canctl0 |= MSCAN_INITRQ;
35524cfbcbaSWolfram Sang 	while (!(regs->canctl1 & MSCAN_INITAK))
35624cfbcbaSWolfram Sang 		udelay(10);
35724cfbcbaSWolfram Sang 
35824cfbcbaSWolfram Sang 	regs->canctl1 = saved_regs.canctl1;
35924cfbcbaSWolfram Sang 	regs->canbtr0 = saved_regs.canbtr0;
36024cfbcbaSWolfram Sang 	regs->canbtr1 = saved_regs.canbtr1;
36124cfbcbaSWolfram Sang 	regs->canidac = saved_regs.canidac;
36224cfbcbaSWolfram Sang 
36324cfbcbaSWolfram Sang 	/* restore masks, buffers etc. */
36424cfbcbaSWolfram Sang 	_memcpy_toio(&regs->canidar1_0, (void *)&saved_regs.canidar1_0,
36524cfbcbaSWolfram Sang 		     sizeof(*regs) - offsetof(struct mscan_regs, canidar1_0));
36624cfbcbaSWolfram Sang 
36724cfbcbaSWolfram Sang 	regs->canctl0 &= ~MSCAN_INITRQ;
36824cfbcbaSWolfram Sang 	regs->cantbsel = saved_regs.cantbsel;
36924cfbcbaSWolfram Sang 	regs->canrier = saved_regs.canrier;
37024cfbcbaSWolfram Sang 	regs->cantier = saved_regs.cantier;
37124cfbcbaSWolfram Sang 	regs->canctl0 = saved_regs.canctl0;
37224cfbcbaSWolfram Sang 
37324cfbcbaSWolfram Sang 	return 0;
37424cfbcbaSWolfram Sang }
37524cfbcbaSWolfram Sang #endif
37624cfbcbaSWolfram Sang 
377bf3af547SWolfgang Grandegger static struct mpc5xxx_can_data __devinitdata mpc5200_can_data = {
378bf3af547SWolfgang Grandegger 	.type = MSCAN_TYPE_MPC5200,
379bf3af547SWolfgang Grandegger 	.get_clock = mpc52xx_can_get_clock,
380bf3af547SWolfgang Grandegger };
381bf3af547SWolfgang Grandegger 
382bf3af547SWolfgang Grandegger static struct mpc5xxx_can_data __devinitdata mpc5121_can_data = {
383bf3af547SWolfgang Grandegger 	.type = MSCAN_TYPE_MPC5121,
384bf3af547SWolfgang Grandegger 	.get_clock = mpc512x_can_get_clock,
385bf3af547SWolfgang Grandegger };
386bf3af547SWolfgang Grandegger 
38724cfbcbaSWolfram Sang static struct of_device_id __devinitdata mpc5xxx_can_table[] = {
388bf3af547SWolfgang Grandegger 	{ .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, },
389bf3af547SWolfgang Grandegger 	/* Note that only MPC5121 Rev. 2 (and later) is supported */
390bf3af547SWolfgang Grandegger 	{ .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, },
39124cfbcbaSWolfram Sang 	{},
39224cfbcbaSWolfram Sang };
39324cfbcbaSWolfram Sang 
39424cfbcbaSWolfram Sang static struct of_platform_driver mpc5xxx_can_driver = {
3954018294bSGrant Likely 	.driver = {
39624cfbcbaSWolfram Sang 		.name = "mpc5xxx_can",
3974018294bSGrant Likely 		.owner = THIS_MODULE,
3984018294bSGrant Likely 		.of_match_table = mpc5xxx_can_table,
3994018294bSGrant Likely 	},
40024cfbcbaSWolfram Sang 	.probe = mpc5xxx_can_probe,
40124cfbcbaSWolfram Sang 	.remove = __devexit_p(mpc5xxx_can_remove),
40224cfbcbaSWolfram Sang #ifdef CONFIG_PM
40324cfbcbaSWolfram Sang 	.suspend = mpc5xxx_can_suspend,
40424cfbcbaSWolfram Sang 	.resume = mpc5xxx_can_resume,
40524cfbcbaSWolfram Sang #endif
40624cfbcbaSWolfram Sang };
40724cfbcbaSWolfram Sang 
40824cfbcbaSWolfram Sang static int __init mpc5xxx_can_init(void)
40924cfbcbaSWolfram Sang {
41024cfbcbaSWolfram Sang 	return of_register_platform_driver(&mpc5xxx_can_driver);
41124cfbcbaSWolfram Sang }
41224cfbcbaSWolfram Sang module_init(mpc5xxx_can_init);
41324cfbcbaSWolfram Sang 
41424cfbcbaSWolfram Sang static void __exit mpc5xxx_can_exit(void)
41524cfbcbaSWolfram Sang {
41624cfbcbaSWolfram Sang 	return of_unregister_platform_driver(&mpc5xxx_can_driver);
41724cfbcbaSWolfram Sang };
41824cfbcbaSWolfram Sang module_exit(mpc5xxx_can_exit);
41924cfbcbaSWolfram Sang 
42024cfbcbaSWolfram Sang MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
421bf3af547SWolfgang Grandegger MODULE_DESCRIPTION("Freescale MPC5xxx CAN driver");
42224cfbcbaSWolfram Sang MODULE_LICENSE("GPL v2");
423