From: Martin Sperl <ker...@martin.sperl.org>

This commit adds basic driver support for the Microchip MCP25XXFD
CAN-FD controller series. This driver currently supports MCP2517FD as the
target controller.

The MCP2517FD is capable of transmitting and receiving standard data
frames, extended data frames, remote frames and Can-FD frames.
The MCP2517FD interfaces with the host over SPI.

This commit provides basic driver functionality such as setting up clocks,
regulators and the infrastructure for the CAN.

Datasheet:
* http://ww1.microchip.com/downloads/en/DeviceDoc/20005688A.pdf
Reference manual:
* http://ww1.microchip.com/downloads/en/DeviceDoc/20005678A.pdf
Errata:
* 
http://ww1.microchip.com/downloads/en/DeviceDoc/MCP2517FD-Silicon-Errata-and-Data-Sheet-Clarification-DS80000792A.pdf

Signed-off-by: Martin Sperl <ker...@martin.sperl.org>
[mani: trimmed the gpio part and done some cleanups]
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasi...@linaro.org>
---
 drivers/net/can/spi/Kconfig                   |   2 +
 drivers/net/can/spi/Makefile                  |   2 +
 drivers/net/can/spi/mcp25xxfd/Kconfig         |   5 +
 drivers/net/can/spi/mcp25xxfd/Makefile        |   7 +
 .../net/can/spi/mcp25xxfd/mcp25xxfd_base.c    | 171 +++++
 .../net/can/spi/mcp25xxfd/mcp25xxfd_base.h    |  14 +
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c | 141 ++++
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h |  16 +
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c | 226 ++++++
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h |  84 +++
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c |  31 +
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h |  15 +
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c |  74 ++
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h |  16 +
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c |  59 ++
 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h |  15 +
 .../net/can/spi/mcp25xxfd/mcp25xxfd_priv.h    |  48 ++
 .../net/can/spi/mcp25xxfd/mcp25xxfd_regs.h    | 656 ++++++++++++++++++
 18 files changed, 1582 insertions(+)
 create mode 100644 drivers/net/can/spi/mcp25xxfd/Kconfig
 create mode 100644 drivers/net/can/spi/mcp25xxfd/Makefile
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.c
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.h
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_priv.h
 create mode 100644 drivers/net/can/spi/mcp25xxfd/mcp25xxfd_regs.h

diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
index 1c50788055cb..d4b68eb5d386 100644
--- a/drivers/net/can/spi/Kconfig
+++ b/drivers/net/can/spi/Kconfig
@@ -15,4 +15,6 @@ config CAN_MCP251X
          Driver for the Microchip MCP251x and MCP25625 SPI CAN
          controllers.
 
+source "drivers/net/can/spi/mcp25xxfd/Kconfig"
+
 endmenu
diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
index f115b2c46623..f56514541ce4 100644
--- a/drivers/net/can/spi/Makefile
+++ b/drivers/net/can/spi/Makefile
@@ -6,3 +6,5 @@
 
 obj-$(CONFIG_CAN_HI311X)       += hi311x.o
 obj-$(CONFIG_CAN_MCP251X)      += mcp251x.o
