brintos

brintos / linux-shallow public Read only

0
0
Text · 12.3 KiB · 0080c39 Raw
450 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * CAN bus driver for the Freescale MPC5xxx embedded CPU.4 *5 * Copyright (C) 2004-2005 Andrey Volkov <avolkov@varma-el.com>,6 *                         Varma Electronics Oy7 * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>8 * Copyright (C) 2009 Wolfram Sang, Pengutronix <kernel@pengutronix.de>9 */10 11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/interrupt.h>14#include <linux/platform_device.h>15#include <linux/property.h>16#include <linux/netdevice.h>17#include <linux/can/dev.h>18#include <linux/of.h>19#include <linux/of_address.h>20#include <linux/of_irq.h>21#include <linux/of_platform.h>22#include <sysdev/fsl_soc.h>23#include <linux/clk.h>24#include <linux/io.h>25#include <asm/mpc52xx.h>26 27#include "mscan.h"28 29#define DRV_NAME "mpc5xxx_can"30 31struct mpc5xxx_can_data {32	unsigned int type;33	u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,34			 int *mscan_clksrc);35	void (*put_clock)(struct platform_device *ofdev);36};37 38#ifdef CONFIG_PPC_MPC52xx39static const struct of_device_id mpc52xx_cdm_ids[] = {40	{ .compatible = "fsl,mpc5200-cdm", },41	{}42};43 44static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,45				 const char *clock_name, int *mscan_clksrc)46{47	unsigned int pvr;48	struct mpc52xx_cdm  __iomem *cdm;49	struct device_node *np_cdm;50	unsigned int freq;51	u32 val;52 53	pvr = mfspr(SPRN_PVR);54 55	/*56	 * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock57	 * (IP_CLK) can be selected as MSCAN clock source. According to58	 * the MPC5200 user's manual, the oscillator clock is the better59	 * choice as it has less jitter. For this reason, it is selected60	 * by default. Unfortunately, it can not be selected for the old61	 * MPC5200 Rev. A chips due to a hardware bug (check errata).62	 */63	if (clock_name && strcmp(clock_name, "ip") == 0)64		*mscan_clksrc = MSCAN_CLKSRC_BUS;65	else66		*mscan_clksrc = MSCAN_CLKSRC_XTAL;67 68	freq = mpc5xxx_get_bus_frequency(&ofdev->dev);69	if (!freq)70		return 0;71 72	if (*mscan_clksrc == MSCAN_CLKSRC_BUS || pvr == 0x80822011)73		return freq;74 75	/* Determine SYS_XTAL_IN frequency from the clock domain settings */76	np_cdm = of_find_matching_node(NULL, mpc52xx_cdm_ids);77	if (!np_cdm) {78		dev_err(&ofdev->dev, "can't get clock node!\n");79		return 0;80	}81	cdm = of_iomap(np_cdm, 0);82	if (!cdm) {83		of_node_put(np_cdm);84		dev_err(&ofdev->dev, "can't map clock node!\n");85		return 0;86	}87 88	if (in_8(&cdm->ipb_clk_sel) & 0x1)89		freq *= 2;90	val = in_be32(&cdm->rstcfg);91 92	freq *= (val & (1 << 5)) ? 8 : 4;93	freq /= (val & (1 << 6)) ? 12 : 16;94 95	of_node_put(np_cdm);96	iounmap(cdm);97 98	return freq;99}100#else /* !CONFIG_PPC_MPC52xx */101static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,102				 const char *clock_name, int *mscan_clksrc)103{104	return 0;105}106#endif /* CONFIG_PPC_MPC52xx */107 108#ifdef CONFIG_PPC_MPC512x109static u32 mpc512x_can_get_clock(struct platform_device *ofdev,110				 const char *clock_source, int *mscan_clksrc)111{112	struct device_node *np;113	u32 clockdiv;114	enum {115		CLK_FROM_AUTO,116		CLK_FROM_IPS,117		CLK_FROM_SYS,118		CLK_FROM_REF,119	} clk_from;120	struct clk *clk_in, *clk_can;121	unsigned long freq_calc;122	struct mscan_priv *priv;123	struct clk *clk_ipg;124 125	/* the caller passed in the clock source spec that was read from126	 * the device tree, get the optional clock divider as well127	 */128	np = ofdev->dev.of_node;129	clockdiv = 1;130	of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);131	dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",132		clock_source ? clock_source : "<NULL>", clockdiv);133 134	/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to135	 * get set, and the 'ips' clock is the input to the MSCAN136	 * component137	 *138	 * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]139	 * bit needs to get cleared, an optional clock-divider may have140	 * been specified (the default value is 1), the appropriate141	 * MSCAN related MCLK is the input to the MSCAN component142	 *143	 * in the absence of a clock-source spec, first an optimal clock144	 * gets determined based on the 'sys' clock, if that fails the145	 * 'ref' clock is used146	 */147	clk_from = CLK_FROM_AUTO;148	if (clock_source) {149		/* interpret the device tree's spec for the clock source */150		if (!strcmp(clock_source, "ip"))151			clk_from = CLK_FROM_IPS;152		else if (!strcmp(clock_source, "sys"))153			clk_from = CLK_FROM_SYS;154		else if (!strcmp(clock_source, "ref"))155			clk_from = CLK_FROM_REF;156		else157			goto err_invalid;158		dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);159	}160	if (clk_from == CLK_FROM_AUTO) {161		/* no spec so far, try the 'sys' clock; round to the162		 * next MHz and see if we can get a multiple of 16MHz163		 */164		dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");165		clk_in = devm_clk_get(&ofdev->dev, "sys");166		if (IS_ERR(clk_in))167			goto err_notavail;168		freq_calc = clk_get_rate(clk_in);169		freq_calc +=  499999;170		freq_calc /= 1000000;171		freq_calc *= 1000000;172		if ((freq_calc % 16000000) == 0) {173			clk_from = CLK_FROM_SYS;174			clockdiv = freq_calc / 16000000;175			dev_dbg(&ofdev->dev,176				"clk fit, sys[%lu] div[%d] freq[%lu]\n",177				freq_calc, clockdiv, freq_calc / clockdiv);178		}179	}180	if (clk_from == CLK_FROM_AUTO) {181		/* no spec so far, use the 'ref' clock */182		dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");183		clk_in = devm_clk_get(&ofdev->dev, "ref");184		if (IS_ERR(clk_in))185			goto err_notavail;186		clk_from = CLK_FROM_REF;187		freq_calc = clk_get_rate(clk_in);188		dev_dbg(&ofdev->dev,189			"clk fit, ref[%lu] (no div) freq[%lu]\n",190			freq_calc, freq_calc);191	}192 193	/* select IPS or MCLK as the MSCAN input (returned to the caller),194	 * setup the MCLK mux source and rate if applicable, apply the195	 * optionally specified or derived above divider, and determine196	 * the actual resulting clock rate to return to the caller197	 */198	switch (clk_from) {199	case CLK_FROM_IPS:200		clk_can = devm_clk_get(&ofdev->dev, "ips");201		if (IS_ERR(clk_can))202			goto err_notavail;203		priv = netdev_priv(dev_get_drvdata(&ofdev->dev));204		priv->clk_can = clk_can;205		freq_calc = clk_get_rate(clk_can);206		*mscan_clksrc = MSCAN_CLKSRC_IPS;207		dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",208			*mscan_clksrc, freq_calc);209		break;210	case CLK_FROM_SYS:211	case CLK_FROM_REF:212		clk_can = devm_clk_get(&ofdev->dev, "mclk");213		if (IS_ERR(clk_can))214			goto err_notavail;215		priv = netdev_priv(dev_get_drvdata(&ofdev->dev));216		priv->clk_can = clk_can;217		if (clk_from == CLK_FROM_SYS)218			clk_in = devm_clk_get(&ofdev->dev, "sys");219		if (clk_from == CLK_FROM_REF)220			clk_in = devm_clk_get(&ofdev->dev, "ref");221		if (IS_ERR(clk_in))222			goto err_notavail;223		clk_set_parent(clk_can, clk_in);224		freq_calc = clk_get_rate(clk_in);225		freq_calc /= clockdiv;226		clk_set_rate(clk_can, freq_calc);227		freq_calc = clk_get_rate(clk_can);228		*mscan_clksrc = MSCAN_CLKSRC_BUS;229		dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",230			*mscan_clksrc, freq_calc);231		break;232	default:233		goto err_invalid;234	}235 236	/* the above clk_can item is used for the bitrate, access to237	 * the peripheral's register set needs the clk_ipg item238	 */239	clk_ipg = devm_clk_get(&ofdev->dev, "ipg");240	if (IS_ERR(clk_ipg))241		goto err_notavail_ipg;242	if (clk_prepare_enable(clk_ipg))243		goto err_notavail_ipg;244	priv = netdev_priv(dev_get_drvdata(&ofdev->dev));245	priv->clk_ipg = clk_ipg;246 247	/* return the determined clock source rate */248	return freq_calc;249 250err_invalid:251	dev_err(&ofdev->dev, "invalid clock source specification\n");252	/* clock source rate could not get determined */253	return 0;254 255err_notavail:256	dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n");257	/* clock source rate could not get determined */258	return 0;259 260err_notavail_ipg:261	dev_err(&ofdev->dev, "cannot acquire or setup register clock\n");262	/* clock source rate could not get determined */263	return 0;264}265 266static void mpc512x_can_put_clock(struct platform_device *ofdev)267{268	struct mscan_priv *priv;269 270	priv = netdev_priv(dev_get_drvdata(&ofdev->dev));271	if (priv->clk_ipg)272		clk_disable_unprepare(priv->clk_ipg);273}274#else /* !CONFIG_PPC_MPC512x */275static u32 mpc512x_can_get_clock(struct platform_device *ofdev,276				 const char *clock_name, int *mscan_clksrc)277{278	return 0;279}280#define mpc512x_can_put_clock NULL281#endif /* CONFIG_PPC_MPC512x */282 283static const struct of_device_id mpc5xxx_can_table[];284static int mpc5xxx_can_probe(struct platform_device *ofdev)285{286	const struct mpc5xxx_can_data *data;287	struct device_node *np = ofdev->dev.of_node;288	struct net_device *dev;289	struct mscan_priv *priv;290	void __iomem *base;291	const char *clock_name = NULL;292	int irq, mscan_clksrc = 0;293	int err = -ENOMEM;294 295	data = device_get_match_data(&ofdev->dev);296	if (!data)297		return -EINVAL;298 299	base = of_iomap(np, 0);300	if (!base)301		return dev_err_probe(&ofdev->dev, err, "couldn't ioremap\n");302 303	irq = irq_of_parse_and_map(np, 0);304	if (!irq) {305		dev_err(&ofdev->dev, "no irq found\n");306		err = -ENODEV;307		goto exit_unmap_mem;308	}309 310	dev = alloc_mscandev();311	if (!dev)312		goto exit_dispose_irq;313	platform_set_drvdata(ofdev, dev);314	SET_NETDEV_DEV(dev, &ofdev->dev);315 316	priv = netdev_priv(dev);317	priv->reg_base = base;318	dev->irq = irq;319 320	clock_name = of_get_property(np, "fsl,mscan-clock-source", NULL);321 322	priv->type = data->type;323	priv->can.clock.freq = data->get_clock(ofdev, clock_name,324					       &mscan_clksrc);325	if (!priv->can.clock.freq) {326		dev_err(&ofdev->dev, "couldn't get MSCAN clock properties\n");327		goto exit_put_clock;328	}329 330	err = register_mscandev(dev, mscan_clksrc);331	if (err) {332		dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",333			DRV_NAME, err);334		goto exit_put_clock;335	}336 337	dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",338		 priv->reg_base, dev->irq, priv->can.clock.freq);339 340	return 0;341 342exit_put_clock:343	if (data->put_clock)344		data->put_clock(ofdev);345	free_candev(dev);346exit_dispose_irq:347	irq_dispose_mapping(irq);348exit_unmap_mem:349	iounmap(base);350 351	return err;352}353 354static void mpc5xxx_can_remove(struct platform_device *ofdev)355{356	const struct mpc5xxx_can_data *data;357	struct net_device *dev = platform_get_drvdata(ofdev);358	struct mscan_priv *priv = netdev_priv(dev);359 360	data = device_get_match_data(&ofdev->dev);361 362	unregister_mscandev(dev);363	if (data && data->put_clock)364		data->put_clock(ofdev);365	iounmap(priv->reg_base);366	irq_dispose_mapping(dev->irq);367	free_candev(dev);368}369 370#ifdef CONFIG_PM371static struct mscan_regs saved_regs;372static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state)373{374	struct net_device *dev = platform_get_drvdata(ofdev);375	struct mscan_priv *priv = netdev_priv(dev);376	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;377 378	_memcpy_fromio(&saved_regs, regs, sizeof(*regs));379 380	return 0;381}382 383static int mpc5xxx_can_resume(struct platform_device *ofdev)384{385	struct net_device *dev = platform_get_drvdata(ofdev);386	struct mscan_priv *priv = netdev_priv(dev);387	struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;388 389	regs->canctl0 |= MSCAN_INITRQ;390	while (!(regs->canctl1 & MSCAN_INITAK))391		udelay(10);392 393	regs->canctl1 = saved_regs.canctl1;394	regs->canbtr0 = saved_regs.canbtr0;395	regs->canbtr1 = saved_regs.canbtr1;396	regs->canidac = saved_regs.canidac;397 398	/* restore masks, buffers etc. */399	_memcpy_toio(&regs->canidar1_0, (void *)&saved_regs.canidar1_0,400		     sizeof(*regs) - offsetof(struct mscan_regs, canidar1_0));401 402	regs->canctl0 &= ~MSCAN_INITRQ;403	regs->cantbsel = saved_regs.cantbsel;404	regs->canrier = saved_regs.canrier;405	regs->cantier = saved_regs.cantier;406	regs->canctl0 = saved_regs.canctl0;407 408	return 0;409}410#endif411 412static const struct mpc5xxx_can_data mpc5200_can_data = {413	.type = MSCAN_TYPE_MPC5200,414	.get_clock = mpc52xx_can_get_clock,415	/* .put_clock not applicable */416};417 418static const struct mpc5xxx_can_data mpc5121_can_data = {419	.type = MSCAN_TYPE_MPC5121,420	.get_clock = mpc512x_can_get_clock,421	.put_clock = mpc512x_can_put_clock,422};423 424static const struct of_device_id mpc5xxx_can_table[] = {425	{ .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, },426	/* Note that only MPC5121 Rev. 2 (and later) is supported */427	{ .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, },428	{},429};430MODULE_DEVICE_TABLE(of, mpc5xxx_can_table);431 432static struct platform_driver mpc5xxx_can_driver = {433	.driver = {434		.name = "mpc5xxx_can",435		.of_match_table = mpc5xxx_can_table,436	},437	.probe = mpc5xxx_can_probe,438	.remove = mpc5xxx_can_remove,439#ifdef CONFIG_PM440	.suspend = mpc5xxx_can_suspend,441	.resume = mpc5xxx_can_resume,442#endif443};444 445module_platform_driver(mpc5xxx_can_driver);446 447MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");448MODULE_DESCRIPTION("Freescale MPC5xxx CAN driver");449MODULE_LICENSE("GPL v2");450