e59986de5f
The MRAM of the tcan4x5x has a size of 2K and starts at 0x8000. There are no further registers in the tcan4x5x making 0x87fc the biggest addressable register. This patch fixes the max register value of the regmap config from 0x8ffc to 0x87fc. Fixes: 6e1caaf8ed22 ("can: tcan4x5x: fix max register value") Link: https://lore.kernel.org/all/20220119064011.2943292-1-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
136 lines
3.8 KiB
C
136 lines
3.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
//
|
|
// tcan4x5x - Texas Instruments TCAN4x5x Family CAN controller driver
|
|
//
|
|
// Copyright (c) 2020 Pengutronix,
|
|
// Marc Kleine-Budde <kernel@pengutronix.de>
|
|
// Copyright (c) 2018-2019 Texas Instruments Incorporated
|
|
// http://www.ti.com/
|
|
|
|
#include "tcan4x5x.h"
|
|
|
|
#define TCAN4X5X_SPI_INSTRUCTION_WRITE (0x61 << 24)
|
|
#define TCAN4X5X_SPI_INSTRUCTION_READ (0x41 << 24)
|
|
|
|
#define TCAN4X5X_MAX_REGISTER 0x87fc
|
|
|
|
static int tcan4x5x_regmap_gather_write(void *context,
|
|
const void *reg, size_t reg_len,
|
|
const void *val, size_t val_len)
|
|
{
|
|
struct spi_device *spi = context;
|
|
struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
|
|
struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx;
|
|
struct spi_transfer xfer[] = {
|
|
{
|
|
.tx_buf = buf_tx,
|
|
.len = sizeof(buf_tx->cmd) + val_len,
|
|
},
|
|
};
|
|
|
|
memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd.cmd) +
|
|
sizeof(buf_tx->cmd.addr));
|
|
tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len);
|
|
memcpy(buf_tx->data, val, val_len);
|
|
|
|
return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
|
|
}
|
|
|
|
static int tcan4x5x_regmap_write(void *context, const void *data, size_t count)
|
|
{
|
|
return tcan4x5x_regmap_gather_write(context, data, sizeof(__be32),
|
|
data + sizeof(__be32),
|
|
count - sizeof(__be32));
|
|
}
|
|
|
|
static int tcan4x5x_regmap_read(void *context,
|
|
const void *reg_buf, size_t reg_len,
|
|
void *val_buf, size_t val_len)
|
|
{
|
|
struct spi_device *spi = context;
|
|
struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
|
|
struct tcan4x5x_map_buf *buf_rx = &priv->map_buf_rx;
|
|
struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx;
|
|
struct spi_transfer xfer[2] = {
|
|
{
|
|
.tx_buf = buf_tx,
|
|
}
|
|
};
|
|
struct spi_message msg;
|
|
int err;
|
|
|
|
spi_message_init(&msg);
|
|
spi_message_add_tail(&xfer[0], &msg);
|
|
|
|
memcpy(&buf_tx->cmd, reg_buf, sizeof(buf_tx->cmd.cmd) +
|
|
sizeof(buf_tx->cmd.addr));
|
|
tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len);
|
|
|
|
if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) {
|
|
xfer[0].len = sizeof(buf_tx->cmd);
|
|
|
|
xfer[1].rx_buf = val_buf;
|
|
xfer[1].len = val_len;
|
|
spi_message_add_tail(&xfer[1], &msg);
|
|
} else {
|
|
xfer[0].rx_buf = buf_rx;
|
|
xfer[0].len = sizeof(buf_tx->cmd) + val_len;
|
|
|
|
if (TCAN4X5X_SANITIZE_SPI)
|
|
memset(buf_tx->data, 0x0, val_len);
|
|
}
|
|
|
|
err = spi_sync(spi, &msg);
|
|
if (err)
|
|
return err;
|
|
|
|
if (!(spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX))
|
|
memcpy(val_buf, buf_rx->data, val_len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct regmap_range tcan4x5x_reg_table_yes_range[] = {
|
|
regmap_reg_range(0x0000, 0x002c), /* Device ID and SPI Registers */
|
|
regmap_reg_range(0x0800, 0x083c), /* Device configuration registers and Interrupt Flags*/
|
|
regmap_reg_range(0x1000, 0x10fc), /* M_CAN */
|
|
regmap_reg_range(0x8000, 0x87fc), /* MRAM */
|
|
};
|
|
|
|
static const struct regmap_access_table tcan4x5x_reg_table = {
|
|
.yes_ranges = tcan4x5x_reg_table_yes_range,
|
|
.n_yes_ranges = ARRAY_SIZE(tcan4x5x_reg_table_yes_range),
|
|
};
|
|
|
|
static const struct regmap_config tcan4x5x_regmap = {
|
|
.reg_bits = 24,
|
|
.reg_stride = 4,
|
|
.pad_bits = 8,
|
|
.val_bits = 32,
|
|
.wr_table = &tcan4x5x_reg_table,
|
|
.rd_table = &tcan4x5x_reg_table,
|
|
.max_register = TCAN4X5X_MAX_REGISTER,
|
|
.cache_type = REGCACHE_NONE,
|
|
.read_flag_mask = (__force unsigned long)
|
|
cpu_to_be32(TCAN4X5X_SPI_INSTRUCTION_READ),
|
|
.write_flag_mask = (__force unsigned long)
|
|
cpu_to_be32(TCAN4X5X_SPI_INSTRUCTION_WRITE),
|
|
};
|
|
|
|
static const struct regmap_bus tcan4x5x_bus = {
|
|
.write = tcan4x5x_regmap_write,
|
|
.gather_write = tcan4x5x_regmap_gather_write,
|
|
.read = tcan4x5x_regmap_read,
|
|
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
|
|
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
|
.max_raw_read = 256,
|
|
.max_raw_write = 256,
|
|
};
|
|
|
|
int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv)
|
|
{
|
|
priv->regmap = devm_regmap_init(&priv->spi->dev, &tcan4x5x_bus,
|
|
priv->spi, &tcan4x5x_regmap);
|
|
return PTR_ERR_OR_ZERO(priv->regmap);
|
|
}
|