summaryrefslogtreecommitdiff
path: root/drivers/net/can/old/mscan/mpc52xx_can.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/can/old/mscan/mpc52xx_can.c')
-rw-r--r--drivers/net/can/old/mscan/mpc52xx_can.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/drivers/net/can/old/mscan/mpc52xx_can.c b/drivers/net/can/old/mscan/mpc52xx_can.c
new file mode 100644
index 000000000000..da1278fa630a
--- /dev/null
+++ b/drivers/net/can/old/mscan/mpc52xx_can.c
@@ -0,0 +1,248 @@
+/*
+ * DESCRIPTION:
+ * CAN bus driver for the Freescale MPC52xx embedded CPU.
+ *
+ * AUTHOR:
+ * Andrey Volkov <avolkov@varma-el.com>
+ *
+ * COPYRIGHT:
+ * 2004-2005, Varma Electronics Oy
+ *
+ * LICENCE:
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * 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
+ *
+ * HISTORY:
+ * 2005-02-03 created
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+
+#include "mscan.h"
+
+
+#define PDEV_MAX 2
+
+struct platform_device *pdev[PDEV_MAX];
+
+static int __devinit mpc52xx_can_probe(struct platform_device *pdev)
+{
+ struct resource *mem;
+ struct net_device *dev;
+ struct mscan_platform_data *pdata = pdev->dev.platform_data;
+ struct can_priv *can;
+ u32 mem_size;
+ int ret = -ENODEV;
+
+ if (!pdata)
+ return ret;
+
+ dev = alloc_mscandev();
+ if (!dev)
+ return -ENOMEM;
+ can = netdev_priv(dev);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->irq = platform_get_irq(pdev, 0);
+ if (!mem || !dev->irq)
+ goto req_error;
+
+ mem_size = mem->end - mem->start + 1;
+ if (!request_mem_region(mem->start, mem_size, pdev->dev.driver->name)) {
+ dev_err(&pdev->dev, "resource unavailable\n");
+ goto req_error;
+ }
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ dev->base_addr = (unsigned long)ioremap_nocache(mem->start, mem_size);
+
+ if (!dev->base_addr) {
+ dev_err(&pdev->dev, "failed to map can port\n");
+ ret = -ENOMEM;
+ goto fail_map;
+ }
+
+ can->can_sys_clock = pdata->clock_frq;
+
+ platform_set_drvdata(pdev, dev);
+
+ ret = register_mscandev(dev, pdata->clock_src);
+ if (ret >= 0) {
+ dev_info(&pdev->dev, "probe for a port 0x%lX done\n",
+ dev->base_addr);
+ return ret;
+ }
+
+ iounmap((unsigned long *)dev->base_addr);
+ fail_map:
+ release_mem_region(mem->start, mem_size);
+ req_error:
+ free_candev(dev);
+ dev_err(&pdev->dev, "probe failed\n");
+ return ret;
+}
+
+static int __devexit mpc52xx_can_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+ unregister_mscandev(dev);
+
+ iounmap((volatile void __iomem *)dev->base_addr);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, mem->end - mem->start + 1);
+ free_candev(dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static struct mscan_regs saved_regs;
+static int mpc52xx_can_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
+
+ _memcpy_fromio(&saved_regs, regs, sizeof(*regs));
+
+ return 0;
+}
+
+static int mpc52xx_can_resume(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
+
+ regs->canctl0 |= MSCAN_INITRQ;
+ while ((regs->canctl1 & MSCAN_INITAK) == 0)
+ udelay(10);
+
+ regs->canctl1 = saved_regs.canctl1;
+ regs->canbtr0 = saved_regs.canbtr0;
+ regs->canbtr1 = saved_regs.canbtr1;
+ regs->canidac = saved_regs.canidac;
+
+ /* restore masks, buffers etc. */
+ _memcpy_toio(&regs->canidar1_0, (void *)&saved_regs.canidar1_0,
+ sizeof(*regs) - offsetof(struct mscan_regs, canidar1_0));
+
+ regs->canctl0 &= ~MSCAN_INITRQ;
+ regs->cantbsel = saved_regs.cantbsel;
+ regs->canrier = saved_regs.canrier;
+ regs->cantier = saved_regs.cantier;
+ regs->canctl0 = saved_regs.canctl0;
+
+ return 0;
+}
+#endif
+
+static struct platform_driver mpc52xx_can_driver = {
+ .driver = {
+ .name = "mpc52xx-mscan",
+ },
+ .probe = mpc52xx_can_probe,
+ .remove = __devexit_p(mpc52xx_can_remove),
+#ifdef CONFIG_PM
+ .suspend = mpc52xx_can_suspend,
+ .resume = mpc52xx_can_resume,
+#endif
+};
+
+#ifdef CONFIG_PPC_MERGE
+static int __init mpc52xx_of_to_pdev(void)
+{
+ struct device_node *np = NULL;
+ unsigned int i;
+ int err = -ENODEV;
+
+ for (i = 0;
+ (np = of_find_compatible_node(np, NULL, "fsl,mpc5200-mscan"));
+ i++) {
+ struct resource r[2] = { };
+ struct mscan_platform_data pdata;
+
+ if (i >= PDEV_MAX) {
+ printk(KERN_WARNING "%s: increase PDEV_MAX for more "
+ "than %i devices\n", __func__, PDEV_MAX);
+ break;
+ }
+
+ err = of_address_to_resource(np, 0, &r[0]);
+ if (err)
+ break;
+
+ of_irq_to_resource(np, 0, &r[1]);
+
+ pdev[i] =
+ platform_device_register_simple("mpc52xx-mscan", i, r, 2);
+ if (IS_ERR(pdev[i])) {
+ err = PTR_ERR(pdev[i]);
+ break;
+ }
+
+ pdata.clock_src = MSCAN_CLKSRC_BUS;
+ pdata.clock_frq = mpc52xx_find_ipb_freq(np);
+ err = platform_device_add_data(pdev[i], &pdata, sizeof(pdata));
+ if (err)
+ break;
+ }
+ return err;
+}
+#else
+#define mscan_of_to_pdev()
+#endif
+
+int __init mpc52xx_can_init(void)
+{
+ printk(KERN_WARNING
+ "This %s driver is DEPRECATED, please switch!\n",
+ mpc52xx_can_driver.driver.name);
+#ifdef CONFIG_PPC_MERGE
+ int err = mpc52xx_of_to_pdev();
+
+ if (err) {
+ printk(KERN_ERR "%s init failed with err=%d\n",
+ mpc52xx_can_driver.driver.name, err);
+ return err;
+ }
+#endif
+ return platform_driver_register(&mpc52xx_can_driver);
+}
+
+void __exit mpc52xx_can_exit(void)
+{
+ int i;
+ platform_driver_unregister(&mpc52xx_can_driver);
+ for (i = 0; i < PDEV_MAX; i++)
+ platform_device_unregister(pdev[i]);
+ printk(KERN_INFO "%s unloaded\n", mpc52xx_can_driver.driver.name);
+}
+
+module_init(mpc52xx_can_init);
+module_exit(mpc52xx_can_exit);
+
+MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
+MODULE_DESCRIPTION("Freescale MPC5200 CAN driver");
+MODULE_LICENSE("GPL v2");