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