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:
Chen Siyu 2023-04-07 17:15:16 +08:00 committed by Jianping Liu
parent db1d1c415b
commit 0cdc4fd1f6
10 changed files with 1671 additions and 1 deletions

View File

@ -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>;
};

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_ */

View File

@ -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");

View File

@ -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");