tcan4x5x-regmap.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // tcan4x5x - Texas Instruments TCAN4x5x Family CAN controller driver
  4. //
  5. // Copyright (c) 2020 Pengutronix,
  6. // Marc Kleine-Budde <[email protected]>
  7. // Copyright (c) 2018-2019 Texas Instruments Incorporated
  8. // http://www.ti.com/
  9. #include "tcan4x5x.h"
  10. #define TCAN4X5X_SPI_INSTRUCTION_WRITE (0x61 << 24)
  11. #define TCAN4X5X_SPI_INSTRUCTION_READ (0x41 << 24)
  12. #define TCAN4X5X_MAX_REGISTER 0x87fc
  13. static int tcan4x5x_regmap_gather_write(void *context,
  14. const void *reg, size_t reg_len,
  15. const void *val, size_t val_len)
  16. {
  17. struct spi_device *spi = context;
  18. struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
  19. struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx;
  20. struct spi_transfer xfer[] = {
  21. {
  22. .tx_buf = buf_tx,
  23. .len = sizeof(buf_tx->cmd) + val_len,
  24. },
  25. };
  26. memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd.cmd) +
  27. sizeof(buf_tx->cmd.addr));
  28. tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len);
  29. memcpy(buf_tx->data, val, val_len);
  30. return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
  31. }
  32. static int tcan4x5x_regmap_write(void *context, const void *data, size_t count)
  33. {
  34. return tcan4x5x_regmap_gather_write(context, data, sizeof(__be32),
  35. data + sizeof(__be32),
  36. count - sizeof(__be32));
  37. }
  38. static int tcan4x5x_regmap_read(void *context,
  39. const void *reg_buf, size_t reg_len,
  40. void *val_buf, size_t val_len)
  41. {
  42. struct spi_device *spi = context;
  43. struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
  44. struct tcan4x5x_map_buf *buf_rx = &priv->map_buf_rx;
  45. struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx;
  46. struct spi_transfer xfer[2] = {
  47. {
  48. .tx_buf = buf_tx,
  49. }
  50. };
  51. struct spi_message msg;
  52. int err;
  53. spi_message_init(&msg);
  54. spi_message_add_tail(&xfer[0], &msg);
  55. memcpy(&buf_tx->cmd, reg_buf, sizeof(buf_tx->cmd.cmd) +
  56. sizeof(buf_tx->cmd.addr));
  57. tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len);
  58. if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) {
  59. xfer[0].len = sizeof(buf_tx->cmd);
  60. xfer[1].rx_buf = val_buf;
  61. xfer[1].len = val_len;
  62. spi_message_add_tail(&xfer[1], &msg);
  63. } else {
  64. xfer[0].rx_buf = buf_rx;
  65. xfer[0].len = sizeof(buf_tx->cmd) + val_len;
  66. if (TCAN4X5X_SANITIZE_SPI)
  67. memset(buf_tx->data, 0x0, val_len);
  68. }
  69. err = spi_sync(spi, &msg);
  70. if (err)
  71. return err;
  72. if (!(spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX))
  73. memcpy(val_buf, buf_rx->data, val_len);
  74. return 0;
  75. }
  76. static const struct regmap_range tcan4x5x_reg_table_yes_range[] = {
  77. regmap_reg_range(0x0000, 0x002c), /* Device ID and SPI Registers */
  78. regmap_reg_range(0x0800, 0x083c), /* Device configuration registers and Interrupt Flags*/
  79. regmap_reg_range(0x1000, 0x10fc), /* M_CAN */
  80. regmap_reg_range(0x8000, 0x87fc), /* MRAM */
  81. };
  82. static const struct regmap_access_table tcan4x5x_reg_table = {
  83. .yes_ranges = tcan4x5x_reg_table_yes_range,
  84. .n_yes_ranges = ARRAY_SIZE(tcan4x5x_reg_table_yes_range),
  85. };
  86. static const struct regmap_config tcan4x5x_regmap = {
  87. .reg_bits = 24,
  88. .reg_stride = 4,
  89. .pad_bits = 8,
  90. .val_bits = 32,
  91. .wr_table = &tcan4x5x_reg_table,
  92. .rd_table = &tcan4x5x_reg_table,
  93. .max_register = TCAN4X5X_MAX_REGISTER,
  94. .cache_type = REGCACHE_NONE,
  95. .read_flag_mask = (__force unsigned long)
  96. cpu_to_be32(TCAN4X5X_SPI_INSTRUCTION_READ),
  97. .write_flag_mask = (__force unsigned long)
  98. cpu_to_be32(TCAN4X5X_SPI_INSTRUCTION_WRITE),
  99. };
  100. static const struct regmap_bus tcan4x5x_bus = {
  101. .write = tcan4x5x_regmap_write,
  102. .gather_write = tcan4x5x_regmap_gather_write,
  103. .read = tcan4x5x_regmap_read,
  104. .reg_format_endian_default = REGMAP_ENDIAN_BIG,
  105. .val_format_endian_default = REGMAP_ENDIAN_BIG,
  106. .max_raw_read = 256,
  107. .max_raw_write = 256,
  108. };
  109. int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv)
  110. {
  111. priv->regmap = devm_regmap_init(&priv->spi->dev, &tcan4x5x_bus,
  112. priv->spi, &tcan4x5x_regmap);
  113. return PTR_ERR_OR_ZERO(priv->regmap);
  114. }