Bhupesh SHARMA wrote:
> SPEAr320 design contains two boards:
> a) CPU board (which houses the ARM926ejs CPU and DDR in addition to some 
> other interfaces like USB host etc..)
> b) Application PLC board (which contains two Bosch CCAN IPs that are 
> interfaced to APB bus in addition to other interfaces like UART etc..)
> [See details here: 
> http://www.st.com/stonline/products/families/embedded_mpu/spear_mpus/spear320_single_core.htm]
> 
> The SPEAr CAN driver relies on 'platform data/board specific details' that 
> are passed by means of relevant evb files present in 'arch/arm/mach-spear3xx' 
> directory.
> 
> Signed-off-by: Bhupesh Sharma <[email protected]>
> 
> Index: spear320_can.c
> ===================================================================
> --- spear320_can.c    (revision 0)
> +++ spear320_can.c    (revision 0)
> @@ -0,0 +1,203 @@
> +/*
> + * drivers/net/can/spear320_can.c
> + *
> + * CAN bus driver for SPEAr320 SoC that houses two independent
> + * Bosch CCAN controllers.
> + *
> + * Copyright (C) 2010 ST Microelectronics
> + * Bhupesh Sharma <[email protected]>
> + *
> + * Borrowed heavily from the original code written for Hynix7202 by:
> + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <[email protected]>
> + * - Simon Kallweit, intefo AG <[email protected]>
> + * which can be viewed here:
> + * http://svn.berlios.de/svnroot/repos/socketcan/trunk/kernel/2.6/
> + * drivers/net/can/old/ccan/
> + *
> + * TODO:
> + * - Power Management support to be added
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/netdevice.h>
> +#include <socketcan/can.h>
> +#include <socketcan/can/dev.h>
> +
> +#include "bosch_ccan.h"
> +
> +#define DRV_NAME     "spear_can"
> +#define CAN_ENABLE   0x0e
> +
> +static u16 spear320_can_read_reg(const struct bosch_ccan_priv *priv,
> +                             enum ccan_regs reg)
> +{
> +     u16 val;
> +
> +     /* shifting 1 place because 16 bit registers are word aligned */
> +     val = readw(priv->reg_base + (reg << 1));
> +     return val;
> +}
> +
> +static void spear320_can_write_reg(const struct bosch_ccan_priv *priv,
> +                             enum ccan_regs reg, u16 val)
> +{
> +     /* shifting 1 place because 16 bit registers are word aligned */
> +     writew(val, priv->reg_base + (reg << 1));
> +}
> +
> +static int spear320_can_drv_probe(struct platform_device *pdev)
> +{
> +     int ret;
> +     void __iomem *addr;
> +     struct net_device *dev;
> +     struct bosch_ccan_priv *priv;
> +     struct resource *mem, *irq;
> +     struct clk *clk;
> +
> +     /* get the appropriate clk */
> +     clk = clk_get(&pdev->dev, NULL);
> +     if (IS_ERR(clk)) {
> +             dev_err(&pdev->dev, "no clock defined\n");
> +             ret = -ENODEV;
> +             goto exit;
> +     }
> +
> +     /* get the platform data */
> +     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +     irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +     if (!mem || !irq) {
> +             ret = -ENODEV;
> +             goto exit_free_clk;
> +     }
> +
> +     if (!request_mem_region(mem->start, resource_size(mem), DRV_NAME)) {
> +             dev_err(&pdev->dev, "resource unavailable\n");
> +             ret = -ENODEV;
> +             goto exit_free_clk;
> +     }
> +
> +     addr = ioremap(mem->start, resource_size(mem));
> +     if (!addr) {
> +             dev_err(&pdev->dev, "failed to map can port\n");
> +             ret = -ENOMEM;
> +             goto exit_release_mem;
> +     }
> +
> +     /* allocate the ccan device */
> +     dev = alloc_bosch_ccandev(0);
> +     if (!dev) {
> +             clk_put(clk);
                ^^^^^^^^^^^^
this is already done in the common error handling path, isn't it?

> +             ret = -ENOMEM;
> +             goto exit_iounmap;
> +     }
> +
> +     priv = netdev_priv(dev);
> +     dev->irq = irq->start;
> +     priv->irq_flags = irq->flags;
> +     priv->reg_base = addr;
> +     priv->can.clock.freq = clk_get_rate(clk);
> +     priv->read_reg = spear320_can_read_reg;
> +     priv->write_reg = spear320_can_write_reg;
> +     priv->clk = clk;
> +
> +     platform_set_drvdata(pdev, dev);
> +     SET_NETDEV_DEV(dev, &pdev->dev);
> +
> +     /* register ccan */
> +     spear320_can_write_reg(priv, CAN_ENABLE, 1);
> +     ret = register_bosch_ccandev(dev);
> +     if (ret) {
> +             dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
> +                     DRV_NAME, ret);
> +             goto exit_free_device;
> +     }
> +
> +     dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n",
> +              DRV_NAME, priv->reg_base, dev->irq);
> +     return 0;
> +
> +exit_free_device:
> +     platform_set_drvdata(pdev, NULL);
> +     free_bosch_ccandev(dev);
> +exit_iounmap:
> +     iounmap(addr);
> +exit_release_mem:
> +     release_mem_region(mem->start, resource_size(mem));
> +exit_free_clk:
> +     clk_put(clk);
> +exit:
> +     dev_err(&pdev->dev, "probe failed\n");
> +
> +     return ret;
> +}
> +
> +static int spear320_can_drv_remove(struct platform_device *pdev)
> +{
> +     struct net_device *dev = platform_get_drvdata(pdev);
> +     struct bosch_ccan_priv *priv = netdev_priv(dev);
> +     struct resource *mem;
> +
> +     unregister_bosch_ccandev(dev);
> +     platform_set_drvdata(pdev, NULL);
> +
> +     if (priv->reg_base)
> +             iounmap(priv->reg_base);

I think reg_base is always set, isn't it?

> +
> +     clk_put(priv->clk);
> +
> +     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +     release_mem_region(mem->start, resource_size(mem));
> +
> +     free_bosch_ccandev(dev);

this isn't look symetrically to the probe function.
> +
> +     return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int spear320_can_drv_suspend(struct platform_device *pdev,
> +                             pm_message_t state)
> +{
> +     return 0;
> +}
> +
> +static int spear320_can_drv_resume(struct platform_device *pdev)
> +{
> +     return 0;
> +}
> +#endif /* CONFIG_PM */

please remove PM if not implemented
> +
> +static struct platform_driver spear320_can_driver = {
> +     .driver         = {
> +             .name   = DRV_NAME,
> +     },
> +     .probe          = spear320_can_drv_probe,
> +     .remove         = spear320_can_drv_remove,
> +#ifdef CONFIG_PM
> +     .suspend        = spear320_can_drv_suspend,
> +     .resume         = spear320_can_drv_resume,
> +#endif       /* CONFIG_PM */
> +};
> +
> +static int __init spear320_can_init(void)
> +{
> +     return platform_driver_register(&spear320_can_driver);
> +}
> +module_init(spear320_can_init);
> +
> +static void __exit spear320_can_cleanup(void)
> +{
> +     platform_driver_unregister(&spear320_can_driver);
> +}
> +module_exit(spear320_can_cleanup);
> +
> +MODULE_AUTHOR("Bhupesh Sharma <[email protected]>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("CAN bus driver for SPEAr320 which has 2 CCAN 
> controllers");
> 
> _______________________________________________
> Socketcan-core mailing list
> [email protected]
> https://lists.berlios.de/mailman/listinfo/socketcan-core

cheers, Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core

Reply via email to