xref: /linux/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
11f0e21a0SMarc Kleine-Budde // SPDX-License-Identifier: GPL-2.0
21f0e21a0SMarc Kleine-Budde //
3eb79a267SMarc Kleine-Budde // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
41f0e21a0SMarc Kleine-Budde //
5c912f19eSMarc Kleine-Budde // Copyright (c) 2019, 2020, 2021 Pengutronix,
61f0e21a0SMarc Kleine-Budde //               Marc Kleine-Budde <kernel@pengutronix.de>
71f0e21a0SMarc Kleine-Budde //
81f0e21a0SMarc Kleine-Budde 
91f0e21a0SMarc Kleine-Budde #include "mcp251xfd.h"
101f0e21a0SMarc Kleine-Budde 
111f0e21a0SMarc Kleine-Budde #include <asm/unaligned.h>
121f0e21a0SMarc Kleine-Budde 
13eb79a267SMarc Kleine-Budde static const struct regmap_config mcp251xfd_regmap_crc;
141f0e21a0SMarc Kleine-Budde 
151f0e21a0SMarc Kleine-Budde static int
16eb79a267SMarc Kleine-Budde mcp251xfd_regmap_nocrc_write(void *context, const void *data, size_t count)
171f0e21a0SMarc Kleine-Budde {
181f0e21a0SMarc Kleine-Budde 	struct spi_device *spi = context;
191f0e21a0SMarc Kleine-Budde 
201f0e21a0SMarc Kleine-Budde 	return spi_write(spi, data, count);
211f0e21a0SMarc Kleine-Budde }
221f0e21a0SMarc Kleine-Budde 
231f0e21a0SMarc Kleine-Budde static int
24eb79a267SMarc Kleine-Budde mcp251xfd_regmap_nocrc_gather_write(void *context,
251f0e21a0SMarc Kleine-Budde 				    const void *reg, size_t reg_len,
261f0e21a0SMarc Kleine-Budde 				    const void *val, size_t val_len)
271f0e21a0SMarc Kleine-Budde {
281f0e21a0SMarc Kleine-Budde 	struct spi_device *spi = context;
29eb79a267SMarc Kleine-Budde 	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
30eb79a267SMarc Kleine-Budde 	struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx;
311f0e21a0SMarc Kleine-Budde 	struct spi_transfer xfer[] = {
321f0e21a0SMarc Kleine-Budde 		{
331f0e21a0SMarc Kleine-Budde 			.tx_buf = buf_tx,
341f0e21a0SMarc Kleine-Budde 			.len = sizeof(buf_tx->cmd) + val_len,
351f0e21a0SMarc Kleine-Budde 		},
361f0e21a0SMarc Kleine-Budde 	};
371f0e21a0SMarc Kleine-Budde 
381f0e21a0SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16));
391f0e21a0SMarc Kleine-Budde 
40eb79a267SMarc Kleine-Budde 	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
411f0e21a0SMarc Kleine-Budde 	    reg_len != sizeof(buf_tx->cmd.cmd))
421f0e21a0SMarc Kleine-Budde 		return -EINVAL;
431f0e21a0SMarc Kleine-Budde 
441f0e21a0SMarc Kleine-Budde 	memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd));
451f0e21a0SMarc Kleine-Budde 	memcpy(buf_tx->data, val, val_len);
461f0e21a0SMarc Kleine-Budde 
471f0e21a0SMarc Kleine-Budde 	return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
481f0e21a0SMarc Kleine-Budde }
491f0e21a0SMarc Kleine-Budde 
50c912f19eSMarc Kleine-Budde static inline bool
51c912f19eSMarc Kleine-Budde mcp251xfd_update_bits_read_reg(const struct mcp251xfd_priv *priv,
52c912f19eSMarc Kleine-Budde 			       unsigned int reg)
531f0e21a0SMarc Kleine-Budde {
54c912f19eSMarc Kleine-Budde 	struct mcp251xfd_rx_ring *ring;
55c912f19eSMarc Kleine-Budde 	int n;
56c912f19eSMarc Kleine-Budde 
571f0e21a0SMarc Kleine-Budde 	switch (reg) {
58eb79a267SMarc Kleine-Budde 	case MCP251XFD_REG_INT:
59eb79a267SMarc Kleine-Budde 	case MCP251XFD_REG_TEFCON:
60eb79a267SMarc Kleine-Budde 	case MCP251XFD_REG_FLTCON(0):
61eb79a267SMarc Kleine-Budde 	case MCP251XFD_REG_ECCSTAT:
62eb79a267SMarc Kleine-Budde 	case MCP251XFD_REG_CRC:
631f0e21a0SMarc Kleine-Budde 		return false;
64eb79a267SMarc Kleine-Budde 	case MCP251XFD_REG_CON:
65eb79a267SMarc Kleine-Budde 	case MCP251XFD_REG_OSC:
66eb79a267SMarc Kleine-Budde 	case MCP251XFD_REG_ECCCON:
671f0e21a0SMarc Kleine-Budde 		return true;
681f0e21a0SMarc Kleine-Budde 	default:
69c912f19eSMarc Kleine-Budde 		mcp251xfd_for_each_rx_ring(priv, ring, n) {
70c912f19eSMarc Kleine-Budde 			if (reg == MCP251XFD_REG_FIFOCON(ring->fifo_nr))
71c912f19eSMarc Kleine-Budde 				return false;
72c912f19eSMarc Kleine-Budde 			if (reg == MCP251XFD_REG_FIFOSTA(ring->fifo_nr))
73c912f19eSMarc Kleine-Budde 				return true;
74c912f19eSMarc Kleine-Budde 		}
75c912f19eSMarc Kleine-Budde 
761f0e21a0SMarc Kleine-Budde 		WARN(1, "Status of reg 0x%04x unknown.\n", reg);
771f0e21a0SMarc Kleine-Budde 	}
781f0e21a0SMarc Kleine-Budde 
791f0e21a0SMarc Kleine-Budde 	return true;
801f0e21a0SMarc Kleine-Budde }
811f0e21a0SMarc Kleine-Budde 
821f0e21a0SMarc Kleine-Budde static int
83eb79a267SMarc Kleine-Budde mcp251xfd_regmap_nocrc_update_bits(void *context, unsigned int reg,
841f0e21a0SMarc Kleine-Budde 				   unsigned int mask, unsigned int val)
851f0e21a0SMarc Kleine-Budde {
861f0e21a0SMarc Kleine-Budde 	struct spi_device *spi = context;
87eb79a267SMarc Kleine-Budde 	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
88eb79a267SMarc Kleine-Budde 	struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx;
89eb79a267SMarc Kleine-Budde 	struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx;
901f0e21a0SMarc Kleine-Budde 	__le32 orig_le32 = 0, mask_le32, val_le32, tmp_le32;
911f0e21a0SMarc Kleine-Budde 	u8 first_byte, last_byte, len;
921f0e21a0SMarc Kleine-Budde 	int err;
931f0e21a0SMarc Kleine-Budde 
941f0e21a0SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16));
951f0e21a0SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16));
961f0e21a0SMarc Kleine-Budde 
97eb79a267SMarc Kleine-Budde 	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
981f0e21a0SMarc Kleine-Budde 	    mask == 0)
991f0e21a0SMarc Kleine-Budde 		return -EINVAL;
1001f0e21a0SMarc Kleine-Budde 
101eb79a267SMarc Kleine-Budde 	first_byte = mcp251xfd_first_byte_set(mask);
102eb79a267SMarc Kleine-Budde 	last_byte = mcp251xfd_last_byte_set(mask);
1031f0e21a0SMarc Kleine-Budde 	len = last_byte - first_byte + 1;
1041f0e21a0SMarc Kleine-Budde 
105c912f19eSMarc Kleine-Budde 	if (mcp251xfd_update_bits_read_reg(priv, reg)) {
1061f0e21a0SMarc Kleine-Budde 		struct spi_transfer xfer[2] = { };
1071f0e21a0SMarc Kleine-Budde 		struct spi_message msg;
1081f0e21a0SMarc Kleine-Budde 
1091f0e21a0SMarc Kleine-Budde 		spi_message_init(&msg);
1101f0e21a0SMarc Kleine-Budde 		spi_message_add_tail(&xfer[0], &msg);
1111f0e21a0SMarc Kleine-Budde 
112eb79a267SMarc Kleine-Budde 		if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) {
1131f0e21a0SMarc Kleine-Budde 			xfer[0].tx_buf = buf_tx;
1141f0e21a0SMarc Kleine-Budde 			xfer[0].len = sizeof(buf_tx->cmd);
1151f0e21a0SMarc Kleine-Budde 
1161f0e21a0SMarc Kleine-Budde 			xfer[1].rx_buf = buf_rx->data;
1171f0e21a0SMarc Kleine-Budde 			xfer[1].len = len;
1181f0e21a0SMarc Kleine-Budde 			spi_message_add_tail(&xfer[1], &msg);
1191f0e21a0SMarc Kleine-Budde 		} else {
1201f0e21a0SMarc Kleine-Budde 			xfer[0].tx_buf = buf_tx;
1211f0e21a0SMarc Kleine-Budde 			xfer[0].rx_buf = buf_rx;
1221f0e21a0SMarc Kleine-Budde 			xfer[0].len = sizeof(buf_tx->cmd) + len;
1231f0e21a0SMarc Kleine-Budde 
124eb79a267SMarc Kleine-Budde 			if (MCP251XFD_SANITIZE_SPI)
1251f0e21a0SMarc Kleine-Budde 				memset(buf_tx->data, 0x0, len);
1261f0e21a0SMarc Kleine-Budde 		}
1271f0e21a0SMarc Kleine-Budde 
128eb79a267SMarc Kleine-Budde 		mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, reg + first_byte);
1291f0e21a0SMarc Kleine-Budde 		err = spi_sync(spi, &msg);
1301f0e21a0SMarc Kleine-Budde 		if (err)
1311f0e21a0SMarc Kleine-Budde 			return err;
1321f0e21a0SMarc Kleine-Budde 
1331f0e21a0SMarc Kleine-Budde 		memcpy(&orig_le32, buf_rx->data, len);
1341f0e21a0SMarc Kleine-Budde 	}
1351f0e21a0SMarc Kleine-Budde 
1361f0e21a0SMarc Kleine-Budde 	mask_le32 = cpu_to_le32(mask >> BITS_PER_BYTE * first_byte);
1371f0e21a0SMarc Kleine-Budde 	val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte);
1381f0e21a0SMarc Kleine-Budde 
1391f0e21a0SMarc Kleine-Budde 	tmp_le32 = orig_le32 & ~mask_le32;
1401f0e21a0SMarc Kleine-Budde 	tmp_le32 |= val_le32 & mask_le32;
1411f0e21a0SMarc Kleine-Budde 
142eb79a267SMarc Kleine-Budde 	mcp251xfd_spi_cmd_write_nocrc(&buf_tx->cmd, reg + first_byte);
1431f0e21a0SMarc Kleine-Budde 	memcpy(buf_tx->data, &tmp_le32, len);
1441f0e21a0SMarc Kleine-Budde 
1451f0e21a0SMarc Kleine-Budde 	return spi_write(spi, buf_tx, sizeof(buf_tx->cmd) + len);
1461f0e21a0SMarc Kleine-Budde }
1471f0e21a0SMarc Kleine-Budde 
1481f0e21a0SMarc Kleine-Budde static int
149eb79a267SMarc Kleine-Budde mcp251xfd_regmap_nocrc_read(void *context,
1501f0e21a0SMarc Kleine-Budde 			    const void *reg, size_t reg_len,
1511f0e21a0SMarc Kleine-Budde 			    void *val_buf, size_t val_len)
1521f0e21a0SMarc Kleine-Budde {
1531f0e21a0SMarc Kleine-Budde 	struct spi_device *spi = context;
154eb79a267SMarc Kleine-Budde 	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
155eb79a267SMarc Kleine-Budde 	struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx;
156eb79a267SMarc Kleine-Budde 	struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx;
1571f0e21a0SMarc Kleine-Budde 	struct spi_transfer xfer[2] = { };
1581f0e21a0SMarc Kleine-Budde 	struct spi_message msg;
1591f0e21a0SMarc Kleine-Budde 	int err;
1601f0e21a0SMarc Kleine-Budde 
1611f0e21a0SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16));
1621f0e21a0SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16));
1631f0e21a0SMarc Kleine-Budde 
164eb79a267SMarc Kleine-Budde 	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
1651f0e21a0SMarc Kleine-Budde 	    reg_len != sizeof(buf_tx->cmd.cmd))
1661f0e21a0SMarc Kleine-Budde 		return -EINVAL;
1671f0e21a0SMarc Kleine-Budde 
1681f0e21a0SMarc Kleine-Budde 	spi_message_init(&msg);
1691f0e21a0SMarc Kleine-Budde 	spi_message_add_tail(&xfer[0], &msg);
1701f0e21a0SMarc Kleine-Budde 
171eb79a267SMarc Kleine-Budde 	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) {
1721f0e21a0SMarc Kleine-Budde 		xfer[0].tx_buf = reg;
1731f0e21a0SMarc Kleine-Budde 		xfer[0].len = sizeof(buf_tx->cmd);
1741f0e21a0SMarc Kleine-Budde 
1751f0e21a0SMarc Kleine-Budde 		xfer[1].rx_buf = val_buf;
1761f0e21a0SMarc Kleine-Budde 		xfer[1].len = val_len;
1771f0e21a0SMarc Kleine-Budde 		spi_message_add_tail(&xfer[1], &msg);
1781f0e21a0SMarc Kleine-Budde 	} else {
1791f0e21a0SMarc Kleine-Budde 		xfer[0].tx_buf = buf_tx;
1801f0e21a0SMarc Kleine-Budde 		xfer[0].rx_buf = buf_rx;
1811f0e21a0SMarc Kleine-Budde 		xfer[0].len = sizeof(buf_tx->cmd) + val_len;
1821f0e21a0SMarc Kleine-Budde 
1831f0e21a0SMarc Kleine-Budde 		memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd));
184eb79a267SMarc Kleine-Budde 		if (MCP251XFD_SANITIZE_SPI)
1851f0e21a0SMarc Kleine-Budde 			memset(buf_tx->data, 0x0, val_len);
186da623840Skernel test robot 	}
1871f0e21a0SMarc Kleine-Budde 
1881f0e21a0SMarc Kleine-Budde 	err = spi_sync(spi, &msg);
1891f0e21a0SMarc Kleine-Budde 	if (err)
1901f0e21a0SMarc Kleine-Budde 		return err;
1911f0e21a0SMarc Kleine-Budde 
192eb79a267SMarc Kleine-Budde 	if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX))
1931f0e21a0SMarc Kleine-Budde 		memcpy(val_buf, buf_rx->data, val_len);
1941f0e21a0SMarc Kleine-Budde 
1951f0e21a0SMarc Kleine-Budde 	return 0;
1961f0e21a0SMarc Kleine-Budde }
1971f0e21a0SMarc Kleine-Budde 
1981f0e21a0SMarc Kleine-Budde static int
199eb79a267SMarc Kleine-Budde mcp251xfd_regmap_crc_gather_write(void *context,
2001f0e21a0SMarc Kleine-Budde 				  const void *reg_p, size_t reg_len,
2011f0e21a0SMarc Kleine-Budde 				  const void *val, size_t val_len)
2021f0e21a0SMarc Kleine-Budde {
2031f0e21a0SMarc Kleine-Budde 	struct spi_device *spi = context;
204eb79a267SMarc Kleine-Budde 	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
205eb79a267SMarc Kleine-Budde 	struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx;
2061f0e21a0SMarc Kleine-Budde 	struct spi_transfer xfer[] = {
2071f0e21a0SMarc Kleine-Budde 		{
2081f0e21a0SMarc Kleine-Budde 			.tx_buf = buf_tx,
2091f0e21a0SMarc Kleine-Budde 			.len = sizeof(buf_tx->cmd) + val_len +
2101f0e21a0SMarc Kleine-Budde 				sizeof(buf_tx->crc),
2111f0e21a0SMarc Kleine-Budde 		},
2121f0e21a0SMarc Kleine-Budde 	};
2131f0e21a0SMarc Kleine-Budde 	u16 reg = *(u16 *)reg_p;
2141f0e21a0SMarc Kleine-Budde 	u16 crc;
2151f0e21a0SMarc Kleine-Budde 
2161f0e21a0SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8));
2171f0e21a0SMarc Kleine-Budde 
218eb79a267SMarc Kleine-Budde 	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
2191f0e21a0SMarc Kleine-Budde 	    reg_len != sizeof(buf_tx->cmd.cmd) +
220eb79a267SMarc Kleine-Budde 	    mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE)
2211f0e21a0SMarc Kleine-Budde 		return -EINVAL;
2221f0e21a0SMarc Kleine-Budde 
223eb79a267SMarc Kleine-Budde 	mcp251xfd_spi_cmd_write_crc(&buf_tx->cmd, reg, val_len);
2241f0e21a0SMarc Kleine-Budde 	memcpy(buf_tx->data, val, val_len);
2251f0e21a0SMarc Kleine-Budde 
226eb79a267SMarc Kleine-Budde 	crc = mcp251xfd_crc16_compute(buf_tx, sizeof(buf_tx->cmd) + val_len);
2271f0e21a0SMarc Kleine-Budde 	put_unaligned_be16(crc, buf_tx->data + val_len);
2281f0e21a0SMarc Kleine-Budde 
2291f0e21a0SMarc Kleine-Budde 	return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
2301f0e21a0SMarc Kleine-Budde }
2311f0e21a0SMarc Kleine-Budde 
2321f0e21a0SMarc Kleine-Budde static int
233eb79a267SMarc Kleine-Budde mcp251xfd_regmap_crc_write(void *context,
2341f0e21a0SMarc Kleine-Budde 			   const void *data, size_t count)
2351f0e21a0SMarc Kleine-Budde {
2361f0e21a0SMarc Kleine-Budde 	const size_t data_offset = sizeof(__be16) +
237eb79a267SMarc Kleine-Budde 		mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE;
2381f0e21a0SMarc Kleine-Budde 
239eb79a267SMarc Kleine-Budde 	return mcp251xfd_regmap_crc_gather_write(context,
2401f0e21a0SMarc Kleine-Budde 						 data, data_offset,
2411f0e21a0SMarc Kleine-Budde 						 data + data_offset,
2421f0e21a0SMarc Kleine-Budde 						 count - data_offset);
2431f0e21a0SMarc Kleine-Budde }
2441f0e21a0SMarc Kleine-Budde 
2451f0e21a0SMarc Kleine-Budde static int
246ef7a8c3eSMarc Kleine-Budde mcp251xfd_regmap_crc_read_check_crc(const struct mcp251xfd_map_buf_crc * const buf_rx,
247ef7a8c3eSMarc Kleine-Budde 				    const struct mcp251xfd_map_buf_crc * const buf_tx,
248ef7a8c3eSMarc Kleine-Budde 				    unsigned int data_len)
2491f0e21a0SMarc Kleine-Budde {
2501f0e21a0SMarc Kleine-Budde 	u16 crc_received, crc_calculated;
2511f0e21a0SMarc Kleine-Budde 
2521f0e21a0SMarc Kleine-Budde 	crc_received = get_unaligned_be16(buf_rx->data + data_len);
253eb79a267SMarc Kleine-Budde 	crc_calculated = mcp251xfd_crc16_compute2(&buf_tx->cmd,
2541f0e21a0SMarc Kleine-Budde 						  sizeof(buf_tx->cmd),
2551f0e21a0SMarc Kleine-Budde 						  buf_rx->data,
2561f0e21a0SMarc Kleine-Budde 						  data_len);
2571f0e21a0SMarc Kleine-Budde 	if (crc_received != crc_calculated)
2581f0e21a0SMarc Kleine-Budde 		return -EBADMSG;
2591f0e21a0SMarc Kleine-Budde 
2601f0e21a0SMarc Kleine-Budde 	return 0;
2611f0e21a0SMarc Kleine-Budde }
2621f0e21a0SMarc Kleine-Budde 
263ef7a8c3eSMarc Kleine-Budde static int
264ef7a8c3eSMarc Kleine-Budde mcp251xfd_regmap_crc_read_one(struct mcp251xfd_priv *priv,
265ef7a8c3eSMarc Kleine-Budde 			      struct spi_message *msg, unsigned int data_len)
266ef7a8c3eSMarc Kleine-Budde {
267ef7a8c3eSMarc Kleine-Budde 	const struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx;
268ef7a8c3eSMarc Kleine-Budde 	const struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx;
269ef7a8c3eSMarc Kleine-Budde 	int err;
270ef7a8c3eSMarc Kleine-Budde 
271ef7a8c3eSMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8));
272ef7a8c3eSMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8));
273ef7a8c3eSMarc Kleine-Budde 
274ef7a8c3eSMarc Kleine-Budde 	err = spi_sync(priv->spi, msg);
275ef7a8c3eSMarc Kleine-Budde 	if (err)
276ef7a8c3eSMarc Kleine-Budde 		return err;
277ef7a8c3eSMarc Kleine-Budde 
278ef7a8c3eSMarc Kleine-Budde 	return mcp251xfd_regmap_crc_read_check_crc(buf_rx, buf_tx, data_len);
279ef7a8c3eSMarc Kleine-Budde }
280ef7a8c3eSMarc Kleine-Budde 
2811f0e21a0SMarc Kleine-Budde static int
282eb79a267SMarc Kleine-Budde mcp251xfd_regmap_crc_read(void *context,
2831f0e21a0SMarc Kleine-Budde 			  const void *reg_p, size_t reg_len,
2841f0e21a0SMarc Kleine-Budde 			  void *val_buf, size_t val_len)
2851f0e21a0SMarc Kleine-Budde {
2861f0e21a0SMarc Kleine-Budde 	struct spi_device *spi = context;
287eb79a267SMarc Kleine-Budde 	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
288eb79a267SMarc Kleine-Budde 	struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx;
289eb79a267SMarc Kleine-Budde 	struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx;
2901f0e21a0SMarc Kleine-Budde 	struct spi_transfer xfer[2] = { };
2911f0e21a0SMarc Kleine-Budde 	struct spi_message msg;
2921f0e21a0SMarc Kleine-Budde 	u16 reg = *(u16 *)reg_p;
2931f0e21a0SMarc Kleine-Budde 	int i, err;
2941f0e21a0SMarc Kleine-Budde 
2951f0e21a0SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8));
2961f0e21a0SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8));
2971f0e21a0SMarc Kleine-Budde 
298eb79a267SMarc Kleine-Budde 	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
2991f0e21a0SMarc Kleine-Budde 	    reg_len != sizeof(buf_tx->cmd.cmd) +
300eb79a267SMarc Kleine-Budde 	    mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE)
3011f0e21a0SMarc Kleine-Budde 		return -EINVAL;
3021f0e21a0SMarc Kleine-Budde 
3031f0e21a0SMarc Kleine-Budde 	spi_message_init(&msg);
3041f0e21a0SMarc Kleine-Budde 	spi_message_add_tail(&xfer[0], &msg);
3051f0e21a0SMarc Kleine-Budde 
306eb79a267SMarc Kleine-Budde 	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) {
3071f0e21a0SMarc Kleine-Budde 		xfer[0].tx_buf = buf_tx;
3081f0e21a0SMarc Kleine-Budde 		xfer[0].len = sizeof(buf_tx->cmd);
3091f0e21a0SMarc Kleine-Budde 
3101f0e21a0SMarc Kleine-Budde 		xfer[1].rx_buf = buf_rx->data;
3111f0e21a0SMarc Kleine-Budde 		xfer[1].len = val_len + sizeof(buf_tx->crc);
3121f0e21a0SMarc Kleine-Budde 		spi_message_add_tail(&xfer[1], &msg);
3131f0e21a0SMarc Kleine-Budde 	} else {
3141f0e21a0SMarc Kleine-Budde 		xfer[0].tx_buf = buf_tx;
3151f0e21a0SMarc Kleine-Budde 		xfer[0].rx_buf = buf_rx;
3161f0e21a0SMarc Kleine-Budde 		xfer[0].len = sizeof(buf_tx->cmd) + val_len +
3171f0e21a0SMarc Kleine-Budde 			sizeof(buf_tx->crc);
3181f0e21a0SMarc Kleine-Budde 
319eb79a267SMarc Kleine-Budde 		if (MCP251XFD_SANITIZE_SPI)
3201f0e21a0SMarc Kleine-Budde 			memset(buf_tx->data, 0x0, val_len +
3211f0e21a0SMarc Kleine-Budde 			       sizeof(buf_tx->crc));
3221f0e21a0SMarc Kleine-Budde 	}
3231f0e21a0SMarc Kleine-Budde 
324eb79a267SMarc Kleine-Budde 	mcp251xfd_spi_cmd_read_crc(&buf_tx->cmd, reg, val_len);
3251f0e21a0SMarc Kleine-Budde 
326eb79a267SMarc Kleine-Budde 	for (i = 0; i < MCP251XFD_READ_CRC_RETRIES_MAX; i++) {
327eb79a267SMarc Kleine-Budde 		err = mcp251xfd_regmap_crc_read_one(priv, &msg, val_len);
3281f0e21a0SMarc Kleine-Budde 		if (!err)
3291f0e21a0SMarc Kleine-Budde 			goto out;
3301f0e21a0SMarc Kleine-Budde 		if (err != -EBADMSG)
3311f0e21a0SMarc Kleine-Budde 			return err;
3321f0e21a0SMarc Kleine-Budde 
333c7eb923cSMarc Kleine-Budde 		/* MCP251XFD_REG_TBC is the time base counter
334c7eb923cSMarc Kleine-Budde 		 * register. It increments once per SYS clock tick,
335c7eb923cSMarc Kleine-Budde 		 * which is 20 or 40 MHz.
336c7eb923cSMarc Kleine-Budde 		 *
337406cc9cdSThomas Kopp 		 * Observation on the mcp2518fd shows that if the
338406cc9cdSThomas Kopp 		 * lowest byte (which is transferred first on the SPI
339406cc9cdSThomas Kopp 		 * bus) of that register is 0x00 or 0x80 the
340406cc9cdSThomas Kopp 		 * calculated CRC doesn't always match the transferred
341406cc9cdSThomas Kopp 		 * one. On the mcp2517fd this problem is not limited
342406cc9cdSThomas Kopp 		 * to the first byte being 0x00 or 0x80.
343c7eb923cSMarc Kleine-Budde 		 *
344c7eb923cSMarc Kleine-Budde 		 * If the highest bit in the lowest byte is flipped
345c7eb923cSMarc Kleine-Budde 		 * the transferred CRC matches the calculated one. We
346*e3d4ee7dSThomas Kopp 		 * assume for now the CRC operates on the correct
347*e3d4ee7dSThomas Kopp 		 * data.
348c7eb923cSMarc Kleine-Budde 		 */
349c7eb923cSMarc Kleine-Budde 		if (reg == MCP251XFD_REG_TBC &&
350406cc9cdSThomas Kopp 		    ((buf_rx->data[0] & 0xf8) == 0x0 ||
351406cc9cdSThomas Kopp 		     (buf_rx->data[0] & 0xf8) == 0x80)) {
352c7eb923cSMarc Kleine-Budde 			/* Flip highest bit in lowest byte of le32 */
353c7eb923cSMarc Kleine-Budde 			buf_rx->data[0] ^= 0x80;
354c7eb923cSMarc Kleine-Budde 
355c7eb923cSMarc Kleine-Budde 			/* re-check CRC */
356c7eb923cSMarc Kleine-Budde 			err = mcp251xfd_regmap_crc_read_check_crc(buf_rx,
357c7eb923cSMarc Kleine-Budde 								  buf_tx,
358c7eb923cSMarc Kleine-Budde 								  val_len);
359c7eb923cSMarc Kleine-Budde 			if (!err) {
360c7eb923cSMarc Kleine-Budde 				/* If CRC is now correct, assume
361*e3d4ee7dSThomas Kopp 				 * flipped data is OK.
362c7eb923cSMarc Kleine-Budde 				 */
363c7eb923cSMarc Kleine-Budde 				goto out;
364c7eb923cSMarc Kleine-Budde 			}
365c7eb923cSMarc Kleine-Budde 		}
366c7eb923cSMarc Kleine-Budde 
367eb79a267SMarc Kleine-Budde 		/* MCP251XFD_REG_OSC is the first ever reg we read from.
3681f0e21a0SMarc Kleine-Budde 		 *
3691f0e21a0SMarc Kleine-Budde 		 * The chip may be in deep sleep and this SPI transfer
3701f0e21a0SMarc Kleine-Budde 		 * (i.e. the assertion of the CS) will wake the chip
3711f0e21a0SMarc Kleine-Budde 		 * up. This takes about 3ms. The CRC of this transfer
3721f0e21a0SMarc Kleine-Budde 		 * is wrong.
3731f0e21a0SMarc Kleine-Budde 		 *
3741f0e21a0SMarc Kleine-Budde 		 * Or there isn't a chip at all, in this case the CRC
3751f0e21a0SMarc Kleine-Budde 		 * will be wrong, too.
3761f0e21a0SMarc Kleine-Budde 		 *
3771f0e21a0SMarc Kleine-Budde 		 * In both cases ignore the CRC and copy the read data
3781f0e21a0SMarc Kleine-Budde 		 * to the caller. It will take care of both cases.
3791f0e21a0SMarc Kleine-Budde 		 *
3801f0e21a0SMarc Kleine-Budde 		 */
38125386c9aSMarc Kleine-Budde 		if (reg == MCP251XFD_REG_OSC && val_len == sizeof(__le32)) {
3821f0e21a0SMarc Kleine-Budde 			err = 0;
3831f0e21a0SMarc Kleine-Budde 			goto out;
3841f0e21a0SMarc Kleine-Budde 		}
3851f0e21a0SMarc Kleine-Budde 
386b4728920SMarc Kleine-Budde 		netdev_info(priv->ndev,
3871f0e21a0SMarc Kleine-Budde 			    "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x) retrying.\n",
3881f0e21a0SMarc Kleine-Budde 			    reg, val_len, (int)val_len, buf_rx->data,
3891f0e21a0SMarc Kleine-Budde 			    get_unaligned_be16(buf_rx->data + val_len));
3901f0e21a0SMarc Kleine-Budde 	}
3911f0e21a0SMarc Kleine-Budde 
3921f0e21a0SMarc Kleine-Budde 	if (err) {
393b4728920SMarc Kleine-Budde 		netdev_err(priv->ndev,
3941f0e21a0SMarc Kleine-Budde 			   "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x).\n",
3951f0e21a0SMarc Kleine-Budde 			   reg, val_len, (int)val_len, buf_rx->data,
3961f0e21a0SMarc Kleine-Budde 			   get_unaligned_be16(buf_rx->data + val_len));
3971f0e21a0SMarc Kleine-Budde 
3981f0e21a0SMarc Kleine-Budde 		return err;
3991f0e21a0SMarc Kleine-Budde 	}
4001f0e21a0SMarc Kleine-Budde out:
4011f0e21a0SMarc Kleine-Budde 	memcpy(val_buf, buf_rx->data, val_len);
4021f0e21a0SMarc Kleine-Budde 
4031f0e21a0SMarc Kleine-Budde 	return 0;
4041f0e21a0SMarc Kleine-Budde }
4051f0e21a0SMarc Kleine-Budde 
406eb79a267SMarc Kleine-Budde static const struct regmap_range mcp251xfd_reg_table_yes_range[] = {
4071f0e21a0SMarc Kleine-Budde 	regmap_reg_range(0x000, 0x2ec),	/* CAN FD Controller Module SFR */
4081f0e21a0SMarc Kleine-Budde 	regmap_reg_range(0x400, 0xbfc),	/* RAM */
4091f0e21a0SMarc Kleine-Budde 	regmap_reg_range(0xe00, 0xe14),	/* MCP2517/18FD SFR */
4101f0e21a0SMarc Kleine-Budde };
4111f0e21a0SMarc Kleine-Budde 
412eb79a267SMarc Kleine-Budde static const struct regmap_access_table mcp251xfd_reg_table = {
413eb79a267SMarc Kleine-Budde 	.yes_ranges = mcp251xfd_reg_table_yes_range,
414eb79a267SMarc Kleine-Budde 	.n_yes_ranges = ARRAY_SIZE(mcp251xfd_reg_table_yes_range),
4151f0e21a0SMarc Kleine-Budde };
4161f0e21a0SMarc Kleine-Budde 
417eb79a267SMarc Kleine-Budde static const struct regmap_config mcp251xfd_regmap_nocrc = {
4181f0e21a0SMarc Kleine-Budde 	.name = "nocrc",
4191f0e21a0SMarc Kleine-Budde 	.reg_bits = 16,
4201f0e21a0SMarc Kleine-Budde 	.reg_stride = 4,
4211f0e21a0SMarc Kleine-Budde 	.pad_bits = 0,
4221f0e21a0SMarc Kleine-Budde 	.val_bits = 32,
4231f0e21a0SMarc Kleine-Budde 	.max_register = 0xffc,
424eb79a267SMarc Kleine-Budde 	.wr_table = &mcp251xfd_reg_table,
425eb79a267SMarc Kleine-Budde 	.rd_table = &mcp251xfd_reg_table,
4261f0e21a0SMarc Kleine-Budde 	.cache_type = REGCACHE_NONE,
4271f0e21a0SMarc Kleine-Budde 	.read_flag_mask = (__force unsigned long)
428eb79a267SMarc Kleine-Budde 		cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_READ),
4291f0e21a0SMarc Kleine-Budde 	.write_flag_mask = (__force unsigned long)
430eb79a267SMarc Kleine-Budde 		cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE),
4311f0e21a0SMarc Kleine-Budde };
4321f0e21a0SMarc Kleine-Budde 
433eb79a267SMarc Kleine-Budde static const struct regmap_bus mcp251xfd_bus_nocrc = {
434eb79a267SMarc Kleine-Budde 	.write = mcp251xfd_regmap_nocrc_write,
435eb79a267SMarc Kleine-Budde 	.gather_write = mcp251xfd_regmap_nocrc_gather_write,
436eb79a267SMarc Kleine-Budde 	.reg_update_bits = mcp251xfd_regmap_nocrc_update_bits,
437eb79a267SMarc Kleine-Budde 	.read = mcp251xfd_regmap_nocrc_read,
4381f0e21a0SMarc Kleine-Budde 	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
4391f0e21a0SMarc Kleine-Budde 	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
440eb79a267SMarc Kleine-Budde 	.max_raw_read = sizeof_field(struct mcp251xfd_map_buf_nocrc, data),
441eb79a267SMarc Kleine-Budde 	.max_raw_write = sizeof_field(struct mcp251xfd_map_buf_nocrc, data),
4421f0e21a0SMarc Kleine-Budde };
4431f0e21a0SMarc Kleine-Budde 
444eb79a267SMarc Kleine-Budde static const struct regmap_config mcp251xfd_regmap_crc = {
4451f0e21a0SMarc Kleine-Budde 	.name = "crc",
4461f0e21a0SMarc Kleine-Budde 	.reg_bits = 16,
4471f0e21a0SMarc Kleine-Budde 	.reg_stride = 4,
4481f0e21a0SMarc Kleine-Budde 	.pad_bits = 16,		/* keep data bits aligned */
4491f0e21a0SMarc Kleine-Budde 	.val_bits = 32,
4501f0e21a0SMarc Kleine-Budde 	.max_register = 0xffc,
451eb79a267SMarc Kleine-Budde 	.wr_table = &mcp251xfd_reg_table,
452eb79a267SMarc Kleine-Budde 	.rd_table = &mcp251xfd_reg_table,
4531f0e21a0SMarc Kleine-Budde 	.cache_type = REGCACHE_NONE,
4541f0e21a0SMarc Kleine-Budde };
4551f0e21a0SMarc Kleine-Budde 
456eb79a267SMarc Kleine-Budde static const struct regmap_bus mcp251xfd_bus_crc = {
457eb79a267SMarc Kleine-Budde 	.write = mcp251xfd_regmap_crc_write,
458eb79a267SMarc Kleine-Budde 	.gather_write = mcp251xfd_regmap_crc_gather_write,
459eb79a267SMarc Kleine-Budde 	.read = mcp251xfd_regmap_crc_read,
4601f0e21a0SMarc Kleine-Budde 	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
4611f0e21a0SMarc Kleine-Budde 	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
462eb79a267SMarc Kleine-Budde 	.max_raw_read = sizeof_field(struct mcp251xfd_map_buf_crc, data),
463eb79a267SMarc Kleine-Budde 	.max_raw_write = sizeof_field(struct mcp251xfd_map_buf_crc, data),
4641f0e21a0SMarc Kleine-Budde };
4651f0e21a0SMarc Kleine-Budde 
4661f0e21a0SMarc Kleine-Budde static inline bool
467eb79a267SMarc Kleine-Budde mcp251xfd_regmap_use_nocrc(struct mcp251xfd_priv *priv)
4681f0e21a0SMarc Kleine-Budde {
469eb79a267SMarc Kleine-Budde 	return (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) ||
470eb79a267SMarc Kleine-Budde 		(!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX));
4711f0e21a0SMarc Kleine-Budde }
4721f0e21a0SMarc Kleine-Budde 
4731f0e21a0SMarc Kleine-Budde static inline bool
474eb79a267SMarc Kleine-Budde mcp251xfd_regmap_use_crc(struct mcp251xfd_priv *priv)
4751f0e21a0SMarc Kleine-Budde {
476eb79a267SMarc Kleine-Budde 	return (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) ||
477eb79a267SMarc Kleine-Budde 		(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX);
4781f0e21a0SMarc Kleine-Budde }
4791f0e21a0SMarc Kleine-Budde 
4801f0e21a0SMarc Kleine-Budde static int
481eb79a267SMarc Kleine-Budde mcp251xfd_regmap_init_nocrc(struct mcp251xfd_priv *priv)
4821f0e21a0SMarc Kleine-Budde {
4831f0e21a0SMarc Kleine-Budde 	if (!priv->map_nocrc) {
4841f0e21a0SMarc Kleine-Budde 		struct regmap *map;
4851f0e21a0SMarc Kleine-Budde 
486eb79a267SMarc Kleine-Budde 		map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_nocrc,
487eb79a267SMarc Kleine-Budde 				       priv->spi, &mcp251xfd_regmap_nocrc);
4881f0e21a0SMarc Kleine-Budde 		if (IS_ERR(map))
4891f0e21a0SMarc Kleine-Budde 			return PTR_ERR(map);
4901f0e21a0SMarc Kleine-Budde 
4911f0e21a0SMarc Kleine-Budde 		priv->map_nocrc = map;
4921f0e21a0SMarc Kleine-Budde 	}
4931f0e21a0SMarc Kleine-Budde 
4941f0e21a0SMarc Kleine-Budde 	if (!priv->map_buf_nocrc_rx) {
4951f0e21a0SMarc Kleine-Budde 		priv->map_buf_nocrc_rx =
4961f0e21a0SMarc Kleine-Budde 			devm_kzalloc(&priv->spi->dev,
4971f0e21a0SMarc Kleine-Budde 				     sizeof(*priv->map_buf_nocrc_rx),
4981f0e21a0SMarc Kleine-Budde 				     GFP_KERNEL);
4991f0e21a0SMarc Kleine-Budde 		if (!priv->map_buf_nocrc_rx)
5001f0e21a0SMarc Kleine-Budde 			return -ENOMEM;
5011f0e21a0SMarc Kleine-Budde 	}
5021f0e21a0SMarc Kleine-Budde 
5031f0e21a0SMarc Kleine-Budde 	if (!priv->map_buf_nocrc_tx) {
5041f0e21a0SMarc Kleine-Budde 		priv->map_buf_nocrc_tx =
5051f0e21a0SMarc Kleine-Budde 			devm_kzalloc(&priv->spi->dev,
5061f0e21a0SMarc Kleine-Budde 				     sizeof(*priv->map_buf_nocrc_tx),
5071f0e21a0SMarc Kleine-Budde 				     GFP_KERNEL);
5081f0e21a0SMarc Kleine-Budde 		if (!priv->map_buf_nocrc_tx)
5091f0e21a0SMarc Kleine-Budde 			return -ENOMEM;
5101f0e21a0SMarc Kleine-Budde 	}
5111f0e21a0SMarc Kleine-Budde 
512eb79a267SMarc Kleine-Budde 	if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG))
5131f0e21a0SMarc Kleine-Budde 		priv->map_reg = priv->map_nocrc;
5141f0e21a0SMarc Kleine-Budde 
515eb79a267SMarc Kleine-Budde 	if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX))
5161f0e21a0SMarc Kleine-Budde 		priv->map_rx = priv->map_nocrc;
5171f0e21a0SMarc Kleine-Budde 
5181f0e21a0SMarc Kleine-Budde 	return 0;
5191f0e21a0SMarc Kleine-Budde }
5201f0e21a0SMarc Kleine-Budde 
521eb79a267SMarc Kleine-Budde static void mcp251xfd_regmap_destroy_nocrc(struct mcp251xfd_priv *priv)
5221f0e21a0SMarc Kleine-Budde {
5231f0e21a0SMarc Kleine-Budde 	if (priv->map_buf_nocrc_rx) {
5241f0e21a0SMarc Kleine-Budde 		devm_kfree(&priv->spi->dev, priv->map_buf_nocrc_rx);
5251f0e21a0SMarc Kleine-Budde 		priv->map_buf_nocrc_rx = NULL;
5261f0e21a0SMarc Kleine-Budde 	}
5271f0e21a0SMarc Kleine-Budde 	if (priv->map_buf_nocrc_tx) {
5281f0e21a0SMarc Kleine-Budde 		devm_kfree(&priv->spi->dev, priv->map_buf_nocrc_tx);
5291f0e21a0SMarc Kleine-Budde 		priv->map_buf_nocrc_tx = NULL;
5301f0e21a0SMarc Kleine-Budde 	}
5311f0e21a0SMarc Kleine-Budde }
5321f0e21a0SMarc Kleine-Budde 
5331f0e21a0SMarc Kleine-Budde static int
534eb79a267SMarc Kleine-Budde mcp251xfd_regmap_init_crc(struct mcp251xfd_priv *priv)
5351f0e21a0SMarc Kleine-Budde {
5361f0e21a0SMarc Kleine-Budde 	if (!priv->map_crc) {
5371f0e21a0SMarc Kleine-Budde 		struct regmap *map;
5381f0e21a0SMarc Kleine-Budde 
539eb79a267SMarc Kleine-Budde 		map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_crc,
540eb79a267SMarc Kleine-Budde 				       priv->spi, &mcp251xfd_regmap_crc);
5411f0e21a0SMarc Kleine-Budde 		if (IS_ERR(map))
5421f0e21a0SMarc Kleine-Budde 			return PTR_ERR(map);
5431f0e21a0SMarc Kleine-Budde 
5441f0e21a0SMarc Kleine-Budde 		priv->map_crc = map;
5451f0e21a0SMarc Kleine-Budde 	}
5461f0e21a0SMarc Kleine-Budde 
5471f0e21a0SMarc Kleine-Budde 	if (!priv->map_buf_crc_rx) {
5481f0e21a0SMarc Kleine-Budde 		priv->map_buf_crc_rx =
5491f0e21a0SMarc Kleine-Budde 			devm_kzalloc(&priv->spi->dev,
5501f0e21a0SMarc Kleine-Budde 				     sizeof(*priv->map_buf_crc_rx),
5511f0e21a0SMarc Kleine-Budde 				     GFP_KERNEL);
5521f0e21a0SMarc Kleine-Budde 		if (!priv->map_buf_crc_rx)
5531f0e21a0SMarc Kleine-Budde 			return -ENOMEM;
5541f0e21a0SMarc Kleine-Budde 	}
5551f0e21a0SMarc Kleine-Budde 
5561f0e21a0SMarc Kleine-Budde 	if (!priv->map_buf_crc_tx) {
5571f0e21a0SMarc Kleine-Budde 		priv->map_buf_crc_tx =
5581f0e21a0SMarc Kleine-Budde 			devm_kzalloc(&priv->spi->dev,
5591f0e21a0SMarc Kleine-Budde 				     sizeof(*priv->map_buf_crc_tx),
5601f0e21a0SMarc Kleine-Budde 				     GFP_KERNEL);
5611f0e21a0SMarc Kleine-Budde 		if (!priv->map_buf_crc_tx)
5621f0e21a0SMarc Kleine-Budde 			return -ENOMEM;
5631f0e21a0SMarc Kleine-Budde 	}
5641f0e21a0SMarc Kleine-Budde 
565eb79a267SMarc Kleine-Budde 	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)
5661f0e21a0SMarc Kleine-Budde 		priv->map_reg = priv->map_crc;
5671f0e21a0SMarc Kleine-Budde 
568eb79a267SMarc Kleine-Budde 	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX)
5691f0e21a0SMarc Kleine-Budde 		priv->map_rx = priv->map_crc;
5701f0e21a0SMarc Kleine-Budde 
5711f0e21a0SMarc Kleine-Budde 	return 0;
5721f0e21a0SMarc Kleine-Budde }
5731f0e21a0SMarc Kleine-Budde 
574eb79a267SMarc Kleine-Budde static void mcp251xfd_regmap_destroy_crc(struct mcp251xfd_priv *priv)
5751f0e21a0SMarc Kleine-Budde {
5761f0e21a0SMarc Kleine-Budde 	if (priv->map_buf_crc_rx) {
5771f0e21a0SMarc Kleine-Budde 		devm_kfree(&priv->spi->dev, priv->map_buf_crc_rx);
5781f0e21a0SMarc Kleine-Budde 		priv->map_buf_crc_rx = NULL;
5791f0e21a0SMarc Kleine-Budde 	}
5801f0e21a0SMarc Kleine-Budde 	if (priv->map_buf_crc_tx) {
5811f0e21a0SMarc Kleine-Budde 		devm_kfree(&priv->spi->dev, priv->map_buf_crc_tx);
5821f0e21a0SMarc Kleine-Budde 		priv->map_buf_crc_tx = NULL;
5831f0e21a0SMarc Kleine-Budde 	}
5841f0e21a0SMarc Kleine-Budde }
5851f0e21a0SMarc Kleine-Budde 
586eb79a267SMarc Kleine-Budde int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv)
5871f0e21a0SMarc Kleine-Budde {
5881f0e21a0SMarc Kleine-Budde 	int err;
5891f0e21a0SMarc Kleine-Budde 
590eb79a267SMarc Kleine-Budde 	if (mcp251xfd_regmap_use_nocrc(priv)) {
591eb79a267SMarc Kleine-Budde 		err = mcp251xfd_regmap_init_nocrc(priv);
5921f0e21a0SMarc Kleine-Budde 
5931f0e21a0SMarc Kleine-Budde 		if (err)
5941f0e21a0SMarc Kleine-Budde 			return err;
5951f0e21a0SMarc Kleine-Budde 	} else {
596eb79a267SMarc Kleine-Budde 		mcp251xfd_regmap_destroy_nocrc(priv);
5971f0e21a0SMarc Kleine-Budde 	}
5981f0e21a0SMarc Kleine-Budde 
599eb79a267SMarc Kleine-Budde 	if (mcp251xfd_regmap_use_crc(priv)) {
600eb79a267SMarc Kleine-Budde 		err = mcp251xfd_regmap_init_crc(priv);
6011f0e21a0SMarc Kleine-Budde 
6021f0e21a0SMarc Kleine-Budde 		if (err)
6031f0e21a0SMarc Kleine-Budde 			return err;
6041f0e21a0SMarc Kleine-Budde 	} else {
605eb79a267SMarc Kleine-Budde 		mcp251xfd_regmap_destroy_crc(priv);
6061f0e21a0SMarc Kleine-Budde 	}
6071f0e21a0SMarc Kleine-Budde 
6081f0e21a0SMarc Kleine-Budde 	return 0;
6091f0e21a0SMarc Kleine-Budde }
610