diff options
Diffstat (limited to 'drivers/net/can/mscan')
| -rw-r--r-- | drivers/net/can/mscan/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/net/can/mscan/mpc5xxx_can.c | 347 | ||||
| -rw-r--r-- | drivers/net/can/mscan/mscan.c | 125 | ||||
| -rw-r--r-- | drivers/net/can/mscan/mscan.h | 13 | 
4 files changed, 281 insertions, 206 deletions
diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig index 27d1d398e25..81c71171949 100644 --- a/drivers/net/can/mscan/Kconfig +++ b/drivers/net/can/mscan/Kconfig @@ -1,5 +1,5 @@  config CAN_MSCAN -	depends on CAN_DEV && (PPC || M68K || M68KNOMMU) +	depends on PPC  	tristate "Support for Freescale MSCAN based chips"  	---help---  	  The Motorola Scalable Controller Area Network (MSCAN) definition diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index 312b9c8f4f3..44725296f72 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -16,8 +16,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * along with this program; if not, see <http://www.gnu.org/licenses/>.   */  #include <linux/kernel.h> @@ -40,17 +39,17 @@ struct mpc5xxx_can_data {  	unsigned int type;  	u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,  			 int *mscan_clksrc); +	void (*put_clock)(struct platform_device *ofdev);  };  #ifdef CONFIG_PPC_MPC52xx -static struct of_device_id __devinitdata mpc52xx_cdm_ids[] = { +static struct of_device_id mpc52xx_cdm_ids[] = {  	{ .compatible = "fsl,mpc5200-cdm", },  	{}  }; -static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev, -					   const char *clock_name, -					   int *mscan_clksrc) +static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, +				 const char *clock_name, int *mscan_clksrc)  {  	unsigned int pvr;  	struct mpc52xx_cdm  __iomem *cdm; @@ -101,156 +100,193 @@ static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev,  	return freq;  }  #else /* !CONFIG_PPC_MPC52xx */ -static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev, -					   const char *clock_name, -					   int *mscan_clksrc) +static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, +				 const char *clock_name, int *mscan_clksrc)  {  	return 0;  }  #endif /* CONFIG_PPC_MPC52xx */  #ifdef CONFIG_PPC_MPC512x -struct mpc512x_clockctl { -	u32 spmr;		/* System PLL Mode Reg */ -	u32 sccr[2];		/* System Clk Ctrl Reg 1 & 2 */ -	u32 scfr1;		/* System Clk Freq Reg 1 */ -	u32 scfr2;		/* System Clk Freq Reg 2 */ -	u32 reserved; -	u32 bcr;		/* Bread Crumb Reg */ -	u32 pccr[12];		/* PSC Clk Ctrl Reg 0-11 */ -	u32 spccr;		/* SPDIF Clk Ctrl Reg */ -	u32 cccr;		/* CFM Clk Ctrl Reg */ -	u32 dccr;		/* DIU Clk Cnfg Reg */ -	u32 mccr[4];		/* MSCAN Clk Ctrl Reg 1-3 */ -}; - -static struct of_device_id __devinitdata mpc512x_clock_ids[] = { -	{ .compatible = "fsl,mpc5121-clock", }, -	{} -}; - -static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, -					   const char *clock_name, -					   int *mscan_clksrc) +static u32 mpc512x_can_get_clock(struct platform_device *ofdev, +				 const char *clock_source, int *mscan_clksrc)  { -	struct mpc512x_clockctl __iomem *clockctl; -	struct device_node *np_clock; -	struct clk *sys_clk, *ref_clk; -	int plen, clockidx, clocksrc = -1; -	u32 sys_freq, val, clockdiv = 1, freq = 0; -	const u32 *pval; - -	np_clock = of_find_matching_node(NULL, mpc512x_clock_ids); -	if (!np_clock) { -		dev_err(&ofdev->dev, "couldn't find clock node\n"); -		return 0; +	struct device_node *np; +	u32 clockdiv; +	enum { +		CLK_FROM_AUTO, +		CLK_FROM_IPS, +		CLK_FROM_SYS, +		CLK_FROM_REF, +	} clk_from; +	struct clk *clk_in, *clk_can; +	unsigned long freq_calc; +	struct mscan_priv *priv; +	struct clk *clk_ipg; + +	/* the caller passed in the clock source spec that was read from +	 * the device tree, get the optional clock divider as well +	 */ +	np = ofdev->dev.of_node; +	clockdiv = 1; +	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv); +	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n", +		clock_source ? clock_source : "<NULL>", clockdiv); + +	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to +	 * get set, and the 'ips' clock is the input to the MSCAN +	 * component +	 * +	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC] +	 * bit needs to get cleared, an optional clock-divider may have +	 * been specified (the default value is 1), the appropriate +	 * MSCAN related MCLK is the input to the MSCAN component +	 * +	 * in the absence of a clock-source spec, first an optimal clock +	 * gets determined based on the 'sys' clock, if that fails the +	 * 'ref' clock is used +	 */ +	clk_from = CLK_FROM_AUTO; +	if (clock_source) { +		/* interpret the device tree's spec for the clock source */ +		if (!strcmp(clock_source, "ip")) +			clk_from = CLK_FROM_IPS; +		else if (!strcmp(clock_source, "sys")) +			clk_from = CLK_FROM_SYS; +		else if (!strcmp(clock_source, "ref")) +			clk_from = CLK_FROM_REF; +		else +			goto err_invalid; +		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);  	} -	clockctl = of_iomap(np_clock, 0); -	if (!clockctl) { -		dev_err(&ofdev->dev, "couldn't map clock registers\n"); -		goto exit_put; +	if (clk_from == CLK_FROM_AUTO) { +		/* no spec so far, try the 'sys' clock; round to the +		 * next MHz and see if we can get a multiple of 16MHz +		 */ +		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n"); +		clk_in = devm_clk_get(&ofdev->dev, "sys"); +		if (IS_ERR(clk_in)) +			goto err_notavail; +		freq_calc = clk_get_rate(clk_in); +		freq_calc +=  499999; +		freq_calc /= 1000000; +		freq_calc *= 1000000; +		if ((freq_calc % 16000000) == 0) { +			clk_from = CLK_FROM_SYS; +			clockdiv = freq_calc / 16000000; +			dev_dbg(&ofdev->dev, +				"clk fit, sys[%lu] div[%d] freq[%lu]\n", +				freq_calc, clockdiv, freq_calc / clockdiv); +		} +	} +	if (clk_from == CLK_FROM_AUTO) { +		/* no spec so far, use the 'ref' clock */ +		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n"); +		clk_in = devm_clk_get(&ofdev->dev, "ref"); +		if (IS_ERR(clk_in)) +			goto err_notavail; +		clk_from = CLK_FROM_REF; +		freq_calc = clk_get_rate(clk_in); +		dev_dbg(&ofdev->dev, +			"clk fit, ref[%lu] (no div) freq[%lu]\n", +			freq_calc, freq_calc);  	} -	/* Determine the MSCAN device index from the physical address */ -	pval = of_get_property(ofdev->dev.of_node, "reg", &plen); -	BUG_ON(!pval || plen < sizeof(*pval)); -	clockidx = (*pval & 0x80) ? 1 : 0; -	if (*pval & 0x2000) -		clockidx += 2; - -	/* -	 * Clock source and divider selection: 3 different clock sources -	 * can be selected: "ip", "ref" or "sys". For the latter two, a -	 * clock divider can be defined as well. If the clock source is -	 * not specified by the device tree, we first try to find an -	 * optimal CAN source clock based on the system clock. If that -	 * is not posslible, the reference clock will be used. +	/* select IPS or MCLK as the MSCAN input (returned to the caller), +	 * setup the MCLK mux source and rate if applicable, apply the +	 * optionally specified or derived above divider, and determine +	 * the actual resulting clock rate to return to the caller  	 */ -	if (clock_name && !strcmp(clock_name, "ip")) { +	switch (clk_from) { +	case CLK_FROM_IPS: +		clk_can = devm_clk_get(&ofdev->dev, "ips"); +		if (IS_ERR(clk_can)) +			goto err_notavail; +		priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); +		priv->clk_can = clk_can; +		freq_calc = clk_get_rate(clk_can);  		*mscan_clksrc = MSCAN_CLKSRC_IPS; -		freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node); -	} else { +		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n", +			*mscan_clksrc, freq_calc); +		break; +	case CLK_FROM_SYS: +	case CLK_FROM_REF: +		clk_can = devm_clk_get(&ofdev->dev, "mclk"); +		if (IS_ERR(clk_can)) +			goto err_notavail; +		priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); +		priv->clk_can = clk_can; +		if (clk_from == CLK_FROM_SYS) +			clk_in = devm_clk_get(&ofdev->dev, "sys"); +		if (clk_from == CLK_FROM_REF) +			clk_in = devm_clk_get(&ofdev->dev, "ref"); +		if (IS_ERR(clk_in)) +			goto err_notavail; +		clk_set_parent(clk_can, clk_in); +		freq_calc = clk_get_rate(clk_in); +		freq_calc /= clockdiv; +		clk_set_rate(clk_can, freq_calc); +		freq_calc = clk_get_rate(clk_can);  		*mscan_clksrc = MSCAN_CLKSRC_BUS; - -		pval = of_get_property(ofdev->dev.of_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; -		} +		dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n", +			*mscan_clksrc, freq_calc); +		break; +	default: +		goto err_invalid;  	} -	/* Disable clock */ -	out_be32(&clockctl->mccr[clockidx], 0x0); -	if (clocksrc >= 0) { -		/* Set source and divider */ -		val = (clocksrc << 14) | ((clockdiv - 1) << 17); -		out_be32(&clockctl->mccr[clockidx], val); -		/* Enable clock */ -		out_be32(&clockctl->mccr[clockidx], val | 0x10000); -	} +	/* the above clk_can item is used for the bitrate, access to +	 * the peripheral's register set needs the clk_ipg item +	 */ +	clk_ipg = devm_clk_get(&ofdev->dev, "ipg"); +	if (IS_ERR(clk_ipg)) +		goto err_notavail_ipg; +	if (clk_prepare_enable(clk_ipg)) +		goto err_notavail_ipg; +	priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); +	priv->clk_ipg = clk_ipg; + +	/* return the determined clock source rate */ +	return freq_calc; + +err_invalid: +	dev_err(&ofdev->dev, "invalid clock source specification\n"); +	/* clock source rate could not get determined */ +	return 0; -	/* Enable MSCAN clock domain */ -	val = in_be32(&clockctl->sccr[1]); -	if (!(val & (1 << 25))) -		out_be32(&clockctl->sccr[1], val | (1 << 25)); +err_notavail: +	dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n"); +	/* clock source rate could not get determined */ +	return 0; + +err_notavail_ipg: +	dev_err(&ofdev->dev, "cannot acquire or setup register clock\n"); +	/* clock source rate could not get determined */ +	return 0; +} -	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); +static void mpc512x_can_put_clock(struct platform_device *ofdev) +{ +	struct mscan_priv *priv; -exit_unmap: -	iounmap(clockctl); -exit_put: -	of_node_put(np_clock); -	return freq; +	priv = netdev_priv(dev_get_drvdata(&ofdev->dev)); +	if (priv->clk_ipg) +		clk_disable_unprepare(priv->clk_ipg);  }  #else /* !CONFIG_PPC_MPC512x */ -static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, -					   const char *clock_name, -					   int *mscan_clksrc) +static u32 mpc512x_can_get_clock(struct platform_device *ofdev, +				 const char *clock_name, int *mscan_clksrc)  {  	return 0;  } +#define mpc512x_can_put_clock NULL  #endif /* CONFIG_PPC_MPC512x */ -static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev, -				       const struct of_device_id *id) +static const struct of_device_id mpc5xxx_can_table[]; +static int mpc5xxx_can_probe(struct platform_device *ofdev)  { -	struct mpc5xxx_can_data *data = (struct mpc5xxx_can_data *)id->data; +	const struct of_device_id *match; +	const struct mpc5xxx_can_data *data;  	struct device_node *np = ofdev->dev.of_node;  	struct net_device *dev;  	struct mscan_priv *priv; @@ -259,6 +295,11 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev,  	int irq, mscan_clksrc = 0;  	int err = -ENOMEM; +	match = of_match_device(mpc5xxx_can_table, &ofdev->dev); +	if (!match) +		return -EINVAL; +	data = match->data; +  	base = of_iomap(np, 0);  	if (!base) {  		dev_err(&ofdev->dev, "couldn't ioremap\n"); @@ -275,6 +316,8 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev,  	dev = alloc_mscandev();  	if (!dev)  		goto exit_dispose_irq; +	platform_set_drvdata(ofdev, dev); +	SET_NETDEV_DEV(dev, &ofdev->dev);  	priv = netdev_priv(dev);  	priv->reg_base = base; @@ -291,8 +334,6 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev,  		goto exit_free_mscan;  	} -	SET_NETDEV_DEV(dev, &ofdev->dev); -  	err = register_mscandev(dev, mscan_clksrc);  	if (err) {  		dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", @@ -300,8 +341,6 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev,  		goto exit_free_mscan;  	} -	dev_set_drvdata(&ofdev->dev, dev); -  	dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",  		 priv->reg_base, dev->irq, priv->can.clock.freq); @@ -317,14 +356,19 @@ exit_unmap_mem:  	return err;  } -static int __devexit mpc5xxx_can_remove(struct platform_device *ofdev) +static int mpc5xxx_can_remove(struct platform_device *ofdev)  { -	struct net_device *dev = dev_get_drvdata(&ofdev->dev); +	const struct of_device_id *match; +	const struct mpc5xxx_can_data *data; +	struct net_device *dev = platform_get_drvdata(ofdev);  	struct mscan_priv *priv = netdev_priv(dev); -	dev_set_drvdata(&ofdev->dev, NULL); +	match = of_match_device(mpc5xxx_can_table, &ofdev->dev); +	data = match ? match->data : NULL;  	unregister_mscandev(dev); +	if (data && data->put_clock) +		data->put_clock(ofdev);  	iounmap(priv->reg_base);  	irq_dispose_mapping(dev->irq);  	free_candev(dev); @@ -336,7 +380,7 @@ static int __devexit mpc5xxx_can_remove(struct platform_device *ofdev)  static struct mscan_regs saved_regs;  static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state)  { -	struct net_device *dev = dev_get_drvdata(&ofdev->dev); +	struct net_device *dev = platform_get_drvdata(ofdev);  	struct mscan_priv *priv = netdev_priv(dev);  	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; @@ -347,7 +391,7 @@ static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state  static int mpc5xxx_can_resume(struct platform_device *ofdev)  { -	struct net_device *dev = dev_get_drvdata(&ofdev->dev); +	struct net_device *dev = platform_get_drvdata(ofdev);  	struct mscan_priv *priv = netdev_priv(dev);  	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; @@ -374,48 +418,41 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)  }  #endif -static struct mpc5xxx_can_data __devinitdata mpc5200_can_data = { +static const struct mpc5xxx_can_data mpc5200_can_data = {  	.type = MSCAN_TYPE_MPC5200,  	.get_clock = mpc52xx_can_get_clock, +	/* .put_clock not applicable */  }; -static struct mpc5xxx_can_data __devinitdata mpc5121_can_data = { +static const struct mpc5xxx_can_data mpc5121_can_data = {  	.type = MSCAN_TYPE_MPC5121,  	.get_clock = mpc512x_can_get_clock, +	.put_clock = mpc512x_can_put_clock,  }; -static struct of_device_id __devinitdata mpc5xxx_can_table[] = { +static const struct of_device_id mpc5xxx_can_table[] = {  	{ .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, },  	/* Note that only MPC5121 Rev. 2 (and later) is supported */  	{ .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, },  	{},  }; +MODULE_DEVICE_TABLE(of, mpc5xxx_can_table); -static struct of_platform_driver mpc5xxx_can_driver = { +static struct platform_driver mpc5xxx_can_driver = {  	.driver = {  		.name = "mpc5xxx_can",  		.owner = THIS_MODULE,  		.of_match_table = mpc5xxx_can_table,  	},  	.probe = mpc5xxx_can_probe, -	.remove = __devexit_p(mpc5xxx_can_remove), +	.remove = mpc5xxx_can_remove,  #ifdef CONFIG_PM  	.suspend = mpc5xxx_can_suspend,  	.resume = mpc5xxx_can_resume,  #endif  }; -static int __init mpc5xxx_can_init(void) -{ -	return of_register_platform_driver(&mpc5xxx_can_driver); -} -module_init(mpc5xxx_can_init); - -static void __exit mpc5xxx_can_exit(void) -{ -	return of_unregister_platform_driver(&mpc5xxx_can_driver); -}; -module_exit(mpc5xxx_can_exit); +module_platform_driver(mpc5xxx_can_driver);  MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");  MODULE_DESCRIPTION("Freescale MPC5xxx CAN driver"); diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 74cd880c7e0..e0c9be5e2ab 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -16,8 +16,7 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * along with this program; if not, see <http://www.gnu.org/licenses/>.   */  #include <linux/kernel.h> @@ -34,7 +33,7 @@  #include "mscan.h" -static struct can_bittiming_const mscan_bittiming_const = { +static const struct can_bittiming_const mscan_bittiming_const = {  	.name = "mscan",  	.tseg1_min = 4,  	.tseg1_max = 16, @@ -62,7 +61,7 @@ static enum can_state state_map[] = {  static int mscan_set_mode(struct net_device *dev, u8 mode)  {  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	int ret = 0;  	int i;  	u8 canctl1; @@ -95,9 +94,9 @@ static int mscan_set_mode(struct net_device *dev, u8 mode)  			 * any, at once.  			 */  			if (i >= MSCAN_SET_MODE_RETRIES) -				dev_dbg(dev->dev.parent, -					"device failed to enter sleep mode. " -					"We proceed anyhow.\n"); +				netdev_dbg(dev, +					   "device failed to enter sleep mode. " +					   "We proceed anyhow.\n");  			else  				priv->can.state = CAN_STATE_SLEEPING;  		} @@ -138,7 +137,7 @@ static int mscan_set_mode(struct net_device *dev, u8 mode)  static int mscan_start(struct net_device *dev)  {  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	u8 canrflg;  	int err; @@ -178,7 +177,7 @@ 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; +		struct mscan_regs __iomem *regs = priv->reg_base;  		priv->can.state = CAN_STATE_ERROR_ACTIVE;  		WARN(!(in_8(®s->canmisc) & MSCAN_BOHOLD), @@ -199,7 +198,7 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct can_frame *frame = (struct can_frame *)skb->data;  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	int i, rtr, buf_id;  	u32 can_id; @@ -213,7 +212,7 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)  	switch (hweight8(i)) {  	case 0:  		netif_stop_queue(dev); -		dev_err(dev->dev.parent, "Tx Ring full when queue awake!\n"); +		netdev_err(dev, "Tx Ring full when queue awake!\n");  		return NETDEV_TX_BUSY;  	case 1:  		/* @@ -246,7 +245,7 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)  		out_be16(®s->tx.idr3_2, can_id);  		can_id >>= 16; -		/* EFF_FLAGS are inbetween the IDs :( */ +		/* EFF_FLAGS are between the IDs :( */  		can_id = (can_id & 0x7) | ((can_id << 2) & 0xffe0)  			 | MSCAN_EFF_FLAGS;  	} else { @@ -261,11 +260,13 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)  		void __iomem *data = ®s->tx.dsr1_0;  		u16 *payload = (u16 *)frame->data; -		/* It is safe to write into dsr[dlc+1] */ -		for (i = 0; i < (frame->can_dlc + 1) / 2; i++) { +		for (i = 0; i < frame->can_dlc / 2; i++) {  			out_be16(data, *payload++);  			data += 2 + _MSCAN_RESERVED_DSR_SIZE;  		} +		/* write remaining byte if necessary */ +		if (frame->can_dlc & 1) +			out_8(data, frame->data[frame->can_dlc - 1]);  	}  	out_8(®s->tx.dlr, frame->can_dlc); @@ -305,7 +306,7 @@ static enum can_state check_set_state(struct net_device *dev, u8 canrflg)  static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)  {  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	u32 can_id;  	int i; @@ -330,10 +331,13 @@ static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)  		void __iomem *data = ®s->rx.dsr1_0;  		u16 *payload = (u16 *)frame->data; -		for (i = 0; i < (frame->can_dlc + 1) / 2; i++) { +		for (i = 0; i < frame->can_dlc / 2; i++) {  			*payload++ = in_be16(data);  			data += 2 + _MSCAN_RESERVED_DSR_SIZE;  		} +		/* read remaining byte if necessary */ +		if (frame->can_dlc & 1) +			frame->data[frame->can_dlc - 1] = in_8(data);  	}  	out_8(®s->canrflg, MSCAN_RXF); @@ -343,11 +347,11 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,  				u8 canrflg)  {  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	struct net_device_stats *stats = &dev->stats;  	enum can_state old_state; -	dev_dbg(dev->dev.parent, "error interrupt (canrflg=%#x)\n", canrflg); +	netdev_dbg(dev, "error interrupt (canrflg=%#x)\n", canrflg);  	frame->can_id = CAN_ERR_FLAG;  	if (canrflg & MSCAN_OVRIF) { @@ -406,7 +410,7 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota)  {  	struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi);  	struct net_device *dev = napi->dev; -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	struct net_device_stats *stats = &dev->stats;  	int npackets = 0;  	int ret = 1; @@ -422,7 +426,7 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota)  		skb = alloc_can_skb(dev, &frame);  		if (!skb) {  			if (printk_ratelimit()) -				dev_notice(dev->dev.parent, "packet dropped\n"); +				netdev_notice(dev, "packet dropped\n");  			stats->rx_dropped++;  			out_8(®s->canrflg, canrflg);  			continue; @@ -453,7 +457,7 @@ static irqreturn_t mscan_isr(int irq, void *dev_id)  {  	struct net_device *dev = (struct net_device *)dev_id;  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	struct net_device_stats *stats = &dev->stats;  	u8 cantier, cantflg, canrflg;  	irqreturn_t ret = IRQ_NONE; @@ -512,12 +516,8 @@ static irqreturn_t mscan_isr(int irq, void *dev_id)  static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)  { -	struct mscan_priv *priv = netdev_priv(dev);  	int ret = 0; -	if (!priv->open_time) -		return -EINVAL; -  	switch (mode) {  	case CAN_MODE_START:  		ret = mscan_restart(dev); @@ -537,7 +537,7 @@ static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)  static int mscan_do_set_bittiming(struct net_device *dev)  {  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	struct can_bittiming *bt = &priv->can.bittiming;  	u8 btr0, btr1; @@ -546,8 +546,7 @@ static int mscan_do_set_bittiming(struct net_device *dev)  		BTR1_SET_TSEG2(bt->phase_seg2) |  		BTR1_SET_SAM(priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)); -	dev_info(dev->dev.parent, "setting BTR0=0x%02x BTR1=0x%02x\n", -		btr0, btr1); +	netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);  	out_8(®s->canbtr0, btr0);  	out_8(®s->canbtr1, btr1); @@ -555,28 +554,52 @@ static int mscan_do_set_bittiming(struct net_device *dev)  	return 0;  } +static int mscan_get_berr_counter(const struct net_device *dev, +				  struct can_berr_counter *bec) +{ +	struct mscan_priv *priv = netdev_priv(dev); +	struct mscan_regs __iomem *regs = priv->reg_base; + +	bec->txerr = in_8(®s->cantxerr); +	bec->rxerr = in_8(®s->canrxerr); + +	return 0; +} +  static int mscan_open(struct net_device *dev)  {  	int ret;  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base; + +	if (priv->clk_ipg) { +		ret = clk_prepare_enable(priv->clk_ipg); +		if (ret) +			goto exit_retcode; +	} +	if (priv->clk_can) { +		ret = clk_prepare_enable(priv->clk_can); +		if (ret) +			goto exit_dis_ipg_clock; +	}  	/* common open */  	ret = open_candev(dev);  	if (ret) -		return ret; +		goto exit_dis_can_clock;  	napi_enable(&priv->napi);  	ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev);  	if (ret < 0) { -		dev_err(dev->dev.parent, "failed to attach interrupt\n"); +		netdev_err(dev, "failed to attach interrupt\n");  		goto exit_napi_disable;  	} -	priv->open_time = jiffies; - -	clrbits8(®s->canctl1, MSCAN_LISTEN); +	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) +		setbits8(®s->canctl1, MSCAN_LISTEN); +	else +		clrbits8(®s->canctl1, MSCAN_LISTEN);  	ret = mscan_start(dev);  	if (ret) @@ -587,18 +610,24 @@ static int mscan_open(struct net_device *dev)  	return 0;  exit_free_irq: -	priv->open_time = 0;  	free_irq(dev->irq, dev);  exit_napi_disable:  	napi_disable(&priv->napi);  	close_candev(dev); +exit_dis_can_clock: +	if (priv->clk_can) +		clk_disable_unprepare(priv->clk_can); +exit_dis_ipg_clock: +	if (priv->clk_ipg) +		clk_disable_unprepare(priv->clk_ipg); +exit_retcode:  	return ret;  }  static int mscan_close(struct net_device *dev)  {  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	netif_stop_queue(dev);  	napi_disable(&priv->napi); @@ -608,21 +637,26 @@ static int mscan_close(struct net_device *dev)  	mscan_set_mode(dev, MSCAN_INIT_MODE);  	close_candev(dev);  	free_irq(dev->irq, dev); -	priv->open_time = 0; + +	if (priv->clk_can) +		clk_disable_unprepare(priv->clk_can); +	if (priv->clk_ipg) +		clk_disable_unprepare(priv->clk_ipg);  	return 0;  }  static const struct net_device_ops mscan_netdev_ops = { -       .ndo_open               = mscan_open, -       .ndo_stop               = mscan_close, -       .ndo_start_xmit         = mscan_start_xmit, +	.ndo_open	= mscan_open, +	.ndo_stop	= mscan_close, +	.ndo_start_xmit	= mscan_start_xmit, +	.ndo_change_mtu	= can_change_mtu,  };  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; +	struct mscan_regs __iomem *regs = priv->reg_base;  	u8 ctl1;  	ctl1 = in_8(®s->canctl1); @@ -631,8 +665,10 @@ int register_mscandev(struct net_device *dev, int mscan_clksrc)  	else  		ctl1 &= ~MSCAN_CLKSRC; -	if (priv->type == MSCAN_TYPE_MPC5121) +	if (priv->type == MSCAN_TYPE_MPC5121) { +		priv->can.do_get_berr_counter = mscan_get_berr_counter;  		ctl1 |= MSCAN_BORM; /* bus-off recovery upon request */ +	}  	ctl1 |= MSCAN_CANE;  	out_8(®s->canctl1, ctl1); @@ -659,7 +695,7 @@ int register_mscandev(struct net_device *dev, int mscan_clksrc)  void unregister_mscandev(struct net_device *dev)  {  	struct mscan_priv *priv = netdev_priv(dev); -	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base; +	struct mscan_regs __iomem *regs = priv->reg_base;  	mscan_set_mode(dev, MSCAN_INIT_MODE);  	clrbits8(®s->canctl1, MSCAN_CANE);  	unregister_candev(dev); @@ -685,7 +721,8 @@ struct net_device *alloc_mscandev(void)  	priv->can.bittiming_const = &mscan_bittiming_const;  	priv->can.do_set_bittiming = mscan_do_set_bittiming;  	priv->can.do_set_mode = mscan_do_set_mode; -	priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; +	priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | +		CAN_CTRLMODE_LISTENONLY;  	for (i = 0; i < TX_QUEUE_SIZE; i++) {  		priv->tx_queue[i].id = i; diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h index b43e9f5d326..ad8e08f9c49 100644 --- a/drivers/net/can/mscan/mscan.h +++ b/drivers/net/can/mscan/mscan.h @@ -14,13 +14,13 @@   * GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * along with this program; if not, see <http://www.gnu.org/licenses/>.   */  #ifndef __MSCAN_H__  #define __MSCAN_H__ +#include <linux/clk.h>  #include <linux/types.h>  /* MSCAN control register 0 (CANCTL0) bits */ @@ -281,9 +281,10 @@ 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 */ +	struct clk *clk_ipg;	/* clock for registers */ +	struct clk *clk_can;	/* clock for bitrates */  	u8 shadow_statflg;  	u8 shadow_canrier;  	u8 cur_pri; @@ -295,8 +296,8 @@ struct mscan_priv {  	struct napi_struct napi;  }; -extern struct net_device *alloc_mscandev(void); -extern int register_mscandev(struct net_device *dev, int mscan_clksrc); -extern void unregister_mscandev(struct net_device *dev); +struct net_device *alloc_mscandev(void); +int register_mscandev(struct net_device *dev, int mscan_clksrc); +void unregister_mscandev(struct net_device *dev);  #endif /* __MSCAN_H__ */  | 
