3559A原生CAN总线调试

我使用的SDK的版本是Hi3559AV100_SDK_V2.0.3.0,海思官方没有can的驱动。从网上下载了一个PATCH,这个patch需要感谢此github https://github.com/benfounder/Hi3559AV100_CAN

diff --git a/arch/arm64/boot/dts/hisilicon/hi3559av100.dtsi b/arch/arm64/boot/dts/hisilicon/hi3559av100.dtsi
index 117937f..b0b7e58 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3559av100.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi3559av100.dtsi
@@ -1342,5 +1342,26 @@
                 interrupt-names = "hi-wdg";
         };
 
+		can0: can@12070000 {
+                 compatible = "hisilicon,hisi-can";
+                 reg = <0x12070000 0x1000>;
+                 interrupts = <0 107 4>;
+                 interrupt-names = "hi-can0";
+        };
+
+		can1: can@12071000 {
+	             compatible = "hisilicon,hisi-can";
+                 reg = <0x12071000 0x1000>;
+                 interrupts = <0 108 4>;
+                 interrupt-names = "hi-can1";
+        };
+
+		can2: can@18040000 {
+                 compatible = "hisilicon,hisi-can";
+                 reg = <0x18040000 0x1000>;
+                 interrupts = <0 201 4>;
+                 interrupt-names = "hi-can2";
+        };
     };
+
 };
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 22570ea..30a6e03 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -70,6 +70,12 @@ config CAN_AT91
 	  This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
 	  and AT91SAM9X5 processors.
 
+config CAN_HISI
+	tristate "Hisilicon 3559AV100 CAN controller"
+	depends on ARCH_HI3559AV100
+	---help---
+	  This is the driver for the SoC CAN controller in Hisilicon 3559AV100 processor.
+
 config CAN_BFIN
 	depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
 	tristate "Analog Devices Blackfin on-chip CAN"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 26ba4b7..171e316 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -30,6 +30,7 @@ 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_HISI)      += hi3559av100_can.o
 
 subdir-ccflags-y += -D__CHECK_ENDIAN__
 subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG
