linux/drivers/net/can/c_can/c_can_platform.c
<<
>>
Prefs
   1/*
   2 * Platform CAN bus driver for Bosch C_CAN controller
   3 *
   4 * Copyright (C) 2010 ST Microelectronics
   5 * Bhupesh Sharma <bhupesh.sharma@st.com>
   6 *
   7 * Borrowed heavily from the C_CAN driver originally written by:
   8 * Copyright (C) 2007
   9 * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
  10 * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
  11 *
  12 * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
  13 * Bosch C_CAN user manual can be obtained from:
  14 * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
  15 * users_manual_c_can.pdf
  16 *
  17 * This file is licensed under the terms of the GNU General Public
  18 * License version 2. This program is licensed "as is" without any
  19 * warranty of any kind, whether express or implied.
  20 */
  21
  22#include <linux/kernel.h>
  23#include <linux/module.h>
  24#include <linux/interrupt.h>
  25#include <linux/delay.h>
  26#include <linux/netdevice.h>
  27#include <linux/if_arp.h>
  28#include <linux/if_ether.h>
  29#include <linux/list.h>
  30#include <linux/io.h>
  31#include <linux/platform_device.h>
  32#include <linux/clk.h>
  33#include <linux/of.h>
  34#include <linux/of_device.h>
  35
  36#include <linux/can/dev.h>
  37
  38#include "c_can.h"
  39
  40#define CAN_RAMINIT_START_MASK(i)       (1 << (i))
  41
  42/*
  43 * 16-bit c_can registers can be arranged differently in the memory
  44 * architecture of different implementations. For example: 16-bit
  45 * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
  46 * Handle the same by providing a common read/write interface.
  47 */
  48static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv,
  49                                                enum reg index)
  50{
  51        return readw(priv->base + priv->regs[index]);
  52}
  53
  54static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv,
  55                                                enum reg index, u16 val)
  56{
  57        writew(val, priv->base + priv->regs[index]);
  58}
  59
  60static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv,
  61                                                enum reg index)
  62{
  63        return readw(priv->base + 2 * priv->regs[index]);
  64}
  65
  66static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
  67                                                enum reg index, u16 val)
  68{
  69        writew(val, priv->base + 2 * priv->regs[index]);
  70}
  71
  72static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
  73{
  74        u32 val;
  75
  76        val = readl(priv->raminit_ctrlreg);
  77        if (enable)
  78                val |= CAN_RAMINIT_START_MASK(priv->instance);
  79        else
  80                val &= ~CAN_RAMINIT_START_MASK(priv->instance);
  81        writel(val, priv->raminit_ctrlreg);
  82}
  83
  84static struct platform_device_id c_can_id_table[] = {
  85        [BOSCH_C_CAN_PLATFORM] = {
  86                .name = KBUILD_MODNAME,
  87                .driver_data = BOSCH_C_CAN,
  88        },
  89        [BOSCH_C_CAN] = {
  90                .name = "c_can",
  91                .driver_data = BOSCH_C_CAN,
  92        },
  93        [BOSCH_D_CAN] = {
  94                .name = "d_can",
  95                .driver_data = BOSCH_D_CAN,
  96        }, {
  97        }
  98};
  99MODULE_DEVICE_TABLE(platform, c_can_id_table);
 100
 101static const struct of_device_id c_can_of_table[] = {
 102        { .compatible = "bosch,c_can", .data = &c_can_id_table[BOSCH_C_CAN] },
 103        { .compatible = "bosch,d_can", .data = &c_can_id_table[BOSCH_D_CAN] },
 104        { /* sentinel */ },
 105};
 106MODULE_DEVICE_TABLE(of, c_can_of_table);
 107
 108static int c_can_plat_probe(struct platform_device *pdev)
 109{
 110        int ret;
 111        void __iomem *addr;
 112        struct net_device *dev;
 113        struct c_can_priv *priv;
 114        const struct of_device_id *match;
 115        const struct platform_device_id *id;
 116        struct resource *mem, *res;
 117        int irq;
 118        struct clk *clk;
 119
 120        if (pdev->dev.of_node) {
 121                match = of_match_device(c_can_of_table, &pdev->dev);
 122                if (!match) {
 123                        dev_err(&pdev->dev, "Failed to find matching dt id\n");
 124                        ret = -EINVAL;
 125                        goto exit;
 126                }
 127                id = match->data;
 128        } else {
 129                id = platform_get_device_id(pdev);
 130        }
 131
 132        /* get the appropriate clk */
 133        clk = clk_get(&pdev->dev, NULL);
 134        if (IS_ERR(clk)) {
 135                dev_err(&pdev->dev, "no clock defined\n");
 136                ret = -ENODEV;
 137                goto exit;
 138        }
 139
 140        /* get the platform data */
 141        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 142        irq = platform_get_irq(pdev, 0);
 143        if (!mem || irq <= 0) {
 144                ret = -ENODEV;
 145                goto exit_free_clk;
 146        }
 147
 148        if (!request_mem_region(mem->start, resource_size(mem),
 149                                KBUILD_MODNAME)) {
 150                dev_err(&pdev->dev, "resource unavailable\n");
 151                ret = -ENODEV;
 152                goto exit_free_clk;
 153        }
 154
 155        addr = ioremap(mem->start, resource_size(mem));
 156        if (!addr) {
 157                dev_err(&pdev->dev, "failed to map can port\n");
 158                ret = -ENOMEM;
 159                goto exit_release_mem;
 160        }
 161
 162        /* allocate the c_can device */
 163        dev = alloc_c_can_dev();
 164        if (!dev) {
 165                ret = -ENOMEM;
 166                goto exit_iounmap;
 167        }
 168
 169        priv = netdev_priv(dev);
 170        switch (id->driver_data) {
 171        case BOSCH_C_CAN:
 172                priv->regs = reg_map_c_can;
 173                switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
 174                case IORESOURCE_MEM_32BIT:
 175                        priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
 176                        priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
 177                        break;
 178                case IORESOURCE_MEM_16BIT:
 179                default:
 180                        priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
 181                        priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
 182                        break;
 183                }
 184                break;
 185        case BOSCH_D_CAN:
 186                priv->regs = reg_map_d_can;
 187                priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
 188                priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
 189                priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
 190
 191                if (pdev->dev.of_node)
 192                        priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can");
 193                else
 194                        priv->instance = pdev->id;
 195
 196                res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 197                priv->raminit_ctrlreg = devm_ioremap_resource(&pdev->dev, res);
 198                if (IS_ERR(priv->raminit_ctrlreg) || (int)priv->instance < 0)
 199                        dev_info(&pdev->dev, "control memory is not used for raminit\n");
 200                else
 201                        priv->raminit = c_can_hw_raminit;
 202                break;
 203        default:
 204                ret = -EINVAL;
 205                goto exit_free_device;
 206        }
 207
 208        dev->irq = irq;
 209        priv->base = addr;
 210        priv->device = &pdev->dev;
 211        priv->can.clock.freq = clk_get_rate(clk);
 212        priv->priv = clk;
 213        priv->type = id->driver_data;
 214
 215        platform_set_drvdata(pdev, dev);
 216        SET_NETDEV_DEV(dev, &pdev->dev);
 217
 218        ret = register_c_can_dev(dev);
 219        if (ret) {
 220                dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
 221                        KBUILD_MODNAME, ret);
 222                goto exit_free_device;
 223        }
 224
 225        dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
 226                 KBUILD_MODNAME, priv->base, dev->irq);
 227        return 0;
 228
 229exit_free_device:
 230        free_c_can_dev(dev);
 231exit_iounmap:
 232        iounmap(addr);
 233exit_release_mem:
 234        release_mem_region(mem->start, resource_size(mem));
 235exit_free_clk:
 236        clk_put(clk);
 237exit:
 238        dev_err(&pdev->dev, "probe failed\n");
 239
 240        return ret;
 241}
 242
 243static int c_can_plat_remove(struct platform_device *pdev)
 244{
 245        struct net_device *dev = platform_get_drvdata(pdev);
 246        struct c_can_priv *priv = netdev_priv(dev);
 247        struct resource *mem;
 248
 249        unregister_c_can_dev(dev);
 250
 251        free_c_can_dev(dev);
 252        iounmap(priv->base);
 253
 254        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 255        release_mem_region(mem->start, resource_size(mem));
 256
 257        clk_put(priv->priv);
 258
 259        return 0;
 260}
 261
 262#ifdef CONFIG_PM
 263static int c_can_suspend(struct platform_device *pdev, pm_message_t state)
 264{
 265        int ret;
 266        struct net_device *ndev = platform_get_drvdata(pdev);
 267        struct c_can_priv *priv = netdev_priv(ndev);
 268
 269        if (priv->type != BOSCH_D_CAN) {
 270                dev_warn(&pdev->dev, "Not supported\n");
 271                return 0;
 272        }
 273
 274        if (netif_running(ndev)) {
 275                netif_stop_queue(ndev);
 276                netif_device_detach(ndev);
 277        }
 278
 279        ret = c_can_power_down(ndev);
 280        if (ret) {
 281                netdev_err(ndev, "failed to enter power down mode\n");
 282                return ret;
 283        }
 284
 285        priv->can.state = CAN_STATE_SLEEPING;
 286
 287        return 0;
 288}
 289
 290static int c_can_resume(struct platform_device *pdev)
 291{
 292        int ret;
 293        struct net_device *ndev = platform_get_drvdata(pdev);
 294        struct c_can_priv *priv = netdev_priv(ndev);
 295
 296        if (priv->type != BOSCH_D_CAN) {
 297                dev_warn(&pdev->dev, "Not supported\n");
 298                return 0;
 299        }
 300
 301        ret = c_can_power_up(ndev);
 302        if (ret) {
 303                netdev_err(ndev, "Still in power down mode\n");
 304                return ret;
 305        }
 306
 307        priv->can.state = CAN_STATE_ERROR_ACTIVE;
 308
 309        if (netif_running(ndev)) {
 310                netif_device_attach(ndev);
 311                netif_start_queue(ndev);
 312        }
 313
 314        return 0;
 315}
 316#else
 317#define c_can_suspend NULL
 318#define c_can_resume NULL
 319#endif
 320
 321static struct platform_driver c_can_plat_driver = {
 322        .driver = {
 323                .name = KBUILD_MODNAME,
 324                .owner = THIS_MODULE,
 325                .of_match_table = c_can_of_table,
 326        },
 327        .probe = c_can_plat_probe,
 328        .remove = c_can_plat_remove,
 329        .suspend = c_can_suspend,
 330        .resume = c_can_resume,
 331        .id_table = c_can_id_table,
 332};
 333
 334module_platform_driver(c_can_plat_driver);
 335
 336MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
 337MODULE_LICENSE("GPL v2");
 338MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");
 339
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.