linux-can-next-for-6.6-20230719
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEDs2BvajyNKlf9TJQvlAcSiqKBOgFAmS3jZATHG1rbEBwZW5n dXRyb25peC5kZQAKCRC+UBxKKooE6Fo4CACVxU4+xMgAszot9Sup7psEiUjbOHKd TCxEEm9GML/aquPbXxx3r0yztyAzd1dF9zXSFGofUyfVV/pdKbu7h1vP+/EndmiL W9eoVhnYzAbz2TivFgqQwqqTlosEgKmZF5qGl4eloH6luOILbvrl/UuD0J70h3gK Ixus6TyEIdI2y1ewTlWXMOriedTVeTX+DC2S02Bi42cVFdAm29nie2fCdHVGhF/o a0KICO3HjKhTmGReSHDpCMro+r93BezmYxoM96K4a911tge7fLzYhQQ1+ZVyQ3Mw DRHMD1ehM6cWd0GUce3LqBjb9zx9ciQK0ohqKzAIaEV+Rta84P/CHtbn =GOLr -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-6.6-20230719' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next Marc Kleine-Budde says: ==================== pull-request: can-next 2023-07-19 The first 2 patches are by Judith Mendez, target the m_can driver and add hrtimer based polling support for TI AM62x SoCs, where the interrupt of the MCU domain's m_can cores is not routed to the Cortex A53 core. A patch by Rob Herring converts the grcan driver to use the correct DT include files. Michal Simek and Srinivas Neeli add support for optional reset control to the xilinx_can driver. The next 2 patches are by Jimmy Assarsson and add support for new Kvaser pciefd to the kvaser_pciefd driver. Mao Zhu's patch for the ucan driver removes a repeated word from a comment. * tag 'linux-can-next-for-6.6-20230719' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next: can: ucan: Remove repeated word can: kvaser_pciefd: Add support for new Kvaser pciefd devices can: kvaser_pciefd: Move hardware specific constants and functions into a driver_data struct can: Explicitly include correct DT includes can: xilinx_can: Add support for controller reset dt-bindings: can: xilinx_can: Add reset description can: m_can: Add hrtimer to generate software interrupt dt-bindings: net: can: Remove interrupt properties for MCAN ==================== Link: https://lore.kernel.org/r/20230719072348.525039-1-mkl@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
97083c21c5
|
@ -122,8 +122,6 @@ required:
|
|||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- bosch,mram-cfg
|
||||
|
@ -132,6 +130,7 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
// Example with interrupts
|
||||
#include <dt-bindings/clock/imx6sx-clock.h>
|
||||
can@20e8000 {
|
||||
compatible = "bosch,m_can";
|
||||
|
@ -149,4 +148,21 @@ examples:
|
|||
};
|
||||
};
|
||||
|
||||
- |
|
||||
// Example with timer polling
|
||||
#include <dt-bindings/clock/imx6sx-clock.h>
|
||||
can@20e8000 {
|
||||
compatible = "bosch,m_can";
|
||||
reg = <0x020e8000 0x4000>, <0x02298000 0x4000>;
|
||||
reg-names = "m_can", "message_ram";
|
||||
clocks = <&clks IMX6SX_CLK_CANFD>,
|
||||
<&clks IMX6SX_CLK_CANFD>;
|
||||
clock-names = "hclk", "cclk";
|
||||
bosch,mram-cfg = <0x0 0 0 32 0 0 0 1>;
|
||||
|
||||
can-transceiver {
|
||||
max-bitrate = <5000000>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
|
@ -46,6 +46,9 @@ properties:
|
|||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: CAN Tx mailbox buffer count (CAN FD)
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
@ -160,8 +160,13 @@ config CAN_KVASER_PCIEFD
|
|||
Kvaser PCIEcan 4xHS
|
||||
Kvaser PCIEcan 2xHS v2
|
||||
Kvaser PCIEcan HS v2
|
||||
Kvaser PCIEcan 1xCAN v3
|
||||
Kvaser PCIEcan 2xCAN v3
|
||||
Kvaser PCIEcan 4xCAN v2
|
||||
Kvaser Mini PCI Express HS v2
|
||||
Kvaser Mini PCI Express 2xHS v2
|
||||
Kvaser Mini PCI Express 1xCAN v3
|
||||
Kvaser Mini PCI Express 2xCAN v3
|
||||
|
||||
config CAN_SLCAN
|
||||
tristate "Serial / USB serial CAN Adaptors (slcan)"
|
||||
|
|
|
@ -30,8 +30,9 @@
|
|||
#include <linux/ethtool.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||
/* Copyright (C) 2018 KVASER AB, Sweden. All rights reserved.
|
||||
* Parts of this driver are based on the following:
|
||||
* - Kvaser linux pciefd driver (version 5.25)
|
||||
* - Kvaser linux pciefd driver (version 5.42)
|
||||
* - PEAK linux canfd driver
|
||||
*/
|
||||
|
||||
|
@ -33,37 +33,27 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
|
|||
#define KVASER_PCIEFD_DMA_SIZE (4U * 1024U)
|
||||
|
||||
#define KVASER_PCIEFD_VENDOR 0x1a07
|
||||
/* Altera based devices */
|
||||
#define KVASER_PCIEFD_4HS_DEVICE_ID 0x000d
|
||||
#define KVASER_PCIEFD_2HS_V2_DEVICE_ID 0x000e
|
||||
#define KVASER_PCIEFD_HS_V2_DEVICE_ID 0x000f
|
||||
#define KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID 0x0010
|
||||
#define KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID 0x0011
|
||||
|
||||
/* PCIe IRQ registers */
|
||||
#define KVASER_PCIEFD_IRQ_REG 0x40
|
||||
#define KVASER_PCIEFD_IEN_REG 0x50
|
||||
/* DMA address translation map register base */
|
||||
#define KVASER_PCIEFD_DMA_MAP_BASE 0x1000
|
||||
/* Loopback control register */
|
||||
#define KVASER_PCIEFD_LOOP_REG 0x1f000
|
||||
/* System identification and information registers */
|
||||
#define KVASER_PCIEFD_SYSID_BASE 0x1f020
|
||||
#define KVASER_PCIEFD_SYSID_VERSION_REG (KVASER_PCIEFD_SYSID_BASE + 0x8)
|
||||
#define KVASER_PCIEFD_SYSID_CANFREQ_REG (KVASER_PCIEFD_SYSID_BASE + 0xc)
|
||||
#define KVASER_PCIEFD_SYSID_BUSFREQ_REG (KVASER_PCIEFD_SYSID_BASE + 0x10)
|
||||
#define KVASER_PCIEFD_SYSID_BUILD_REG (KVASER_PCIEFD_SYSID_BASE + 0x14)
|
||||
/* Shared receive buffer registers */
|
||||
#define KVASER_PCIEFD_SRB_BASE 0x1f200
|
||||
#define KVASER_PCIEFD_SRB_FIFO_LAST_REG (KVASER_PCIEFD_SRB_BASE + 0x1f4)
|
||||
#define KVASER_PCIEFD_SRB_CMD_REG (KVASER_PCIEFD_SRB_BASE + 0x200)
|
||||
#define KVASER_PCIEFD_SRB_IEN_REG (KVASER_PCIEFD_SRB_BASE + 0x204)
|
||||
#define KVASER_PCIEFD_SRB_IRQ_REG (KVASER_PCIEFD_SRB_BASE + 0x20c)
|
||||
#define KVASER_PCIEFD_SRB_STAT_REG (KVASER_PCIEFD_SRB_BASE + 0x210)
|
||||
#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG (KVASER_PCIEFD_SRB_BASE + 0x214)
|
||||
#define KVASER_PCIEFD_SRB_CTRL_REG (KVASER_PCIEFD_SRB_BASE + 0x218)
|
||||
/* SmartFusion2 based devices */
|
||||
#define KVASER_PCIEFD_2CAN_V3_DEVICE_ID 0x0012
|
||||
#define KVASER_PCIEFD_1CAN_V3_DEVICE_ID 0x0013
|
||||
#define KVASER_PCIEFD_4CAN_V2_DEVICE_ID 0x0014
|
||||
#define KVASER_PCIEFD_MINIPCIE_2CAN_V3_DEVICE_ID 0x0015
|
||||
#define KVASER_PCIEFD_MINIPCIE_1CAN_V3_DEVICE_ID 0x0016
|
||||
|
||||
/* Altera SerDes Enable 64-bit DMA address translation */
|
||||
#define KVASER_PCIEFD_ALTERA_DMA_64BIT BIT(0)
|
||||
|
||||
/* SmartFusion2 SerDes LSB address translation mask */
|
||||
#define KVASER_PCIEFD_SF2_DMA_LSB_MASK GENMASK(31, 12)
|
||||
|
||||
/* Kvaser KCAN CAN controller registers */
|
||||
#define KVASER_PCIEFD_KCAN0_BASE 0x10000
|
||||
#define KVASER_PCIEFD_KCAN_BASE_OFFSET 0x1000
|
||||
#define KVASER_PCIEFD_KCAN_FIFO_REG 0x100
|
||||
#define KVASER_PCIEFD_KCAN_FIFO_LAST_REG 0x180
|
||||
#define KVASER_PCIEFD_KCAN_CTRL_REG 0x2c0
|
||||
|
@ -77,13 +67,20 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
|
|||
#define KVASER_PCIEFD_KCAN_BUS_LOAD_REG 0x424
|
||||
#define KVASER_PCIEFD_KCAN_BTRD_REG 0x428
|
||||
#define KVASER_PCIEFD_KCAN_PWM_REG 0x430
|
||||
|
||||
/* PCI interrupt fields */
|
||||
#define KVASER_PCIEFD_IRQ_SRB BIT(4)
|
||||
#define KVASER_PCIEFD_IRQ_ALL_MASK GENMASK(4, 0)
|
||||
|
||||
/* Enable 64-bit DMA address translation */
|
||||
#define KVASER_PCIEFD_64BIT_DMA_BIT BIT(0)
|
||||
/* System identification and information registers */
|
||||
#define KVASER_PCIEFD_SYSID_VERSION_REG 0x8
|
||||
#define KVASER_PCIEFD_SYSID_CANFREQ_REG 0xc
|
||||
#define KVASER_PCIEFD_SYSID_BUSFREQ_REG 0x10
|
||||
#define KVASER_PCIEFD_SYSID_BUILD_REG 0x14
|
||||
/* Shared receive buffer FIFO registers */
|
||||
#define KVASER_PCIEFD_SRB_FIFO_LAST_REG 0x1f4
|
||||
/* Shared receive buffer registers */
|
||||
#define KVASER_PCIEFD_SRB_CMD_REG 0x0
|
||||
#define KVASER_PCIEFD_SRB_IEN_REG 0x04
|
||||
#define KVASER_PCIEFD_SRB_IRQ_REG 0x0c
|
||||
#define KVASER_PCIEFD_SRB_STAT_REG 0x10
|
||||
#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG 0x14
|
||||
#define KVASER_PCIEFD_SRB_CTRL_REG 0x18
|
||||
|
||||
/* System build information fields */
|
||||
#define KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK GENMASK(31, 24)
|
||||
|
@ -253,7 +250,122 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
|
|||
/* KCAN Error detected packet, second word */
|
||||
#define KVASER_PCIEFD_EPACK_DIR_TX BIT(0)
|
||||
|
||||
/* Macros for calculating addresses of registers */
|
||||
#define KVASER_PCIEFD_GET_BLOCK_ADDR(pcie, block) \
|
||||
((pcie)->reg_base + (pcie)->driver_data->address_offset->block)
|
||||
#define KVASER_PCIEFD_PCI_IEN_ADDR(pcie) \
|
||||
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), pci_ien))
|
||||
#define KVASER_PCIEFD_PCI_IRQ_ADDR(pcie) \
|
||||
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), pci_irq))
|
||||
#define KVASER_PCIEFD_SERDES_ADDR(pcie) \
|
||||
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), serdes))
|
||||
#define KVASER_PCIEFD_SYSID_ADDR(pcie) \
|
||||
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), sysid))
|
||||
#define KVASER_PCIEFD_LOOPBACK_ADDR(pcie) \
|
||||
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), loopback))
|
||||
#define KVASER_PCIEFD_SRB_FIFO_ADDR(pcie) \
|
||||
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_srb_fifo))
|
||||
#define KVASER_PCIEFD_SRB_ADDR(pcie) \
|
||||
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_srb))
|
||||
#define KVASER_PCIEFD_KCAN_CH0_ADDR(pcie) \
|
||||
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_ch0))
|
||||
#define KVASER_PCIEFD_KCAN_CH1_ADDR(pcie) \
|
||||
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_ch1))
|
||||
#define KVASER_PCIEFD_KCAN_CHANNEL_SPAN(pcie) \
|
||||
(KVASER_PCIEFD_KCAN_CH1_ADDR((pcie)) - KVASER_PCIEFD_KCAN_CH0_ADDR((pcie)))
|
||||
#define KVASER_PCIEFD_KCAN_CHX_ADDR(pcie, i) \
|
||||
(KVASER_PCIEFD_KCAN_CH0_ADDR((pcie)) + (i) * KVASER_PCIEFD_KCAN_CHANNEL_SPAN((pcie)))
|
||||
|
||||
struct kvaser_pciefd;
|
||||
static void kvaser_pciefd_write_dma_map_altera(struct kvaser_pciefd *pcie,
|
||||
dma_addr_t addr, int index);
|
||||
static void kvaser_pciefd_write_dma_map_sf2(struct kvaser_pciefd *pcie,
|
||||
dma_addr_t addr, int index);
|
||||
|
||||
struct kvaser_pciefd_address_offset {
|
||||
u32 serdes;
|
||||
u32 pci_ien;
|
||||
u32 pci_irq;
|
||||
u32 sysid;
|
||||
u32 loopback;
|
||||
u32 kcan_srb_fifo;
|
||||
u32 kcan_srb;
|
||||
u32 kcan_ch0;
|
||||
u32 kcan_ch1;
|
||||
};
|
||||
|
||||
struct kvaser_pciefd_dev_ops {
|
||||
void (*kvaser_pciefd_write_dma_map)(struct kvaser_pciefd *pcie,
|
||||
dma_addr_t addr, int index);
|
||||
};
|
||||
|
||||
struct kvaser_pciefd_irq_mask {
|
||||
u32 kcan_rx0;
|
||||
u32 kcan_tx[KVASER_PCIEFD_MAX_CAN_CHANNELS];
|
||||
u32 all;
|
||||
};
|
||||
|
||||
struct kvaser_pciefd_driver_data {
|
||||
const struct kvaser_pciefd_address_offset *address_offset;
|
||||
const struct kvaser_pciefd_irq_mask *irq_mask;
|
||||
const struct kvaser_pciefd_dev_ops *ops;
|
||||
};
|
||||
|
||||
static const struct kvaser_pciefd_address_offset kvaser_pciefd_altera_address_offset = {
|
||||
.serdes = 0x1000,
|
||||
.pci_ien = 0x50,
|
||||
.pci_irq = 0x40,
|
||||
.sysid = 0x1f020,
|
||||
.loopback = 0x1f000,
|
||||
.kcan_srb_fifo = 0x1f200,
|
||||
.kcan_srb = 0x1f400,
|
||||
.kcan_ch0 = 0x10000,
|
||||
.kcan_ch1 = 0x11000,
|
||||
};
|
||||
|
||||
static const struct kvaser_pciefd_address_offset kvaser_pciefd_sf2_address_offset = {
|
||||
.serdes = 0x280c8,
|
||||
.pci_ien = 0x102004,
|
||||
.pci_irq = 0x102008,
|
||||
.sysid = 0x100000,
|
||||
.loopback = 0x103000,
|
||||
.kcan_srb_fifo = 0x120000,
|
||||
.kcan_srb = 0x121000,
|
||||
.kcan_ch0 = 0x140000,
|
||||
.kcan_ch1 = 0x142000,
|
||||
};
|
||||
|
||||
static const struct kvaser_pciefd_irq_mask kvaser_pciefd_altera_irq_mask = {
|
||||
.kcan_rx0 = BIT(4),
|
||||
.kcan_tx = { BIT(0), BIT(1), BIT(2), BIT(3) },
|
||||
.all = GENMASK(4, 0),
|
||||
};
|
||||
|
||||
static const struct kvaser_pciefd_irq_mask kvaser_pciefd_sf2_irq_mask = {
|
||||
.kcan_rx0 = BIT(4),
|
||||
.kcan_tx = { BIT(16), BIT(17), BIT(18), BIT(19) },
|
||||
.all = GENMASK(19, 16) | BIT(4),
|
||||
};
|
||||
|
||||
static const struct kvaser_pciefd_dev_ops kvaser_pciefd_altera_dev_ops = {
|
||||
.kvaser_pciefd_write_dma_map = kvaser_pciefd_write_dma_map_altera,
|
||||
};
|
||||
|
||||
static const struct kvaser_pciefd_dev_ops kvaser_pciefd_sf2_dev_ops = {
|
||||
.kvaser_pciefd_write_dma_map = kvaser_pciefd_write_dma_map_sf2,
|
||||
};
|
||||
|
||||
static const struct kvaser_pciefd_driver_data kvaser_pciefd_altera_driver_data = {
|
||||
.address_offset = &kvaser_pciefd_altera_address_offset,
|
||||
.irq_mask = &kvaser_pciefd_altera_irq_mask,
|
||||
.ops = &kvaser_pciefd_altera_dev_ops,
|
||||
};
|
||||
|
||||
static const struct kvaser_pciefd_driver_data kvaser_pciefd_sf2_driver_data = {
|
||||
.address_offset = &kvaser_pciefd_sf2_address_offset,
|
||||
.irq_mask = &kvaser_pciefd_sf2_irq_mask,
|
||||
.ops = &kvaser_pciefd_sf2_dev_ops,
|
||||
};
|
||||
|
||||
struct kvaser_pciefd_can {
|
||||
struct can_priv can;
|
||||
|
@ -273,6 +385,7 @@ struct kvaser_pciefd {
|
|||
struct pci_dev *pci;
|
||||
void __iomem *reg_base;
|
||||
struct kvaser_pciefd_can *can[KVASER_PCIEFD_MAX_CAN_CHANNELS];
|
||||
const struct kvaser_pciefd_driver_data *driver_data;
|
||||
void *dma_data[KVASER_PCIEFD_DMA_COUNT];
|
||||
u8 nr_channels;
|
||||
u32 bus_freq;
|
||||
|
@ -305,18 +418,43 @@ static const struct can_bittiming_const kvaser_pciefd_bittiming_const = {
|
|||
static struct pci_device_id kvaser_pciefd_id_table[] = {
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4HS_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2HS_V2_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_HS_V2_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2CAN_V3_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_1CAN_V3_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4CAN_V2_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_2CAN_V3_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_1CAN_V3_DEVICE_ID),
|
||||
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
|
||||
},
|
||||
{
|
||||
0,
|
||||
|
@ -783,8 +921,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
|
|||
can = netdev_priv(netdev);
|
||||
netdev->netdev_ops = &kvaser_pciefd_netdev_ops;
|
||||
netdev->ethtool_ops = &kvaser_pciefd_ethtool_ops;
|
||||
can->reg_base = pcie->reg_base + KVASER_PCIEFD_KCAN0_BASE +
|
||||
i * KVASER_PCIEFD_KCAN_BASE_OFFSET;
|
||||
can->reg_base = KVASER_PCIEFD_KCAN_CHX_ADDR(pcie, i);
|
||||
can->kv_pcie = pcie;
|
||||
can->cmd_seq = 0;
|
||||
can->err_rep_cnt = 0;
|
||||
|
@ -865,20 +1002,37 @@ static int kvaser_pciefd_reg_candev(struct kvaser_pciefd *pcie)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_write_dma_map(struct kvaser_pciefd *pcie,
|
||||
dma_addr_t addr, int offset)
|
||||
static void kvaser_pciefd_write_dma_map_altera(struct kvaser_pciefd *pcie,
|
||||
dma_addr_t addr, int index)
|
||||
{
|
||||
void __iomem *serdes_base;
|
||||
u32 word1, word2;
|
||||
|
||||
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
|
||||
word1 = addr | KVASER_PCIEFD_64BIT_DMA_BIT;
|
||||
word1 = addr | KVASER_PCIEFD_ALTERA_DMA_64BIT;
|
||||
word2 = addr >> 32;
|
||||
#else
|
||||
word1 = addr;
|
||||
word2 = 0;
|
||||
#endif
|
||||
iowrite32(word1, pcie->reg_base + offset);
|
||||
iowrite32(word2, pcie->reg_base + offset + 4);
|
||||
serdes_base = KVASER_PCIEFD_SERDES_ADDR(pcie) + 0x8 * index;
|
||||
iowrite32(word1, serdes_base);
|
||||
iowrite32(word2, serdes_base + 0x4);
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_write_dma_map_sf2(struct kvaser_pciefd *pcie,
|
||||
dma_addr_t addr, int index)
|
||||
{
|
||||
void __iomem *serdes_base;
|
||||
u32 lsb = addr & KVASER_PCIEFD_SF2_DMA_LSB_MASK;
|
||||
u32 msb = 0x0;
|
||||
|
||||
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
|
||||
msb = addr >> 32;
|
||||
#endif
|
||||
serdes_base = KVASER_PCIEFD_SERDES_ADDR(pcie) + 0x10 * index;
|
||||
iowrite32(lsb, serdes_base);
|
||||
iowrite32(msb, serdes_base + 0x4);
|
||||
}
|
||||
|
||||
static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
|
||||
|
@ -889,10 +1043,8 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
|
|||
dma_addr_t dma_addr[KVASER_PCIEFD_DMA_COUNT];
|
||||
|
||||
/* Disable the DMA */
|
||||
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG);
|
||||
iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
|
||||
for (i = 0; i < KVASER_PCIEFD_DMA_COUNT; i++) {
|
||||
unsigned int offset = KVASER_PCIEFD_DMA_MAP_BASE + 8 * i;
|
||||
|
||||
pcie->dma_data[i] = dmam_alloc_coherent(&pcie->pci->dev,
|
||||
KVASER_PCIEFD_DMA_SIZE,
|
||||
&dma_addr[i],
|
||||
|
@ -903,24 +1055,25 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
|
|||
KVASER_PCIEFD_DMA_SIZE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
kvaser_pciefd_write_dma_map(pcie, dma_addr[i], offset);
|
||||
pcie->driver_data->ops->kvaser_pciefd_write_dma_map(pcie, dma_addr[i], i);
|
||||
}
|
||||
|
||||
/* Reset Rx FIFO, and both DMA buffers */
|
||||
iowrite32(KVASER_PCIEFD_SRB_CMD_FOR | KVASER_PCIEFD_SRB_CMD_RDB0 |
|
||||
KVASER_PCIEFD_SRB_CMD_RDB1,
|
||||
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
/* Empty Rx FIFO */
|
||||
srb_packet_count =
|
||||
FIELD_GET(KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK,
|
||||
ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG));
|
||||
ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) +
|
||||
KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG));
|
||||
while (srb_packet_count) {
|
||||
/* Drop current packet in FIFO */
|
||||
ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_FIFO_LAST_REG);
|
||||
ioread32(KVASER_PCIEFD_SRB_FIFO_ADDR(pcie) + KVASER_PCIEFD_SRB_FIFO_LAST_REG);
|
||||
srb_packet_count--;
|
||||
}
|
||||
|
||||
srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG);
|
||||
srb_status = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_STAT_REG);
|
||||
if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DI)) {
|
||||
dev_err(&pcie->pci->dev, "DMA not idle before enabling\n");
|
||||
return -EIO;
|
||||
|
@ -928,7 +1081,7 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
|
|||
|
||||
/* Enable the DMA */
|
||||
iowrite32(KVASER_PCIEFD_SRB_CTRL_DMA_ENABLE,
|
||||
pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG);
|
||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -937,30 +1090,29 @@ static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie)
|
|||
{
|
||||
u32 version, srb_status, build;
|
||||
|
||||
version = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_VERSION_REG);
|
||||
version = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_VERSION_REG);
|
||||
pcie->nr_channels = min(KVASER_PCIEFD_MAX_CAN_CHANNELS,
|
||||
FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK, version));
|
||||
|
||||
build = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_BUILD_REG);
|
||||
build = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_BUILD_REG);
|
||||
dev_dbg(&pcie->pci->dev, "Version %lu.%lu.%lu\n",
|
||||
FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MAJOR_MASK, version),
|
||||
FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MINOR_MASK, version),
|
||||
FIELD_GET(KVASER_PCIEFD_SYSID_BUILD_SEQ_MASK, build));
|
||||
|
||||
srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG);
|
||||
srb_status = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_STAT_REG);
|
||||
if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DMA)) {
|
||||
dev_err(&pcie->pci->dev, "Hardware without DMA is not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pcie->bus_freq = ioread32(pcie->reg_base +
|
||||
KVASER_PCIEFD_SYSID_BUSFREQ_REG);
|
||||
pcie->freq = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_CANFREQ_REG);
|
||||
pcie->bus_freq = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_BUSFREQ_REG);
|
||||
pcie->freq = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_CANFREQ_REG);
|
||||
pcie->freq_to_ticks_div = pcie->freq / 1000000;
|
||||
if (pcie->freq_to_ticks_div == 0)
|
||||
pcie->freq_to_ticks_div = 1;
|
||||
/* Turn off all loopback functionality */
|
||||
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_LOOP_REG);
|
||||
iowrite32(0, KVASER_PCIEFD_LOOPBACK_ADDR(pcie));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1430,21 +1582,20 @@ static int kvaser_pciefd_read_buffer(struct kvaser_pciefd *pcie, int dma_buf)
|
|||
|
||||
static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
|
||||
{
|
||||
u32 irq;
|
||||
u32 irq = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||
|
||||
irq = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) {
|
||||
kvaser_pciefd_read_buffer(pcie, 0);
|
||||
/* Reset DMA buffer 0 */
|
||||
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0,
|
||||
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
}
|
||||
|
||||
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) {
|
||||
kvaser_pciefd_read_buffer(pcie, 1);
|
||||
/* Reset DMA buffer 1 */
|
||||
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1,
|
||||
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
}
|
||||
|
||||
if (irq & KVASER_PCIEFD_SRB_IRQ_DOF0 ||
|
||||
|
@ -1453,7 +1604,7 @@ static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
|
|||
irq & KVASER_PCIEFD_SRB_IRQ_DUF1)
|
||||
dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq);
|
||||
|
||||
iowrite32(irq, pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||
iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can)
|
||||
|
@ -1479,15 +1630,14 @@ static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can)
|
|||
static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev)
|
||||
{
|
||||
struct kvaser_pciefd *pcie = (struct kvaser_pciefd *)dev;
|
||||
u32 board_irq;
|
||||
const struct kvaser_pciefd_irq_mask *irq_mask = pcie->driver_data->irq_mask;
|
||||
u32 board_irq = ioread32(KVASER_PCIEFD_PCI_IRQ_ADDR(pcie));
|
||||
int i;
|
||||
|
||||
board_irq = ioread32(pcie->reg_base + KVASER_PCIEFD_IRQ_REG);
|
||||
|
||||
if (!(board_irq & KVASER_PCIEFD_IRQ_ALL_MASK))
|
||||
if (!(board_irq & irq_mask->all))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (board_irq & KVASER_PCIEFD_IRQ_SRB)
|
||||
if (board_irq & irq_mask->kcan_rx0)
|
||||
kvaser_pciefd_receive_irq(pcie);
|
||||
|
||||
for (i = 0; i < pcie->nr_channels; i++) {
|
||||
|
@ -1498,7 +1648,7 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev)
|
|||
}
|
||||
|
||||
/* Check that mask matches channel (i) IRQ mask */
|
||||
if (board_irq & (1 << i))
|
||||
if (board_irq & irq_mask->kcan_tx[i])
|
||||
kvaser_pciefd_transmit_irq(pcie->can[i]);
|
||||
}
|
||||
|
||||
|
@ -1525,6 +1675,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||
{
|
||||
int err;
|
||||
struct kvaser_pciefd *pcie;
|
||||
const struct kvaser_pciefd_irq_mask *irq_mask;
|
||||
void __iomem *irq_en_base;
|
||||
|
||||
pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
|
||||
if (!pcie)
|
||||
|
@ -1532,6 +1684,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||
|
||||
pci_set_drvdata(pdev, pcie);
|
||||
pcie->pci = pdev;
|
||||
pcie->driver_data = (const struct kvaser_pciefd_driver_data *)id->driver_data;
|
||||
irq_mask = pcie->driver_data->irq_mask;
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err)
|
||||
|
@ -1567,22 +1721,21 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||
goto err_teardown_can_ctrls;
|
||||
|
||||
iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1,
|
||||
pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||
|
||||
iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1 |
|
||||
KVASER_PCIEFD_SRB_IRQ_DOF0 | KVASER_PCIEFD_SRB_IRQ_DOF1 |
|
||||
KVASER_PCIEFD_SRB_IRQ_DUF0 | KVASER_PCIEFD_SRB_IRQ_DUF1,
|
||||
pcie->reg_base + KVASER_PCIEFD_SRB_IEN_REG);
|
||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG);
|
||||
|
||||
/* Enable PCI interrupts */
|
||||
iowrite32(KVASER_PCIEFD_IRQ_ALL_MASK,
|
||||
pcie->reg_base + KVASER_PCIEFD_IEN_REG);
|
||||
|
||||
irq_en_base = KVASER_PCIEFD_PCI_IEN_ADDR(pcie);
|
||||
iowrite32(irq_mask->all, irq_en_base);
|
||||
/* Ready the DMA buffers */
|
||||
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0,
|
||||
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1,
|
||||
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
|
||||
err = kvaser_pciefd_reg_candev(pcie);
|
||||
if (err)
|
||||
|
@ -1592,12 +1745,12 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||
|
||||
err_free_irq:
|
||||
/* Disable PCI interrupts */
|
||||
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_IEN_REG);
|
||||
iowrite32(0, irq_en_base);
|
||||
free_irq(pcie->pci->irq, pcie);
|
||||
|
||||
err_teardown_can_ctrls:
|
||||
kvaser_pciefd_teardown_can_ctrls(pcie);
|
||||
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG);
|
||||
iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
|
||||
pci_clear_master(pdev);
|
||||
|
||||
err_pci_iounmap:
|
||||
|
@ -1636,8 +1789,8 @@ static void kvaser_pciefd_remove(struct pci_dev *pdev)
|
|||
kvaser_pciefd_remove_all_ctrls(pcie);
|
||||
|
||||
/* Disable interrupts */
|
||||
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG);
|
||||
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_IEN_REG);
|
||||
iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
|
||||
iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
|
||||
|
||||
free_irq(pcie->pci->irq, pcie);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/bitfield.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
@ -308,6 +309,9 @@ enum m_can_reg {
|
|||
#define TX_EVENT_MM_MASK GENMASK(31, 24)
|
||||
#define TX_EVENT_TXTS_MASK GENMASK(15, 0)
|
||||
|
||||
/* Hrtimer polling interval */
|
||||
#define HRTIMER_POLL_INTERVAL_MS 1
|
||||
|
||||
/* The ID and DLC registers are adjacent in M_CAN FIFO memory,
|
||||
* and we can save a (potentially slow) bus round trip by combining
|
||||
* reads and writes to them.
|
||||
|
@ -1414,6 +1418,12 @@ static int m_can_start(struct net_device *dev)
|
|||
|
||||
m_can_enable_all_interrupts(cdev);
|
||||
|
||||
if (!dev->irq) {
|
||||
dev_dbg(cdev->dev, "Start hrtimer\n");
|
||||
hrtimer_start(&cdev->hrtimer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS),
|
||||
HRTIMER_MODE_REL_PINNED);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1568,6 +1578,11 @@ static void m_can_stop(struct net_device *dev)
|
|||
{
|
||||
struct m_can_classdev *cdev = netdev_priv(dev);
|
||||
|
||||
if (!dev->irq) {
|
||||
dev_dbg(cdev->dev, "Stop hrtimer\n");
|
||||
hrtimer_cancel(&cdev->hrtimer);
|
||||
}
|
||||
|
||||
/* disable all interrupts */
|
||||
m_can_disable_all_interrupts(cdev);
|
||||
|
||||
|
@ -1793,6 +1808,18 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
|
|||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer)
|
||||
{
|
||||
struct m_can_classdev *cdev = container_of(timer, struct
|
||||
m_can_classdev, hrtimer);
|
||||
|
||||
m_can_isr(0, cdev->net);
|
||||
|
||||
hrtimer_forward_now(timer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS));
|
||||
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
static int m_can_open(struct net_device *dev)
|
||||
{
|
||||
struct m_can_classdev *cdev = netdev_priv(dev);
|
||||
|
@ -1831,7 +1858,7 @@ static int m_can_open(struct net_device *dev)
|
|||
err = request_threaded_irq(dev->irq, NULL, m_can_isr,
|
||||
IRQF_ONESHOT,
|
||||
dev->name, dev);
|
||||
} else {
|
||||
} else if (dev->irq) {
|
||||
err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name,
|
||||
dev);
|
||||
}
|
||||
|
@ -2027,6 +2054,9 @@ int m_can_class_register(struct m_can_classdev *cdev)
|
|||
goto clk_disable;
|
||||
}
|
||||
|
||||
if (!cdev->net->irq)
|
||||
cdev->hrtimer.function = &hrtimer_callback;
|
||||
|
||||
ret = m_can_dev_setup(cdev);
|
||||
if (ret)
|
||||
goto rx_offload_del;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
@ -93,6 +94,8 @@ struct m_can_classdev {
|
|||
int is_peripheral;
|
||||
|
||||
struct mram_cfg mcfg[MRAM_CFG_NUM];
|
||||
|
||||
struct hrtimer hrtimer;
|
||||
};
|
||||
|
||||
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
//
|
||||
// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
|
||||
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
|
@ -82,7 +83,7 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
|||
void __iomem *addr;
|
||||
void __iomem *mram_addr;
|
||||
struct phy *transceiver;
|
||||
int irq, ret = 0;
|
||||
int irq = 0, ret = 0;
|
||||
|
||||
mcan_class = m_can_class_allocate_dev(&pdev->dev,
|
||||
sizeof(struct m_can_plat_priv));
|
||||
|
@ -96,12 +97,24 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
|||
goto probe_fail;
|
||||
|
||||
addr = devm_platform_ioremap_resource_byname(pdev, "m_can");
|
||||
irq = platform_get_irq_byname(pdev, "int0");
|
||||
if (IS_ERR(addr) || irq < 0) {
|
||||
ret = -EINVAL;
|
||||
if (IS_ERR(addr)) {
|
||||
ret = PTR_ERR(addr);
|
||||
goto probe_fail;
|
||||
}
|
||||
|
||||
if (device_property_present(mcan_class->dev, "interrupts") ||
|
||||
device_property_present(mcan_class->dev, "interrupt-names")) {
|
||||
irq = platform_get_irq_byname(pdev, "int0");
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto probe_fail;
|
||||
}
|
||||
} else {
|
||||
dev_dbg(mcan_class->dev, "Polling enabled, initialize hrtimer");
|
||||
hrtimer_init(&mcan_class->hrtimer, CLOCK_MONOTONIC,
|
||||
HRTIMER_MODE_REL_PINNED);
|
||||
}
|
||||
|
||||
/* message ram could be shared */
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
|
||||
if (!res) {
|
||||
|
|
|
@ -284,7 +284,7 @@ struct ucan_priv {
|
|||
*/
|
||||
spinlock_t echo_skb_lock;
|
||||
|
||||
/* usb device information information */
|
||||
/* usb device information */
|
||||
u8 intf_index;
|
||||
u8 in_ep_addr;
|
||||
u8 out_ep_addr;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/can/error.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#define DRIVER_NAME "xilinx_can"
|
||||
|
||||
|
@ -200,6 +201,7 @@ struct xcan_devtype_data {
|
|||
* @can_clk: Pointer to struct clk
|
||||
* @devtype: Device type specific constants
|
||||
* @transceiver: Optional pointer to associated CAN transceiver
|
||||
* @rstc: Pointer to reset control
|
||||
*/
|
||||
struct xcan_priv {
|
||||
struct can_priv can;
|
||||
|
@ -218,6 +220,7 @@ struct xcan_priv {
|
|||
struct clk *can_clk;
|
||||
struct xcan_devtype_data devtype;
|
||||
struct phy *transceiver;
|
||||
struct reset_control *rstc;
|
||||
};
|
||||
|
||||
/* CAN Bittiming constants as per Xilinx CAN specs */
|
||||
|
@ -1799,6 +1802,16 @@ static int xcan_probe(struct platform_device *pdev)
|
|||
priv->can.do_get_berr_counter = xcan_get_berr_counter;
|
||||
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
|
||||
CAN_CTRLMODE_BERR_REPORTING;
|
||||
priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(priv->rstc)) {
|
||||
dev_err(&pdev->dev, "Cannot get CAN reset.\n");
|
||||
ret = PTR_ERR(priv->rstc);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ret = reset_control_reset(priv->rstc);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
if (devtype->cantype == XAXI_CANFD) {
|
||||
priv->can.data_bittiming_const =
|
||||
|
@ -1827,7 +1840,7 @@ static int xcan_probe(struct platform_device *pdev)
|
|||
/* Get IRQ for the device */
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
goto err_free;
|
||||
goto err_reset;
|
||||
|
||||
ndev->irq = ret;
|
||||
|
||||
|
@ -1843,21 +1856,21 @@ static int xcan_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(priv->can_clk)) {
|
||||
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk),
|
||||
"device clock not found\n");
|
||||
goto err_free;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
|
||||
if (IS_ERR(priv->bus_clk)) {
|
||||
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk),
|
||||
"bus clock not found\n");
|
||||
goto err_free;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
transceiver = devm_phy_optional_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(transceiver)) {
|
||||
ret = PTR_ERR(transceiver);
|
||||
dev_err_probe(&pdev->dev, ret, "failed to get phy\n");
|
||||
goto err_free;
|
||||
goto err_reset;
|
||||
}
|
||||
priv->transceiver = transceiver;
|
||||
|
||||
|
@ -1904,6 +1917,8 @@ static int xcan_probe(struct platform_device *pdev)
|
|||
err_disableclks:
|
||||
pm_runtime_put(priv->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
err_reset:
|
||||
reset_control_assert(priv->rstc);
|
||||
err_free:
|
||||
free_candev(ndev);
|
||||
err:
|
||||
|
@ -1920,9 +1935,11 @@ err:
|
|||
static void xcan_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *ndev = platform_get_drvdata(pdev);
|
||||
struct xcan_priv *priv = netdev_priv(ndev);
|
||||
|
||||
unregister_candev(ndev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
reset_control_assert(priv->rstc);
|
||||
free_candev(ndev);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue