1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
*
* CTU CAN FD IP Core
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
* Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
*
* Project advisors:
* Jiri Novak <jnovak@fel.cvut.cz>
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
*
* Department of Measurement (http://meas.fel.cvut.cz/)
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
* Czech Technical University (http://www.cvut.cz/)
******************************************************************************/
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include "ctucanfd.h"
#define DRV_NAME "ctucanfd"
static void ctucan_platform_set_drvdata(struct device *dev,
struct net_device *ndev)
{
struct platform_device *pdev = container_of(dev, struct platform_device,
dev);
platform_set_drvdata(pdev, ndev);
}
/**
* ctucan_platform_probe - Platform registration call
* @pdev: Handle to the platform device structure
*
* This function does all the memory allocation and registration for the CAN
* device.
*
* Return: 0 on success and failure value on error
*/
static int ctucan_platform_probe(struct platform_device *pdev)
{
struct resource *res; /* IO mem resources */
struct device *dev = &pdev->dev;
void __iomem *addr;
int ret;
unsigned int ntxbufs;
int irq;
/* Get the virtual base address for the device */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = devm_ioremap_resource(dev, res);
if (IS_ERR(addr)) {
ret = PTR_ERR(addr);
goto err;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
goto err;
}
/* Number of tx bufs might be change in HW for future. If so,
* it will be passed as property via device tree
*/
ntxbufs = 4;
ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 0,
1, ctucan_platform_set_drvdata);
if (ret < 0)
platform_set_drvdata(pdev, NULL);
err:
return ret;
}
/**
* ctucan_platform_remove - Unregister the device after releasing the resources
* @pdev: Handle to the platform device structure
*
* This function frees all the resources allocated to the device.
* Return: 0 always
*/
static int ctucan_platform_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct ctucan_priv *priv = netdev_priv(ndev);
netdev_dbg(ndev, "ctucan_remove");
unregister_candev(ndev);
pm_runtime_disable(&pdev->dev);
netif_napi_del(&priv->napi);
free_candev(ndev);
return 0;
}
static SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume);
/* Match table for OF platform binding */
static const struct of_device_id ctucan_of_match[] = {
{ .compatible = "ctu,ctucanfd-2", },
{ .compatible = "ctu,ctucanfd", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, ctucan_of_match);
static struct platform_driver ctucanfd_driver = {
.probe = ctucan_platform_probe,
.remove = ctucan_platform_remove,
.driver = {
.name = DRV_NAME,
.pm = &ctucan_platform_pm_ops,
.of_match_table = ctucan_of_match,
},
};
module_platform_driver(ctucanfd_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Martin Jerabek");
MODULE_DESCRIPTION("CTU CAN FD for platform");
|