18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright (c) 2019, 2020 Pengutronix,
68c2ecf20Sopenharmony_ci//                          Marc Kleine-Budde <kernel@pengutronix.de>
78c2ecf20Sopenharmony_ci//
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "mcp251xfd.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic const struct regmap_config mcp251xfd_regmap_crc;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic int
168c2ecf20Sopenharmony_cimcp251xfd_regmap_nocrc_write(void *context, const void *data, size_t count)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	struct spi_device *spi = context;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	return spi_write(spi, data, count);
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic int
248c2ecf20Sopenharmony_cimcp251xfd_regmap_nocrc_gather_write(void *context,
258c2ecf20Sopenharmony_ci				    const void *reg, size_t reg_len,
268c2ecf20Sopenharmony_ci				    const void *val, size_t val_len)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	struct spi_device *spi = context;
298c2ecf20Sopenharmony_ci	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
308c2ecf20Sopenharmony_ci	struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx;
318c2ecf20Sopenharmony_ci	struct spi_transfer xfer[] = {
328c2ecf20Sopenharmony_ci		{
338c2ecf20Sopenharmony_ci			.tx_buf = buf_tx,
348c2ecf20Sopenharmony_ci			.len = sizeof(buf_tx->cmd) + val_len,
358c2ecf20Sopenharmony_ci		},
368c2ecf20Sopenharmony_ci	};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16));
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
418c2ecf20Sopenharmony_ci	    reg_len != sizeof(buf_tx->cmd.cmd))
428c2ecf20Sopenharmony_ci		return -EINVAL;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd));
458c2ecf20Sopenharmony_ci	memcpy(buf_tx->data, val, val_len);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic inline bool mcp251xfd_update_bits_read_reg(unsigned int reg)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	switch (reg) {
538c2ecf20Sopenharmony_ci	case MCP251XFD_REG_INT:
548c2ecf20Sopenharmony_ci	case MCP251XFD_REG_TEFCON:
558c2ecf20Sopenharmony_ci	case MCP251XFD_REG_FIFOCON(MCP251XFD_RX_FIFO(0)):
568c2ecf20Sopenharmony_ci	case MCP251XFD_REG_FLTCON(0):
578c2ecf20Sopenharmony_ci	case MCP251XFD_REG_ECCSTAT:
588c2ecf20Sopenharmony_ci	case MCP251XFD_REG_CRC:
598c2ecf20Sopenharmony_ci		return false;
608c2ecf20Sopenharmony_ci	case MCP251XFD_REG_CON:
618c2ecf20Sopenharmony_ci	case MCP251XFD_REG_FIFOSTA(MCP251XFD_RX_FIFO(0)):
628c2ecf20Sopenharmony_ci	case MCP251XFD_REG_OSC:
638c2ecf20Sopenharmony_ci	case MCP251XFD_REG_ECCCON:
648c2ecf20Sopenharmony_ci		return true;
658c2ecf20Sopenharmony_ci	default:
668c2ecf20Sopenharmony_ci		WARN(1, "Status of reg 0x%04x unknown.\n", reg);
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	return true;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int
738c2ecf20Sopenharmony_cimcp251xfd_regmap_nocrc_update_bits(void *context, unsigned int reg,
748c2ecf20Sopenharmony_ci				   unsigned int mask, unsigned int val)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct spi_device *spi = context;
778c2ecf20Sopenharmony_ci	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
788c2ecf20Sopenharmony_ci	struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx;
798c2ecf20Sopenharmony_ci	struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx;
808c2ecf20Sopenharmony_ci	__le32 orig_le32 = 0, mask_le32, val_le32, tmp_le32;
818c2ecf20Sopenharmony_ci	u8 first_byte, last_byte, len;
828c2ecf20Sopenharmony_ci	int err;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16));
858c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16));
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
888c2ecf20Sopenharmony_ci	    mask == 0)
898c2ecf20Sopenharmony_ci		return -EINVAL;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	first_byte = mcp251xfd_first_byte_set(mask);
928c2ecf20Sopenharmony_ci	last_byte = mcp251xfd_last_byte_set(mask);
938c2ecf20Sopenharmony_ci	len = last_byte - first_byte + 1;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (mcp251xfd_update_bits_read_reg(reg)) {
968c2ecf20Sopenharmony_ci		struct spi_transfer xfer[2] = { };
978c2ecf20Sopenharmony_ci		struct spi_message msg;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		spi_message_init(&msg);
1008c2ecf20Sopenharmony_ci		spi_message_add_tail(&xfer[0], &msg);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) {
1038c2ecf20Sopenharmony_ci			xfer[0].tx_buf = buf_tx;
1048c2ecf20Sopenharmony_ci			xfer[0].len = sizeof(buf_tx->cmd);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci			xfer[1].rx_buf = buf_rx->data;
1078c2ecf20Sopenharmony_ci			xfer[1].len = len;
1088c2ecf20Sopenharmony_ci			spi_message_add_tail(&xfer[1], &msg);
1098c2ecf20Sopenharmony_ci		} else {
1108c2ecf20Sopenharmony_ci			xfer[0].tx_buf = buf_tx;
1118c2ecf20Sopenharmony_ci			xfer[0].rx_buf = buf_rx;
1128c2ecf20Sopenharmony_ci			xfer[0].len = sizeof(buf_tx->cmd) + len;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci			if (MCP251XFD_SANITIZE_SPI)
1158c2ecf20Sopenharmony_ci				memset(buf_tx->data, 0x0, len);
1168c2ecf20Sopenharmony_ci		}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, reg + first_byte);
1198c2ecf20Sopenharmony_ci		err = spi_sync(spi, &msg);
1208c2ecf20Sopenharmony_ci		if (err)
1218c2ecf20Sopenharmony_ci			return err;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		memcpy(&orig_le32, buf_rx->data, len);
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	mask_le32 = cpu_to_le32(mask >> BITS_PER_BYTE * first_byte);
1278c2ecf20Sopenharmony_ci	val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	tmp_le32 = orig_le32 & ~mask_le32;
1308c2ecf20Sopenharmony_ci	tmp_le32 |= val_le32 & mask_le32;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	mcp251xfd_spi_cmd_write_nocrc(&buf_tx->cmd, reg + first_byte);
1338c2ecf20Sopenharmony_ci	memcpy(buf_tx->data, &tmp_le32, len);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return spi_write(spi, buf_tx, sizeof(buf_tx->cmd) + len);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int
1398c2ecf20Sopenharmony_cimcp251xfd_regmap_nocrc_read(void *context,
1408c2ecf20Sopenharmony_ci			    const void *reg, size_t reg_len,
1418c2ecf20Sopenharmony_ci			    void *val_buf, size_t val_len)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct spi_device *spi = context;
1448c2ecf20Sopenharmony_ci	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
1458c2ecf20Sopenharmony_ci	struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx;
1468c2ecf20Sopenharmony_ci	struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx;
1478c2ecf20Sopenharmony_ci	struct spi_transfer xfer[2] = { };
1488c2ecf20Sopenharmony_ci	struct spi_message msg;
1498c2ecf20Sopenharmony_ci	int err;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16));
1528c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16));
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
1558c2ecf20Sopenharmony_ci	    reg_len != sizeof(buf_tx->cmd.cmd))
1568c2ecf20Sopenharmony_ci		return -EINVAL;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	spi_message_init(&msg);
1598c2ecf20Sopenharmony_ci	spi_message_add_tail(&xfer[0], &msg);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) {
1628c2ecf20Sopenharmony_ci		xfer[0].tx_buf = reg;
1638c2ecf20Sopenharmony_ci		xfer[0].len = sizeof(buf_tx->cmd);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		xfer[1].rx_buf = val_buf;
1668c2ecf20Sopenharmony_ci		xfer[1].len = val_len;
1678c2ecf20Sopenharmony_ci		spi_message_add_tail(&xfer[1], &msg);
1688c2ecf20Sopenharmony_ci	} else {
1698c2ecf20Sopenharmony_ci		xfer[0].tx_buf = buf_tx;
1708c2ecf20Sopenharmony_ci		xfer[0].rx_buf = buf_rx;
1718c2ecf20Sopenharmony_ci		xfer[0].len = sizeof(buf_tx->cmd) + val_len;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci		memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd));
1748c2ecf20Sopenharmony_ci		if (MCP251XFD_SANITIZE_SPI)
1758c2ecf20Sopenharmony_ci			memset(buf_tx->data, 0x0, val_len);
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	err = spi_sync(spi, &msg);
1798c2ecf20Sopenharmony_ci	if (err)
1808c2ecf20Sopenharmony_ci		return err;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX))
1838c2ecf20Sopenharmony_ci		memcpy(val_buf, buf_rx->data, val_len);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return 0;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int
1898c2ecf20Sopenharmony_cimcp251xfd_regmap_crc_gather_write(void *context,
1908c2ecf20Sopenharmony_ci				  const void *reg_p, size_t reg_len,
1918c2ecf20Sopenharmony_ci				  const void *val, size_t val_len)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct spi_device *spi = context;
1948c2ecf20Sopenharmony_ci	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
1958c2ecf20Sopenharmony_ci	struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx;
1968c2ecf20Sopenharmony_ci	struct spi_transfer xfer[] = {
1978c2ecf20Sopenharmony_ci		{
1988c2ecf20Sopenharmony_ci			.tx_buf = buf_tx,
1998c2ecf20Sopenharmony_ci			.len = sizeof(buf_tx->cmd) + val_len +
2008c2ecf20Sopenharmony_ci				sizeof(buf_tx->crc),
2018c2ecf20Sopenharmony_ci		},
2028c2ecf20Sopenharmony_ci	};
2038c2ecf20Sopenharmony_ci	u16 reg = *(u16 *)reg_p;
2048c2ecf20Sopenharmony_ci	u16 crc;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8));
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
2098c2ecf20Sopenharmony_ci	    reg_len != sizeof(buf_tx->cmd.cmd) +
2108c2ecf20Sopenharmony_ci	    mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE)
2118c2ecf20Sopenharmony_ci		return -EINVAL;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	mcp251xfd_spi_cmd_write_crc(&buf_tx->cmd, reg, val_len);
2148c2ecf20Sopenharmony_ci	memcpy(buf_tx->data, val, val_len);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	crc = mcp251xfd_crc16_compute(buf_tx, sizeof(buf_tx->cmd) + val_len);
2178c2ecf20Sopenharmony_ci	put_unaligned_be16(crc, buf_tx->data + val_len);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic int
2238c2ecf20Sopenharmony_cimcp251xfd_regmap_crc_write(void *context,
2248c2ecf20Sopenharmony_ci			   const void *data, size_t count)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	const size_t data_offset = sizeof(__be16) +
2278c2ecf20Sopenharmony_ci		mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	return mcp251xfd_regmap_crc_gather_write(context,
2308c2ecf20Sopenharmony_ci						 data, data_offset,
2318c2ecf20Sopenharmony_ci						 data + data_offset,
2328c2ecf20Sopenharmony_ci						 count - data_offset);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic int
2368c2ecf20Sopenharmony_cimcp251xfd_regmap_crc_read_one(struct mcp251xfd_priv *priv,
2378c2ecf20Sopenharmony_ci			      struct spi_message *msg, unsigned int data_len)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	const struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx;
2408c2ecf20Sopenharmony_ci	const struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx;
2418c2ecf20Sopenharmony_ci	u16 crc_received, crc_calculated;
2428c2ecf20Sopenharmony_ci	int err;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8));
2458c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8));
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	err = spi_sync(priv->spi, msg);
2488c2ecf20Sopenharmony_ci	if (err)
2498c2ecf20Sopenharmony_ci		return err;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	crc_received = get_unaligned_be16(buf_rx->data + data_len);
2528c2ecf20Sopenharmony_ci	crc_calculated = mcp251xfd_crc16_compute2(&buf_tx->cmd,
2538c2ecf20Sopenharmony_ci						  sizeof(buf_tx->cmd),
2548c2ecf20Sopenharmony_ci						  buf_rx->data,
2558c2ecf20Sopenharmony_ci						  data_len);
2568c2ecf20Sopenharmony_ci	if (crc_received != crc_calculated)
2578c2ecf20Sopenharmony_ci		return -EBADMSG;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return 0;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic int
2638c2ecf20Sopenharmony_cimcp251xfd_regmap_crc_read(void *context,
2648c2ecf20Sopenharmony_ci			  const void *reg_p, size_t reg_len,
2658c2ecf20Sopenharmony_ci			  void *val_buf, size_t val_len)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct spi_device *spi = context;
2688c2ecf20Sopenharmony_ci	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
2698c2ecf20Sopenharmony_ci	struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx;
2708c2ecf20Sopenharmony_ci	struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx;
2718c2ecf20Sopenharmony_ci	struct spi_transfer xfer[2] = { };
2728c2ecf20Sopenharmony_ci	struct spi_message msg;
2738c2ecf20Sopenharmony_ci	u16 reg = *(u16 *)reg_p;
2748c2ecf20Sopenharmony_ci	int i, err;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8));
2778c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8));
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
2808c2ecf20Sopenharmony_ci	    reg_len != sizeof(buf_tx->cmd.cmd) +
2818c2ecf20Sopenharmony_ci	    mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE)
2828c2ecf20Sopenharmony_ci		return -EINVAL;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	spi_message_init(&msg);
2858c2ecf20Sopenharmony_ci	spi_message_add_tail(&xfer[0], &msg);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) {
2888c2ecf20Sopenharmony_ci		xfer[0].tx_buf = buf_tx;
2898c2ecf20Sopenharmony_ci		xfer[0].len = sizeof(buf_tx->cmd);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci		xfer[1].rx_buf = buf_rx->data;
2928c2ecf20Sopenharmony_ci		xfer[1].len = val_len + sizeof(buf_tx->crc);
2938c2ecf20Sopenharmony_ci		spi_message_add_tail(&xfer[1], &msg);
2948c2ecf20Sopenharmony_ci	} else {
2958c2ecf20Sopenharmony_ci		xfer[0].tx_buf = buf_tx;
2968c2ecf20Sopenharmony_ci		xfer[0].rx_buf = buf_rx;
2978c2ecf20Sopenharmony_ci		xfer[0].len = sizeof(buf_tx->cmd) + val_len +
2988c2ecf20Sopenharmony_ci			sizeof(buf_tx->crc);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		if (MCP251XFD_SANITIZE_SPI)
3018c2ecf20Sopenharmony_ci			memset(buf_tx->data, 0x0, val_len +
3028c2ecf20Sopenharmony_ci			       sizeof(buf_tx->crc));
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	mcp251xfd_spi_cmd_read_crc(&buf_tx->cmd, reg, val_len);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	for (i = 0; i < MCP251XFD_READ_CRC_RETRIES_MAX; i++) {
3088c2ecf20Sopenharmony_ci		err = mcp251xfd_regmap_crc_read_one(priv, &msg, val_len);
3098c2ecf20Sopenharmony_ci		if (!err)
3108c2ecf20Sopenharmony_ci			goto out;
3118c2ecf20Sopenharmony_ci		if (err != -EBADMSG)
3128c2ecf20Sopenharmony_ci			return err;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci		/* MCP251XFD_REG_OSC is the first ever reg we read from.
3158c2ecf20Sopenharmony_ci		 *
3168c2ecf20Sopenharmony_ci		 * The chip may be in deep sleep and this SPI transfer
3178c2ecf20Sopenharmony_ci		 * (i.e. the assertion of the CS) will wake the chip
3188c2ecf20Sopenharmony_ci		 * up. This takes about 3ms. The CRC of this transfer
3198c2ecf20Sopenharmony_ci		 * is wrong.
3208c2ecf20Sopenharmony_ci		 *
3218c2ecf20Sopenharmony_ci		 * Or there isn't a chip at all, in this case the CRC
3228c2ecf20Sopenharmony_ci		 * will be wrong, too.
3238c2ecf20Sopenharmony_ci		 *
3248c2ecf20Sopenharmony_ci		 * In both cases ignore the CRC and copy the read data
3258c2ecf20Sopenharmony_ci		 * to the caller. It will take care of both cases.
3268c2ecf20Sopenharmony_ci		 *
3278c2ecf20Sopenharmony_ci		 */
3288c2ecf20Sopenharmony_ci		if (reg == MCP251XFD_REG_OSC) {
3298c2ecf20Sopenharmony_ci			err = 0;
3308c2ecf20Sopenharmony_ci			goto out;
3318c2ecf20Sopenharmony_ci		}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		netdev_info(priv->ndev,
3348c2ecf20Sopenharmony_ci			    "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x) retrying.\n",
3358c2ecf20Sopenharmony_ci			    reg, val_len, (int)val_len, buf_rx->data,
3368c2ecf20Sopenharmony_ci			    get_unaligned_be16(buf_rx->data + val_len));
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (err) {
3408c2ecf20Sopenharmony_ci		netdev_err(priv->ndev,
3418c2ecf20Sopenharmony_ci			   "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x).\n",
3428c2ecf20Sopenharmony_ci			   reg, val_len, (int)val_len, buf_rx->data,
3438c2ecf20Sopenharmony_ci			   get_unaligned_be16(buf_rx->data + val_len));
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		return err;
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci out:
3488c2ecf20Sopenharmony_ci	memcpy(val_buf, buf_rx->data, val_len);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return 0;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic const struct regmap_range mcp251xfd_reg_table_yes_range[] = {
3548c2ecf20Sopenharmony_ci	regmap_reg_range(0x000, 0x2ec),	/* CAN FD Controller Module SFR */
3558c2ecf20Sopenharmony_ci	regmap_reg_range(0x400, 0xbfc),	/* RAM */
3568c2ecf20Sopenharmony_ci	regmap_reg_range(0xe00, 0xe14),	/* MCP2517/18FD SFR */
3578c2ecf20Sopenharmony_ci};
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic const struct regmap_access_table mcp251xfd_reg_table = {
3608c2ecf20Sopenharmony_ci	.yes_ranges = mcp251xfd_reg_table_yes_range,
3618c2ecf20Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(mcp251xfd_reg_table_yes_range),
3628c2ecf20Sopenharmony_ci};
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic const struct regmap_config mcp251xfd_regmap_nocrc = {
3658c2ecf20Sopenharmony_ci	.name = "nocrc",
3668c2ecf20Sopenharmony_ci	.reg_bits = 16,
3678c2ecf20Sopenharmony_ci	.reg_stride = 4,
3688c2ecf20Sopenharmony_ci	.pad_bits = 0,
3698c2ecf20Sopenharmony_ci	.val_bits = 32,
3708c2ecf20Sopenharmony_ci	.max_register = 0xffc,
3718c2ecf20Sopenharmony_ci	.wr_table = &mcp251xfd_reg_table,
3728c2ecf20Sopenharmony_ci	.rd_table = &mcp251xfd_reg_table,
3738c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_NONE,
3748c2ecf20Sopenharmony_ci	.read_flag_mask = (__force unsigned long)
3758c2ecf20Sopenharmony_ci		cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_READ),
3768c2ecf20Sopenharmony_ci	.write_flag_mask = (__force unsigned long)
3778c2ecf20Sopenharmony_ci		cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE),
3788c2ecf20Sopenharmony_ci};
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic const struct regmap_bus mcp251xfd_bus_nocrc = {
3818c2ecf20Sopenharmony_ci	.write = mcp251xfd_regmap_nocrc_write,
3828c2ecf20Sopenharmony_ci	.gather_write = mcp251xfd_regmap_nocrc_gather_write,
3838c2ecf20Sopenharmony_ci	.reg_update_bits = mcp251xfd_regmap_nocrc_update_bits,
3848c2ecf20Sopenharmony_ci	.read = mcp251xfd_regmap_nocrc_read,
3858c2ecf20Sopenharmony_ci	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
3868c2ecf20Sopenharmony_ci	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
3878c2ecf20Sopenharmony_ci	.max_raw_read = sizeof_field(struct mcp251xfd_map_buf_nocrc, data),
3888c2ecf20Sopenharmony_ci	.max_raw_write = sizeof_field(struct mcp251xfd_map_buf_nocrc, data),
3898c2ecf20Sopenharmony_ci};
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic const struct regmap_config mcp251xfd_regmap_crc = {
3928c2ecf20Sopenharmony_ci	.name = "crc",
3938c2ecf20Sopenharmony_ci	.reg_bits = 16,
3948c2ecf20Sopenharmony_ci	.reg_stride = 4,
3958c2ecf20Sopenharmony_ci	.pad_bits = 16,		/* keep data bits aligned */
3968c2ecf20Sopenharmony_ci	.val_bits = 32,
3978c2ecf20Sopenharmony_ci	.max_register = 0xffc,
3988c2ecf20Sopenharmony_ci	.wr_table = &mcp251xfd_reg_table,
3998c2ecf20Sopenharmony_ci	.rd_table = &mcp251xfd_reg_table,
4008c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_NONE,
4018c2ecf20Sopenharmony_ci};
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic const struct regmap_bus mcp251xfd_bus_crc = {
4048c2ecf20Sopenharmony_ci	.write = mcp251xfd_regmap_crc_write,
4058c2ecf20Sopenharmony_ci	.gather_write = mcp251xfd_regmap_crc_gather_write,
4068c2ecf20Sopenharmony_ci	.read = mcp251xfd_regmap_crc_read,
4078c2ecf20Sopenharmony_ci	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
4088c2ecf20Sopenharmony_ci	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
4098c2ecf20Sopenharmony_ci	.max_raw_read = sizeof_field(struct mcp251xfd_map_buf_crc, data),
4108c2ecf20Sopenharmony_ci	.max_raw_write = sizeof_field(struct mcp251xfd_map_buf_crc, data),
4118c2ecf20Sopenharmony_ci};
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic inline bool
4148c2ecf20Sopenharmony_cimcp251xfd_regmap_use_nocrc(struct mcp251xfd_priv *priv)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	return (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) ||
4178c2ecf20Sopenharmony_ci		(!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX));
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic inline bool
4218c2ecf20Sopenharmony_cimcp251xfd_regmap_use_crc(struct mcp251xfd_priv *priv)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	return (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) ||
4248c2ecf20Sopenharmony_ci		(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic int
4288c2ecf20Sopenharmony_cimcp251xfd_regmap_init_nocrc(struct mcp251xfd_priv *priv)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	if (!priv->map_nocrc) {
4318c2ecf20Sopenharmony_ci		struct regmap *map;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_nocrc,
4348c2ecf20Sopenharmony_ci				       priv->spi, &mcp251xfd_regmap_nocrc);
4358c2ecf20Sopenharmony_ci		if (IS_ERR(map))
4368c2ecf20Sopenharmony_ci			return PTR_ERR(map);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		priv->map_nocrc = map;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (!priv->map_buf_nocrc_rx) {
4428c2ecf20Sopenharmony_ci		priv->map_buf_nocrc_rx =
4438c2ecf20Sopenharmony_ci			devm_kzalloc(&priv->spi->dev,
4448c2ecf20Sopenharmony_ci				     sizeof(*priv->map_buf_nocrc_rx),
4458c2ecf20Sopenharmony_ci				     GFP_KERNEL);
4468c2ecf20Sopenharmony_ci		if (!priv->map_buf_nocrc_rx)
4478c2ecf20Sopenharmony_ci			return -ENOMEM;
4488c2ecf20Sopenharmony_ci	}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (!priv->map_buf_nocrc_tx) {
4518c2ecf20Sopenharmony_ci		priv->map_buf_nocrc_tx =
4528c2ecf20Sopenharmony_ci			devm_kzalloc(&priv->spi->dev,
4538c2ecf20Sopenharmony_ci				     sizeof(*priv->map_buf_nocrc_tx),
4548c2ecf20Sopenharmony_ci				     GFP_KERNEL);
4558c2ecf20Sopenharmony_ci		if (!priv->map_buf_nocrc_tx)
4568c2ecf20Sopenharmony_ci			return -ENOMEM;
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG))
4608c2ecf20Sopenharmony_ci		priv->map_reg = priv->map_nocrc;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX))
4638c2ecf20Sopenharmony_ci		priv->map_rx = priv->map_nocrc;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return 0;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic void mcp251xfd_regmap_destroy_nocrc(struct mcp251xfd_priv *priv)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	if (priv->map_buf_nocrc_rx) {
4718c2ecf20Sopenharmony_ci		devm_kfree(&priv->spi->dev, priv->map_buf_nocrc_rx);
4728c2ecf20Sopenharmony_ci		priv->map_buf_nocrc_rx = NULL;
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci	if (priv->map_buf_nocrc_tx) {
4758c2ecf20Sopenharmony_ci		devm_kfree(&priv->spi->dev, priv->map_buf_nocrc_tx);
4768c2ecf20Sopenharmony_ci		priv->map_buf_nocrc_tx = NULL;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic int
4818c2ecf20Sopenharmony_cimcp251xfd_regmap_init_crc(struct mcp251xfd_priv *priv)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	if (!priv->map_crc) {
4848c2ecf20Sopenharmony_ci		struct regmap *map;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_crc,
4878c2ecf20Sopenharmony_ci				       priv->spi, &mcp251xfd_regmap_crc);
4888c2ecf20Sopenharmony_ci		if (IS_ERR(map))
4898c2ecf20Sopenharmony_ci			return PTR_ERR(map);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		priv->map_crc = map;
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	if (!priv->map_buf_crc_rx) {
4958c2ecf20Sopenharmony_ci		priv->map_buf_crc_rx =
4968c2ecf20Sopenharmony_ci			devm_kzalloc(&priv->spi->dev,
4978c2ecf20Sopenharmony_ci				     sizeof(*priv->map_buf_crc_rx),
4988c2ecf20Sopenharmony_ci				     GFP_KERNEL);
4998c2ecf20Sopenharmony_ci		if (!priv->map_buf_crc_rx)
5008c2ecf20Sopenharmony_ci			return -ENOMEM;
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (!priv->map_buf_crc_tx) {
5048c2ecf20Sopenharmony_ci		priv->map_buf_crc_tx =
5058c2ecf20Sopenharmony_ci			devm_kzalloc(&priv->spi->dev,
5068c2ecf20Sopenharmony_ci				     sizeof(*priv->map_buf_crc_tx),
5078c2ecf20Sopenharmony_ci				     GFP_KERNEL);
5088c2ecf20Sopenharmony_ci		if (!priv->map_buf_crc_tx)
5098c2ecf20Sopenharmony_ci			return -ENOMEM;
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)
5138c2ecf20Sopenharmony_ci		priv->map_reg = priv->map_crc;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX)
5168c2ecf20Sopenharmony_ci		priv->map_rx = priv->map_crc;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	return 0;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic void mcp251xfd_regmap_destroy_crc(struct mcp251xfd_priv *priv)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	if (priv->map_buf_crc_rx) {
5248c2ecf20Sopenharmony_ci		devm_kfree(&priv->spi->dev, priv->map_buf_crc_rx);
5258c2ecf20Sopenharmony_ci		priv->map_buf_crc_rx = NULL;
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci	if (priv->map_buf_crc_tx) {
5288c2ecf20Sopenharmony_ci		devm_kfree(&priv->spi->dev, priv->map_buf_crc_tx);
5298c2ecf20Sopenharmony_ci		priv->map_buf_crc_tx = NULL;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ciint mcp251xfd_regmap_init(struct mcp251xfd_priv *priv)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	int err;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (mcp251xfd_regmap_use_nocrc(priv)) {
5388c2ecf20Sopenharmony_ci		err = mcp251xfd_regmap_init_nocrc(priv);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci		if (err)
5418c2ecf20Sopenharmony_ci			return err;
5428c2ecf20Sopenharmony_ci	} else {
5438c2ecf20Sopenharmony_ci		mcp251xfd_regmap_destroy_nocrc(priv);
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (mcp251xfd_regmap_use_crc(priv)) {
5478c2ecf20Sopenharmony_ci		err = mcp251xfd_regmap_init_crc(priv);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci		if (err)
5508c2ecf20Sopenharmony_ci			return err;
5518c2ecf20Sopenharmony_ci	} else {
5528c2ecf20Sopenharmony_ci		mcp251xfd_regmap_destroy_crc(priv);
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	return 0;
5568c2ecf20Sopenharmony_ci}
557