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