Commit | Line | Data |
---|---|---|
67def4ef MKB |
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 <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 | ||
15 | #define TCAN4X5X_MAX_REGISTER 0x8fff | |
16 | ||
17 | static int regmap_spi_gather_write(void *context, const void *reg, | |
18 | size_t reg_len, const void *val, | |
19 | size_t val_len) | |
20 | { | |
21 | struct device *dev = context; | |
22 | struct spi_device *spi = to_spi_device(dev); | |
23 | struct spi_message m; | |
24 | u32 addr; | |
25 | struct spi_transfer t[2] = { | |
26 | { .tx_buf = &addr, .len = reg_len, .cs_change = 0,}, | |
27 | { .tx_buf = val, .len = val_len, }, | |
28 | }; | |
29 | ||
30 | addr = TCAN4X5X_WRITE_CMD | (*((u16 *)reg) << 8) | val_len >> 2; | |
31 | ||
32 | spi_message_init(&m); | |
33 | spi_message_add_tail(&t[0], &m); | |
34 | spi_message_add_tail(&t[1], &m); | |
35 | ||
36 | return spi_sync(spi, &m); | |
37 | } | |
38 | ||
39 | static int tcan4x5x_regmap_write(void *context, const void *data, size_t count) | |
40 | { | |
41 | u16 *reg = (u16 *)(data); | |
42 | const u32 *val = data + 4; | |
43 | ||
44 | return regmap_spi_gather_write(context, reg, 4, val, count - 4); | |
45 | } | |
46 | ||
47 | static int regmap_spi_async_write(void *context, | |
48 | const void *reg, size_t reg_len, | |
49 | const void *val, size_t val_len, | |
50 | struct regmap_async *a) | |
51 | { | |
52 | return -ENOTSUPP; | |
53 | } | |
54 | ||
55 | static struct regmap_async *regmap_spi_async_alloc(void) | |
56 | { | |
57 | return NULL; | |
58 | } | |
59 | ||
60 | static int tcan4x5x_regmap_read(void *context, | |
61 | const void *reg, size_t reg_size, | |
62 | void *val, size_t val_size) | |
63 | { | |
64 | struct device *dev = context; | |
65 | struct spi_device *spi = to_spi_device(dev); | |
66 | ||
67 | u32 addr = TCAN4X5X_READ_CMD | (*((u16 *)reg) << 8) | val_size >> 2; | |
68 | ||
69 | return spi_write_then_read(spi, &addr, reg_size, (u32 *)val, val_size); | |
70 | } | |
71 | ||
72 | static const struct regmap_config tcan4x5x_regmap = { | |
73 | .reg_bits = 32, | |
74 | .val_bits = 32, | |
75 | .cache_type = REGCACHE_NONE, | |
76 | .max_register = TCAN4X5X_MAX_REGISTER, | |
77 | }; | |
78 | ||
1784aa14 | 79 | static const struct regmap_bus tcan4x5x_bus = { |
67def4ef MKB |
80 | .write = tcan4x5x_regmap_write, |
81 | .gather_write = regmap_spi_gather_write, | |
82 | .async_write = regmap_spi_async_write, | |
83 | .async_alloc = regmap_spi_async_alloc, | |
84 | .read = tcan4x5x_regmap_read, | |
67def4ef MKB |
85 | .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, |
86 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, | |
87 | }; | |
88 | ||
89 | int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv) | |
90 | { | |
91 | priv->regmap = devm_regmap_init(&priv->spi->dev, &tcan4x5x_bus, | |
92 | &priv->spi->dev, &tcan4x5x_regmap); | |
93 | return PTR_ERR_OR_ZERO(priv->regmap); | |
94 | } |