162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * CTU CAN FD IP Core
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
762306a36Sopenharmony_ci * Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
862306a36Sopenharmony_ci * Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
962306a36Sopenharmony_ci * Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Project advisors:
1262306a36Sopenharmony_ci *     Jiri Novak <jnovak@fel.cvut.cz>
1362306a36Sopenharmony_ci *     Pavel Pisa <pisa@cmp.felk.cvut.cz>
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * Department of Measurement         (http://meas.fel.cvut.cz/)
1662306a36Sopenharmony_ci * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
1762306a36Sopenharmony_ci * Czech Technical University        (http://www.cvut.cz/)
1862306a36Sopenharmony_ci ******************************************************************************/
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/netdevice.h>
2262306a36Sopenharmony_ci#include <linux/of.h>
2362306a36Sopenharmony_ci#include <linux/platform_device.h>
2462306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "ctucanfd.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define DRV_NAME	"ctucanfd"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic void ctucan_platform_set_drvdata(struct device *dev,
3162306a36Sopenharmony_ci					struct net_device *ndev)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	struct platform_device *pdev = container_of(dev, struct platform_device,
3462306a36Sopenharmony_ci						    dev);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	platform_set_drvdata(pdev, ndev);
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/**
4062306a36Sopenharmony_ci * ctucan_platform_probe - Platform registration call
4162306a36Sopenharmony_ci * @pdev:	Handle to the platform device structure
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * This function does all the memory allocation and registration for the CAN
4462306a36Sopenharmony_ci * device.
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * Return: 0 on success and failure value on error
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_cistatic int ctucan_platform_probe(struct platform_device *pdev)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct device	*dev = &pdev->dev;
5162306a36Sopenharmony_ci	void __iomem *addr;
5262306a36Sopenharmony_ci	int ret;
5362306a36Sopenharmony_ci	unsigned int ntxbufs;
5462306a36Sopenharmony_ci	int irq;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/* Get the virtual base address for the device */
5762306a36Sopenharmony_ci	addr = devm_platform_ioremap_resource(pdev, 0);
5862306a36Sopenharmony_ci	if (IS_ERR(addr)) {
5962306a36Sopenharmony_ci		ret = PTR_ERR(addr);
6062306a36Sopenharmony_ci		goto err;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
6362306a36Sopenharmony_ci	if (irq < 0) {
6462306a36Sopenharmony_ci		ret = irq;
6562306a36Sopenharmony_ci		goto err;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* Number of tx bufs might be change in HW for future. If so,
6962306a36Sopenharmony_ci	 * it will be passed as property via device tree
7062306a36Sopenharmony_ci	 */
7162306a36Sopenharmony_ci	ntxbufs = 4;
7262306a36Sopenharmony_ci	ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 0,
7362306a36Sopenharmony_ci				  1, ctucan_platform_set_drvdata);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (ret < 0)
7662306a36Sopenharmony_ci		platform_set_drvdata(pdev, NULL);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cierr:
7962306a36Sopenharmony_ci	return ret;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/**
8362306a36Sopenharmony_ci * ctucan_platform_remove - Unregister the device after releasing the resources
8462306a36Sopenharmony_ci * @pdev:	Handle to the platform device structure
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci * This function frees all the resources allocated to the device.
8762306a36Sopenharmony_ci * Return: 0 always
8862306a36Sopenharmony_ci */
8962306a36Sopenharmony_cistatic void ctucan_platform_remove(struct platform_device *pdev)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct net_device *ndev = platform_get_drvdata(pdev);
9262306a36Sopenharmony_ci	struct ctucan_priv *priv = netdev_priv(ndev);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	netdev_dbg(ndev, "ctucan_remove");
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	unregister_candev(ndev);
9762306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
9862306a36Sopenharmony_ci	netif_napi_del(&priv->napi);
9962306a36Sopenharmony_ci	free_candev(ndev);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/* Match table for OF platform binding */
10562306a36Sopenharmony_cistatic const struct of_device_id ctucan_of_match[] = {
10662306a36Sopenharmony_ci	{ .compatible = "ctu,ctucanfd-2", },
10762306a36Sopenharmony_ci	{ .compatible = "ctu,ctucanfd", },
10862306a36Sopenharmony_ci	{ /* end of list */ },
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ctucan_of_match);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic struct platform_driver ctucanfd_driver = {
11362306a36Sopenharmony_ci	.probe	= ctucan_platform_probe,
11462306a36Sopenharmony_ci	.remove_new = ctucan_platform_remove,
11562306a36Sopenharmony_ci	.driver	= {
11662306a36Sopenharmony_ci		.name = DRV_NAME,
11762306a36Sopenharmony_ci		.pm = &ctucan_platform_pm_ops,
11862306a36Sopenharmony_ci		.of_match_table	= ctucan_of_match,
11962306a36Sopenharmony_ci	},
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cimodule_platform_driver(ctucanfd_driver);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
12562306a36Sopenharmony_ciMODULE_AUTHOR("Martin Jerabek");
12662306a36Sopenharmony_ciMODULE_DESCRIPTION("CTU CAN FD for platform");
127