mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-28 05:34:13 -05:00
can: mcp251xfd: add workaround for errata 5
According to Errata DS80000789E 5 writing IOCON register using one SPI write command clears LAT0/LAT1. Errata Fix/Work Around suggests to write registers with single byte write instructions. However, it seems that every write to the second byte causes the overwrite of LAT0/LAT1. Never write byte 2 of IOCON register to avoid clearing of LAT0/LAT1. Signed-off-by: Gregor Herburger <gregor.herburger@ew.tq-group.com> Tested-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com> Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com> Reviewed-by: Manivannan Sadhasivam <mani@kernel.org> Link: https://patch.msgid.link/20251001091006.4003841-4-viken.dadhaniya@oss.qualcomm.com [mkl: add missing MCP251XFD_REG_IOCON_GPIO_MASK] Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
committed by
Marc Kleine-Budde
parent
f5982a679a
commit
c902835fc6
@@ -13,9 +13,9 @@
|
||||
static const struct regmap_config mcp251xfd_regmap_crc;
|
||||
|
||||
static int
|
||||
mcp251xfd_regmap_nocrc_gather_write(void *context,
|
||||
const void *reg, size_t reg_len,
|
||||
const void *val, size_t val_len)
|
||||
_mcp251xfd_regmap_nocrc_gather_write(void *context,
|
||||
const void *reg, size_t reg_len,
|
||||
const void *val, size_t val_len)
|
||||
{
|
||||
struct spi_device *spi = context;
|
||||
struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
|
||||
@@ -39,6 +39,45 @@ mcp251xfd_regmap_nocrc_gather_write(void *context,
|
||||
return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
|
||||
}
|
||||
|
||||
static int
|
||||
mcp251xfd_regmap_nocrc_gather_write(void *context,
|
||||
const void *reg_p, size_t reg_len,
|
||||
const void *val, size_t val_len)
|
||||
{
|
||||
const u16 byte_exclude = MCP251XFD_REG_IOCON +
|
||||
mcp251xfd_first_byte_set(MCP251XFD_REG_IOCON_GPIO_MASK);
|
||||
u16 reg = be16_to_cpu(*(__be16 *)reg_p) & MCP251XFD_SPI_ADDRESS_MASK;
|
||||
int ret;
|
||||
|
||||
/* Never write to bits 16..23 of IOCON register to avoid clearing of LAT0/LAT1
|
||||
*
|
||||
* According to MCP2518FD Errata DS80000789E 5 writing IOCON register using one
|
||||
* SPI write command clears LAT0/LAT1.
|
||||
*
|
||||
* Errata Fix/Work Around suggests to write registers with single byte
|
||||
* write instructions. However, it seems that the byte at 0xe06(IOCON[23:16])
|
||||
* is for read-only access and writing to it causes the clearing of LAT0/LAT1.
|
||||
*/
|
||||
if (reg <= byte_exclude && reg + val_len > byte_exclude) {
|
||||
size_t len = byte_exclude - reg;
|
||||
|
||||
/* Write up to 0xe05 */
|
||||
ret = _mcp251xfd_regmap_nocrc_gather_write(context, reg_p, reg_len, val, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write from 0xe07 on */
|
||||
reg += len + 1;
|
||||
reg = (__force unsigned short)cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE | reg);
|
||||
return _mcp251xfd_regmap_nocrc_gather_write(context, ®, reg_len,
|
||||
val + len + 1,
|
||||
val_len - len - 1);
|
||||
}
|
||||
|
||||
return _mcp251xfd_regmap_nocrc_gather_write(context, reg_p, reg_len,
|
||||
val, val_len);
|
||||
}
|
||||
|
||||
static int
|
||||
mcp251xfd_regmap_nocrc_write(void *context, const void *data, size_t count)
|
||||
{
|
||||
@@ -197,9 +236,9 @@ mcp251xfd_regmap_nocrc_read(void *context,
|
||||
}
|
||||
|
||||
static int
|
||||
mcp251xfd_regmap_crc_gather_write(void *context,
|
||||
const void *reg_p, size_t reg_len,
|
||||
const void *val, size_t val_len)
|
||||
_mcp251xfd_regmap_crc_gather_write(void *context,
|
||||
const void *reg_p, size_t reg_len,
|
||||
const void *val, size_t val_len)
|
||||
{
|
||||
struct spi_device *spi = context;
|
||||
struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
|
||||
@@ -230,6 +269,44 @@ mcp251xfd_regmap_crc_gather_write(void *context,
|
||||
return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
|
||||
}
|
||||
|
||||
static int
|
||||
mcp251xfd_regmap_crc_gather_write(void *context,
|
||||
const void *reg_p, size_t reg_len,
|
||||
const void *val, size_t val_len)
|
||||
{
|
||||
const u16 byte_exclude = MCP251XFD_REG_IOCON +
|
||||
mcp251xfd_first_byte_set(MCP251XFD_REG_IOCON_GPIO_MASK);
|
||||
u16 reg = *(u16 *)reg_p;
|
||||
int ret;
|
||||
|
||||
/* Never write to bits 16..23 of IOCON register to avoid clearing of LAT0/LAT1
|
||||
*
|
||||
* According to MCP2518FD Errata DS80000789E 5 writing IOCON register using one
|
||||
* SPI write command clears LAT0/LAT1.
|
||||
*
|
||||
* Errata Fix/Work Around suggests to write registers with single byte
|
||||
* write instructions. However, it seems that the byte at 0xe06(IOCON[23:16])
|
||||
* is for read-only access and writing to it causes the clearing of LAT0/LAT1.
|
||||
*/
|
||||
if (reg <= byte_exclude && reg + val_len > byte_exclude) {
|
||||
size_t len = byte_exclude - reg;
|
||||
|
||||
/* Write up to 0xe05 */
|
||||
ret = _mcp251xfd_regmap_crc_gather_write(context, ®, reg_len, val, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write from 0xe07 on */
|
||||
reg += len + 1;
|
||||
return _mcp251xfd_regmap_crc_gather_write(context, ®, reg_len,
|
||||
val + len + 1,
|
||||
val_len - len - 1);
|
||||
}
|
||||
|
||||
return _mcp251xfd_regmap_crc_gather_write(context, reg_p, reg_len,
|
||||
val, val_len);
|
||||
}
|
||||
|
||||
static int
|
||||
mcp251xfd_regmap_crc_write(void *context,
|
||||
const void *data, size_t count)
|
||||
|
||||
@@ -337,6 +337,7 @@
|
||||
#define MCP251XFD_REG_IOCON_PM0 BIT(24)
|
||||
#define MCP251XFD_REG_IOCON_GPIO1 BIT(17)
|
||||
#define MCP251XFD_REG_IOCON_GPIO0 BIT(16)
|
||||
#define MCP251XFD_REG_IOCON_GPIO_MASK GENMASK(17, 16)
|
||||
#define MCP251XFD_REG_IOCON_LAT1 BIT(9)
|
||||
#define MCP251XFD_REG_IOCON_LAT0 BIT(8)
|
||||
#define MCP251XFD_REG_IOCON_XSTBYEN BIT(6)
|
||||
|
||||
Reference in New Issue
Block a user