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 
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  */
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 		dev_err(dev, "Cannot remap address.\n");
62 		ret = PTR_ERR(addr);
63 		goto err;
64 	}
65 	irq = platform_get_irq(pdev, 0);
66 	if (irq < 0) {
67 		ret = irq;
68 		goto err;
69 	}
70 
71 	/* Number of tx bufs might be change in HW for future. If so,
72 	 * it will be passed as property via device tree
73 	 */
74 	ntxbufs = 4;
75 	ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 0,
76 				  1, ctucan_platform_set_drvdata);
77 
78 	if (ret < 0)
79 		platform_set_drvdata(pdev, NULL);
80 
81 err:
82 	return ret;
83 }
84 
85 /**
86  * ctucan_platform_remove - Unregister the device after releasing the resources
87  * @pdev:	Handle to the platform device structure
88  *
89  * This function frees all the resources allocated to the device.
90  * Return: 0 always
91  */
92 static int ctucan_platform_remove(struct platform_device *pdev)
93 {
94 	struct net_device *ndev = platform_get_drvdata(pdev);
95 	struct ctucan_priv *priv = netdev_priv(ndev);
96 
97 	netdev_dbg(ndev, "ctucan_remove");
98 
99 	unregister_candev(ndev);
100 	pm_runtime_disable(&pdev->dev);
101 	netif_napi_del(&priv->napi);
102 	free_candev(ndev);
103 
104 	return 0;
105 }
106 
107 static SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume);
108 
109 /* Match table for OF platform binding */
110 static const struct of_device_id ctucan_of_match[] = {
111 	{ .compatible = "ctu,ctucanfd-2", },
112 	{ .compatible = "ctu,ctucanfd", },
113 	{ /* end of list */ },
114 };
115 MODULE_DEVICE_TABLE(of, ctucan_of_match);
116 
117 static struct platform_driver ctucanfd_driver = {
118 	.probe	= ctucan_platform_probe,
119 	.remove	= ctucan_platform_remove,
120 	.driver	= {
121 		.name = DRV_NAME,
122 		.pm = &ctucan_platform_pm_ops,
123 		.of_match_table	= ctucan_of_match,
124 	},
125 };
126 
127 module_platform_driver(ctucanfd_driver);
128 
129 MODULE_LICENSE("GPL");
130 MODULE_AUTHOR("Martin Jerabek");
131 MODULE_DESCRIPTION("CTU CAN FD for platform");
132