162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// mcp251xfd - Microchip MCP251xFD Family CAN controller driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) 2019, 2020, 2021 Pengutronix, 662306a36Sopenharmony_ci// Marc Kleine-Budde <kernel@pengutronix.de> 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "mcp251xfd.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <asm/unaligned.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic const struct regmap_config mcp251xfd_regmap_crc; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic int 1662306a36Sopenharmony_cimcp251xfd_regmap_nocrc_write(void *context, const void *data, size_t count) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci struct spi_device *spi = context; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci return spi_write(spi, data, count); 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int 2462306a36Sopenharmony_cimcp251xfd_regmap_nocrc_gather_write(void *context, 2562306a36Sopenharmony_ci const void *reg, size_t reg_len, 2662306a36Sopenharmony_ci const void *val, size_t val_len) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct spi_device *spi = context; 2962306a36Sopenharmony_ci struct mcp251xfd_priv *priv = spi_get_drvdata(spi); 3062306a36Sopenharmony_ci struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx; 3162306a36Sopenharmony_ci struct spi_transfer xfer[] = { 3262306a36Sopenharmony_ci { 3362306a36Sopenharmony_ci .tx_buf = buf_tx, 3462306a36Sopenharmony_ci .len = sizeof(buf_tx->cmd) + val_len, 3562306a36Sopenharmony_ci }, 3662306a36Sopenharmony_ci }; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16)); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && 4162306a36Sopenharmony_ci reg_len != sizeof(buf_tx->cmd.cmd)) 4262306a36Sopenharmony_ci return -EINVAL; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd)); 4562306a36Sopenharmony_ci memcpy(buf_tx->data, val, val_len); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer)); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic inline bool 5162306a36Sopenharmony_cimcp251xfd_update_bits_read_reg(const struct mcp251xfd_priv *priv, 5262306a36Sopenharmony_ci unsigned int reg) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct mcp251xfd_rx_ring *ring; 5562306a36Sopenharmony_ci int n; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci switch (reg) { 5862306a36Sopenharmony_ci case MCP251XFD_REG_INT: 5962306a36Sopenharmony_ci case MCP251XFD_REG_TEFCON: 6062306a36Sopenharmony_ci case MCP251XFD_REG_FLTCON(0): 6162306a36Sopenharmony_ci case MCP251XFD_REG_ECCSTAT: 6262306a36Sopenharmony_ci case MCP251XFD_REG_CRC: 6362306a36Sopenharmony_ci return false; 6462306a36Sopenharmony_ci case MCP251XFD_REG_CON: 6562306a36Sopenharmony_ci case MCP251XFD_REG_OSC: 6662306a36Sopenharmony_ci case MCP251XFD_REG_ECCCON: 6762306a36Sopenharmony_ci return true; 6862306a36Sopenharmony_ci default: 6962306a36Sopenharmony_ci mcp251xfd_for_each_rx_ring(priv, ring, n) { 7062306a36Sopenharmony_ci if (reg == MCP251XFD_REG_FIFOCON(ring->fifo_nr)) 7162306a36Sopenharmony_ci return false; 7262306a36Sopenharmony_ci if (reg == MCP251XFD_REG_FIFOSTA(ring->fifo_nr)) 7362306a36Sopenharmony_ci return true; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci WARN(1, "Status of reg 0x%04x unknown.\n", reg); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return true; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int 8362306a36Sopenharmony_cimcp251xfd_regmap_nocrc_update_bits(void *context, unsigned int reg, 8462306a36Sopenharmony_ci unsigned int mask, unsigned int val) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct spi_device *spi = context; 8762306a36Sopenharmony_ci struct mcp251xfd_priv *priv = spi_get_drvdata(spi); 8862306a36Sopenharmony_ci struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx; 8962306a36Sopenharmony_ci struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx; 9062306a36Sopenharmony_ci __le32 orig_le32 = 0, mask_le32, val_le32, tmp_le32; 9162306a36Sopenharmony_ci u8 first_byte, last_byte, len; 9262306a36Sopenharmony_ci int err; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16)); 9562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16)); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && 9862306a36Sopenharmony_ci mask == 0) 9962306a36Sopenharmony_ci return -EINVAL; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci first_byte = mcp251xfd_first_byte_set(mask); 10262306a36Sopenharmony_ci last_byte = mcp251xfd_last_byte_set(mask); 10362306a36Sopenharmony_ci len = last_byte - first_byte + 1; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (mcp251xfd_update_bits_read_reg(priv, reg)) { 10662306a36Sopenharmony_ci struct spi_transfer xfer[2] = { }; 10762306a36Sopenharmony_ci struct spi_message msg; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci spi_message_init(&msg); 11062306a36Sopenharmony_ci spi_message_add_tail(&xfer[0], &msg); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) { 11362306a36Sopenharmony_ci xfer[0].tx_buf = buf_tx; 11462306a36Sopenharmony_ci xfer[0].len = sizeof(buf_tx->cmd); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci xfer[1].rx_buf = buf_rx->data; 11762306a36Sopenharmony_ci xfer[1].len = len; 11862306a36Sopenharmony_ci spi_message_add_tail(&xfer[1], &msg); 11962306a36Sopenharmony_ci } else { 12062306a36Sopenharmony_ci xfer[0].tx_buf = buf_tx; 12162306a36Sopenharmony_ci xfer[0].rx_buf = buf_rx; 12262306a36Sopenharmony_ci xfer[0].len = sizeof(buf_tx->cmd) + len; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (MCP251XFD_SANITIZE_SPI) 12562306a36Sopenharmony_ci memset(buf_tx->data, 0x0, len); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, reg + first_byte); 12962306a36Sopenharmony_ci err = spi_sync(spi, &msg); 13062306a36Sopenharmony_ci if (err) 13162306a36Sopenharmony_ci return err; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci memcpy(&orig_le32, buf_rx->data, len); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci mask_le32 = cpu_to_le32(mask >> BITS_PER_BYTE * first_byte); 13762306a36Sopenharmony_ci val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci tmp_le32 = orig_le32 & ~mask_le32; 14062306a36Sopenharmony_ci tmp_le32 |= val_le32 & mask_le32; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci mcp251xfd_spi_cmd_write_nocrc(&buf_tx->cmd, reg + first_byte); 14362306a36Sopenharmony_ci memcpy(buf_tx->data, &tmp_le32, len); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return spi_write(spi, buf_tx, sizeof(buf_tx->cmd) + len); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int 14962306a36Sopenharmony_cimcp251xfd_regmap_nocrc_read(void *context, 15062306a36Sopenharmony_ci const void *reg, size_t reg_len, 15162306a36Sopenharmony_ci void *val_buf, size_t val_len) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct spi_device *spi = context; 15462306a36Sopenharmony_ci struct mcp251xfd_priv *priv = spi_get_drvdata(spi); 15562306a36Sopenharmony_ci struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx; 15662306a36Sopenharmony_ci struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx; 15762306a36Sopenharmony_ci struct spi_transfer xfer[2] = { }; 15862306a36Sopenharmony_ci struct spi_message msg; 15962306a36Sopenharmony_ci int err; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16)); 16262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16)); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && 16562306a36Sopenharmony_ci reg_len != sizeof(buf_tx->cmd.cmd)) 16662306a36Sopenharmony_ci return -EINVAL; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci spi_message_init(&msg); 16962306a36Sopenharmony_ci spi_message_add_tail(&xfer[0], &msg); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) { 17262306a36Sopenharmony_ci xfer[0].tx_buf = reg; 17362306a36Sopenharmony_ci xfer[0].len = sizeof(buf_tx->cmd); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci xfer[1].rx_buf = val_buf; 17662306a36Sopenharmony_ci xfer[1].len = val_len; 17762306a36Sopenharmony_ci spi_message_add_tail(&xfer[1], &msg); 17862306a36Sopenharmony_ci } else { 17962306a36Sopenharmony_ci xfer[0].tx_buf = buf_tx; 18062306a36Sopenharmony_ci xfer[0].rx_buf = buf_rx; 18162306a36Sopenharmony_ci xfer[0].len = sizeof(buf_tx->cmd) + val_len; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd)); 18462306a36Sopenharmony_ci if (MCP251XFD_SANITIZE_SPI) 18562306a36Sopenharmony_ci memset(buf_tx->data, 0x0, val_len); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci err = spi_sync(spi, &msg); 18962306a36Sopenharmony_ci if (err) 19062306a36Sopenharmony_ci return err; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX)) 19362306a36Sopenharmony_ci memcpy(val_buf, buf_rx->data, val_len); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int 19962306a36Sopenharmony_cimcp251xfd_regmap_crc_gather_write(void *context, 20062306a36Sopenharmony_ci const void *reg_p, size_t reg_len, 20162306a36Sopenharmony_ci const void *val, size_t val_len) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct spi_device *spi = context; 20462306a36Sopenharmony_ci struct mcp251xfd_priv *priv = spi_get_drvdata(spi); 20562306a36Sopenharmony_ci struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx; 20662306a36Sopenharmony_ci struct spi_transfer xfer[] = { 20762306a36Sopenharmony_ci { 20862306a36Sopenharmony_ci .tx_buf = buf_tx, 20962306a36Sopenharmony_ci .len = sizeof(buf_tx->cmd) + val_len + 21062306a36Sopenharmony_ci sizeof(buf_tx->crc), 21162306a36Sopenharmony_ci }, 21262306a36Sopenharmony_ci }; 21362306a36Sopenharmony_ci u16 reg = *(u16 *)reg_p; 21462306a36Sopenharmony_ci u16 crc; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8)); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && 21962306a36Sopenharmony_ci reg_len != sizeof(buf_tx->cmd.cmd) + 22062306a36Sopenharmony_ci mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE) 22162306a36Sopenharmony_ci return -EINVAL; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci mcp251xfd_spi_cmd_write_crc(&buf_tx->cmd, reg, val_len); 22462306a36Sopenharmony_ci memcpy(buf_tx->data, val, val_len); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci crc = mcp251xfd_crc16_compute(buf_tx, sizeof(buf_tx->cmd) + val_len); 22762306a36Sopenharmony_ci put_unaligned_be16(crc, buf_tx->data + val_len); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer)); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int 23362306a36Sopenharmony_cimcp251xfd_regmap_crc_write(void *context, 23462306a36Sopenharmony_ci const void *data, size_t count) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci const size_t data_offset = sizeof(__be16) + 23762306a36Sopenharmony_ci mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return mcp251xfd_regmap_crc_gather_write(context, 24062306a36Sopenharmony_ci data, data_offset, 24162306a36Sopenharmony_ci data + data_offset, 24262306a36Sopenharmony_ci count - data_offset); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int 24662306a36Sopenharmony_cimcp251xfd_regmap_crc_read_check_crc(const struct mcp251xfd_map_buf_crc * const buf_rx, 24762306a36Sopenharmony_ci const struct mcp251xfd_map_buf_crc * const buf_tx, 24862306a36Sopenharmony_ci unsigned int data_len) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci u16 crc_received, crc_calculated; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci crc_received = get_unaligned_be16(buf_rx->data + data_len); 25362306a36Sopenharmony_ci crc_calculated = mcp251xfd_crc16_compute2(&buf_tx->cmd, 25462306a36Sopenharmony_ci sizeof(buf_tx->cmd), 25562306a36Sopenharmony_ci buf_rx->data, 25662306a36Sopenharmony_ci data_len); 25762306a36Sopenharmony_ci if (crc_received != crc_calculated) 25862306a36Sopenharmony_ci return -EBADMSG; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int 26462306a36Sopenharmony_cimcp251xfd_regmap_crc_read_one(struct mcp251xfd_priv *priv, 26562306a36Sopenharmony_ci struct spi_message *msg, unsigned int data_len) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci const struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx; 26862306a36Sopenharmony_ci const struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx; 26962306a36Sopenharmony_ci int err; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8)); 27262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8)); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci err = spi_sync(priv->spi, msg); 27562306a36Sopenharmony_ci if (err) 27662306a36Sopenharmony_ci return err; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return mcp251xfd_regmap_crc_read_check_crc(buf_rx, buf_tx, data_len); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic int 28262306a36Sopenharmony_cimcp251xfd_regmap_crc_read(void *context, 28362306a36Sopenharmony_ci const void *reg_p, size_t reg_len, 28462306a36Sopenharmony_ci void *val_buf, size_t val_len) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct spi_device *spi = context; 28762306a36Sopenharmony_ci struct mcp251xfd_priv *priv = spi_get_drvdata(spi); 28862306a36Sopenharmony_ci struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx; 28962306a36Sopenharmony_ci struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx; 29062306a36Sopenharmony_ci struct spi_transfer xfer[2] = { }; 29162306a36Sopenharmony_ci struct spi_message msg; 29262306a36Sopenharmony_ci u16 reg = *(u16 *)reg_p; 29362306a36Sopenharmony_ci int i, err; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8)); 29662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8)); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && 29962306a36Sopenharmony_ci reg_len != sizeof(buf_tx->cmd.cmd) + 30062306a36Sopenharmony_ci mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE) 30162306a36Sopenharmony_ci return -EINVAL; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci spi_message_init(&msg); 30462306a36Sopenharmony_ci spi_message_add_tail(&xfer[0], &msg); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) { 30762306a36Sopenharmony_ci xfer[0].tx_buf = buf_tx; 30862306a36Sopenharmony_ci xfer[0].len = sizeof(buf_tx->cmd); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci xfer[1].rx_buf = buf_rx->data; 31162306a36Sopenharmony_ci xfer[1].len = val_len + sizeof(buf_tx->crc); 31262306a36Sopenharmony_ci spi_message_add_tail(&xfer[1], &msg); 31362306a36Sopenharmony_ci } else { 31462306a36Sopenharmony_ci xfer[0].tx_buf = buf_tx; 31562306a36Sopenharmony_ci xfer[0].rx_buf = buf_rx; 31662306a36Sopenharmony_ci xfer[0].len = sizeof(buf_tx->cmd) + val_len + 31762306a36Sopenharmony_ci sizeof(buf_tx->crc); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (MCP251XFD_SANITIZE_SPI) 32062306a36Sopenharmony_ci memset(buf_tx->data, 0x0, val_len + 32162306a36Sopenharmony_ci sizeof(buf_tx->crc)); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci mcp251xfd_spi_cmd_read_crc(&buf_tx->cmd, reg, val_len); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci for (i = 0; i < MCP251XFD_READ_CRC_RETRIES_MAX; i++) { 32762306a36Sopenharmony_ci err = mcp251xfd_regmap_crc_read_one(priv, &msg, val_len); 32862306a36Sopenharmony_ci if (!err) 32962306a36Sopenharmony_ci goto out; 33062306a36Sopenharmony_ci if (err != -EBADMSG) 33162306a36Sopenharmony_ci return err; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* MCP251XFD_REG_TBC is the time base counter 33462306a36Sopenharmony_ci * register. It increments once per SYS clock tick, 33562306a36Sopenharmony_ci * which is 20 or 40 MHz. 33662306a36Sopenharmony_ci * 33762306a36Sopenharmony_ci * Observation on the mcp2518fd shows that if the 33862306a36Sopenharmony_ci * lowest byte (which is transferred first on the SPI 33962306a36Sopenharmony_ci * bus) of that register is 0x00 or 0x80 the 34062306a36Sopenharmony_ci * calculated CRC doesn't always match the transferred 34162306a36Sopenharmony_ci * one. On the mcp2517fd this problem is not limited 34262306a36Sopenharmony_ci * to the first byte being 0x00 or 0x80. 34362306a36Sopenharmony_ci * 34462306a36Sopenharmony_ci * If the highest bit in the lowest byte is flipped 34562306a36Sopenharmony_ci * the transferred CRC matches the calculated one. We 34662306a36Sopenharmony_ci * assume for now the CRC operates on the correct 34762306a36Sopenharmony_ci * data. 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci if (reg == MCP251XFD_REG_TBC && 35062306a36Sopenharmony_ci ((buf_rx->data[0] & 0xf8) == 0x0 || 35162306a36Sopenharmony_ci (buf_rx->data[0] & 0xf8) == 0x80)) { 35262306a36Sopenharmony_ci /* Flip highest bit in lowest byte of le32 */ 35362306a36Sopenharmony_ci buf_rx->data[0] ^= 0x80; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* re-check CRC */ 35662306a36Sopenharmony_ci err = mcp251xfd_regmap_crc_read_check_crc(buf_rx, 35762306a36Sopenharmony_ci buf_tx, 35862306a36Sopenharmony_ci val_len); 35962306a36Sopenharmony_ci if (!err) { 36062306a36Sopenharmony_ci /* If CRC is now correct, assume 36162306a36Sopenharmony_ci * flipped data is OK. 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci goto out; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* MCP251XFD_REG_OSC is the first ever reg we read from. 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * The chip may be in deep sleep and this SPI transfer 37062306a36Sopenharmony_ci * (i.e. the assertion of the CS) will wake the chip 37162306a36Sopenharmony_ci * up. This takes about 3ms. The CRC of this transfer 37262306a36Sopenharmony_ci * is wrong. 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci * Or there isn't a chip at all, in this case the CRC 37562306a36Sopenharmony_ci * will be wrong, too. 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * In both cases ignore the CRC and copy the read data 37862306a36Sopenharmony_ci * to the caller. It will take care of both cases. 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci if (reg == MCP251XFD_REG_OSC && val_len == sizeof(__le32)) { 38262306a36Sopenharmony_ci err = 0; 38362306a36Sopenharmony_ci goto out; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci netdev_info(priv->ndev, 38762306a36Sopenharmony_ci "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x) retrying.\n", 38862306a36Sopenharmony_ci reg, val_len, (int)val_len, buf_rx->data, 38962306a36Sopenharmony_ci get_unaligned_be16(buf_rx->data + val_len)); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (err) { 39362306a36Sopenharmony_ci netdev_err(priv->ndev, 39462306a36Sopenharmony_ci "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x).\n", 39562306a36Sopenharmony_ci reg, val_len, (int)val_len, buf_rx->data, 39662306a36Sopenharmony_ci get_unaligned_be16(buf_rx->data + val_len)); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return err; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci out: 40162306a36Sopenharmony_ci memcpy(val_buf, buf_rx->data, val_len); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic const struct regmap_range mcp251xfd_reg_table_yes_range[] = { 40762306a36Sopenharmony_ci regmap_reg_range(0x000, 0x2ec), /* CAN FD Controller Module SFR */ 40862306a36Sopenharmony_ci regmap_reg_range(0x400, 0xbfc), /* RAM */ 40962306a36Sopenharmony_ci regmap_reg_range(0xe00, 0xe14), /* MCP2517/18FD SFR */ 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic const struct regmap_access_table mcp251xfd_reg_table = { 41362306a36Sopenharmony_ci .yes_ranges = mcp251xfd_reg_table_yes_range, 41462306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(mcp251xfd_reg_table_yes_range), 41562306a36Sopenharmony_ci}; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic const struct regmap_config mcp251xfd_regmap_nocrc = { 41862306a36Sopenharmony_ci .name = "nocrc", 41962306a36Sopenharmony_ci .reg_bits = 16, 42062306a36Sopenharmony_ci .reg_stride = 4, 42162306a36Sopenharmony_ci .pad_bits = 0, 42262306a36Sopenharmony_ci .val_bits = 32, 42362306a36Sopenharmony_ci .max_register = 0xffc, 42462306a36Sopenharmony_ci .wr_table = &mcp251xfd_reg_table, 42562306a36Sopenharmony_ci .rd_table = &mcp251xfd_reg_table, 42662306a36Sopenharmony_ci .cache_type = REGCACHE_NONE, 42762306a36Sopenharmony_ci .read_flag_mask = (__force unsigned long) 42862306a36Sopenharmony_ci cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_READ), 42962306a36Sopenharmony_ci .write_flag_mask = (__force unsigned long) 43062306a36Sopenharmony_ci cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE), 43162306a36Sopenharmony_ci}; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic const struct regmap_bus mcp251xfd_bus_nocrc = { 43462306a36Sopenharmony_ci .write = mcp251xfd_regmap_nocrc_write, 43562306a36Sopenharmony_ci .gather_write = mcp251xfd_regmap_nocrc_gather_write, 43662306a36Sopenharmony_ci .reg_update_bits = mcp251xfd_regmap_nocrc_update_bits, 43762306a36Sopenharmony_ci .read = mcp251xfd_regmap_nocrc_read, 43862306a36Sopenharmony_ci .reg_format_endian_default = REGMAP_ENDIAN_BIG, 43962306a36Sopenharmony_ci .val_format_endian_default = REGMAP_ENDIAN_LITTLE, 44062306a36Sopenharmony_ci .max_raw_read = sizeof_field(struct mcp251xfd_map_buf_nocrc, data), 44162306a36Sopenharmony_ci .max_raw_write = sizeof_field(struct mcp251xfd_map_buf_nocrc, data), 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic const struct regmap_config mcp251xfd_regmap_crc = { 44562306a36Sopenharmony_ci .name = "crc", 44662306a36Sopenharmony_ci .reg_bits = 16, 44762306a36Sopenharmony_ci .reg_stride = 4, 44862306a36Sopenharmony_ci .pad_bits = 16, /* keep data bits aligned */ 44962306a36Sopenharmony_ci .val_bits = 32, 45062306a36Sopenharmony_ci .max_register = 0xffc, 45162306a36Sopenharmony_ci .wr_table = &mcp251xfd_reg_table, 45262306a36Sopenharmony_ci .rd_table = &mcp251xfd_reg_table, 45362306a36Sopenharmony_ci .cache_type = REGCACHE_NONE, 45462306a36Sopenharmony_ci}; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic const struct regmap_bus mcp251xfd_bus_crc = { 45762306a36Sopenharmony_ci .write = mcp251xfd_regmap_crc_write, 45862306a36Sopenharmony_ci .gather_write = mcp251xfd_regmap_crc_gather_write, 45962306a36Sopenharmony_ci .read = mcp251xfd_regmap_crc_read, 46062306a36Sopenharmony_ci .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 46162306a36Sopenharmony_ci .val_format_endian_default = REGMAP_ENDIAN_LITTLE, 46262306a36Sopenharmony_ci .max_raw_read = sizeof_field(struct mcp251xfd_map_buf_crc, data), 46362306a36Sopenharmony_ci .max_raw_write = sizeof_field(struct mcp251xfd_map_buf_crc, data), 46462306a36Sopenharmony_ci}; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic inline bool 46762306a36Sopenharmony_cimcp251xfd_regmap_use_nocrc(struct mcp251xfd_priv *priv) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci return (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) || 47062306a36Sopenharmony_ci (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX)); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic inline bool 47462306a36Sopenharmony_cimcp251xfd_regmap_use_crc(struct mcp251xfd_priv *priv) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci return (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) || 47762306a36Sopenharmony_ci (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int 48162306a36Sopenharmony_cimcp251xfd_regmap_init_nocrc(struct mcp251xfd_priv *priv) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci if (!priv->map_nocrc) { 48462306a36Sopenharmony_ci struct regmap *map; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_nocrc, 48762306a36Sopenharmony_ci priv->spi, &mcp251xfd_regmap_nocrc); 48862306a36Sopenharmony_ci if (IS_ERR(map)) 48962306a36Sopenharmony_ci return PTR_ERR(map); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci priv->map_nocrc = map; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (!priv->map_buf_nocrc_rx) { 49562306a36Sopenharmony_ci priv->map_buf_nocrc_rx = 49662306a36Sopenharmony_ci devm_kzalloc(&priv->spi->dev, 49762306a36Sopenharmony_ci sizeof(*priv->map_buf_nocrc_rx), 49862306a36Sopenharmony_ci GFP_KERNEL); 49962306a36Sopenharmony_ci if (!priv->map_buf_nocrc_rx) 50062306a36Sopenharmony_ci return -ENOMEM; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (!priv->map_buf_nocrc_tx) { 50462306a36Sopenharmony_ci priv->map_buf_nocrc_tx = 50562306a36Sopenharmony_ci devm_kzalloc(&priv->spi->dev, 50662306a36Sopenharmony_ci sizeof(*priv->map_buf_nocrc_tx), 50762306a36Sopenharmony_ci GFP_KERNEL); 50862306a36Sopenharmony_ci if (!priv->map_buf_nocrc_tx) 50962306a36Sopenharmony_ci return -ENOMEM; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) 51362306a36Sopenharmony_ci priv->map_reg = priv->map_nocrc; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX)) 51662306a36Sopenharmony_ci priv->map_rx = priv->map_nocrc; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return 0; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic void mcp251xfd_regmap_destroy_nocrc(struct mcp251xfd_priv *priv) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci if (priv->map_buf_nocrc_rx) { 52462306a36Sopenharmony_ci devm_kfree(&priv->spi->dev, priv->map_buf_nocrc_rx); 52562306a36Sopenharmony_ci priv->map_buf_nocrc_rx = NULL; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci if (priv->map_buf_nocrc_tx) { 52862306a36Sopenharmony_ci devm_kfree(&priv->spi->dev, priv->map_buf_nocrc_tx); 52962306a36Sopenharmony_ci priv->map_buf_nocrc_tx = NULL; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int 53462306a36Sopenharmony_cimcp251xfd_regmap_init_crc(struct mcp251xfd_priv *priv) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci if (!priv->map_crc) { 53762306a36Sopenharmony_ci struct regmap *map; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_crc, 54062306a36Sopenharmony_ci priv->spi, &mcp251xfd_regmap_crc); 54162306a36Sopenharmony_ci if (IS_ERR(map)) 54262306a36Sopenharmony_ci return PTR_ERR(map); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci priv->map_crc = map; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (!priv->map_buf_crc_rx) { 54862306a36Sopenharmony_ci priv->map_buf_crc_rx = 54962306a36Sopenharmony_ci devm_kzalloc(&priv->spi->dev, 55062306a36Sopenharmony_ci sizeof(*priv->map_buf_crc_rx), 55162306a36Sopenharmony_ci GFP_KERNEL); 55262306a36Sopenharmony_ci if (!priv->map_buf_crc_rx) 55362306a36Sopenharmony_ci return -ENOMEM; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (!priv->map_buf_crc_tx) { 55762306a36Sopenharmony_ci priv->map_buf_crc_tx = 55862306a36Sopenharmony_ci devm_kzalloc(&priv->spi->dev, 55962306a36Sopenharmony_ci sizeof(*priv->map_buf_crc_tx), 56062306a36Sopenharmony_ci GFP_KERNEL); 56162306a36Sopenharmony_ci if (!priv->map_buf_crc_tx) 56262306a36Sopenharmony_ci return -ENOMEM; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) 56662306a36Sopenharmony_ci priv->map_reg = priv->map_crc; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX) 56962306a36Sopenharmony_ci priv->map_rx = priv->map_crc; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic void mcp251xfd_regmap_destroy_crc(struct mcp251xfd_priv *priv) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci if (priv->map_buf_crc_rx) { 57762306a36Sopenharmony_ci devm_kfree(&priv->spi->dev, priv->map_buf_crc_rx); 57862306a36Sopenharmony_ci priv->map_buf_crc_rx = NULL; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci if (priv->map_buf_crc_tx) { 58162306a36Sopenharmony_ci devm_kfree(&priv->spi->dev, priv->map_buf_crc_tx); 58262306a36Sopenharmony_ci priv->map_buf_crc_tx = NULL; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ciint mcp251xfd_regmap_init(struct mcp251xfd_priv *priv) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci int err; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (mcp251xfd_regmap_use_nocrc(priv)) { 59162306a36Sopenharmony_ci err = mcp251xfd_regmap_init_nocrc(priv); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (err) 59462306a36Sopenharmony_ci return err; 59562306a36Sopenharmony_ci } else { 59662306a36Sopenharmony_ci mcp251xfd_regmap_destroy_nocrc(priv); 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (mcp251xfd_regmap_use_crc(priv)) { 60062306a36Sopenharmony_ci err = mcp251xfd_regmap_init_crc(priv); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (err) 60362306a36Sopenharmony_ci return err; 60462306a36Sopenharmony_ci } else { 60562306a36Sopenharmony_ci mcp251xfd_regmap_destroy_crc(priv); 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci} 610