cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

m_can_platform.c (5551B)


      1// SPDX-License-Identifier: GPL-2.0
      2// IOMapped CAN bus driver for Bosch M_CAN controller
      3// Copyright (C) 2014 Freescale Semiconductor, Inc.
      4//	Dong Aisheng <b29396@freescale.com>
      5//
      6// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
      7
      8#include <linux/platform_device.h>
      9#include <linux/phy/phy.h>
     10
     11#include "m_can.h"
     12
     13struct m_can_plat_priv {
     14	struct m_can_classdev cdev;
     15
     16	void __iomem *base;
     17	void __iomem *mram_base;
     18};
     19
     20static inline struct m_can_plat_priv *cdev_to_priv(struct m_can_classdev *cdev)
     21{
     22	return container_of(cdev, struct m_can_plat_priv, cdev);
     23}
     24
     25static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
     26{
     27	struct m_can_plat_priv *priv = cdev_to_priv(cdev);
     28
     29	return readl(priv->base + reg);
     30}
     31
     32static int iomap_read_fifo(struct m_can_classdev *cdev, int offset, void *val, size_t val_count)
     33{
     34	struct m_can_plat_priv *priv = cdev_to_priv(cdev);
     35	void __iomem *src = priv->mram_base + offset;
     36
     37	while (val_count--) {
     38		*(unsigned int *)val = ioread32(src);
     39		val += 4;
     40		src += 4;
     41	}
     42
     43	return 0;
     44}
     45
     46static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
     47{
     48	struct m_can_plat_priv *priv = cdev_to_priv(cdev);
     49
     50	writel(val, priv->base + reg);
     51
     52	return 0;
     53}
     54
     55static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
     56			    const void *val, size_t val_count)
     57{
     58	struct m_can_plat_priv *priv = cdev_to_priv(cdev);
     59	void __iomem *dst = priv->mram_base + offset;
     60
     61	while (val_count--) {
     62		iowrite32(*(unsigned int *)val, dst);
     63		val += 4;
     64		dst += 4;
     65	}
     66
     67	return 0;
     68}
     69
     70static struct m_can_ops m_can_plat_ops = {
     71	.read_reg = iomap_read_reg,
     72	.write_reg = iomap_write_reg,
     73	.write_fifo = iomap_write_fifo,
     74	.read_fifo = iomap_read_fifo,
     75};
     76
     77static int m_can_plat_probe(struct platform_device *pdev)
     78{
     79	struct m_can_classdev *mcan_class;
     80	struct m_can_plat_priv *priv;
     81	struct resource *res;
     82	void __iomem *addr;
     83	void __iomem *mram_addr;
     84	struct phy *transceiver;
     85	int irq, ret = 0;
     86
     87	mcan_class = m_can_class_allocate_dev(&pdev->dev,
     88					      sizeof(struct m_can_plat_priv));
     89	if (!mcan_class)
     90		return -ENOMEM;
     91
     92	priv = cdev_to_priv(mcan_class);
     93
     94	ret = m_can_class_get_clocks(mcan_class);
     95	if (ret)
     96		goto probe_fail;
     97
     98	addr = devm_platform_ioremap_resource_byname(pdev, "m_can");
     99	irq = platform_get_irq_byname(pdev, "int0");
    100	if (IS_ERR(addr) || irq < 0) {
    101		ret = -EINVAL;
    102		goto probe_fail;
    103	}
    104
    105	/* message ram could be shared */
    106	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
    107	if (!res) {
    108		ret = -ENODEV;
    109		goto probe_fail;
    110	}
    111
    112	mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
    113	if (!mram_addr) {
    114		ret = -ENOMEM;
    115		goto probe_fail;
    116	}
    117
    118	transceiver = devm_phy_optional_get(&pdev->dev, NULL);
    119	if (IS_ERR(transceiver)) {
    120		ret = PTR_ERR(transceiver);
    121		dev_err_probe(&pdev->dev, ret, "failed to get phy\n");
    122		goto probe_fail;
    123	}
    124
    125	if (transceiver)
    126		mcan_class->can.bitrate_max = transceiver->attrs.max_link_rate;
    127
    128	priv->base = addr;
    129	priv->mram_base = mram_addr;
    130
    131	mcan_class->net->irq = irq;
    132	mcan_class->pm_clock_support = 1;
    133	mcan_class->can.clock.freq = clk_get_rate(mcan_class->cclk);
    134	mcan_class->dev = &pdev->dev;
    135	mcan_class->transceiver = transceiver;
    136
    137	mcan_class->ops = &m_can_plat_ops;
    138
    139	mcan_class->is_peripheral = false;
    140
    141	platform_set_drvdata(pdev, mcan_class);
    142
    143	ret = m_can_init_ram(mcan_class);
    144	if (ret)
    145		goto probe_fail;
    146
    147	pm_runtime_enable(mcan_class->dev);
    148	ret = m_can_class_register(mcan_class);
    149	if (ret)
    150		goto out_runtime_disable;
    151
    152	return ret;
    153
    154out_runtime_disable:
    155	pm_runtime_disable(mcan_class->dev);
    156probe_fail:
    157	m_can_class_free_dev(mcan_class->net);
    158	return ret;
    159}
    160
    161static __maybe_unused int m_can_suspend(struct device *dev)
    162{
    163	return m_can_class_suspend(dev);
    164}
    165
    166static __maybe_unused int m_can_resume(struct device *dev)
    167{
    168	return m_can_class_resume(dev);
    169}
    170
    171static int m_can_plat_remove(struct platform_device *pdev)
    172{
    173	struct m_can_plat_priv *priv = platform_get_drvdata(pdev);
    174	struct m_can_classdev *mcan_class = &priv->cdev;
    175
    176	m_can_class_unregister(mcan_class);
    177
    178	m_can_class_free_dev(mcan_class->net);
    179
    180	return 0;
    181}
    182
    183static int __maybe_unused m_can_runtime_suspend(struct device *dev)
    184{
    185	struct m_can_plat_priv *priv = dev_get_drvdata(dev);
    186	struct m_can_classdev *mcan_class = &priv->cdev;
    187
    188	clk_disable_unprepare(mcan_class->cclk);
    189	clk_disable_unprepare(mcan_class->hclk);
    190
    191	return 0;
    192}
    193
    194static int __maybe_unused m_can_runtime_resume(struct device *dev)
    195{
    196	struct m_can_plat_priv *priv = dev_get_drvdata(dev);
    197	struct m_can_classdev *mcan_class = &priv->cdev;
    198	int err;
    199
    200	err = clk_prepare_enable(mcan_class->hclk);
    201	if (err)
    202		return err;
    203
    204	err = clk_prepare_enable(mcan_class->cclk);
    205	if (err)
    206		clk_disable_unprepare(mcan_class->hclk);
    207
    208	return err;
    209}
    210
    211static const struct dev_pm_ops m_can_pmops = {
    212	SET_RUNTIME_PM_OPS(m_can_runtime_suspend,
    213			   m_can_runtime_resume, NULL)
    214	SET_SYSTEM_SLEEP_PM_OPS(m_can_suspend, m_can_resume)
    215};
    216
    217static const struct of_device_id m_can_of_table[] = {
    218	{ .compatible = "bosch,m_can", .data = NULL },
    219	{ /* sentinel */ },
    220};
    221MODULE_DEVICE_TABLE(of, m_can_of_table);
    222
    223static struct platform_driver m_can_plat_driver = {
    224	.driver = {
    225		.name = KBUILD_MODNAME,
    226		.of_match_table = m_can_of_table,
    227		.pm     = &m_can_pmops,
    228	},
    229	.probe = m_can_plat_probe,
    230	.remove = m_can_plat_remove,
    231};
    232
    233module_platform_driver(m_can_plat_driver);
    234
    235MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
    236MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
    237MODULE_LICENSE("GPL v2");
    238MODULE_DESCRIPTION("M_CAN driver for IO Mapped Bosch controllers");