+
+obj-y                           += mcp25xxfd/
diff --git a/drivers/net/can/spi/mcp25xxfd/Kconfig 
b/drivers/net/can/spi/mcp25xxfd/Kconfig
new file mode 100644
index 000000000000..f720f1377612
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/Kconfig
@@ -0,0 +1,5 @@
+config CAN_MCP25XXFD
+       tristate "Microchip MCP25xxFD SPI CAN controllers"
+       depends on HAS_DMA
+       help
+         Driver for the Microchip MCP25XXFD SPI FD-CAN controller family.
diff --git a/drivers/net/can/spi/mcp25xxfd/Makefile 
b/drivers/net/can/spi/mcp25xxfd/Makefile
new file mode 100644
index 000000000000..d8fdb76a9578
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_CAN_MCP25XXFD)    += mcp25xxfd.o
+mcp25xxfd-objs                  := mcp25xxfd_base.o
+mcp25xxfd-objs                  += mcp25xxfd_can.o
+mcp25xxfd-objs                  += mcp25xxfd_cmd.o
+mcp25xxfd-objs                  += mcp25xxfd_crc.o
+mcp25xxfd-objs                  += mcp25xxfd_ecc.o
+mcp25xxfd-objs                  += mcp25xxfd_int.o
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.c 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.c
new file mode 100644
index 000000000000..4be456df0998
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "mcp25xxfd_base.h"
+#include "mcp25xxfd_can.h"
+#include "mcp25xxfd_cmd.h"
+#include "mcp25xxfd_ecc.h"
+#include "mcp25xxfd_int.h"
+#include "mcp25xxfd_priv.h"
+
+int mcp25xxfd_base_power_enable(struct regulator *reg, int enable)
+{
+       if (enable)
+               return regulator_enable(reg);
+       else
+               return regulator_disable(reg);
+}
+
+static const struct of_device_id mcp25xxfd_of_match[] = {
+       {
+               .compatible     = "microchip,mcp2517fd",
+               .data           = (void *)CAN_MCP2517FD,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mcp25xxfd_of_match);
+
+static int mcp25xxfd_base_probe(struct spi_device *spi)
+{
+       const struct of_device_id *of_id =
+               of_match_device(mcp25xxfd_of_match, &spi->dev);
+       struct mcp25xxfd_priv *priv;
+       struct clk *clk;
+       enum mcp25xxfd_model model;
+       u32 freq;
+       int ret;
+
+       /* Check whether valid IRQ line is defined or not */
+       if (spi->irq <= 0) {
+               dev_err(&spi->dev, "no valid irq line defined: irq = %i\n",
+                       spi->irq);
+               return -EINVAL;
+       }
+
+       priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, priv);
+       priv->spi = spi;
+
+       /* Assign device name */
+       snprintf(priv->device_name, sizeof(priv->device_name),
+                DEVICE_NAME "-%s", dev_name(&priv->spi->dev));
+
+       /* assign model from of or driver_data */
+       if (of_id)
+               model = (enum mcp25xxfd_model)of_id->data;
+       else
+               model = spi_get_device_id(spi)->driver_data;
+
+       clk = devm_clk_get(&spi->dev, NULL);
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
+               goto out_free;
+       }
+
+       freq = clk_get_rate(clk);
+       if (!(freq == CLOCK_4_MHZ || freq == CLOCK_10_MHZ ||
+             freq == CLOCK_40_MHZ)) {
+               ret = -ERANGE;
+               goto out_free;
+       }
+
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               goto out_free;
+
+       priv->clk = clk;
+       priv->clock_freq = freq;
+
+       /* Configure the SPI bus */
+       spi->bits_per_word = 8;
+
+       /* The frequency of SCK has to be less than or equal to half the
+        * frequency of SYSCLK.
+        */
+       spi->max_speed_hz = freq / 2;
+       ret = spi_setup(spi);
+       if (ret)
+               goto out_clk;
+
+       priv->power = devm_regulator_get(&spi->dev, "vdd");
+       if (IS_ERR(priv->power)) {
+               if (PTR_ERR(priv->power) != -EPROBE_DEFER)
+                       dev_err(&spi->dev, "failed to get vdd\n");
+               ret = PTR_ERR(priv->power);
+               goto out_clk;
+       }
+
+       ret = mcp25xxfd_base_power_enable(priv->power, 1);
+       if (ret)
+               goto out_clk;
+
+       /* disable interrupts */
+       ret = mcp25xxfd_int_enable(priv, false);
+       if (ret)
+               goto out_power;
+
+       /* setup ECC for SRAM */
+       ret = mcp25xxfd_ecc_enable(priv);
+       if (ret)
+               goto out_power;
+
+       dev_info(&spi->dev,
+                "MCP%04x successfully initialized.\n", model);
+       return 0;
+
+out_power:
+       mcp25xxfd_base_power_enable(priv->power, 0);
+out_clk:
+       clk_disable_unprepare(clk);
+out_free:
+       dev_err(&spi->dev, "Probe failed, err=%d\n", -ret);
+       return ret;
+}
+
+static int mcp25xxfd_base_remove(struct spi_device *spi)
+{
+       struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
+
+       mcp25xxfd_base_power_enable(priv->power, 0);
+       clk_disable_unprepare(priv->clk);
+
+       return 0;
+}
+
+static const struct spi_device_id mcp25xxfd_id_table[] = {
+       {
+               .name           = "mcp2517fd",
+               .driver_data    = (kernel_ulong_t)CAN_MCP2517FD,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, mcp25xxfd_id_table);
+
+static struct spi_driver mcp25xxfd_can_driver = {
+       .driver = {
+               .name = DEVICE_NAME,
+               .of_match_table = mcp25xxfd_of_match,
+       },
+       .id_table = mcp25xxfd_id_table,
+       .probe = mcp25xxfd_base_probe,
+       .remove = mcp25xxfd_base_remove,
+};
+module_spi_driver(mcp25xxfd_can_driver);
+
+MODULE_AUTHOR("Martin Sperl <ker...@martin.sperl.org>");
+MODULE_DESCRIPTION("Microchip 25XXFD CAN driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.h 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.h
new file mode 100644
index 000000000000..4559ac60645c
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_base.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+#ifndef __MCP25XXFD_BASE_H
+#define __MCP25XXFD_BASE_H
+
+#include <linux/regulator/consumer.h>
+
+int mcp25xxfd_base_power_enable(struct regulator *reg, int enable);
+
+#endif /* __MCP25XXFD_BASE_H */
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c
new file mode 100644
index 000000000000..41a5ab508582
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+
+#include "mcp25xxfd_can.h"
+#include "mcp25xxfd_cmd.h"
+#include "mcp25xxfd_priv.h"
+#include "mcp25xxfd_regs.h"
+
+int mcp25xxfd_can_get_mode(struct mcp25xxfd_priv *priv, u32 *reg)
+{
+       int ret;
+
+       ret = mcp25xxfd_cmd_read(priv->spi, MCP25XXFD_CAN_CON, reg);
+       if (ret)
+               return ret;
+
+       return FIELD_GET(MCP25XXFD_CAN_CON_OPMOD_MASK, *reg);
+}
+
+static int mcp25xxfd_can_switch_mode(struct mcp25xxfd_priv *priv,
+                                    u32 *reg, int mode)
+{
+       int ret, i;
+
+       ret = mcp25xxfd_can_get_mode(priv, reg);
+       if (ret < 0)
+               return ret;
+
+       /* Compute the effective mode in osc*/
+       *reg &= ~(MCP25XXFD_CAN_CON_REQOP_MASK |
+                 MCP25XXFD_CAN_CON_OPMOD_MASK);
+       *reg |= FIELD_PREP(MCP25XXFD_CAN_CON_REQOP_MASK, mode) |
+               FIELD_PREP(MCP25XXFD_CAN_CON_OPMOD_MASK, mode);
+
+       /* Request the mode switch */
+       ret = mcp25xxfd_cmd_write(priv->spi, MCP25XXFD_CAN_CON, *reg);
+       if (ret)
+               return ret;
+
+       /* Wait for 256 rounds to stabilize. This is essentially > 12ms
+        * at 1MHz
+        */
+       for (i = 0; i < 256; i++) {
+               /* get the mode */
+               ret = mcp25xxfd_can_get_mode(priv, reg);
+               if (ret < 0)
+                       return ret;
+               /* check that we have reached our mode */
+               if (ret == mode)
+                       return 0;
+       }
+
+       dev_err(&priv->spi->dev, "Failed to switch to mode %u in time\n",
+               mode);
+
+       return -ETIMEDOUT;
+}
+
+static int mcp25xxfd_can_probe_modeswitch(struct mcp25xxfd_priv *priv)
+{
+       u32 mode_data;
+       int ret;
+
+       /* We should be in config mode now, so move to INT_LOOPBACK */
+       ret = mcp25xxfd_can_switch_mode(priv, &mode_data,
+                                       MCP25XXFD_CAN_CON_MODE_INT_LOOPBACK);
+       if (ret) {
+               dev_err(&priv->spi->dev,
+                       "Failed to switch into loopback mode\n");
+               return ret;
+       }
+
+       /* Switch back into config mode */
+       ret = mcp25xxfd_can_switch_mode(priv, &mode_data,
+                                       MCP25XXFD_CAN_CON_MODE_CONFIG);
+       if (ret) {
+               dev_err(&priv->spi->dev,
+                       "Failed to switch back to config mode\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+int mcp25xxfd_can_probe(struct mcp25xxfd_priv *priv)
+{
+       struct spi_device *spi = priv->spi;
+       u32 mode_data;
+       int mode, ret;
+
+       /* For sanity check read TXQCON register. The TXEN bit should always
+        * be read as 1.
+        */
+       ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_CAN_TXQCON, &mode_data);
+       if (ret)
+               return ret;
+
+       if ((mode_data & MCP25XXFD_CAN_TXQCON_TXEN) == 0) {
+               dev_err(&spi->dev, "TXQCON does not have TXEN bit set");
+               return -EINVAL;
+       }
+
+       /* Try to get the current mode */
+       mode = mcp25xxfd_can_get_mode(priv, &mode_data);
+       if (mode < 0)
+               return mode;
+
+       /* SPI-reset should have moved us into config mode. But then the
+        * documentation says that SPI-reset may only work reliably when already
+        * in config mode. So if we are in config mode then everything is fine
+        * and we check that a mode switch works properly.
+        */
+       if (mode == MCP25XXFD_CAN_CON_MODE_CONFIG)
+               return mcp25xxfd_can_probe_modeswitch(priv);
+
+       /* Any other mode is unexpected */
+       dev_err(&spi->dev,
+               "Found controller in unexpected mode: %d\n", mode);
+
+       /* Once again try to move to config mode. If this fails, we'll
+        * bail out.
+        */
+       ret = mcp25xxfd_can_switch_mode(priv, &mode_data,
+                                       MCP25XXFD_CAN_CON_MODE_CONFIG);
+       if (ret) {
+               dev_err(&priv->spi->dev,
+                       "Unable to switch to config mode\n");
+               return -EINVAL;
+       }
+
+       /* Finally check if modeswitch is really working */
+       return mcp25xxfd_can_probe_modeswitch(priv);
+}
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h
new file mode 100644
index 000000000000..f54c716735fb
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#ifndef __MCP25XXFD_CAN_H
+#define __MCP25XXFD_CAN_H
+
+#include "mcp25xxfd_priv.h"
+
+/* probe the can controller */
+int mcp25xxfd_can_probe(struct mcp25xxfd_priv *priv);
+
+#endif /* __MCP25XXFD_CAN_H */
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c
new file mode 100644
index 000000000000..24d01e6f59d4
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include "mcp25xxfd_cmd.h"
+#include "mcp25xxfd_priv.h"
+
+static int mcp25xxfd_cmd_sync_write(struct spi_device *spi,
+                                   const void *tx_buf,
+                                   unsigned int tx_len)
+{
+       struct spi_transfer xfer;
+
+       memset(&xfer, 0, sizeof(xfer));
+       xfer.tx_buf = tx_buf;
+       xfer.len = tx_len;
+
+       return spi_sync_transfer(spi, &xfer, 1);
+}
+
+static int mcp25xxfd_cmd_write_then_read(struct spi_device *spi,
+                                        const void *tx_buf,
+                                        unsigned int tx_len,
+                                        void *rx_buf,
+                                        unsigned int rx_len)
+{
+       struct spi_transfer xfer[2];
+       u8 *spi_tx, *spi_rx;
+       int xfers;
+       int ret;
+
+       spi_tx = kzalloc(tx_len + rx_len, GFP_KERNEL);
+       if (!spi_tx)
+               return -ENOMEM;
+
+       spi_rx = spi_tx + tx_len;
+       memset(xfer, 0, sizeof(xfer));
+
+       /* Special handling for half-duplex */
+       if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
+               xfers = 2;
+               xfer[0].tx_buf = spi_tx;
+               xfer[0].len = tx_len;
+               /* Offset for rx_buf needs to get aligned */
+               xfer[1].rx_buf = spi_rx + tx_len;
+               xfer[1].len = rx_len;
+       } else {
+               xfers = 1;
+               xfer[0].len = tx_len + rx_len;
+               xfer[0].tx_buf = spi_tx;
+               xfer[0].rx_buf = spi_rx;
+       }
+
+       memcpy(spi_tx, tx_buf, tx_len);
+       ret = spi_sync_transfer(spi, xfer, xfers);
+       if (ret)
+               goto out;
+
+       memcpy(rx_buf, xfer[0].rx_buf + tx_len, rx_len);
+
+out:
+       kfree(spi_tx);
+
+       return ret;
+}
+
+static int mcp25xxfd_cmd_write_then_write(struct spi_device *spi,
+                                         const void *tx_buf,
+                                         unsigned int tx_len,
+                                         const void *tx2_buf,
+                                         unsigned int tx2_len)
+{
+       struct spi_transfer xfer;
+       u8 *spi_tx;
+       int ret;
+
+       spi_tx = kzalloc(tx_len + tx2_len, GFP_KERNEL);
+       if (!spi_tx)
+               return -ENOMEM;
+
+       memset(&xfer, 0, sizeof(xfer));
+       xfer.len = tx_len + tx2_len;
+       xfer.tx_buf = spi_tx;
+
+       memcpy(spi_tx, tx_buf, tx_len);
+       memcpy(spi_tx + tx_len, tx2_buf, tx2_len);
+
+       ret = spi_sync_transfer(spi, &xfer, 1);
+       kfree(spi_tx);
+
+       return ret;
+}
+
+/* Read multiple bytes from registers */
+int mcp25xxfd_cmd_read_multi(struct spi_device *spi, u32 reg,
+                            void *data, int n)
+{
+       u8 cmd[2];
+       int ret;
+
+       mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_READ, reg, cmd);
+
+       ret = mcp25xxfd_cmd_write_then_read(spi, &cmd, 2, data, n);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int mcp25xxfd_cmd_read_mask(struct spi_device *spi, u32 reg,
+                           u32 *data, u32 mask)
+{
+       int first_byte, last_byte, len_byte;
+       int ret;
+
+       /* Make sure at least one bit is set */
+       if (!mask)
+               return -EINVAL;
+
+       /* Calculate first and last byte used */
+       first_byte = mcp25xxfd_cmd_first_byte(mask);
+       last_byte = mcp25xxfd_cmd_last_byte(mask);
+       len_byte = last_byte - first_byte + 1;
+
+       *data = 0;
+       ret = mcp25xxfd_cmd_read_multi(spi, reg + first_byte,
+                                      ((void *)data + first_byte), len_byte);
+       if (ret)
+               return ret;
+
+       mcp25xxfd_cmd_convert_to_cpu(data, 1);
+
+       return 0;
+}
+
+/* Write multiple bytes to registers */
+int mcp25xxfd_cmd_write_multi(struct spi_device *spi, u32 reg,
+                             void *data, int n)
+{
+       int ret;
+       u8 cmd[2];
+
+       mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_WRITE, reg, cmd);
+
+       ret = mcp25xxfd_cmd_write_then_write(spi, &cmd, 2, data, n);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int mcp25xxfd_cmd_write_mask(struct spi_device *spi, u32 reg,
+                            u32 data, u32 mask)
+{
+       int first_byte, last_byte, len_byte;
+       u8 cmd[2];
+
+       /* Make sure at least one bit is set */
+       if (!mask)
+               return -EINVAL;
+
+       /* calculate first and last byte used */
+       first_byte = mcp25xxfd_cmd_first_byte(mask);
+       last_byte = mcp25xxfd_cmd_last_byte(mask);
+       len_byte = last_byte - first_byte + 1;
+
+       mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_WRITE,
+                          reg + first_byte, cmd);
+
+       mcp25xxfd_cmd_convert_from_cpu(&data, 1);
+
+       return mcp25xxfd_cmd_write_then_write(spi,
+                                             cmd, sizeof(cmd),
+                                             ((void *)&data + first_byte),
+                                             len_byte);
+}
+
+int mcp25xxfd_cmd_write_regs(struct spi_device *spi, u32 reg,
+                            u32 *data, u32 bytes)
+{
+       int ret;
+
+       mcp25xxfd_cmd_convert_from_cpu(data, bytes / sizeof(bytes));
+
+       ret = mcp25xxfd_cmd_write_multi(spi, reg, data, bytes);
+
+       mcp25xxfd_cmd_convert_to_cpu(data, bytes / sizeof(bytes));
+
+       return ret;
+}
+
+int mcp25xxfd_cmd_read_regs(struct spi_device *spi, u32 reg,
+                           u32 *data, u32 bytes)
+{
+       int ret;
+
+       ret = mcp25xxfd_cmd_read_multi(spi, reg, data, bytes);
+
+       mcp25xxfd_cmd_convert_to_cpu((u32 *)data, bytes / sizeof(bytes));
+
+       return ret;
+}
+
+int mcp25xxfd_cmd_reset(struct spi_device *spi)
+{
+       u8 *cmd;
+       int ret;
+
+       cmd = kzalloc(2, GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       mcp25xxfd_cmd_calc(MCP25XXFD_INSTRUCTION_RESET, 0, cmd);
+
+       ret = mcp25xxfd_cmd_sync_write(spi, cmd, 2);
+
+       kfree(cmd);
+
+       return ret;
+}
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h
new file mode 100644
index 000000000000..a61815f97bf6
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_cmd.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#ifndef __MCP25XXFD_CMD_H
+#define __MCP25XXFD_CMD_H
+
+#include <linux/byteorder/generic.h>
+#include <linux/spi/spi.h>
+
+/* SPI commands */
+#define MCP25XXFD_INSTRUCTION_RESET            0x0000
+#define MCP25XXFD_INSTRUCTION_READ             0x3000
+#define MCP25XXFD_INSTRUCTION_WRITE            0x2000
+#define MCP25XXFD_INSTRUCTION_READ_CRC         0xB000
+#define MCP25XXFD_INSTRUCTION_WRITE_CRC                0xA000
+#define MCP25XXFD_INSTRUCTION_WRITE_SAVE       0xC000
+
+#define MCP25XXFD_ADDRESS_MASK                 0x0fff
+
+static inline void mcp25xxfd_cmd_convert_to_cpu(u32 *data, int n)
+{
+       le32_to_cpu_array(data, n);
+}
+
+static inline void mcp25xxfd_cmd_convert_from_cpu(u32 *data, int n)
+{
+       cpu_to_le32_array(data, n);
+}
+
+static inline void mcp25xxfd_cmd_calc(u16 cmd, u16 addr, u8 *data)
+{
+       cmd = cmd | (addr & MCP25XXFD_ADDRESS_MASK);
+
+       data[0] = (cmd >> 8) & 0xff;
+       data[1] = (cmd >> 0) & 0xff;
+}
+
+static inline int mcp25xxfd_cmd_first_byte(u32 mask)
+{
+       return (mask & 0x0000ffff) ?
+               ((mask & 0x000000ff) ? 0 : 1) :
+               ((mask & 0x00ff0000) ? 2 : 3);
+}
+
+static inline int mcp25xxfd_cmd_last_byte(u32 mask)
+{
+       return (mask & 0xffff0000) ?
+               ((mask & 0xff000000) ? 3 : 2) :
+               ((mask & 0x0000ff00) ? 1 : 0);
+}
+
+int mcp25xxfd_cmd_read_multi(struct spi_device *spi, u32 reg,
+                            void *data, int n);
+int mcp25xxfd_cmd_read_mask(struct spi_device *spi, u32 reg,
+                           u32 *data, u32 mask);
+static inline int mcp25xxfd_cmd_read(struct spi_device *spi, u32 reg,
+                                    u32 *data)
+{
+       return mcp25xxfd_cmd_read_mask(spi, reg, data, -1);
+}
+
+int mcp25xxfd_cmd_read_regs(struct spi_device *spi, u32 reg,
+                           u32 *data, u32 bytes);
+
+int mcp25xxfd_cmd_write_multi(struct spi_device *spi, u32 reg,
+                             void *data, int n);
+int mcp25xxfd_cmd_write_mask(struct spi_device *spi, u32 reg,
+                            u32 data, u32 mask);
+static inline int mcp25xxfd_cmd_write(struct spi_device *spi, u32 reg,
+                                     u32 data)
+{
+       return mcp25xxfd_cmd_write_mask(spi, reg, data, -1);
+}
+
+int mcp25xxfd_cmd_write_regs(struct spi_device *spi, u32 reg,
+                            u32 *data, u32 bytes);
+
+int mcp25xxfd_cmd_reset(struct spi_device *spi);
+
+#endif /* __MCP25XXFD_CMD_H */
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c
new file mode 100644
index 000000000000..b893d8009448
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include "mcp25xxfd_cmd.h"
+#include "mcp25xxfd_crc.h"
+#include "mcp25xxfd_regs.h"
+#include "mcp25xxfd_priv.h"
+
+int mcp25xxfd_crc_enable_int(struct mcp25xxfd_priv *priv, bool enable)
+{
+       u32 mask = MCP25XXFD_CRC_CRCERRIE | MCP25XXFD_CRC_FERRIE;
+
+       priv->regs.crc &= ~mask;
+       priv->regs.crc |= enable ? mask : 0;
+
+       return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_CRC,
+                                       priv->regs.crc, mask);
+}
+
+int mcp25xxfd_crc_clear_int(struct mcp25xxfd_priv *priv)
+{
+       return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_CRC, 0,
+                                       MCP25XXFD_CRC_CRCERRIF |
+                                       MCP25XXFD_CRC_FERRIF);
+}
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h
new file mode 100644
index 000000000000..6e42fe0fad0f
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_crc.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+#ifndef __MCP25XXFD_CRC_H
+#define __MCP25XXFD_CRC_H
+
+#include "mcp25xxfd_priv.h"
+
+int mcp25xxfd_crc_enable_int(struct mcp25xxfd_priv *priv, bool enable);
+int mcp25xxfd_crc_clear_int(struct mcp25xxfd_priv *priv);
+
+#endif /* __MCP25XXFD_CRC_H */
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c
new file mode 100644
index 000000000000..56e2c4fbf52d
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include "mcp25xxfd_cmd.h"
+#include "mcp25xxfd_ecc.h"
+#include "mcp25xxfd_priv.h"
+#include "mcp25xxfd_regs.h"
+
+int mcp25xxfd_ecc_clear_int(struct mcp25xxfd_priv *priv)
+{
+       u32 val, addr;
+       int ret;
+
+       /* First report the error address */
+       ret = mcp25xxfd_cmd_read(priv->spi, MCP25XXFD_ECCSTAT, &val);
+       if (ret)
+               return ret;
+
+       /* If no flags are set then nothing to do */
+       if (!(val & (MCP25XXFD_ECCSTAT_SECIF | MCP25XXFD_ECCSTAT_DEDIF)))
+               return 0;
+
+       addr = (val & MCP25XXFD_ECCSTAT_ERRADDR_MASK) >>
+               MCP25XXFD_ECCSTAT_ERRADDR_SHIFT;
+
+       dev_err_ratelimited(&priv->spi->dev, "ECC %s bit error at %03x\n",
+                           (val & MCP25XXFD_ECCSTAT_DEDIF) ?
+                           "double" : "single",
+                           addr);
+
+       /* Clear the error */
+       return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_ECCSTAT, 0,
+                                       MCP25XXFD_ECCSTAT_SECIF |
+                                       MCP25XXFD_ECCSTAT_DEDIF);
+}
+
+int mcp25xxfd_ecc_enable_int(struct mcp25xxfd_priv *priv, bool enable)
+{
+       u32 mask = MCP25XXFD_ECCCON_SECIE | MCP25XXFD_ECCCON_DEDIE;
+
+       priv->regs.ecccon &= ~mask;
+       priv->regs.ecccon |= MCP25XXFD_ECCCON_ECCEN | (enable ? mask : 0);
+
+       return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_ECCCON,
+                                       priv->regs.ecccon,
+                                       MCP25XXFD_ECCCON_ECCEN | mask);
+}
+
+int mcp25xxfd_ecc_enable(struct mcp25xxfd_priv *priv)
+{
+       u8 buffer[256];
+       int i, ret;
+
+       ret = mcp25xxfd_ecc_enable_int(priv, false);
+       if (ret)
+               return ret;
+
+       memset(buffer, 0, sizeof(buffer));
+       for (i = 0; i < MCP25XXFD_SRAM_SIZE; i += sizeof(buffer)) {
+               ret = mcp25xxfd_cmd_write_multi(priv->spi,
+                                               MCP25XXFD_SRAM_ADDR(i),
+                                               buffer, sizeof(buffer));
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h
new file mode 100644
index 000000000000..117f58c65a46
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_ecc.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+#ifndef __MCP25XXFD_ECC_H
+#define __MCP25XXFD_ECC_H
+
+#include "mcp25xxfd_priv.h"
+
+int mcp25xxfd_ecc_clear_int(struct mcp25xxfd_priv *priv);
+int mcp25xxfd_ecc_enable_int(struct mcp25xxfd_priv *priv, bool enable);
+int mcp25xxfd_ecc_enable(struct mcp25xxfd_priv *priv);
+
+#endif /* __MCP25XXFD_ECC_H */
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c
new file mode 100644
index 000000000000..5e274d452646
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+
+#include "mcp25xxfd_crc.h"
+#include "mcp25xxfd_ecc.h"
+#include "mcp25xxfd_int.h"
+#include "mcp25xxfd_priv.h"
+
+int mcp25xxfd_int_clear(struct mcp25xxfd_priv *priv)
+{
+       int ret;
+
+       ret = mcp25xxfd_ecc_clear_int(priv);
+       if (ret)
+               return ret;
+
+       return mcp25xxfd_crc_clear_int(priv);
+}
+
+int mcp25xxfd_int_enable(struct mcp25xxfd_priv *priv, bool enable)
+{
+       int ret;
+
+       /* If we enable interrupts, then clear interrupt first */
+       if (enable) {
+               ret = mcp25xxfd_int_clear(priv);
+               if (ret)
+                       return ret;
+       }
+
+       ret = mcp25xxfd_crc_enable_int(priv, enable);
+       if (ret)
+               return ret;
+
+       ret = mcp25xxfd_ecc_enable(priv);
+       if (ret)
+               goto out_crc;
+
+       ret = mcp25xxfd_ecc_enable_int(priv, enable);
+       if (ret)
+               goto out_crc;
+
+       /* If we disable interrupts, then clear interrupt flags last */
+       if (!enable)
+               mcp25xxfd_int_clear(priv);
+
+       return 0;
+
+out_crc:
+       mcp25xxfd_crc_enable_int(priv, false);
+       return ret;
+}
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h
new file mode 100644
index 000000000000..4daf0182d1af
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_int.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+#ifndef __MCP25XXFD_INT_H
+#define __MCP25XXFD_INT_H
+
+#include "mcp25xxfd_priv.h"
+
+int mcp25xxfd_int_clear(struct mcp25xxfd_priv *priv);
+int mcp25xxfd_int_enable(struct mcp25xxfd_priv *priv, bool enable);
+
+#endif /* __MCP25XXFD_INT_H */
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_priv.h 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_priv.h
new file mode 100644
index 000000000000..8bc7a599224c
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_priv.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#ifndef __MCP25XXFD_PRIV_H
+#define __MCP25XXFD_PRIV_H
+
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include "mcp25xxfd_regs.h"
+
+#define DEVICE_NAME "mcp25xxfd"
+#define CLOCK_4_MHZ 4000000
+#define CLOCK_10_MHZ 10000000
+#define CLOCK_40_MHZ 40000000
+
+enum mcp25xxfd_model {
+       CAN_MCP2517FD   = 0x2517,
+};
+
+struct mcp25xxfd_priv {
+       struct spi_device *spi;
+       struct clk *clk;
+
+       /* actual model of the mcp25xxfd */
+       enum mcp25xxfd_model model;
+
+       /* full device name used for interrupts */
+       char device_name[32];
+
+       int clock_freq;
+       struct regulator *power;
+
+       /* configuration registers */
+       struct {
+               u32 osc;
+               u32 iocon;
+               u32 crc;
+               u32 ecccon;
+       } regs;
+};
+
+#endif /* __MCP25XXFD_PRIV_H */
diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_regs.h 
b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_regs.h
new file mode 100644
index 000000000000..b500cb46b9a4
--- /dev/null
+++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_regs.h
@@ -0,0 +1,656 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
+ *
+ * Copyright 2019 Martin Sperl <ker...@martin.sperl.org>
+ */
+
+#ifndef __MCP25XXFD_REGS_H
+#define __MCP25XXFD_REGS_H
+
+#include <linux/bitops.h>
+
+/* some constants derived from the datasheets */
+#define MCP25XXFD_OST_DELAY_MS         3
+#define MCP25XXFD_MIN_CLOCK_FREQUENCY  1000000
+#define MCP25XXFD_MAX_CLOCK_FREQUENCY  40000000
+#define MCP25XXFD_PLL_MULTIPLIER       10
+#define MCP25XXFD_AUTO_PLL_MAX_CLOCK_FREQUENCY                         \
+       (MCP25XXFD_MAX_CLOCK_FREQUENCY / MCP25XXFD_PLL_MULTIPLIER)
+#define MCP25XXFD_SCLK_DIVIDER         2
+
+/* GPIO, clock, ecc related register definitions of Controller itself */
+#define MCP25XXFD_SFR_BASE(x)                  (0xE00 + (x))
+#define MCP25XXFD_OSC                          MCP25XXFD_SFR_BASE(0x00)
+#  define MCP25XXFD_OSC_PLLEN                  BIT(0)
+#  define MCP25XXFD_OSC_OSCDIS                 BIT(2)
+#  define MCP25XXFD_OSC_SCLKDIV                        BIT(4)
+#  define MCP25XXFD_OSC_CLKODIV_BITS           2
+#  define MCP25XXFD_OSC_CLKODIV_SHIFT          5
+#  define MCP25XXFD_OSC_CLKODIV_MASK                                   \
+       GENMASK(MCP25XXFD_OSC_CLKODIV_SHIFT                             \
+               + MCP25XXFD_OSC_CLKODIV_BITS - 1,                       \
+               MCP25XXFD_OSC_CLKODIV_SHIFT)
+#  define MCP25XXFD_OSC_CLKODIV_10             3
+#  define MCP25XXFD_OSC_CLKODIV_4              2
+#  define MCP25XXFD_OSC_CLKODIV_2              1
+#  define MCP25XXFD_OSC_CLKODIV_1              0
+#  define MCP25XXFD_OSC_PLLRDY                 BIT(8)
+#  define MCP25XXFD_OSC_OSCRDY                 BIT(10)
+#  define MCP25XXFD_OSC_SCLKRDY                        BIT(12)
+#define MCP25XXFD_IOCON                                MCP25XXFD_SFR_BASE(0x04)
+#  define MCP25XXFD_IOCON_TRIS0                        BIT(0)
+#  define MCP25XXFD_IOCON_TRIS1                        BIT(1)
+#  define MCP25XXFD_IOCON_XSTBYEN              BIT(6)
+#  define MCP25XXFD_IOCON_LAT0                 BIT(8)
+#  define MCP25XXFD_IOCON_LAT1                 BIT(9)
+#  define MCP25XXFD_IOCON_GPIO0                        BIT(16)
+#  define MCP25XXFD_IOCON_GPIO1                        BIT(17)
+#  define MCP25XXFD_IOCON_PM0                  BIT(24)
+#  define MCP25XXFD_IOCON_PM1                  BIT(25)
+#  define MCP25XXFD_IOCON_TXCANOD              BIT(28)
+#  define MCP25XXFD_IOCON_SOF                  BIT(29)
+#  define MCP25XXFD_IOCON_INTOD                        BIT(30)
+#define MCP25XXFD_CRC                          MCP25XXFD_SFR_BASE(0x08)
+#  define MCP25XXFD_CRC_MASK                   GENMASK(15, 0)
+#  define MCP25XXFD_CRC_CRCERRIE               BIT(16)
+#  define MCP25XXFD_CRC_FERRIE                 BIT(17)
+#  define MCP25XXFD_CRC_CRCERRIF               BIT(24)
+#  define MCP25XXFD_CRC_FERRIF                 BIT(25)
+#define MCP25XXFD_ECCCON                       MCP25XXFD_SFR_BASE(0x0C)
+#  define MCP25XXFD_ECCCON_ECCEN               BIT(0)
+#  define MCP25XXFD_ECCCON_SECIE               BIT(1)
+#  define MCP25XXFD_ECCCON_DEDIE               BIT(2)
+#  define MCP25XXFD_ECCCON_PARITY_BITS         6
+#  define MCP25XXFD_ECCCON_PARITY_SHIFT                8
+#  define MCP25XXFD_ECCCON_PARITY_MASK                                 \
+       GENMASK(MCP25XXFD_ECCCON_PARITY_SHIFT                           \
+               + MCP25XXFD_ECCCON_PARITY_BITS - 1,                     \
+               MCP25XXFD_ECCCON_PARITY_SHIFT)
+#define MCP25XXFD_ECCSTAT                      MCP25XXFD_SFR_BASE(0x10)
+#  define MCP25XXFD_ECCSTAT_SECIF              BIT(1)
+#  define MCP25XXFD_ECCSTAT_DEDIF              BIT(2)
+#  define MCP25XXFD_ECCSTAT_ERRADDR_SHIFT      8
+#  define MCP25XXFD_ECCSTAT_ERRADDR_MASK                               \
+       GENMASK(MCP25XXFD_ECCSTAT_ERRADDR_SHIFT + 11,                   \
+               MCP25XXFD_ECCSTAT_ERRADDR_SHIFT)
+
+/* CAN related register definitions of Controller CAN block */
+#define MCP25XXFD_CAN_SFR_BASE(x)              (0x000 + (x))
+#define MCP25XXFD_CAN_CON                                              \
+       MCP25XXFD_CAN_SFR_BASE(0x00)
+#  define MCP25XXFD_CAN_CON_DNCNT_BITS         5
+#  define MCP25XXFD_CAN_CON_DNCNT_SHIFT                0
+#  define MCP25XXFD_CAN_CON_DNCNT_MASK                                 \
+       GENMASK(MCP25XXFD_CAN_CON_DNCNT_SHIFT +                         \
+               MCP25XXFD_CAN_CON_DNCNT_BITS - 1,                       \
+               MCP25XXFD_CAN_CON_DNCNT_SHIFT)
+#  define MCP25XXFD_CAN_CON_ISOCRCEN           BIT(5)
+#  define MCP25XXFD_CAN_CON_PXEDIS             BIT(6)
+#  define MCP25XXFD_CAN_CON_WAKFIL             BIT(8)
+#  define MCP25XXFD_CAN_CON_WFT_BITS           2
+#  define MCP25XXFD_CAN_CON_WFT_SHIFT          9
+#  define MCP25XXFD_CAN_CON_WFT_MASK                                   \
+       GENMASK(MCP25XXFD_CAN_CON_WFT_SHIFT +                           \
+               MCP25XXFD_CAN_CON_WFT_BITS - 1,                         \
+               MCP25XXFD_CAN_CON_WFT_SHIFT)
+#  define MCP25XXFD_CAN_CON_BUSY               BIT(11)
+#  define MCP25XXFD_CAN_CON_BRSDIS             BIT(12)
+#  define MCP25XXFD_CAN_CON_RTXAT              BIT(16)
+#  define MCP25XXFD_CAN_CON_ESIGM              BIT(17)
+#  define MCP25XXFD_CAN_CON_SERR2LOM           BIT(18)
+#  define MCP25XXFD_CAN_CON_STEF               BIT(19)
+#  define MCP25XXFD_CAN_CON_TXQEN              BIT(20)
+#  define MCP25XXFD_CAN_CON_OPMODE_BITS                3
+#  define MCP25XXFD_CAN_CON_OPMOD_SHIFT                21
+#  define MCP25XXFD_CAN_CON_OPMOD_MASK                                 \
+       GENMASK(MCP25XXFD_CAN_CON_OPMOD_SHIFT +                         \
+               MCP25XXFD_CAN_CON_OPMODE_BITS - 1,                      \
+               MCP25XXFD_CAN_CON_OPMOD_SHIFT)
+#  define MCP25XXFD_CAN_CON_REQOP_BITS         3
+#  define MCP25XXFD_CAN_CON_REQOP_SHIFT                24
+#  define MCP25XXFD_CAN_CON_REQOP_MASK                                 \
+       GENMASK(MCP25XXFD_CAN_CON_REQOP_SHIFT +                         \
+               MCP25XXFD_CAN_CON_REQOP_BITS - 1,                       \
+               MCP25XXFD_CAN_CON_REQOP_SHIFT)
+#    define MCP25XXFD_CAN_CON_MODE_MIXED       0
+#    define MCP25XXFD_CAN_CON_MODE_SLEEP       1
+#    define MCP25XXFD_CAN_CON_MODE_INT_LOOPBACK        2
+#    define MCP25XXFD_CAN_CON_MODE_LISTENONLY  3
+#    define MCP25XXFD_CAN_CON_MODE_CONFIG      4
+#    define MCP25XXFD_CAN_CON_MODE_EXT_LOOPBACK        5
+#    define MCP25XXFD_CAN_CON_MODE_CAN2_0      6
+#    define MCP25XXFD_CAN_CON_MODE_RESTRICTED  7
+#  define MCP25XXFD_CAN_CON_ABAT               BIT(27)
+#  define MCP25XXFD_CAN_CON_TXBWS_BITS         3
+#  define MCP25XXFD_CAN_CON_TXBWS_SHIFT                28
+#  define MCP25XXFD_CAN_CON_TXBWS_MASK                                 \
+       GENMASK(MCP25XXFD_CAN_CON_TXBWS_SHIFT +                         \
+               MCP25XXFD_CAN_CON_TXBWS_BITS - 1,                       \
+               MCP25XXFD_CAN_CON_TXBWS_SHIFT)
+#  define MCP25XXFD_CAN_CON_DEFAULT                                    \
+       (MCP25XXFD_CAN_CON_ISOCRCEN |                                   \
+        MCP25XXFD_CAN_CON_PXEDIS |                                     \
+        MCP25XXFD_CAN_CON_WAKFIL |                                     \
+        (3 << MCP25XXFD_CAN_CON_WFT_SHIFT) |                           \
+        MCP25XXFD_CAN_CON_STEF |                                       \
+        MCP25XXFD_CAN_CON_TXQEN |                                      \
+        (MCP25XXFD_CAN_CON_MODE_CONFIG << MCP25XXFD_CAN_CON_OPMOD_SHIFT) | \
+        (MCP25XXFD_CAN_CON_MODE_CONFIG << MCP25XXFD_CAN_CON_REQOP_SHIFT))
+#  define MCP25XXFD_CAN_CON_DEFAULT_MASK                               \
+       (MCP25XXFD_CAN_CON_DNCNT_MASK |                                 \
+        MCP25XXFD_CAN_CON_ISOCRCEN |                                   \
+        MCP25XXFD_CAN_CON_PXEDIS |                                     \
+        MCP25XXFD_CAN_CON_WAKFIL |                                     \
+        MCP25XXFD_CAN_CON_WFT_MASK |                                   \
+        MCP25XXFD_CAN_CON_BRSDIS |                                     \
+        MCP25XXFD_CAN_CON_RTXAT |                                      \
+        MCP25XXFD_CAN_CON_ESIGM |                                      \
+        MCP25XXFD_CAN_CON_SERR2LOM |                                   \
+        MCP25XXFD_CAN_CON_STEF |                                       \
+        MCP25XXFD_CAN_CON_TXQEN |                                      \
+        MCP25XXFD_CAN_CON_OPMOD_MASK |                                 \
+        MCP25XXFD_CAN_CON_REQOP_MASK |                                 \
+        MCP25XXFD_CAN_CON_ABAT |                                       \
+        MCP25XXFD_CAN_CON_TXBWS_MASK)
+#define MCP25XXFD_CAN_NBTCFG                   MCP25XXFD_CAN_SFR_BASE(0x04)
+#  define MCP25XXFD_CAN_NBTCFG_SJW_BITS                7
+#  define MCP25XXFD_CAN_NBTCFG_SJW_SHIFT       0
+#  define MCP25XXFD_CAN_NBTCFG_SJW_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_NBTCFG_SJW_SHIFT +                        \
+               MCP25XXFD_CAN_NBTCFG_SJW_BITS - 1,                      \
+               MCP25XXFD_CAN_NBTCFG_SJW_SHIFT)
+#  define MCP25XXFD_CAN_NBTCFG_TSEG2_BITS      7
+#  define MCP25XXFD_CAN_NBTCFG_TSEG2_SHIFT     8
+#  define MCP25XXFD_CAN_NBTCFG_TSEG2_MASK                              \
+       GENMASK(MCP25XXFD_CAN_NBTCFG_TSEG2_SHIFT +                      \
+               MCP25XXFD_CAN_NBTCFG_TSEG2_BITS - 1,                    \
+               MCP25XXFD_CAN_NBTCFG_TSEG2_SHIFT)
+#  define MCP25XXFD_CAN_NBTCFG_TSEG1_BITS      8
+#  define MCP25XXFD_CAN_NBTCFG_TSEG1_SHIFT     16
+#  define MCP25XXFD_CAN_NBTCFG_TSEG1_MASK                              \
+       GENMASK(MCP25XXFD_CAN_NBTCFG_TSEG1_SHIFT +                      \
+               MCP25XXFD_CAN_NBTCFG_TSEG1_BITS - 1,                    \
+               MCP25XXFD_CAN_NBTCFG_TSEG1_SHIFT)
+#  define MCP25XXFD_CAN_NBTCFG_BRP_BITS                8
+#  define MCP25XXFD_CAN_NBTCFG_BRP_SHIFT       24
+#  define MCP25XXFD_CAN_NBTCFG_BRP_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_NBTCFG_BRP_SHIFT +                        \
+               MCP25XXFD_CAN_NBTCFG_BRP_BITS - 1,                      \
+               MCP25XXFD_CAN_NBTCFG_BRP_SHIFT)
+#define MCP25XXFD_CAN_DBTCFG                   MCP25XXFD_CAN_SFR_BASE(0x08)
+#  define MCP25XXFD_CAN_DBTCFG_SJW_BITS                4
+#  define MCP25XXFD_CAN_DBTCFG_SJW_SHIFT       0
+#  define MCP25XXFD_CAN_DBTCFG_SJW_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_DBTCFG_SJW_SHIFT +                        \
+               MCP25XXFD_CAN_DBTCFG_SJW_BITS - 1,                      \
+               MCP25XXFD_CAN_DBTCFG_SJW_SHIFT)
+#  define MCP25XXFD_CAN_DBTCFG_TSEG2_BITS      4
+#  define MCP25XXFD_CAN_DBTCFG_TSEG2_SHIFT     8
+#  define MCP25XXFD_CAN_DBTCFG_TSEG2_MASK                              \
+       GENMASK(MCP25XXFD_CAN_DBTCFG_TSEG2_SHIFT +                      \
+               MCP25XXFD_CAN_DBTCFG_TSEG2_BITS - 1,                    \
+               MCP25XXFD_CAN_DBTCFG_TSEG2_SHIFT)
+#  define MCP25XXFD_CAN_DBTCFG_TSEG1_BITS      5
+#  define MCP25XXFD_CAN_DBTCFG_TSEG1_SHIFT     16
+#  define MCP25XXFD_CAN_DBTCFG_TSEG1_MASK                              \
+       GENMASK(MCP25XXFD_CAN_DBTCFG_TSEG1_SHIFT +                      \
+               MCP25XXFD_CAN_DBTCFG_TSEG1_BITS - 1,                    \
+               MCP25XXFD_CAN_DBTCFG_TSEG1_SHIFT)
+#  define MCP25XXFD_CAN_DBTCFG_BRP_BITS                8
+#  define MCP25XXFD_CAN_DBTCFG_BRP_SHIFT       24
+#  define MCP25XXFD_CAN_DBTCFG_BRP_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_DBTCFG_BRP_SHIFT +                        \
+               MCP25XXFD_CAN_DBTCFG_BRP_BITS - 1,                      \
+               MCP25XXFD_CAN_DBTCFG_BRP_SHIFT)
+#define MCP25XXFD_CAN_TDC                      MCP25XXFD_CAN_SFR_BASE(0x0C)
+#  define MCP25XXFD_CAN_TDC_TDCV_BITS          5
+#  define MCP25XXFD_CAN_TDC_TDCV_SHIFT         0
+#  define MCP25XXFD_CAN_TDC_TDCV_MASK                                  \
+       GENMASK(MCP25XXFD_CAN_TDC_TDCV_SHIFT +                          \
+               MCP25XXFD_CAN_TDC_TDCV_BITS - 1,                        \
+               MCP25XXFD_CAN_TDC_TDCV_SHIFT)
+#  define MCP25XXFD_CAN_TDC_TDCO_BITS          5
+#  define MCP25XXFD_CAN_TDC_TDCO_SHIFT         8
+#  define MCP25XXFD_CAN_TDC_TDCO_MASK                                  \
+       GENMASK(MCP25XXFD_CAN_TDC_TDCO_SHIFT +                          \
+               MCP25XXFD_CAN_TDC_TDCO_BITS - 1,                        \
+               MCP25XXFD_CAN_TDC_TDCO_SHIFT)
+#  define MCP25XXFD_CAN_TDC_TDCMOD_BITS                2
+#  define MCP25XXFD_CAN_TDC_TDCMOD_SHIFT       16
+#  define MCP25XXFD_CAN_TDC_TDCMOD_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_TDC_TDCMOD_SHIFT +                        \
+               MCP25XXFD_CAN_TDC_TDCMOD_BITS - 1,                      \
+               MCP25XXFD_CAN_TDC_TDCMOD_SHIFT)
+#  define MCP25XXFD_CAN_TDC_TDCMOD_DISABLED    0
+#  define MCP25XXFD_CAN_TDC_TDCMOD_MANUAL      1
+#  define MCP25XXFD_CAN_TDC_TDCMOD_AUTO                2
+#  define MCP25XXFD_CAN_TDC_SID11EN            BIT(24)
+#  define MCP25XXFD_CAN_TDC_EDGFLTEN           BIT(25)
+#define MCP25XXFD_CAN_TBC                      MCP25XXFD_CAN_SFR_BASE(0x10)
+#define MCP25XXFD_CAN_TSCON                    MCP25XXFD_CAN_SFR_BASE(0x14)
+#  define MCP25XXFD_CAN_TSCON_TBCPRE_BITS      10
+#  define MCP25XXFD_CAN_TSCON_TBCPRE_SHIFT     0
+#  define MCP25XXFD_CAN_TSCON_TBCPRE_MASK                              \
+       GENMASK(MCP25XXFD_CAN_TSCON_TBCPRE_SHIFT +                      \
+               MCP25XXFD_CAN_TSCON_TBCPRE_BITS - 1,                    \
+               MCP25XXFD_CAN_TSCON_TBCPRE_SHIFT)
+#  define MCP25XXFD_CAN_TSCON_TBCEN            BIT(16)
+#  define MCP25XXFD_CAN_TSCON_TSEOF            BIT(17)
+#  define MCP25XXFD_CAN_TSCON_TSRES            BIT(18)
+#define MCP25XXFD_CAN_VEC                      MCP25XXFD_CAN_SFR_BASE(0x18)
+#  define MCP25XXFD_CAN_VEC_ICODE_BITS         7
+#  define MCP25XXFD_CAN_VEC_ICODE_SHIFT                0
+#  define MCP25XXFD_CAN_VEC_ICODE_MASK                                 \
+       GENMASK(MCP25XXFD_CAN_VEC_ICODE_SHIFT +                         \
+               MCP25XXFD_CAN_VEC_ICODE_BITS - 1,                       \
+               MCP25XXFD_CAN_VEC_ICODE_SHIFT)
+#  define MCP25XXFD_CAN_VEC_FILHIT_BITS                5
+#  define MCP25XXFD_CAN_VEC_FILHIT_SHIFT       8
+#  define MCP25XXFD_CAN_VEC_FILHIT_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_VEC_FILHIT_SHIFT +                        \
+               MCP25XXFD_CAN_VEC_FILHIT_BITS - 1,                      \
+               MCP25XXFD_CAN_VEC_FILHIT_SHIFT)
+#  define MCP25XXFD_CAN_VEC_TXCODE_BITS                7
+#  define MCP25XXFD_CAN_VEC_TXCODE_SHIFT       16
+#  define MCP25XXFD_CAN_VEC_TXCODE_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_VEC_TXCODE_SHIFT +                        \
+               MCP25XXFD_CAN_VEC_TXCODE_BITS - 1,                      \
+               MCP25XXFD_CAN_VEC_TXCODE_SHIFT)
+#  define MCP25XXFD_CAN_VEC_RXCODE_BITS                7
+#  define MCP25XXFD_CAN_VEC_RXCODE_SHIFT       24
+#  define MCP25XXFD_CAN_VEC_RXCODE_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_VEC_RXCODE_SHIFT +                        \
+               MCP25XXFD_CAN_VEC_RXCODE_BITS - 1,                      \
+               MCP25XXFD_CAN_VEC_RXCODE_SHIFT)
+#define MCP25XXFD_CAN_INT                      MCP25XXFD_CAN_SFR_BASE(0x1C)
+#  define MCP25XXFD_CAN_INT_IF_SHIFT           0
+#  define MCP25XXFD_CAN_INT_TXIF               BIT(0)
+#  define MCP25XXFD_CAN_INT_RXIF               BIT(1)
+#  define MCP25XXFD_CAN_INT_TBCIF              BIT(2)
+#  define MCP25XXFD_CAN_INT_MODIF              BIT(3)
+#  define MCP25XXFD_CAN_INT_TEFIF              BIT(4)
+#  define MCP25XXFD_CAN_INT_ECCIF              BIT(8)
+#  define MCP25XXFD_CAN_INT_SPICRCIF           BIT(9)
+#  define MCP25XXFD_CAN_INT_TXATIF             BIT(10)
+#  define MCP25XXFD_CAN_INT_RXOVIF             BIT(11)
+#  define MCP25XXFD_CAN_INT_SERRIF             BIT(12)
+#  define MCP25XXFD_CAN_INT_CERRIF             BIT(13)
+#  define MCP25XXFD_CAN_INT_WAKIF              BIT(14)
+#  define MCP25XXFD_CAN_INT_IVMIF              BIT(15)
+#  define MCP25XXFD_CAN_INT_IF_MASK                                    \
+       (MCP25XXFD_CAN_INT_TXIF |                                       \
+        MCP25XXFD_CAN_INT_RXIF |                                       \
+        MCP25XXFD_CAN_INT_TBCIF |                                      \
+        MCP25XXFD_CAN_INT_MODIF |                                      \
+        MCP25XXFD_CAN_INT_TEFIF |                                      \
+        MCP25XXFD_CAN_INT_ECCIF |                                      \
+        MCP25XXFD_CAN_INT_SPICRCIF |                                   \
+        MCP25XXFD_CAN_INT_TXATIF |                                     \
+        MCP25XXFD_CAN_INT_RXOVIF |                                     \
+        MCP25XXFD_CAN_INT_CERRIF |                                     \
+        MCP25XXFD_CAN_INT_SERRIF |                                     \
+        MCP25XXFD_CAN_INT_WAKIF |                                      \
+        MCP25XXFD_CAN_INT_IVMIF)
+#  define MCP25XXFD_CAN_INT_IF_CLEAR_MASK                              \
+       (MCP25XXFD_CAN_INT_TBCIF  |                                     \
+        MCP25XXFD_CAN_INT_MODIF  |                                     \
+        MCP25XXFD_CAN_INT_CERRIF |                                     \
+        MCP25XXFD_CAN_INT_SERRIF |                                     \
+        MCP25XXFD_CAN_INT_WAKIF |                                      \
+        MCP25XXFD_CAN_INT_IVMIF)
+#  define MCP25XXFD_CAN_INT_IE_SHIFT           16
+#  define MCP25XXFD_CAN_INT_TXIE                                       \
+       (MCP25XXFD_CAN_INT_TXIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_RXIE                                       \
+       (MCP25XXFD_CAN_INT_RXIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_TBCIE                                      \
+       (MCP25XXFD_CAN_INT_TBCIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_MODIE                                      \
+       (MCP25XXFD_CAN_INT_MODIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_TEFIE                                      \
+       (MCP25XXFD_CAN_INT_TEFIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_ECCIE                                      \
+       (MCP25XXFD_CAN_INT_ECCIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_SPICRCIE                                   \
+       (MCP25XXFD_CAN_INT_SPICRCIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_TXATIE                                     \
+       (MCP25XXFD_CAN_INT_TXATIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_RXOVIE                                     \
+       (MCP25XXFD_CAN_INT_RXOVIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_CERRIE                                     \
+       (MCP25XXFD_CAN_INT_CERRIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_SERRIE                                     \
+       (MCP25XXFD_CAN_INT_SERRIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_WAKIE                                      \
+       (MCP25XXFD_CAN_INT_WAKIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_IVMIE                                      \
+       (MCP25XXFD_CAN_INT_IVMIF << MCP25XXFD_CAN_INT_IE_SHIFT)
+#  define MCP25XXFD_CAN_INT_IE_MASK                                    \
+       (MCP25XXFD_CAN_INT_TXIE |                                       \
+        MCP25XXFD_CAN_INT_RXIE |                                       \
+        MCP25XXFD_CAN_INT_TBCIE |                                      \
+        MCP25XXFD_CAN_INT_MODIE |                                      \
+        MCP25XXFD_CAN_INT_TEFIE |                                      \
+        MCP25XXFD_CAN_INT_ECCIE |                                      \
+        MCP25XXFD_CAN_INT_SPICRCIE |                                   \
+        MCP25XXFD_CAN_INT_TXATIE |                                     \
+        MCP25XXFD_CAN_INT_RXOVIE |                                     \
+        MCP25XXFD_CAN_INT_CERRIE |                                     \
+        MCP25XXFD_CAN_INT_SERRIE |                                     \
+        MCP25XXFD_CAN_INT_WAKIE |                                      \
+        MCP25XXFD_CAN_INT_IVMIE)
+#define MCP25XXFD_CAN_RXIF                     MCP25XXFD_CAN_SFR_BASE(0x20)
+#define MCP25XXFD_CAN_TXIF                     MCP25XXFD_CAN_SFR_BASE(0x24)
+#define MCP25XXFD_CAN_RXOVIF                   MCP25XXFD_CAN_SFR_BASE(0x28)
+#define MCP25XXFD_CAN_TXATIF                   MCP25XXFD_CAN_SFR_BASE(0x2C)
+#define MCP25XXFD_CAN_TXREQ                    MCP25XXFD_CAN_SFR_BASE(0x30)
+#define MCP25XXFD_CAN_TREC                     MCP25XXFD_CAN_SFR_BASE(0x34)
+#  define MCP25XXFD_CAN_TREC_REC_BITS          8
+#  define MCP25XXFD_CAN_TREC_REC_SHIFT         0
+#  define MCP25XXFD_CAN_TREC_REC_MASK                                  \
+       GENMASK(MCP25XXFD_CAN_TREC_REC_SHIFT +                          \
+               MCP25XXFD_CAN_TREC_REC_BITS - 1,                        \
+               MCP25XXFD_CAN_TREC_REC_SHIFT)
+#  define MCP25XXFD_CAN_TREC_TEC_BITS          8
+#  define MCP25XXFD_CAN_TREC_TEC_SHIFT         8
+#  define MCP25XXFD_CAN_TREC_TEC_MASK                                  \
+       GENMASK(MCP25XXFD_CAN_TREC_TEC_SHIFT +                          \
+               MCP25XXFD_CAN_TREC_TEC_BITS - 1,                        \
+               MCP25XXFD_CAN_TREC_TEC_SHIFT)
+#  define MCP25XXFD_CAN_TREC_EWARN             BIT(16)
+#  define MCP25XXFD_CAN_TREC_RXWARN            BIT(17)
+#  define MCP25XXFD_CAN_TREC_TXWARN            BIT(18)
+#  define MCP25XXFD_CAN_TREC_RXBP              BIT(19)
+#  define MCP25XXFD_CAN_TREC_TXBP              BIT(20)
+#  define MCP25XXFD_CAN_TREC_TXBO              BIT(21)
+#define MCP25XXFD_CAN_BDIAG0                   MCP25XXFD_CAN_SFR_BASE(0x38)
+#  define MCP25XXFD_CAN_BDIAG0_NRERRCNT_BITS   8
+#  define MCP25XXFD_CAN_BDIAG0_NRERRCNT_SHIFT  0
+#  define MCP25XXFD_CAN_BDIAG0_NRERRCNT_MASK                           \
+       GENMASK(MCP25XXFD_CAN_BDIAG0_NRERRCNT_SHIFT +                   \
+               MCP25XXFD_CAN_BDIAG0_NRERRCNT_BITS - 1,                 \
+               MCP25XXFD_CAN_BDIAG0_NRERRCNT_SHIFT)
+#  define MCP25XXFD_CAN_BDIAG0_NTERRCNT_BITS   8
+#  define MCP25XXFD_CAN_BDIAG0_NTERRCNT_SHIFT  8
+#  define MCP25XXFD_CAN_BDIAG0_NTERRCNT_MASK                           \
+       GENMASK(MCP25XXFD_CAN_BDIAG0_NTERRCNT_SHIFT +                   \
+               MCP25XXFD_CAN_BDIAG0_NTERRCNT_BITS - 1,                 \
+               MCP25XXFD_CAN_BDIAG0_NTERRCNT_SHIFT)
+#  define MCP25XXFD_CAN_BDIAG0_DRERRCNT_BITS   8
+#  define MCP25XXFD_CAN_BDIAG0_DRERRCNT_SHIFT  16
+#  define MCP25XXFD_CAN_BDIAG0_DRERRCNT_MASK                           \
+       GENMASK(MCP25XXFD_CAN_BDIAG0_DRERRCNT_SHIFT +                   \
+               MCP25XXFD_CAN_BDIAG0_DRERRCNT_BITS - 1,                 \
+               MCP25XXFD_CAN_BDIAG0_DRERRCNT_SHIFT)
+#  define MCP25XXFD_CAN_BDIAG0_DTERRCNT_BITS   8
+#  define MCP25XXFD_CAN_BDIAG0_DTERRCNT_SHIFT  24
+#  define MCP25XXFD_CAN_BDIAG0_DTERRCNT_MASK                           \
+       GENMASK(MCP25XXFD_CAN_BDIAG0_DTERRCNT_SHIFT +                   \
+               MCP25XXFD_CAN_BDIAG0_DTERRCNT_BITS - 1,                 \
+               MCP25XXFD_CAN_BDIAG0_DTERRCNT_SHIFT)
+#define MCP25XXFD_CAN_BDIAG1                   MCP25XXFD_CAN_SFR_BASE(0x3C)
+#  define MCP25XXFD_CAN_BDIAG1_EFMSGCNT_BITS   16
+#  define MCP25XXFD_CAN_BDIAG1_EFMSGCNT_SHIFT  0
+#  define MCP25XXFD_CAN_BDIAG1_EFMSGCNT_MASK                           \
+       GENMASK(MCP25XXFD_CAN_BDIAG1_EFMSGCNT_SHIFT +                   \
+               MCP25XXFD_CAN_BDIAG1_EFMSGCNT_BITS - 1,                 \
+               MCP25XXFD_CAN_BDIAG1_EFMSGCNT_SHIFT)
+#  define MCP25XXFD_CAN_BDIAG1_NBIT0ERR                BIT(16)
+#  define MCP25XXFD_CAN_BDIAG1_NBIT1ERR                BIT(17)
+#  define MCP25XXFD_CAN_BDIAG1_NACKERR         BIT(18)
+#  define MCP25XXFD_CAN_BDIAG1_NSTUFERR                BIT(19)
+#  define MCP25XXFD_CAN_BDIAG1_NFORMERR                BIT(20)
+#  define MCP25XXFD_CAN_BDIAG1_NCRCERR         BIT(21)
+#  define MCP25XXFD_CAN_BDIAG1_TXBOERR         BIT(23)
+#  define MCP25XXFD_CAN_BDIAG1_DBIT0ERR                BIT(24)
+#  define MCP25XXFD_CAN_BDIAG1_DBIT1ERR                BIT(25)
+#  define MCP25XXFD_CAN_BDIAG1_DFORMERR                BIT(27)
+#  define MCP25XXFD_CAN_BDIAG1_DSTUFERR                BIT(28)
+#  define MCP25XXFD_CAN_BDIAG1_DCRCERR         BIT(29)
+#  define MCP25XXFD_CAN_BDIAG1_ESI             BIT(30)
+#  define MCP25XXFD_CAN_BDIAG1_DLCMM           BIT(31)
+#define MCP25XXFD_CAN_TEFCON                   MCP25XXFD_CAN_SFR_BASE(0x40)
+#  define MCP25XXFD_CAN_TEFCON_TEFNEIE         BIT(0)
+#  define MCP25XXFD_CAN_TEFCON_TEFHIE          BIT(1)
+#  define MCP25XXFD_CAN_TEFCON_TEFFIE          BIT(2)
+#  define MCP25XXFD_CAN_TEFCON_TEFOVIE         BIT(3)
+#  define MCP25XXFD_CAN_TEFCON_TEFTSEN         BIT(5)
+#  define MCP25XXFD_CAN_TEFCON_UINC            BIT(8)
+#  define MCP25XXFD_CAN_TEFCON_FRESET          BIT(10)
+#  define MCP25XXFD_CAN_TEFCON_FSIZE_BITS      5
+#  define MCP25XXFD_CAN_TEFCON_FSIZE_SHIFT     24
+#  define MCP25XXFD_CAN_TEFCON_FSIZE_MASK                              \
+       GENMASK(MCP25XXFD_CAN_TEFCON_FSIZE_SHIFT +                      \
+               MCP25XXFD_CAN_TEFCON_FSIZE_BITS - 1,                    \
+               MCP25XXFD_CAN_TEFCON_FSIZE_SHIFT)
+#define MCP25XXFD_CAN_TEFSTA                   MCP25XXFD_CAN_SFR_BASE(0x44)
+#  define MCP25XXFD_CAN_TEFSTA_TEFNEIF         BIT(0)
+#  define MCP25XXFD_CAN_TEFSTA_TEFHIF          BIT(1)
+#  define MCP25XXFD_CAN_TEFSTA_TEFFIF          BIT(2)
+#  define MCP25XXFD_CAN_TEFSTA_TEVOVIF         BIT(3)
+#define MCP25XXFD_CAN_TEFUA                    MCP25XXFD_CAN_SFR_BASE(0x48)
+#define MCP25XXFD_CAN_RESERVED                 MCP25XXFD_CAN_SFR_BASE(0x4C)
+#define MCP25XXFD_CAN_TXQCON                   MCP25XXFD_CAN_SFR_BASE(0x50)
+#  define MCP25XXFD_CAN_TXQCON_TXQNIE          BIT(0)
+#  define MCP25XXFD_CAN_TXQCON_TXQEIE          BIT(2)
+#  define MCP25XXFD_CAN_TXQCON_TXATIE          BIT(4)
+#  define MCP25XXFD_CAN_TXQCON_TXEN            BIT(7)
+#  define MCP25XXFD_CAN_TXQCON_UINC            BIT(8)
+#  define MCP25XXFD_CAN_TXQCON_TXREQ           BIT(9)
+#  define MCP25XXFD_CAN_TXQCON_FRESET          BIT(10)
+#  define MCP25XXFD_CAN_TXQCON_TXPRI_BITS      5
+#  define MCP25XXFD_CAN_TXQCON_TXPRI_SHIFT     16
+#  define MCP25XXFD_CAN_TXQCON_TXPRI_MASK                              \
+       GENMASK(MCP25XXFD_CAN_TXQCON_TXPRI_SHIFT +                      \
+               MCP25XXFD_CAN_TXQCON_TXPRI_BITS - 1,                    \
+               MCP25XXFD_CAN_TXQCON_TXPRI_SHIFT)
+#  define MCP25XXFD_CAN_TXQCON_TXAT_BITS       2
+#  define MCP25XXFD_CAN_TXQCON_TXAT_SHIFT      21
+#  define MCP25XXFD_CAN_TXQCON_TXAT_MASK                               \
+       GENMASK(MCP25XXFD_CAN_TXQCON_TXAT_SHIFT +                       \
+               #MCP25XXFD_CAN_TXQCON_TXAT_BITS - 1,                    \
+               MCP25XXFD_CAN_TXQCON_TXAT_SHIFT)
+#  define MCP25XXFD_CAN_TXQCON_FSIZE_BITS      5
+#  define MCP25XXFD_CAN_TXQCON_FSIZE_SHIFT     24
+#  define MCP25XXFD_CAN_TXQCON_FSIZE_MASK                              \
+       GENMASK(MCP25XXFD_CAN_TXQCON_FSIZE_SHIFT +                      \
+               MCP25XXFD_CAN_TXQCON_FSIZE_BITS - 1,                    \
+               MCP25XXFD_CAN_TXQCON_FSIZE_SHIFT)
+#  define MCP25XXFD_CAN_TXQCON_PLSIZE_BITS     3
+#  define MCP25XXFD_CAN_TXQCON_PLSIZE_SHIFT    29
+#  define MCP25XXFD_CAN_TXQCON_PLSIZE_MASK                             \
+       GENMASK(MCP25XXFD_CAN_TXQCON_PLSIZE_SHIFT +                     \
+               MCP25XXFD_CAN_TXQCON_PLSIZE_BITS - 1,                   \
+               MCP25XXFD_CAN_TXQCON_PLSIZE_SHIFT)
+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_8      0
+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_12     1
+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_16     2
+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_20     3
+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_24     4
+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_32     5
+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_48     6
+#    define MCP25XXFD_CAN_TXQCON_PLSIZE_64     7
+
+#define MCP25XXFD_CAN_TXQSTA                   MCP25XXFD_CAN_SFR_BASE(0x54)
+#  define MCP25XXFD_CAN_TXQSTA_TXQNIF          BIT(0)
+#  define MCP25XXFD_CAN_TXQSTA_TXQEIF          BIT(2)
+#  define MCP25XXFD_CAN_TXQSTA_TXATIF          BIT(4)
+#  define MCP25XXFD_CAN_TXQSTA_TXERR           BIT(5)
+#  define MCP25XXFD_CAN_TXQSTA_TXLARB          BIT(6)
+#  define MCP25XXFD_CAN_TXQSTA_TXABT           BIT(7)
+#  define MCP25XXFD_CAN_TXQSTA_TXQCI_BITS      5
+#  define MCP25XXFD_CAN_TXQSTA_TXQCI_SHIFT     8
+#  define MCP25XXFD_CAN_TXQSTA_TXQCI_MASK                              \
+       GENMASK(MCP25XXFD_CAN_TXQSTA_TXQCI_SHIFT +                      \
+               MCP25XXFD_CAN_TXQSTA_TXQCI_BITS - 1,                    \
+               MCP25XXFD_CAN_TXQSTA_TXQCI_SHIFT)
+
+#define MCP25XXFD_CAN_TXQUA                    MCP25XXFD_CAN_SFR_BASE(0x58)
+#define MCP25XXFD_CAN_FIFOCON(x)                                       \
+       MCP25XXFD_CAN_SFR_BASE(0x5C + 12 * ((x) - 1))
+#define MCP25XXFD_CAN_FIFOCON_TFNRFNIE         BIT(0)
+#define MCP25XXFD_CAN_FIFOCON_TFHRFHIE         BIT(1)
+#define MCP25XXFD_CAN_FIFOCON_TFERFFIE         BIT(2)
+#define MCP25XXFD_CAN_FIFOCON_RXOVIE           BIT(3)
+#define MCP25XXFD_CAN_FIFOCON_TXATIE           BIT(4)
+#define MCP25XXFD_CAN_FIFOCON_RXTSEN           BIT(5)
+#define MCP25XXFD_CAN_FIFOCON_RTREN            BIT(6)
+#define MCP25XXFD_CAN_FIFOCON_TXEN             BIT(7)
+#define MCP25XXFD_CAN_FIFOCON_UINC             BIT(8)
+#define MCP25XXFD_CAN_FIFOCON_TXREQ            BIT(9)
+#define MCP25XXFD_CAN_FIFOCON_FRESET           BIT(10)
+#  define MCP25XXFD_CAN_FIFOCON_TXPRI_BITS     5
+#  define MCP25XXFD_CAN_FIFOCON_TXPRI_SHIFT    16
+#  define MCP25XXFD_CAN_FIFOCON_TXPRI_MASK                             \
+       GENMASK(MCP25XXFD_CAN_FIFOCON_TXPRI_SHIFT +                     \
+               MCP25XXFD_CAN_FIFOCON_TXPRI_BITS - 1,                   \
+               MCP25XXFD_CAN_FIFOCON_TXPRI_SHIFT)
+#  define MCP25XXFD_CAN_FIFOCON_TXAT_BITS      2
+#  define MCP25XXFD_CAN_FIFOCON_TXAT_SHIFT     21
+#  define MCP25XXFD_CAN_FIFOCON_TXAT_MASK                              \
+       GENMASK(MCP25XXFD_CAN_FIFOCON_TXAT_SHIFT +                      \
+               MCP25XXFD_CAN_FIFOCON_TXAT_BITS - 1,                    \
+               MCP25XXFD_CAN_FIFOCON_TXAT_SHIFT)
+#  define MCP25XXFD_CAN_FIFOCON_TXAT_ONE_SHOT  0
+#  define MCP25XXFD_CAN_FIFOCON_TXAT_THREE_SHOT        1
+#  define MCP25XXFD_CAN_FIFOCON_TXAT_UNLIMITED 2
+#  define MCP25XXFD_CAN_FIFOCON_FSIZE_BITS     5
+#  define MCP25XXFD_CAN_FIFOCON_FSIZE_SHIFT    24
+#  define MCP25XXFD_CAN_FIFOCON_FSIZE_MASK                             \
+       GENMASK(MCP25XXFD_CAN_FIFOCON_FSIZE_SHIFT +                     \
+               MCP25XXFD_CAN_FIFOCON_FSIZE_BITS - 1,                   \
+               MCP25XXFD_CAN_FIFOCON_FSIZE_SHIFT)
+#  define MCP25XXFD_CAN_FIFOCON_PLSIZE_BITS    3
+#  define MCP25XXFD_CAN_FIFOCON_PLSIZE_SHIFT   29
+#  define MCP25XXFD_CAN_FIFOCON_PLSIZE_MASK                            \
+       GENMASK(MCP25XXFD_CAN_FIFOCON_PLSIZE_SHIFT +                    \
+               MCP25XXFD_CAN_FIFOCON_PLSIZE_BITS - 1,                  \
+               MCP25XXFD_CAN_FIFOCON_PLSIZE_SHIFT)
+#define MCP25XXFD_CAN_FIFOSTA(x)                                       \
+       MCP25XXFD_CAN_SFR_BASE(0x60 + 12 * ((x) - 1))
+#  define MCP25XXFD_CAN_FIFOSTA_TFNRFNIF       BIT(0)
+#  define MCP25XXFD_CAN_FIFOSTA_TFHRFHIF       BIT(1)
+#  define MCP25XXFD_CAN_FIFOSTA_TFERFFIF       BIT(2)
+#  define MCP25XXFD_CAN_FIFOSTA_RXOVIF         BIT(3)
+#  define MCP25XXFD_CAN_FIFOSTA_TXATIF         BIT(4)
+#  define MCP25XXFD_CAN_FIFOSTA_TXERR          BIT(5)
+#  define MCP25XXFD_CAN_FIFOSTA_TXLARB         BIT(6)
+#  define MCP25XXFD_CAN_FIFOSTA_TXABT          BIT(7)
+#  define MCP25XXFD_CAN_FIFOSTA_FIFOCI_BITS    5
+#  define MCP25XXFD_CAN_FIFOSTA_FIFOCI_SHIFT   8
+#  define MCP25XXFD_CAN_FIFOSTA_FIFOCI_MASK                            \
+       GENMASK(MCP25XXFD_CAN_FIFOSTA_FIFOCI_SHIFT +                    \
+               MCP25XXFD_CAN_FIFOSTA_FIFOCI_BITS - 1,                  \
+               MCP25XXFD_CAN_FIFOSTA_FIFOCI_SHIFT)
+#define MCP25XXFD_CAN_FIFOUA(x)                                                
\
+       MCP25XXFD_CAN_SFR_BASE(0x64 + 12 * ((x) - 1))
+#define MCP25XXFD_CAN_FLTCON(x)                                                
\
+       MCP25XXFD_CAN_SFR_BASE(0x1D0 + ((x) & 0x1c))
+#  define MCP25XXFD_CAN_FILCON_SHIFT(x)                (((x) & 3) * 8)
+#  define MCP25XXFD_CAN_FILCON_BITS(x)         MCP25XXFD_CAN_FILCON_BITS_
+#  define MCP25XXFD_CAN_FILCON_BITS_           4
+       /* avoid macro reuse warning, so do not use GENMASK as above */
+#  define MCP25XXFD_CAN_FILCON_MASK(x)                                 \
+       (GENMASK(MCP25XXFD_CAN_FILCON_BITS_ - 1, 0) <<                  \
+        MCP25XXFD_CAN_FILCON_SHIFT(x))
+#  define MCP25XXFD_CAN_FIFOCON_FLTEN(x)                               \
+       BIT(7 + MCP25XXFD_CAN_FILCON_SHIFT(x))
+#define MCP25XXFD_CAN_FLTOBJ(x)                                                
\
+       MCP25XXFD_CAN_SFR_BASE(0x1F0 + 8 * (x))
+#  define MCP25XXFD_CAN_FILOBJ_SID_BITS                11
+#  define MCP25XXFD_CAN_FILOBJ_SID_SHIFT       0
+#  define MCP25XXFD_CAN_FILOBJ_SID_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_FILOBJ_SID_SHIFT +                        \
+               MCP25XXFD_CAN_FILOBJ_SID_BITS - 1,                      \
+               MCP25XXFD_CAN_FILOBJ_SID_SHIFT)
+#  define MCP25XXFD_CAN_FILOBJ_EID_BITS                18
+#  define MCP25XXFD_CAN_FILOBJ_EID_SHIFT       12
+#  define MCP25XXFD_CAN_FILOBJ_EID_MASK                                        
\
+       GENMASK(MCP25XXFD_CAN_FILOBJ_EID_SHIFT +                        \
+               MCP25XXFD_CAN_FILOBJ_EID_BITS - 1,                      \
+               MCP25XXFD_CAN_FILOBJ_EID_SHIFT)
+#  define MCP25XXFD_CAN_FILOBJ_SID11           BIT(29)
+#  define MCP25XXFD_CAN_FILOBJ_EXIDE           BIT(30)
+#define MCP25XXFD_CAN_FLTMASK(x)                                       \
+       MCP25XXFD_CAN_SFR_BASE(0x1F4 + 8 * (x))
+#  define MCP25XXFD_CAN_FILMASK_MSID_BITS      11
+#  define MCP25XXFD_CAN_FILMASK_MSID_SHIFT     0
+#  define MCP25XXFD_CAN_FILMASK_MSID_MASK                              \
+       GENMASK(MCP25XXFD_CAN_FILMASK_MSID_SHIFT +                      \
+               MCP25XXFD_CAN_FILMASK_MSID_BITS - 1,                    \
+               MCP25XXFD_CAN_FILMASK_MSID_SHIFT)
+#  define MCP25XXFD_CAN_FILMASK_MEID_BITS      18
+#  define MCP25XXFD_CAN_FILMASK_MEID_SHIFT     12
+#  define MCP25XXFD_CAN_FILMASK_MEID_MASK                              \
+       GENMASK(MCP25XXFD_CAN_FILMASK_MEID_SHIFT +                      \
+               MCP25XXFD_CAN_FILMASK_MEID_BITS - 1,                    \
+               MCP25XXFD_CAN_FILMASK_MEID_SHIFT)
+#  define MCP25XXFD_CAN_FILMASK_MSID11         BIT(29)
+#  define MCP25XXFD_CAN_FILMASK_MIDE           BIT(30)
+
+/* the FIFO Objects in SRAM */
+#define MCP25XXFD_SRAM_SIZE 2048
+#define MCP25XXFD_SRAM_ADDR(x) (0x400 + (x))
+
+/* memory structure in sram for tx fifos */
+struct mcp25xxfd_can_obj_tx {
+       u32 id;
+       u32 flags;
+       u8 data[];
+};
+
+/* memory structure in sram for rx fifos */
+struct mcp25xxfd_can_obj_rx {
+       u32 id;
+       u32 flags;
+       u32 ts;
+       u8 data[];
+};
+
+/* memory structure in sram for tef fifos */
+struct mcp25xxfd_can_obj_tef {
+       u32 id;
+       u32 flags;
+       u32 ts;
+};
+
+#define MCP25XXFD_CAN_OBJ_ID_SID_BITS          11
+#define MCP25XXFD_CAN_OBJ_ID_SID_SHIFT         0
+#define MCP25XXFD_CAN_OBJ_ID_SID_MASK                                  \
+       GENMASK(MCP25XXFD_CAN_OBJ_ID_SID_SHIFT +                        \
+               MCP25XXFD_CAN_OBJ_ID_SID_BITS - 1,                      \
+               MCP25XXFD_CAN_OBJ_ID_SID_SHIFT)
+#define MCP25XXFD_CAN_OBJ_ID_EID_BITS          18
+#define MCP25XXFD_CAN_OBJ_ID_EID_SHIFT         11
+#define MCP25XXFD_CAN_OBJ_ID_EID_MASK                                  \
+       GENMASK(MCP25XXFD_CAN_OBJ_ID_EID_SHIFT +                        \
+               MCP25XXFD_CAN_OBJ_ID_EID_BITS - 1,                      \
+               MCP25XXFD_CAN_OBJ_ID_EID_SHIFT)
+#define MCP25XXFD_CAN_OBJ_ID_SID_BIT11         BIT(29)
+
+#define MCP25XXFD_CAN_OBJ_FLAGS_DLC_BITS       4
+#define MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT      0
+#define MCP25XXFD_CAN_OBJ_FLAGS_DLC_MASK                               \
+       GENMASK(MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT +                     \
+               MCP25XXFD_CAN_OBJ_FLAGS_DLC_BITS - 1,                   \
+               MCP25XXFD_CAN_OBJ_FLAGS_DLC_SHIFT)
+#define MCP25XXFD_CAN_OBJ_FLAGS_IDE            BIT(4)
+#define MCP25XXFD_CAN_OBJ_FLAGS_RTR            BIT(5)
+#define MCP25XXFD_CAN_OBJ_FLAGS_BRS            BIT(6)
+#define MCP25XXFD_CAN_OBJ_FLAGS_FDF            BIT(7)
+#define MCP25XXFD_CAN_OBJ_FLAGS_ESI            BIT(8)
+#define MCP25XXFD_CAN_OBJ_FLAGS_SEQ_BITS       7
+#define MCP25XXFD_CAN_OBJ_FLAGS_SEQ_SHIFT      9
+#define MCP25XXFD_CAN_OBJ_FLAGS_SEQ_MASK                               \
+       GENMASK(MCP25XXFD_CAN_OBJ_FLAGS_SEQ_SHIFT +                     \
+               MCP25XXFD_CAN_OBJ_FLAGS_SEQ_BITS - 1,                   \
+               MCP25XXFD_CAN_OBJ_FLAGS_SEQ_SHIFT)
+#define MCP25XXFD_CAN_OBJ_FLAGS_FILHIT_BITS    11
+#define MCP25XXFD_CAN_OBJ_FLAGS_FILHIT_SHIFT   5
+#define MCP25XXFD_CAN_OBJ_FLAGS_FILHIT_MASK                            \
+       GENMASK(MCP25XXFD_CAN_FLAGS_FILHIT_SHIFT +                      \
+               MCP25XXFD_CAN_FLAGS_FILHIT_BITS - 1,                    \
+               MCP25XXFD_CAN_FLAGS_FILHIT_SHIFT)
+
+#endif /* __MCP25XXFD_REGS_H */
-- 
2.17.1

Reply via email to