Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // tcan4x5x - Texas Instruments TCAN4x5x Family CAN controller driver
0004 //
0005 // Copyright (c) 2020 Pengutronix,
0006 //                    Marc Kleine-Budde <kernel@pengutronix.de>
0007 // Copyright (c) 2018-2019 Texas Instruments Incorporated
0008 //                    http://www.ti.com/
0009 
0010 #include "tcan4x5x.h"
0011 
0012 #define TCAN4X5X_SPI_INSTRUCTION_WRITE (0x61 << 24)
0013 #define TCAN4X5X_SPI_INSTRUCTION_READ (0x41 << 24)
0014 
0015 #define TCAN4X5X_MAX_REGISTER 0x87fc
0016 
0017 static int tcan4x5x_regmap_gather_write(void *context,
0018                     const void *reg, size_t reg_len,
0019                     const void *val, size_t val_len)
0020 {
0021     struct spi_device *spi = context;
0022     struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
0023     struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx;
0024     struct spi_transfer xfer[] = {
0025         {
0026             .tx_buf = buf_tx,
0027             .len = sizeof(buf_tx->cmd) + val_len,
0028         },
0029     };
0030 
0031     memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd.cmd) +
0032            sizeof(buf_tx->cmd.addr));
0033     tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len);
0034     memcpy(buf_tx->data, val, val_len);
0035 
0036     return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
0037 }
0038 
0039 static int tcan4x5x_regmap_write(void *context, const void *data, size_t count)
0040 {
0041     return tcan4x5x_regmap_gather_write(context, data, sizeof(__be32),
0042                         data + sizeof(__be32),
0043                         count - sizeof(__be32));
0044 }
0045 
0046 static int tcan4x5x_regmap_read(void *context,
0047                 const void *reg_buf, size_t reg_len,
0048                 void *val_buf, size_t val_len)
0049 {
0050     struct spi_device *spi = context;
0051     struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
0052     struct tcan4x5x_map_buf *buf_rx = &priv->map_buf_rx;
0053     struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx;
0054     struct spi_transfer xfer[2] = {
0055         {
0056             .tx_buf = buf_tx,
0057         }
0058     };
0059     struct spi_message msg;
0060     int err;
0061 
0062     spi_message_init(&msg);
0063     spi_message_add_tail(&xfer[0], &msg);
0064 
0065     memcpy(&buf_tx->cmd, reg_buf, sizeof(buf_tx->cmd.cmd) +
0066            sizeof(buf_tx->cmd.addr));
0067     tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len);
0068 
0069     if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) {
0070         xfer[0].len = sizeof(buf_tx->cmd);
0071 
0072         xfer[1].rx_buf = val_buf;
0073         xfer[1].len = val_len;
0074         spi_message_add_tail(&xfer[1], &msg);
0075     } else {
0076         xfer[0].rx_buf = buf_rx;
0077         xfer[0].len = sizeof(buf_tx->cmd) + val_len;
0078 
0079         if (TCAN4X5X_SANITIZE_SPI)
0080             memset(buf_tx->data, 0x0, val_len);
0081     }
0082 
0083     err = spi_sync(spi, &msg);
0084     if (err)
0085         return err;
0086 
0087     if (!(spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX))
0088         memcpy(val_buf, buf_rx->data, val_len);
0089 
0090     return 0;
0091 }
0092 
0093 static const struct regmap_range tcan4x5x_reg_table_yes_range[] = {
0094     regmap_reg_range(0x0000, 0x002c),   /* Device ID and SPI Registers */
0095     regmap_reg_range(0x0800, 0x083c),   /* Device configuration registers and Interrupt Flags*/
0096     regmap_reg_range(0x1000, 0x10fc),   /* M_CAN */
0097     regmap_reg_range(0x8000, 0x87fc),   /* MRAM */
0098 };
0099 
0100 static const struct regmap_access_table tcan4x5x_reg_table = {
0101     .yes_ranges = tcan4x5x_reg_table_yes_range,
0102     .n_yes_ranges = ARRAY_SIZE(tcan4x5x_reg_table_yes_range),
0103 };
0104 
0105 static const struct regmap_config tcan4x5x_regmap = {
0106     .reg_bits = 24,
0107     .reg_stride = 4,
0108     .pad_bits = 8,
0109     .val_bits = 32,
0110     .wr_table = &tcan4x5x_reg_table,
0111     .rd_table = &tcan4x5x_reg_table,
0112     .max_register = TCAN4X5X_MAX_REGISTER,
0113     .cache_type = REGCACHE_NONE,
0114     .read_flag_mask = (__force unsigned long)
0115         cpu_to_be32(TCAN4X5X_SPI_INSTRUCTION_READ),
0116     .write_flag_mask = (__force unsigned long)
0117         cpu_to_be32(TCAN4X5X_SPI_INSTRUCTION_WRITE),
0118 };
0119 
0120 static const struct regmap_bus tcan4x5x_bus = {
0121     .write = tcan4x5x_regmap_write,
0122     .gather_write = tcan4x5x_regmap_gather_write,
0123     .read = tcan4x5x_regmap_read,
0124     .reg_format_endian_default = REGMAP_ENDIAN_BIG,
0125     .val_format_endian_default = REGMAP_ENDIAN_BIG,
0126     .max_raw_read = 256,
0127     .max_raw_write = 256,
0128 };
0129 
0130 int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv)
0131 {
0132     priv->regmap = devm_regmap_init(&priv->spi->dev, &tcan4x5x_bus,
0133                     priv->spi, &tcan4x5x_regmap);
0134     return PTR_ERR_OR_ZERO(priv->regmap);
0135 }