blob: 73be4b6613055e2e7eb4aa31f393ae82dc018b4c [file] [log] [blame]
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +01001// 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 <kernel@pengutronix.de>
7// Copyright (c) 2018-2019 Texas Instruments Incorporated
8// http://www.ti.com/
9
10#include "tcan4x5x.h"
11
12#define TCAN4X5X_WRITE_CMD (0x61 << 24)
13#define TCAN4X5X_READ_CMD (0x41 << 24)
14
Marc Kleine-Budde6e1caaf2020-12-16 00:17:41 +010015#define TCAN4X5X_MAX_REGISTER 0x8ffc
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010016
Marc Kleine-Budde52be9772020-12-16 00:17:38 +010017static int tcan4x5x_regmap_gather_write(void *context, const void *reg,
18 size_t reg_len, const void *val,
19 size_t val_len)
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010020{
Marc Kleine-Buddebf722fd2020-12-16 00:17:40 +010021 struct spi_device *spi = context;
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010022 struct spi_message m;
23 u32 addr;
24 struct spi_transfer t[2] = {
25 { .tx_buf = &addr, .len = reg_len, .cs_change = 0,},
26 { .tx_buf = val, .len = val_len, },
27 };
28
29 addr = TCAN4X5X_WRITE_CMD | (*((u16 *)reg) << 8) | val_len >> 2;
30
31 spi_message_init(&m);
32 spi_message_add_tail(&t[0], &m);
33 spi_message_add_tail(&t[1], &m);
34
35 return spi_sync(spi, &m);
36}
37
38static int tcan4x5x_regmap_write(void *context, const void *data, size_t count)
39{
Marc Kleine-Budde0c053452020-12-16 00:17:39 +010040 return tcan4x5x_regmap_gather_write(context, data, sizeof(u32),
41 data + sizeof(u32),
42 count - sizeof(u32));
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010043}
44
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010045static int tcan4x5x_regmap_read(void *context,
46 const void *reg, size_t reg_size,
47 void *val, size_t val_size)
48{
Marc Kleine-Buddebf722fd2020-12-16 00:17:40 +010049 struct spi_device *spi = context;
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010050
51 u32 addr = TCAN4X5X_READ_CMD | (*((u16 *)reg) << 8) | val_size >> 2;
52
53 return spi_write_then_read(spi, &addr, reg_size, (u32 *)val, val_size);
54}
55
56static const struct regmap_config tcan4x5x_regmap = {
57 .reg_bits = 32,
58 .val_bits = 32,
59 .cache_type = REGCACHE_NONE,
60 .max_register = TCAN4X5X_MAX_REGISTER,
61};
62
Marc Kleine-Budde1784aa12020-12-16 00:17:35 +010063static const struct regmap_bus tcan4x5x_bus = {
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010064 .write = tcan4x5x_regmap_write,
Marc Kleine-Budde52be9772020-12-16 00:17:38 +010065 .gather_write = tcan4x5x_regmap_gather_write,
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010066 .read = tcan4x5x_regmap_read,
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010067 .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
68 .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
69};
70
71int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv)
72{
73 priv->regmap = devm_regmap_init(&priv->spi->dev, &tcan4x5x_bus,
Marc Kleine-Buddebf722fd2020-12-16 00:17:40 +010074 priv->spi, &tcan4x5x_regmap);
Marc Kleine-Budde67def4ef2020-12-16 00:17:34 +010075 return PTR_ERR_OR_ZERO(priv->regmap);
76}