drivers,can: dt-bindings-can-phytium-Add-bindings-for-Phytium-CAN
add-Phytium-CAN-controller-support
Conflicts:
MAINTAINERS
reviewed-by: Chen Siyu <chensiyu1321@phytium.com.cn>
Signed-off-by: Cheng Quan <chengquan@phytium.com.cn>
Signed-off-by: Li Zhengguang <lizhengguang1317@phytium.com.cn>
Signed-off-by: Chen Baozi <chenbaozi@phytium.com.cn>
Signed-off-by: Chen Siyu <chensiyu1321@phytium.com.cn>
(cherry picked from commit 213232efb8
)
Signed-off-by: Alex Shi <alexsshi@tencent.com>
Signed-off-by: Jianping Liu <frankjpliu@tencent.com>
This commit is contained in:
parent
db1d1c415b
commit
0cdc4fd1f6
|
@ -0,0 +1,29 @@
|
|||
Phytium CAN controller
|
||||
------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be:
|
||||
- "phytium,can" for Phytium CAN controllers
|
||||
- "phytium,canfd" for Phytium CAN controllers with CANFD support
|
||||
- reg: Should contain CANFD controller registers location and length
|
||||
- interrupts: Should contain IRQ line for the CANFD controller
|
||||
- clocks: CLocks used by the controller
|
||||
- clock-names: Input clock names, should be "can_clk"
|
||||
- tx-fifo-depth: Indicates the length of TX FIFO
|
||||
- rx-fifo-depth: Indicates the length of TX FIFO
|
||||
|
||||
Optional property:
|
||||
- extend_brp: Indicates to apply the extend BRP parameter of bit timming for
|
||||
early version of CAN controller
|
||||
|
||||
Example:
|
||||
|
||||
can0: can@2800a000{
|
||||
compatible = "phytium,canfd";
|
||||
reg = <0x0 0x2800a000 0x0 0x1000>;
|
||||
interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&sysclk_600mhz>;
|
||||
clock-names = "can_clk";
|
||||
tx-fifo-depth = <64>;
|
||||
rx-fifo-depth = <64>;
|
||||
};
|
|
@ -2089,6 +2089,14 @@ W: http://hackndev.com
|
|||
S: Maintained
|
||||
F: arch/arm/mach-pxa/palmz72.*
|
||||
|
||||
ARM/PHYTIUM SOC SUPPORT
|
||||
M: Chen Baozi <chenbaozi@phytium.com.cn>
|
||||
S: Maintained
|
||||
W: https://www.phytium.com.cn
|
||||
F: arch/arm64/boot/dts/phytium/*
|
||||
F: Documentation/devicetree/bindings/net/can/phytium-can.txt
|
||||
F: drivers/net/can/phytium/*
|
||||
|
||||
ARM/PLEB SUPPORT
|
||||
M: Peter Chubb <pleb@gelato.unsw.edu.au>
|
||||
W: http://www.disy.cse.unsw.edu.au/Hardware/PLEB
|
||||
|
|
|
@ -173,6 +173,7 @@ source "drivers/net/can/ifi_canfd/Kconfig"
|
|||
source "drivers/net/can/m_can/Kconfig"
|
||||
source "drivers/net/can/mscan/Kconfig"
|
||||
source "drivers/net/can/peak_canfd/Kconfig"
|
||||
source "drivers/net/can/phytium/Kconfig"
|
||||
source "drivers/net/can/rcar/Kconfig"
|
||||
source "drivers/net/can/sja1000/Kconfig"
|
||||
source "drivers/net/can/softing/Kconfig"
|
||||
|
|
|
@ -29,5 +29,5 @@ obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o
|
|||
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
|
||||
obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o
|
||||
obj-$(CONFIG_PCH_CAN) += pch_can.o
|
||||
|
||||
obj-$(CONFIG_CAN_PHYTIUM) += phytium/
|
||||
subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
menuconfig CAN_PHYTIUM
|
||||
tristate "Phytium CAN support"
|
||||
help
|
||||
Say Y here if you want support for Phytium CAN controller framework.
|
||||
This is common support for devices that embed the Phytium CAN IP.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called phytium_can.
|
||||
|
||||
if CAN_PHYTIUM
|
||||
|
||||
config CAN_PHYTIUM_PLATFORM
|
||||
tristate "Phytium CAN support for io-mapped devices"
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Say Y here is you want to support for IO Mapped Phytium CAN controller.
|
||||
This support is for devices that have the Phytium CAN controller IP
|
||||
embedded into the device and the IP is IO Mapped to the processor.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called phytium_can_platform.
|
||||
|
||||
config CAN_PHYTIUM_PCI
|
||||
tristate "Phytium CAN support for PCI devices"
|
||||
depends on PCI
|
||||
help
|
||||
Say Y here is you want to support for Phytium CAN controller connected
|
||||
to the PCI bus. This support is for devices that have the Phytium CAN
|
||||
controller IP embedded into a PCI device.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called phytium_can_pci.
|
||||
endif
|
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# Makefile for the Phytium CAN controller drivers.
|
||||
#
|
||||
#
|
||||
|
||||
obj-$(CONFIG_CAN_PHYTIUM) += phytium_can.o
|
||||
obj-$(CONFIG_CAN_PHYTIUM_PLATFORM) += phytium_can_platform.o
|
||||
obj-$(CONFIG_CAN_PHYTIUM_PCI) += phytium_can_pci.o
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,66 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Phytium CAN controller driver
|
||||
*
|
||||
* Copyright (C) 2021-2023, Phytium Technology Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _PHYTIUM_CAN_H_
|
||||
#define _PHYTIUM_CAN_H_
|
||||
|
||||
#include <linux/can/core.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
enum phytium_can_ip_type {
|
||||
PHYTIUM_CAN = 0,
|
||||
PHYTIUM_CANFD,
|
||||
};
|
||||
|
||||
struct phytium_can_devtype {
|
||||
enum phytium_can_ip_type cantype;
|
||||
const struct can_bittiming_const *bittiming_const;
|
||||
};
|
||||
|
||||
struct phytium_can_dev {
|
||||
struct can_priv can;
|
||||
unsigned int tx_head;
|
||||
unsigned int tx_tail;
|
||||
unsigned int tx_max;
|
||||
struct napi_struct napi;
|
||||
struct net_device *net;
|
||||
struct device *dev;
|
||||
struct clk *clk;
|
||||
|
||||
struct sk_buff *tx_skb;
|
||||
|
||||
const struct can_bittiming_const *bit_timing;
|
||||
|
||||
int fdmode;
|
||||
u32 isr;
|
||||
u32 tx_fifo_depth;
|
||||
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
struct phytium_can_dev *phytium_can_allocate_dev(struct device *dev, int sizeof_priv,
|
||||
int tx_fifo_depth);
|
||||
void phytium_can_free_dev(struct net_device *net);
|
||||
|
||||
int phytium_can_register(struct phytium_can_dev *cdev);
|
||||
void phytium_can_unregister(struct phytium_can_dev *cdev);
|
||||
|
||||
int phytium_can_suspend(struct device *dev);
|
||||
int phytium_can_resume(struct device *dev);
|
||||
#endif /* _PHYTIUM_CAN_H_ */
|
|
@ -0,0 +1,135 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Platform CAN bus driver for Phytium CAN controller
|
||||
*
|
||||
* Copyright (C) 2021-2023, Phytium Technology Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "phytium_can.h"
|
||||
|
||||
struct phytium_can_pci_config {
|
||||
const struct phytium_can_devtype *devtype;
|
||||
unsigned int clock_freq;
|
||||
unsigned int tx_fifo_depth;
|
||||
};
|
||||
|
||||
#define cdev2priv(dev) container_of(dev, struct phytium_can_pci, cdev)
|
||||
|
||||
struct phytium_can_pci {
|
||||
struct phytium_can_dev cdev;
|
||||
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static const struct can_bittiming_const phytium_bittiming_const_8192 = {
|
||||
.name = "phytium_can",
|
||||
.tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 1, /* Time segment 2 = phase_seg2 */
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4, /* Synchronisation jump width */
|
||||
.brp_min = 1, /* Bit-rate prescaler */
|
||||
.brp_max = 8192,
|
||||
.brp_inc = 2,
|
||||
};
|
||||
|
||||
static const struct phytium_can_devtype phytium_can_pci = {
|
||||
.cantype = PHYTIUM_CAN,
|
||||
.bittiming_const = &phytium_bittiming_const_8192,
|
||||
};
|
||||
|
||||
static const struct phytium_can_pci_config phytium_can_pci_data = {
|
||||
.devtype = &phytium_can_pci,
|
||||
.clock_freq = 600000000,
|
||||
.tx_fifo_depth = 64,
|
||||
};
|
||||
|
||||
static int phytium_can_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
const struct phytium_can_pci_config *cfg;
|
||||
struct phytium_can_dev *cdev;
|
||||
struct phytium_can_pci *priv;
|
||||
int ret;
|
||||
|
||||
cfg = (const struct phytium_can_pci_config *)id->driver_data;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = pcim_iomap_regions(pdev, 0x1, pci_name(pdev));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
cdev = phytium_can_allocate_dev(&pdev->dev, sizeof(struct phytium_can_pci),
|
||||
cfg->tx_fifo_depth);
|
||||
if (!cdev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = cdev2priv(cdev);
|
||||
priv->base = pcim_iomap_table(pdev)[0];
|
||||
|
||||
cdev->dev = &pdev->dev;
|
||||
cdev->fdmode = cfg->devtype->cantype;
|
||||
cdev->bit_timing = cfg->devtype->bittiming_const;
|
||||
cdev->can.clock.freq = cfg->clock_freq;
|
||||
cdev->tx_fifo_depth = cfg->tx_fifo_depth;
|
||||
|
||||
cdev->base = priv->base;
|
||||
cdev->net->irq = pdev->irq;
|
||||
|
||||
pci_set_drvdata(pdev, cdev->net);
|
||||
|
||||
pm_runtime_enable(cdev->dev);
|
||||
ret = phytium_can_register(cdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void phytium_can_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct phytium_can_dev *cdev = netdev_priv(dev);
|
||||
|
||||
phytium_can_unregister(cdev);
|
||||
phytium_can_free_dev(cdev->net);
|
||||
}
|
||||
|
||||
static __maybe_unused int phytium_can_pci_suspend(struct device *dev)
|
||||
{
|
||||
return phytium_can_suspend(dev);
|
||||
}
|
||||
|
||||
static __maybe_unused int phytium_can_pci_resume(struct device *dev)
|
||||
{
|
||||
return phytium_can_resume(dev);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(phytium_can_pci_pm_ops,
|
||||
phytium_can_pci_suspend, phytium_can_pci_resume);
|
||||
|
||||
static const struct pci_device_id phytium_can_pci_id_table[] = {
|
||||
{ PCI_VDEVICE(PHYTIUM, 0xdc2d), (kernel_ulong_t)&phytium_can_pci_data, },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct pci_driver phytium_can_pci_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.probe = phytium_can_pci_probe,
|
||||
.remove = phytium_can_pci_remove,
|
||||
.id_table = phytium_can_pci_id_table,
|
||||
.driver = {
|
||||
.pm = &phytium_can_pci_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_pci_driver(phytium_can_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Cheng Quan <chengquan@phytium.com.cn");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Phytium CAN driver for PCI-based controllers");
|
|
@ -0,0 +1,228 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Platform CAN bus driver for Phytium CAN controller
|
||||
*
|
||||
* Copyright (C) 2021-2023, Phytium Technology Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
#include "phytium_can.h"
|
||||
|
||||
#define cdev2priv(dev) container_of(dev, struct phytium_can_plat, cdev)
|
||||
|
||||
struct phytium_can_plat {
|
||||
struct phytium_can_dev cdev;
|
||||
struct phytium_can_devtype *devtype;
|
||||
|
||||
int irq;
|
||||
void __iomem *reg_base;
|
||||
};
|
||||
|
||||
static const struct can_bittiming_const phytium_bittiming_const_512 = {
|
||||
.name = "phytium_can",
|
||||
.tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 1, /* Time segment 2 = phase_seg2 */
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4, /* Synchronisation jump width */
|
||||
.brp_min = 1, /* Bit-rate prescaler */
|
||||
.brp_max = 512,
|
||||
.brp_inc = 2,
|
||||
};
|
||||
|
||||
static const struct can_bittiming_const phytium_bittiming_const_8192 = {
|
||||
.name = "phytium_can",
|
||||
.tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 1, /* Time segment 2 = phase_seg2 */
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4, /* Synchronisation jump width */
|
||||
.brp_min = 1, /* Bit-rate prescaler */
|
||||
.brp_max = 8192,
|
||||
.brp_inc = 2,
|
||||
};
|
||||
|
||||
static const struct phytium_can_devtype phytium_can_data = {
|
||||
.cantype = PHYTIUM_CAN,
|
||||
.bittiming_const = &phytium_bittiming_const_512,
|
||||
};
|
||||
|
||||
static const struct phytium_can_devtype phytium_canfd_data = {
|
||||
.cantype = PHYTIUM_CANFD,
|
||||
.bittiming_const = &phytium_bittiming_const_8192,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id phytium_can_acpi_ids[] = {
|
||||
{ "PHYT000A", 0 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, phytium_can_acpi_ids);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id phytium_can_of_ids[] = {
|
||||
{ .compatible = "phytium,can", .data = &phytium_can_data },
|
||||
{ .compatible = "phytium,canfd", .data = &phytium_canfd_data },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, phytium_can_of_ids);
|
||||
#endif
|
||||
|
||||
static int phytium_can_plat_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct phytium_can_dev *cdev;
|
||||
struct phytium_can_plat *priv;
|
||||
struct resource *res;
|
||||
const struct of_device_id *of_id;
|
||||
const struct phytium_can_devtype *devtype = &phytium_can_data;
|
||||
u32 tx_fifo_depth;
|
||||
int ret;
|
||||
const char *str = "canfd";
|
||||
|
||||
ret = fwnode_property_read_u32(dev_fwnode(&pdev->dev), "tx-fifo-depth", &tx_fifo_depth);
|
||||
if (ret)
|
||||
tx_fifo_depth = 64;
|
||||
|
||||
cdev = phytium_can_allocate_dev(&pdev->dev, sizeof(struct phytium_can_plat),
|
||||
tx_fifo_depth);
|
||||
if (!cdev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = cdev2priv(cdev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->reg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
if (IS_ERR(priv->reg_base) || cdev->net->irq < 0) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
cdev->clk = devm_clk_get(&pdev->dev, "can_clk");
|
||||
if (IS_ERR(cdev->clk)) {
|
||||
dev_err(&pdev->dev, "no clock found\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
cdev->can.clock.freq = clk_get_rate(cdev->clk);
|
||||
|
||||
of_id = of_match_device(phytium_can_of_ids, &pdev->dev);
|
||||
if (of_id && of_id->data)
|
||||
devtype = of_id->data;
|
||||
} else if (has_acpi_companion(&pdev->dev)) {
|
||||
ret = fwnode_property_read_u32(dev_fwnode(&pdev->dev),
|
||||
"clock-frequency",
|
||||
&cdev->can.clock.freq);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get clock frequency.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fwnode_property_read_string(dev_fwnode(&pdev->dev),
|
||||
"mode-select", &str);
|
||||
if (!(strcmp(str, "canfd")))
|
||||
devtype = &phytium_canfd_data;
|
||||
else
|
||||
devtype = &phytium_can_data;
|
||||
}
|
||||
|
||||
cdev->tx_fifo_depth = tx_fifo_depth;
|
||||
cdev->tx_head = 0;
|
||||
cdev->tx_tail = 0;
|
||||
cdev->tx_max = tx_fifo_depth;
|
||||
|
||||
if (devtype->cantype == PHYTIUM_CANFD)
|
||||
cdev->fdmode = 1;
|
||||
else
|
||||
cdev->fdmode = 0;
|
||||
|
||||
if (fwnode_property_present(dev_fwnode(&pdev->dev), "extend_brp"))
|
||||
cdev->bit_timing = &phytium_bittiming_const_8192;
|
||||
else
|
||||
cdev->bit_timing = devtype->bittiming_const;
|
||||
cdev->can.bittiming_const = devtype->bittiming_const;
|
||||
cdev->base = priv->reg_base;
|
||||
cdev->net->irq = priv->irq;
|
||||
|
||||
platform_set_drvdata(pdev, cdev->net);
|
||||
|
||||
pm_runtime_enable(cdev->dev);
|
||||
ret = phytium_can_register(cdev);
|
||||
if (ret)
|
||||
goto out_runtime_disable;
|
||||
|
||||
return ret;
|
||||
|
||||
out_runtime_disable:
|
||||
pm_runtime_disable(cdev->dev);
|
||||
fail:
|
||||
phytium_can_free_dev(cdev->net);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __maybe_unused int phytium_can_plat_suspend(struct device *dev)
|
||||
{
|
||||
return phytium_can_suspend(dev);
|
||||
}
|
||||
|
||||
static __maybe_unused int phytium_can_plat_resume(struct device *dev)
|
||||
{
|
||||
return phytium_can_resume(dev);
|
||||
}
|
||||
|
||||
static int phytium_can_plat_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *dev = platform_get_drvdata(pdev);
|
||||
struct phytium_can_dev *cdev = netdev_priv(dev);
|
||||
|
||||
phytium_can_unregister(cdev);
|
||||
|
||||
phytium_can_free_dev(cdev->net);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused phytium_can_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct phytium_can_dev *cdev = netdev_priv(ndev);
|
||||
|
||||
clk_disable_unprepare(cdev->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused phytium_can_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct phytium_can_dev *cdev = netdev_priv(ndev);
|
||||
|
||||
return clk_prepare_enable(cdev->clk);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops phytium_can_plat_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(phytium_can_runtime_suspend,
|
||||
phytium_can_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(phytium_can_suspend, phytium_can_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver phytium_can_plat_driver = {
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = of_match_ptr(phytium_can_of_ids),
|
||||
.acpi_match_table = ACPI_PTR(phytium_can_acpi_ids),
|
||||
.pm = &phytium_can_plat_pm_ops,
|
||||
},
|
||||
.probe = phytium_can_plat_probe,
|
||||
.remove = phytium_can_plat_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(phytium_can_plat_driver);
|
||||
|
||||
MODULE_AUTHOR("Cheng Quan <chengquan@phytium.com.cn>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Phytium CAN driver for IO Mapped controllers");
|
Loading…
Reference in New Issue