diff --git a/drivers/net/can/hi3559av100_can.c b/drivers/net/can/hi3559av100_can.c
new file mode 100644
index 0000000..f53f56d
--- /dev/null
+++ b/drivers/net/can/hi3559av100_can.c
@@ -0,0 +1,691 @@
+/*
+ * hi3559av100_can.c - CAN network driver for Hisilicon 3559A Soc CAN controller
+ *
+ * (C) 2018 by Ben Wang <benfounder@gmail.com>
+ *
+ * This software may be distributed under the terms of GNU General
+ * Public License ("GPL") version 2 as distributed in the 'COPYING'
+ * file from the main directory of the linux kernel source.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rtnetlink.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/printk.h>
+#include <linux/spinlock.h>
+
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/led.h>
+
+#define CAN_CONTROL              0x0000
+#define CAN_STATUS               0x0004
+#define CAN_ERROR_COUNTER        0x0008
+#define BIT_TIMING               0x000C
+#define CAN_INTERRUPT            0x0010
+#define CAN_TEST                 0x0014
+#define BRP_EXTENSION            0x0018
+#define IF1_COMMAND_REQUEST      0x0020
+#define IF1_COMMAND_MASK         0x0024
+#define IF1_MASK1                0x0028
+#define IF1_MASK2                0x002C
+#define IF1_ARBITRATION1         0x0030
+#define IF1_ARBITRATION2         0x0034
+#define IF1_MESSAGE_CONTROL      0x0038
+#define IF1_DATAA1               0x003C
+#define IF1_DATAA2               0x0040
+#define IF1_DATAB1               0x0044
+#define IF1_DATAB2               0x0048
+#define IF2_COMMAND_REQUEST      0x0080
+#define IF2_COMMAND_MASK         0x0084
+#define IF2_MASK1                0x0088
+#define IF2_MASK2                0x008C
+#define IF2_ARBITRATION1         0x0090
+#define IF2_ARBITRATION2         0x0094
+#define IF2_MESSAGE_CONTROL      0x0098
+#define IF2_DATAA1               0x009C
+#define IF2_DATAA2               0x00A0
+#define IF2_DATAB1               0x00A4
+#define IF2_DATAB2               0x00A8
+#define TRANSMISSION_REQUEST1    0x0100
+#define TRANSMISSION_REQUEST2    0x0104
+#define NEW_DATA1                0x0120
+#define NEW_DATA2                0x0124
+#define INTERRUPT_PENDING1       0x0140
+#define INTERRUPT_PENDING2       0x0144
+#define MESSAGE_VALID1           0x0160
+#define MESSAGE_VALID2           0x0164
+
+struct hisi_can_priv {
+    struct can_priv can;		/* must be the first member */
+    void __iomem *reg_base;
+    spinlock_t lock;
+    u32 free_mailbox;
+    u32 can_status;
+};
+
+static u32 std_recv_map = 0x00000FFF;
+static u32 ext_recv_map = 0x00FFF000;
+static u32 all_send_map = 0xFF000000;
+static u8  send_start_index = 24;
+
+static void hisi_can_init(struct hisi_can_priv *priv)
+{
+    u32 index, reg;
+    const struct can_bittiming *bt = &(priv->can.bittiming);
+
+    /* Step 1 */
+    writel(0x01, priv->reg_base+CAN_CONTROL);
+    /* Step 2 */
+    writel(0xF3, priv->reg_base+IF1_COMMAND_MASK);
+    for (index = 1; index <= 32; index++) {
+        /* Step 3 */
+        writel(index, priv->reg_base+IF1_COMMAND_REQUEST);
+        /* Step 4 */
+        do {
+            reg = readl(priv->reg_base+IF1_COMMAND_REQUEST);
+        } while (reg & 0x8000);
+    }
+    /* Step 5 */
+    writel(0x41, priv->reg_base+CAN_CONTROL);
+    /* Step 6 */
+    reg = 0;
+    reg |= (bt->phase_seg2 - 1) << 12;
+    reg |= (bt->phase_seg1 + bt->prop_seg - 1) << 8;
+    reg |= (bt->sjw - 1) << 6;
+    reg |= (bt->brp - 1);
+    writel(reg, priv->reg_base+BIT_TIMING);
+    /* Step 7 */
+    writel(0x0F, priv->reg_base+CAN_CONTROL);
+    /* Step 8 */
+    writel(0x0E, priv->reg_base+CAN_CONTROL);
+    return;
+}
+
+static void hisi_can_uninit(struct hisi_can_priv *priv)
+{
+    /* Step 1 */
+    writel(0x01, priv->reg_base+CAN_CONTROL);
+    return;
+}
+
+static int hisi_can_preread(struct hisi_can_priv *priv, u8 index)
+{
+    u32 reg;
+    u32 map = 1;
+    u8 end;
+
+    /* Step 1 */
+    map <<= index - 1;
+    if (0 != (map & std_recv_map)) {
+        writel(0x8000, priv->reg_base+IF2_ARBITRATION2);
+        writel(0x0000, priv->reg_base+IF2_ARBITRATION1);
+        map <<= 1;
+        if (0 == (map & std_recv_map))
+            end = 1;
+        else
+            end = 0;
+    } else if (0 != (map & ext_recv_map)) {
+        writel(0xC000, priv->reg_base+IF2_ARBITRATION2);
+        writel(0x0000, priv->reg_base+IF2_ARBITRATION1);
+        if (0 == (map & ext_recv_map))
+            end = 1;
+        else
+            end = 0;
+    }
+#if 0
+    else if (index <= 15) {
+        writel(0x9000, priv->reg_base+IF2_ARBITRATION2);
+        writel(0x0000, priv->reg_base+IF2_ARBITRATION1);
+    } else if (index <= 16) {
+        writel(0xE000, priv->reg_base+IF2_ARBITRATION2);
+        writel(0x0000, priv->reg_base+IF2_ARBITRATION1);
+    }
+#endif
+    else {
+        return -1;
+    }
+    /* Step 2 */
+    writel(0xD000, priv->reg_base+IF2_MASK2);
+    /* Step 3 */
+    writel(0xFFFF, priv->reg_base+IF2_MASK1);
+    /* Step 4 */
+    if (end) {
+        writel(0x1488, priv->reg_base+IF2_MESSAGE_CONTROL);
+    } else {
+        writel(0x1408, priv->reg_base+IF2_MESSAGE_CONTROL);
+    }
+    /* Step 5 */
+    writel(0x00F3, priv->reg_base+IF2_COMMAND_MASK);
+    /* Step 6 */
+    reg = index;
+    reg |= 0x8000;
+    reg &= 0x803F;
+    writel(reg, priv->reg_base+IF2_COMMAND_REQUEST);
+    return 0;
+}
+
+static void hisi_can_read(struct hisi_can_priv *priv, u8 index, struct can_frame *cf)
+{
+    u32 reg;
+
+    /* Step 1 */
+    writel(0x7F, priv->reg_base+IF2_COMMAND_MASK);
+    /* Step 2 */
+    reg = index;
+    reg |= 0x8000;
+    reg &= 0x803F;
+    writel(reg, priv->reg_base+IF2_COMMAND_REQUEST);
+    /* Step 3 */
+    do {
+        reg = readl(priv->reg_base+IF2_COMMAND_REQUEST);
+    } while (reg & 0x8000);
+    /* Step 4 */
+    reg = readl(priv->reg_base+IF2_ARBITRATION2);
+    if (reg & 0x4000) {
+        /* Extended Frame */
+        cf->can_id = readl(priv->reg_base+IF2_ARBITRATION1) & 0xFFFF;
+        reg &= 0x1FFF;
+        reg <<= 16;
+        cf->can_id |= reg;
+    } else {
+        /* Standard Frame */
+        reg = (reg >> 2) & 0x7FF;
+        cf->can_id = reg;
+    }
+    reg = readl(priv->reg_base+IF2_MESSAGE_CONTROL);
+    cf->can_dlc = (u8)(reg & 0xF);
+    reg = readl(priv->reg_base+IF2_DATAA1);
+    cf->data[0] = (u8)(reg & 0xFF);
+    cf->data[1] = (u8)((reg >> 8) & 0xFF);
+    reg = readl(priv->reg_base+IF2_DATAA2);
+    cf->data[2] = (u8)(reg & 0xFF);
+    cf->data[3] = (u8)((reg >> 8) & 0xFF);
+    reg = readl(priv->reg_base+IF2_DATAB1);
+    cf->data[4] = (u8)(reg & 0xFF);
+    cf->data[5] = (u8)((reg >> 8) & 0xFF);
+    reg = readl(priv->reg_base+IF2_DATAB2);
+    cf->data[6] = (u8)(reg & 0xFF);
+    cf->data[7] = (u8)((reg >> 8) & 0xFF);
+    return;
+}
+
+static void hisi_can_write_finish(struct hisi_can_priv *priv, u8 index)
+{
+    u32 reg;
+
+    /* Step 1 */
+    writel(0x7F, priv->reg_base + IF2_COMMAND_MASK);
+    /* Step 2 */
+    reg = index;
+    reg |= 0x8000;
+    reg &= 0x803F;
+    writel(reg, priv->reg_base + IF2_COMMAND_REQUEST);
+    /* Step 3 */
+    do {
+        reg = readl(priv->reg_base + IF2_COMMAND_REQUEST);
+    } while (reg & 0x8000);
+
+    return;
+}
+
+static void hisi_can_write(struct hisi_can_priv *priv, u8 index, struct can_frame *cf)
+{
+    u32 reg;
+
+    /* Step 1 */
+    if (cf->can_id & CAN_EFF_FLAG) {
+        if (cf->can_id & CAN_RTR_FLAG) {
+            /* Remote EFF */
+            reg = ((cf->can_id & CAN_EFF_MASK) >> 16) | 0xC000;
+        } else {
+            /* Data EFF */
+            reg = ((cf->can_id & CAN_EFF_MASK) >> 16) | 0xE000;
+        }
+        writel(reg, priv->reg_base + IF1_ARBITRATION2);
+        reg = (cf->can_id & CAN_EFF_MASK) & 0xFFFF;
+        writel(reg, priv->reg_base + IF1_ARBITRATION1);
+    } else {
+        if (cf->can_id & CAN_RTR_FLAG) {
+            /* Remote SFF */
+            reg = (cf->can_id & CAN_SFF_MASK) << 2 | 0x8000;
+        } else {
+            /* Data SFF */
+            reg = (cf->can_id & CAN_SFF_MASK) << 2 | 0xA000;
+        }
+        writel(reg, priv->reg_base + IF1_ARBITRATION2);
+        writel(0, priv->reg_base + IF1_ARBITRATION1);
+    }
+    /* Step 2 */
+    writel(0xDFFF, priv->reg_base + IF1_MASK2);
+    /* Step 3 */
+    writel(0xFFFF, priv->reg_base + IF1_MASK1);
+    /* Step 4 */
+    reg = 0x8980 | cf->can_dlc;
+    writel(reg, priv->reg_base + IF1_MESSAGE_CONTROL);
+    /* Step 5 */
+    reg = ((u32)cf->data[1]) << 8;
+    reg |= (u32)cf->data[0];
+    writel(reg, priv->reg_base + IF1_DATAA1);
+    reg = ((u32)cf->data[3]) << 8;
+    reg |= (u32)cf->data[2];
+    writel(reg, priv->reg_base + IF1_DATAA2);
+    reg = ((u32)cf->data[5]) << 8;
+    reg |= (u32)cf->data[4];
+    writel(reg, priv->reg_base + IF1_DATAB1);
+    reg = ((u32)cf->data[7]) << 8;
+    reg |= (u32)cf->data[6];
+    writel(reg, priv->reg_base + IF1_DATAB2);
+    /* Step 6 */
+    writel(0x00F3, priv->reg_base + IF1_COMMAND_MASK);
+    /* Step 7 */
+    reg = 0x8000 | index;
+    writel(reg, priv->reg_base + IF1_COMMAND_REQUEST);
+
+    return;
+}
+
+static irqreturn_t hisi_can_irq(int irq, void *dev_id)
+{
+    struct net_device *dev = dev_id;
+    struct hisi_can_priv *priv = netdev_priv(dev);
+    struct net_device_stats *stats = &(dev->stats);
+    irqreturn_t handled = IRQ_NONE;
+    struct sk_buff *skb;
+    struct can_frame *cf;
+    u32 reg_status, reg_interrupt, reg_tmp, reg_pending, index, tmp;
+    unsigned long flags;
+
+    reg_interrupt = readl(priv->reg_base + CAN_INTERRUPT);
+    handled = IRQ_HANDLED;
+    //printk(KERN_ERR "%s:%d reg_interrupt 0x%x\n", __FUNCTION__, __LINE__, reg_interrupt);
+    /* Check Error */
+    if (reg_interrupt == 0x8000) {
+        reg_status = readl(priv->reg_base + CAN_STATUS);
+        //printk(KERN_ERR "%s:%d reg_status 0x%x\n", __FUNCTION__, __LINE__, reg_status);
+        writel(0x7, priv->reg_base + CAN_STATUS);
+        reg_tmp = priv->can_status ^ reg_status;
+        if (reg_tmp & 0x80) {
+            /* Boff change */
+            if (reg_status & 0x80) {
+                /* bus-off */
+                netdev_dbg(dev, "bus-off\n");
+                netif_carrier_off(dev);
+                /* error msg */
+#if 0
+                skb = alloc_can_err_skb(dev, &cf);
+                if (unlikely(!skb))
+                    goto exit;
+
+                cf->can_id |= CAN_ERR_CRTL;
+                cf->data[1] = CAN_ERR_CRTL
+
+                              dev->stats.rx_packets++;
+                dev->stats.rx_bytes += cf->can_dlc;
+                netif_rx(skb);
+                hisi_can_error(cf);
+#endif
+                /* restart controller */
+                reg_tmp = readl(priv->reg_base + CAN_CONTROL);
+                reg_tmp |= 0x1;
+                writel(reg_tmp, priv->reg_base + CAN_CONTROL);
+                reg_tmp &= 0xFFFFFFFE;
+                writel(reg_tmp, priv->reg_base + CAN_CONTROL);
+            } else {
+                /* bus-on */
+                netdev_dbg(dev, "restarted\n");
+                netif_carrier_on(dev);
+                netif_wake_queue(dev);
+            }
+        }
+#if 0
+        if (reg_tmp & 0x20) {
+            /* Epass change */
+            if (reg_status & 0x20) {
+                /* Passive Error */
+            } else {
+
+            }
+        }
+        if (reg_tmp & 0x40) {
+            /* Ewarn change */
+            new_state = CAN_STATE_ERROR_WARNING;
+        }
+#endif
+        priv->can_status = reg_status;
+    } else if ((reg_interrupt <= 0x20) && (reg_interrupt > 0)) {
+        /* Clean Interrupt */
+        //readl(priv->reg_base + IF2_COMMAND_MASK);
+        //readl(priv->reg_base + IF2_COMMAND_REQUEST);
+        reg_tmp = readl(priv->reg_base + INTERRUPT_PENDING1);
+        reg_pending = reg_tmp;
+        reg_tmp = readl(priv->reg_base + INTERRUPT_PENDING2);
+        reg_pending |= reg_tmp << 16;
+
+        /* Check Transmit Complete */
+        reg_tmp  = reg_pending & all_send_map;
+        //printk(KERN_ERR "%s:%d TX pending 0x%x\n", __FUNCTION__, __LINE__, reg_tmp);
+        if (reg_tmp) {
+            for (index = send_start_index; index < 32; index++) {
+                if (reg_tmp & (1UL << index)) {
+                    hisi_can_write_finish(priv, index + 1);
+                    can_get_echo_skb(dev, (index - send_start_index));
+                    stats->tx_packets++;
+                    can_led_event(dev, CAN_LED_EVENT_TX);
+                    spin_lock_irqsave(&(priv->lock), flags);
+                    tmp = priv->free_mailbox;
+                    priv->free_mailbox |= 1UL << index;
+                    if (0 == tmp)
+                        netif_wake_queue(dev);
+                    spin_unlock_irqrestore(&(priv->lock), flags);
+                }
+            }
+        }
+
+        /* Check Receive Complete */
+        reg_tmp = reg_pending & std_recv_map;
+        //printk(KERN_ERR "%s:%d RX pending 0x%x\n", __FUNCTION__, __LINE__, reg_tmp);
+        if (reg_tmp) {
+            for (index = 0; index < send_start_index; index++) {
+                if (reg_tmp & (1UL << index)) {
+                    skb = alloc_can_skb(dev, &cf);
+                    if (unlikely(!skb)) {
+                        stats->rx_dropped++;
+                        printk(KERN_ERR "%s:%d Should never happen\n", __FUNCTION__, __LINE__);
+                        goto exit;
+                    }
+                    hisi_can_read(priv, index + 1, cf);
+                    hisi_can_preread(priv, index + 1);
+                    stats->rx_packets++;
+                    stats->rx_bytes += cf->can_dlc;
+                    netif_rx(skb);
+                    can_led_event(dev, CAN_LED_EVENT_RX);
+                }
+            }
+        }
+    }
+
+exit:
+    return handled;
+}
+
+static int hisi_can_open(struct net_device *dev)
+{
+    struct hisi_can_priv *priv = netdev_priv(dev);
+    int err;
+    u8 index;
+
+    /* check or determing and set bittime */
+    err = open_candev(dev);
+    if (err)
+        goto out_close;
+
+    /* register interrupt handler */
+    if (request_irq(dev->irq, hisi_can_irq, IRQF_SHARED, dev->name, dev)) {
+        err = -EAGAIN;
+        goto out_close;
+    }
+
+    can_led_event(dev, CAN_LED_EVENT_OPEN);
+
+    /* start chip and queuing */
+    hisi_can_init(priv);
+    priv->free_mailbox = all_send_map;
+    spin_lock_init(&(priv->lock));
+    netif_start_queue(dev);
+
+    for (index = 0; index < 32; index ++) {
+        if (std_recv_map & (1UL << index)) {
+            //printk(KERN_ERR "Listen standard data packet on mailbox %u\n", index+1);
+            hisi_can_preread(priv, index+1);
+        } else
+            break;
+    }
+
+    return 0;
+
+out_close:
+    close_candev(dev);
+
+    return err;
+}
+
+static int hisi_can_close(struct net_device *dev)
+{
+    struct hisi_can_priv *priv = netdev_priv(dev);
+
+    netif_stop_queue(dev);
+    hisi_can_uninit(priv);
+
+    free_irq(dev->irq, dev);
+
+    close_candev(dev);
+
+    can_led_event(dev, CAN_LED_EVENT_STOP);
+
+    return 0;
+}
+
+static netdev_tx_t hisi_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    struct hisi_can_priv *priv = netdev_priv(dev);
+    struct net_device_stats *stats = &dev->stats;
+    struct can_frame *cf = (struct can_frame *)skb->data;
+    unsigned long flags;
+    u8 index;
+
+    if (can_dropped_invalid_skb(dev, skb))
+        return NETDEV_TX_OK;
+
+    spin_lock_irqsave(&(priv->lock), flags);
+    //printk(KERN_ERR "%s:%d free_mailbox 0x%08x\n", __FUNCTION__, __LINE__, priv->free_mailbox);
+    for (index = send_start_index; index < 32; index ++) {
+        if (priv->free_mailbox & (1UL << index)) {
+            priv->free_mailbox &= ~(1UL << index);
+            break;
+        }
+    }
+    spin_unlock_irqrestore(&(priv->lock), flags);
+
+    if (unlikely(index == 32)) {
+        netif_stop_queue(dev);
+        netdev_err(dev, "BUG! TX buffer full when queue awake (0x%08x)!\n", priv->free_mailbox);
+        return NETDEV_TX_BUSY;
+    }
+
+    can_put_echo_skb(skb, dev, (index - send_start_index));
+
+    hisi_can_write(priv, index+1, cf);
+
+    stats->tx_bytes += cf->can_dlc;
+
+    return NETDEV_TX_OK;
+}
+
+static int hisi_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+    struct hisi_can_priv *priv = netdev_priv(dev);
+
+    switch (mode) {
+    case CAN_MODE_START:
+        hisi_can_init(priv);
+        netif_wake_queue(dev);
+        break;
+    default:
+        return -EOPNOTSUPP;
+    }
+    return 0;
+}
+
+static int hisi_can_get_berr_counter(const struct net_device *dev,
+                                     struct can_berr_counter *bec)
+{
+    const struct hisi_can_priv *priv = netdev_priv(dev);
+    u32 reg;
+    reg = readl(priv->reg_base+CAN_ERROR_COUNTER) & 0x7FFF;
+    bec->rxerr = (u16)(reg >> 8);
+    bec->txerr = (u16)(reg & 0xFF);
+    return 0;
+}
+
+static const struct can_bittiming_const hisi_bittiming_const = {
+    .name      = KBUILD_MODNAME,
+    .tseg1_min = 1,
+    .tseg1_max = 16,
+    .tseg2_min = 1,
+    .tseg2_max = 8,
+    .sjw_max   = 4,
+    .brp_min   = 1,
+    .brp_max   = 64,
+    .brp_inc   = 1,
+};
+
+static const struct net_device_ops hisi_can_netdev_ops = {
+    .ndo_open = hisi_can_open,
+    .ndo_stop = hisi_can_close,
+    .ndo_start_xmit = hisi_can_start_xmit,
+    .ndo_change_mtu = can_change_mtu,
+};
+
+static int hisi_can_set_bittiming(struct net_device *dev)
+{
+    struct hisi_can_priv *priv = netdev_priv(dev);
+
+    hisi_can_init(priv);
+    return 0;
+}
+
+static int hisi_can_probe(struct platform_device *pdev)
+{
+    struct net_device *dev;
+    struct hisi_can_priv *priv;
+    struct resource *res;
+    void __iomem *addr;
+    int err, irq;
+
+    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+    irq = platform_get_irq(pdev, 0);
+    if (!res || irq <= 0) {
+        err = -ENODEV;
+        goto exit;
+    }
+
+    if (!request_mem_region(res->start,
+                            resource_size(res),
+                            pdev->name)) {
+        err = -EBUSY;
+        goto exit;
+    }
+
+    addr = ioremap_nocache(res->start, resource_size(res));
+    if (!addr) {
+        err = -ENOMEM;
+        goto exit_release;
+    }
+
+    dev = alloc_candev(sizeof(struct hisi_can_priv), 16);
+    if (!dev) {
+        err = -ENOMEM;
+        goto exit_iounmap;
+    }
+
+    dev->netdev_ops = &hisi_can_netdev_ops;
+    dev->irq = irq;
+    dev->flags |= IFF_ECHO;
+
+    priv = netdev_priv(dev);
+    priv->reg_base = addr;
+    priv->can.clock.freq = 50000000;
+    priv->can.bittiming_const = &hisi_bittiming_const;
+    priv->can.do_set_bittiming = &hisi_can_set_bittiming;
+    priv->can.do_set_mode = hisi_can_set_mode;
+    priv->can.do_get_berr_counter = hisi_can_get_berr_counter;
+    priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY;
+
+    platform_set_drvdata(pdev, dev);
+    SET_NETDEV_DEV(dev, &pdev->dev);
+
+    err = register_candev(dev);
+    if (err) {
+        dev_err(&pdev->dev, "registering netdev failed\n");
+        goto exit_free;
+    }
+
+    devm_can_led_init(dev);
+
+    dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
+             priv->reg_base, dev->irq);
+
+    return 0;
+
+exit_free:
+    free_candev(dev);
+exit_iounmap:
+    iounmap(addr);
+exit_release:
+    release_mem_region(res->start, resource_size(res));
+exit:
+    return err;
+}
+
+static int hisi_can_remove(struct platform_device *pdev)
+{
+    struct net_device *dev = platform_get_drvdata(pdev);
+    struct hisi_can_priv *priv = netdev_priv(dev);
+    struct resource *res;
+
+    unregister_netdev(dev);
+
+    iounmap(priv->reg_base);
+
+    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+    release_mem_region(res->start, resource_size(res));
+
+    free_candev(dev);
+
+    return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id hisi_can_dt_ids[] = {
+    {
+        .compatible = "hisilicon,hisi-can",
+    }, {
+        /* sentinel */
+    }
+};
+MODULE_DEVICE_TABLE(of, hisi_can_dt_ids);
+#endif
+
+static const struct platform_device_id hisi_can_id_table[] = {
+    {
+        .name = "hisi_can",
+    }, {
+        /* sentinel */
+    }
+};
+MODULE_DEVICE_TABLE(platform, hisi_can_id_table);
+
+static struct platform_driver hisi_can_driver = {
+    .probe = hisi_can_probe,
+    .remove = hisi_can_remove,
+    .driver = {
+        .name = "hisi_can",
+        .of_match_table = of_match_ptr(hisi_can_dt_ids),
+    },
+    .id_table = hisi_can_id_table,
+};
+
+module_platform_driver(hisi_can_driver);
+
+MODULE_AUTHOR("Ben Wang <benfounder@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(KBUILD_MODNAME " Hi3559AV100 CAN driver");

然后   cp arch/arm64/configs/hi3559av100_arm64_big_little_emmc_defconfig .config

 make ARCH=arm64 CROSS_COMPILE=aarch64-himix100-linux- menuconfig

之后重新编译 内核即可

配置CAN1,波特率100000

ip link set can1 down 
ip link set can1 type can bitrate 100000
ip -details link show can1
ip link set can1 up

发送CAN信息

cansend can1 1f334455#1122334455667788_B

接受ID为123 的can标准帧

candump can1,123:7ff

接收到CAN信息

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值