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