1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // mcp251xfd - Microchip MCP251xFD Family CAN controller driver |
4 | // |
5 | // Copyright (c) 2019, 2020, 2021 Pengutronix, |
6 | // Marc Kleine-Budde <kernel@pengutronix.de> |
7 | // |
8 | |
9 | #include "mcp251xfd.h" |
10 | |
11 | #include <asm/unaligned.h> |
12 | |
13 | static const struct regmap_config mcp251xfd_regmap_crc; |
14 | |
15 | static int |
16 | mcp251xfd_regmap_nocrc_write(void *context, const void *data, size_t count) |
17 | { |
18 | struct spi_device *spi = context; |
19 | |
20 | return spi_write(spi, buf: data, len: count); |
21 | } |
22 | |
23 | static int |
24 | mcp251xfd_regmap_nocrc_gather_write(void *context, |
25 | const void *reg, size_t reg_len, |
26 | const void *val, size_t val_len) |
27 | { |
28 | struct spi_device *spi = context; |
29 | struct mcp251xfd_priv *priv = spi_get_drvdata(spi); |
30 | struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx; |
31 | struct spi_transfer xfer[] = { |
32 | { |
33 | .tx_buf = buf_tx, |
34 | .len = sizeof(buf_tx->cmd) + val_len, |
35 | }, |
36 | }; |
37 | |
38 | BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16)); |
39 | |
40 | if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && |
41 | reg_len != sizeof(buf_tx->cmd.cmd)) |
42 | return -EINVAL; |
43 | |
44 | memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd)); |
45 | memcpy(buf_tx->data, val, val_len); |
46 | |
47 | return spi_sync_transfer(spi, xfers: xfer, ARRAY_SIZE(xfer)); |
48 | } |
49 | |
50 | static inline bool |
51 | mcp251xfd_update_bits_read_reg(const struct mcp251xfd_priv *priv, |
52 | unsigned int reg) |
53 | { |
54 | struct mcp251xfd_rx_ring *ring; |
55 | int n; |
56 | |
57 | switch (reg) { |
58 | case MCP251XFD_REG_INT: |
59 | case MCP251XFD_REG_TEFCON: |
60 | case MCP251XFD_REG_FLTCON(0): |
61 | case MCP251XFD_REG_ECCSTAT: |
62 | case MCP251XFD_REG_CRC: |
63 | return false; |
64 | case MCP251XFD_REG_CON: |
65 | case MCP251XFD_REG_OSC: |
66 | case MCP251XFD_REG_ECCCON: |
67 | return true; |
68 | default: |
69 | mcp251xfd_for_each_rx_ring(priv, ring, n) { |
70 | if (reg == MCP251XFD_REG_FIFOCON(ring->fifo_nr)) |
71 | return false; |
72 | if (reg == MCP251XFD_REG_FIFOSTA(ring->fifo_nr)) |
73 | return true; |
74 | } |
75 | |
76 | WARN(1, "Status of reg 0x%04x unknown.\n" , reg); |
77 | } |
78 | |
79 | return true; |
80 | } |
81 | |
82 | static int |
83 | mcp251xfd_regmap_nocrc_update_bits(void *context, unsigned int reg, |
84 | unsigned int mask, unsigned int val) |
85 | { |
86 | struct spi_device *spi = context; |
87 | struct mcp251xfd_priv *priv = spi_get_drvdata(spi); |
88 | struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx; |
89 | struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx; |
90 | __le32 orig_le32 = 0, mask_le32, val_le32, tmp_le32; |
91 | u8 first_byte, last_byte, len; |
92 | int err; |
93 | |
94 | BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16)); |
95 | BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16)); |
96 | |
97 | if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && |
98 | mask == 0) |
99 | return -EINVAL; |
100 | |
101 | first_byte = mcp251xfd_first_byte_set(mask); |
102 | last_byte = mcp251xfd_last_byte_set(mask); |
103 | len = last_byte - first_byte + 1; |
104 | |
105 | if (mcp251xfd_update_bits_read_reg(priv, reg)) { |
106 | struct spi_transfer xfer[2] = { }; |
107 | struct spi_message msg; |
108 | |
109 | spi_message_init(m: &msg); |
110 | spi_message_add_tail(t: &xfer[0], m: &msg); |
111 | |
112 | if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) { |
113 | xfer[0].tx_buf = buf_tx; |
114 | xfer[0].len = sizeof(buf_tx->cmd); |
115 | |
116 | xfer[1].rx_buf = buf_rx->data; |
117 | xfer[1].len = len; |
118 | spi_message_add_tail(t: &xfer[1], m: &msg); |
119 | } else { |
120 | xfer[0].tx_buf = buf_tx; |
121 | xfer[0].rx_buf = buf_rx; |
122 | xfer[0].len = sizeof(buf_tx->cmd) + len; |
123 | |
124 | if (MCP251XFD_SANITIZE_SPI) |
125 | memset(buf_tx->data, 0x0, len); |
126 | } |
127 | |
128 | mcp251xfd_spi_cmd_read_nocrc(cmd: &buf_tx->cmd, addr: reg + first_byte); |
129 | err = spi_sync(spi, message: &msg); |
130 | if (err) |
131 | return err; |
132 | |
133 | memcpy(&orig_le32, buf_rx->data, len); |
134 | } |
135 | |
136 | mask_le32 = cpu_to_le32(mask >> BITS_PER_BYTE * first_byte); |
137 | val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte); |
138 | |
139 | tmp_le32 = orig_le32 & ~mask_le32; |
140 | tmp_le32 |= val_le32 & mask_le32; |
141 | |
142 | mcp251xfd_spi_cmd_write_nocrc(cmd: &buf_tx->cmd, addr: reg + first_byte); |
143 | memcpy(buf_tx->data, &tmp_le32, len); |
144 | |
145 | return spi_write(spi, buf: buf_tx, len: sizeof(buf_tx->cmd) + len); |
146 | } |
147 | |
148 | static int |
149 | mcp251xfd_regmap_nocrc_read(void *context, |
150 | const void *reg, size_t reg_len, |
151 | void *val_buf, size_t val_len) |
152 | { |
153 | struct spi_device *spi = context; |
154 | struct mcp251xfd_priv *priv = spi_get_drvdata(spi); |
155 | struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx; |
156 | struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx; |
157 | struct spi_transfer xfer[2] = { }; |
158 | struct spi_message msg; |
159 | int err; |
160 | |
161 | BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16)); |
162 | BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16)); |
163 | |
164 | if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && |
165 | reg_len != sizeof(buf_tx->cmd.cmd)) |
166 | return -EINVAL; |
167 | |
168 | spi_message_init(m: &msg); |
169 | spi_message_add_tail(t: &xfer[0], m: &msg); |
170 | |
171 | if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) { |
172 | xfer[0].tx_buf = reg; |
173 | xfer[0].len = sizeof(buf_tx->cmd); |
174 | |
175 | xfer[1].rx_buf = val_buf; |
176 | xfer[1].len = val_len; |
177 | spi_message_add_tail(t: &xfer[1], m: &msg); |
178 | } else { |
179 | xfer[0].tx_buf = buf_tx; |
180 | xfer[0].rx_buf = buf_rx; |
181 | xfer[0].len = sizeof(buf_tx->cmd) + val_len; |
182 | |
183 | memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd)); |
184 | if (MCP251XFD_SANITIZE_SPI) |
185 | memset(buf_tx->data, 0x0, val_len); |
186 | } |
187 | |
188 | err = spi_sync(spi, message: &msg); |
189 | if (err) |
190 | return err; |
191 | |
192 | if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX)) |
193 | memcpy(val_buf, buf_rx->data, val_len); |
194 | |
195 | return 0; |
196 | } |
197 | |
198 | static int |
199 | mcp251xfd_regmap_crc_gather_write(void *context, |
200 | const void *reg_p, size_t reg_len, |
201 | const void *val, size_t val_len) |
202 | { |
203 | struct spi_device *spi = context; |
204 | struct mcp251xfd_priv *priv = spi_get_drvdata(spi); |
205 | struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx; |
206 | struct spi_transfer xfer[] = { |
207 | { |
208 | .tx_buf = buf_tx, |
209 | .len = sizeof(buf_tx->cmd) + val_len + |
210 | sizeof(buf_tx->crc), |
211 | }, |
212 | }; |
213 | u16 reg = *(u16 *)reg_p; |
214 | u16 crc; |
215 | |
216 | BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8)); |
217 | |
218 | if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && |
219 | reg_len != sizeof(buf_tx->cmd.cmd) + |
220 | mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE) |
221 | return -EINVAL; |
222 | |
223 | mcp251xfd_spi_cmd_write_crc(cmd: &buf_tx->cmd, addr: reg, len: val_len); |
224 | memcpy(buf_tx->data, val, val_len); |
225 | |
226 | crc = mcp251xfd_crc16_compute(data: buf_tx, data_size: sizeof(buf_tx->cmd) + val_len); |
227 | put_unaligned_be16(val: crc, p: buf_tx->data + val_len); |
228 | |
229 | return spi_sync_transfer(spi, xfers: xfer, ARRAY_SIZE(xfer)); |
230 | } |
231 | |
232 | static int |
233 | mcp251xfd_regmap_crc_write(void *context, |
234 | const void *data, size_t count) |
235 | { |
236 | const size_t data_offset = sizeof(__be16) + |
237 | mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE; |
238 | |
239 | return mcp251xfd_regmap_crc_gather_write(context, |
240 | reg_p: data, reg_len: data_offset, |
241 | val: data + data_offset, |
242 | val_len: count - data_offset); |
243 | } |
244 | |
245 | static int |
246 | mcp251xfd_regmap_crc_read_check_crc(const struct mcp251xfd_map_buf_crc * const buf_rx, |
247 | const struct mcp251xfd_map_buf_crc * const buf_tx, |
248 | unsigned int data_len) |
249 | { |
250 | u16 crc_received, crc_calculated; |
251 | |
252 | crc_received = get_unaligned_be16(p: buf_rx->data + data_len); |
253 | crc_calculated = mcp251xfd_crc16_compute2(cmd: &buf_tx->cmd, |
254 | cmd_size: sizeof(buf_tx->cmd), |
255 | data: buf_rx->data, |
256 | data_size: data_len); |
257 | if (crc_received != crc_calculated) |
258 | return -EBADMSG; |
259 | |
260 | return 0; |
261 | } |
262 | |
263 | static int |
264 | mcp251xfd_regmap_crc_read_one(struct mcp251xfd_priv *priv, |
265 | struct spi_message *msg, unsigned int data_len) |
266 | { |
267 | const struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx; |
268 | const struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx; |
269 | int err; |
270 | |
271 | BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8)); |
272 | BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8)); |
273 | |
274 | err = spi_sync(spi: priv->spi, message: msg); |
275 | if (err) |
276 | return err; |
277 | |
278 | return mcp251xfd_regmap_crc_read_check_crc(buf_rx, buf_tx, data_len); |
279 | } |
280 | |
281 | static int |
282 | mcp251xfd_regmap_crc_read(void *context, |
283 | const void *reg_p, size_t reg_len, |
284 | void *val_buf, size_t val_len) |
285 | { |
286 | struct spi_device *spi = context; |
287 | struct mcp251xfd_priv *priv = spi_get_drvdata(spi); |
288 | struct mcp251xfd_map_buf_crc *buf_rx = priv->map_buf_crc_rx; |
289 | struct mcp251xfd_map_buf_crc *buf_tx = priv->map_buf_crc_tx; |
290 | struct spi_transfer xfer[2] = { }; |
291 | struct spi_message msg; |
292 | u16 reg = *(u16 *)reg_p; |
293 | int i, err; |
294 | |
295 | BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16) + sizeof(u8)); |
296 | BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16) + sizeof(u8)); |
297 | |
298 | if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) && |
299 | reg_len != sizeof(buf_tx->cmd.cmd) + |
300 | mcp251xfd_regmap_crc.pad_bits / BITS_PER_BYTE) |
301 | return -EINVAL; |
302 | |
303 | spi_message_init(m: &msg); |
304 | spi_message_add_tail(t: &xfer[0], m: &msg); |
305 | |
306 | if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) { |
307 | xfer[0].tx_buf = buf_tx; |
308 | xfer[0].len = sizeof(buf_tx->cmd); |
309 | |
310 | xfer[1].rx_buf = buf_rx->data; |
311 | xfer[1].len = val_len + sizeof(buf_tx->crc); |
312 | spi_message_add_tail(t: &xfer[1], m: &msg); |
313 | } else { |
314 | xfer[0].tx_buf = buf_tx; |
315 | xfer[0].rx_buf = buf_rx; |
316 | xfer[0].len = sizeof(buf_tx->cmd) + val_len + |
317 | sizeof(buf_tx->crc); |
318 | |
319 | if (MCP251XFD_SANITIZE_SPI) |
320 | memset(buf_tx->data, 0x0, val_len + |
321 | sizeof(buf_tx->crc)); |
322 | } |
323 | |
324 | mcp251xfd_spi_cmd_read_crc(cmd: &buf_tx->cmd, addr: reg, len: val_len); |
325 | |
326 | for (i = 0; i < MCP251XFD_READ_CRC_RETRIES_MAX; i++) { |
327 | err = mcp251xfd_regmap_crc_read_one(priv, msg: &msg, data_len: val_len); |
328 | if (!err) |
329 | goto out; |
330 | if (err != -EBADMSG) |
331 | return err; |
332 | |
333 | /* MCP251XFD_REG_TBC is the time base counter |
334 | * register. It increments once per SYS clock tick, |
335 | * which is 20 or 40 MHz. |
336 | * |
337 | * Observation on the mcp2518fd shows that if the |
338 | * lowest byte (which is transferred first on the SPI |
339 | * bus) of that register is 0x00 or 0x80 the |
340 | * calculated CRC doesn't always match the transferred |
341 | * one. On the mcp2517fd this problem is not limited |
342 | * to the first byte being 0x00 or 0x80. |
343 | * |
344 | * If the highest bit in the lowest byte is flipped |
345 | * the transferred CRC matches the calculated one. We |
346 | * assume for now the CRC operates on the correct |
347 | * data. |
348 | */ |
349 | if (reg == MCP251XFD_REG_TBC && |
350 | ((buf_rx->data[0] & 0xf8) == 0x0 || |
351 | (buf_rx->data[0] & 0xf8) == 0x80)) { |
352 | /* Flip highest bit in lowest byte of le32 */ |
353 | buf_rx->data[0] ^= 0x80; |
354 | |
355 | /* re-check CRC */ |
356 | err = mcp251xfd_regmap_crc_read_check_crc(buf_rx, |
357 | buf_tx, |
358 | data_len: val_len); |
359 | if (!err) { |
360 | /* If CRC is now correct, assume |
361 | * flipped data is OK. |
362 | */ |
363 | goto out; |
364 | } |
365 | } |
366 | |
367 | /* MCP251XFD_REG_OSC is the first ever reg we read from. |
368 | * |
369 | * The chip may be in deep sleep and this SPI transfer |
370 | * (i.e. the assertion of the CS) will wake the chip |
371 | * up. This takes about 3ms. The CRC of this transfer |
372 | * is wrong. |
373 | * |
374 | * Or there isn't a chip at all, in this case the CRC |
375 | * will be wrong, too. |
376 | * |
377 | * In both cases ignore the CRC and copy the read data |
378 | * to the caller. It will take care of both cases. |
379 | * |
380 | */ |
381 | if (reg == MCP251XFD_REG_OSC && val_len == sizeof(__le32)) { |
382 | err = 0; |
383 | goto out; |
384 | } |
385 | |
386 | netdev_info(dev: priv->ndev, |
387 | format: "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x) retrying.\n" , |
388 | reg, val_len, (int)val_len, buf_rx->data, |
389 | get_unaligned_be16(p: buf_rx->data + val_len)); |
390 | } |
391 | |
392 | if (err) { |
393 | netdev_err(dev: priv->ndev, |
394 | format: "CRC read error at address 0x%04x (length=%zd, data=%*ph, CRC=0x%04x).\n" , |
395 | reg, val_len, (int)val_len, buf_rx->data, |
396 | get_unaligned_be16(p: buf_rx->data + val_len)); |
397 | |
398 | return err; |
399 | } |
400 | out: |
401 | memcpy(val_buf, buf_rx->data, val_len); |
402 | |
403 | return 0; |
404 | } |
405 | |
406 | static const struct regmap_range mcp251xfd_reg_table_yes_range[] = { |
407 | regmap_reg_range(0x000, 0x2ec), /* CAN FD Controller Module SFR */ |
408 | regmap_reg_range(0x400, 0xbfc), /* RAM */ |
409 | regmap_reg_range(0xe00, 0xe14), /* MCP2517/18FD SFR */ |
410 | }; |
411 | |
412 | static const struct regmap_access_table mcp251xfd_reg_table = { |
413 | .yes_ranges = mcp251xfd_reg_table_yes_range, |
414 | .n_yes_ranges = ARRAY_SIZE(mcp251xfd_reg_table_yes_range), |
415 | }; |
416 | |
417 | static const struct regmap_config mcp251xfd_regmap_nocrc = { |
418 | .name = "nocrc" , |
419 | .reg_bits = 16, |
420 | .reg_stride = 4, |
421 | .pad_bits = 0, |
422 | .val_bits = 32, |
423 | .max_register = 0xffc, |
424 | .wr_table = &mcp251xfd_reg_table, |
425 | .rd_table = &mcp251xfd_reg_table, |
426 | .cache_type = REGCACHE_NONE, |
427 | .read_flag_mask = (__force unsigned long) |
428 | cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_READ), |
429 | .write_flag_mask = (__force unsigned long) |
430 | cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE), |
431 | }; |
432 | |
433 | static const struct regmap_bus mcp251xfd_bus_nocrc = { |
434 | .write = mcp251xfd_regmap_nocrc_write, |
435 | .gather_write = mcp251xfd_regmap_nocrc_gather_write, |
436 | .reg_update_bits = mcp251xfd_regmap_nocrc_update_bits, |
437 | .read = mcp251xfd_regmap_nocrc_read, |
438 | .reg_format_endian_default = REGMAP_ENDIAN_BIG, |
439 | .val_format_endian_default = REGMAP_ENDIAN_LITTLE, |
440 | .max_raw_read = sizeof_field(struct mcp251xfd_map_buf_nocrc, data), |
441 | .max_raw_write = sizeof_field(struct mcp251xfd_map_buf_nocrc, data), |
442 | }; |
443 | |
444 | static const struct regmap_config mcp251xfd_regmap_crc = { |
445 | .name = "crc" , |
446 | .reg_bits = 16, |
447 | .reg_stride = 4, |
448 | .pad_bits = 16, /* keep data bits aligned */ |
449 | .val_bits = 32, |
450 | .max_register = 0xffc, |
451 | .wr_table = &mcp251xfd_reg_table, |
452 | .rd_table = &mcp251xfd_reg_table, |
453 | .cache_type = REGCACHE_NONE, |
454 | }; |
455 | |
456 | static const struct regmap_bus mcp251xfd_bus_crc = { |
457 | .write = mcp251xfd_regmap_crc_write, |
458 | .gather_write = mcp251xfd_regmap_crc_gather_write, |
459 | .read = mcp251xfd_regmap_crc_read, |
460 | .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, |
461 | .val_format_endian_default = REGMAP_ENDIAN_LITTLE, |
462 | .max_raw_read = sizeof_field(struct mcp251xfd_map_buf_crc, data), |
463 | .max_raw_write = sizeof_field(struct mcp251xfd_map_buf_crc, data), |
464 | }; |
465 | |
466 | static inline bool |
467 | mcp251xfd_regmap_use_nocrc(struct mcp251xfd_priv *priv) |
468 | { |
469 | return (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) || |
470 | (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX)); |
471 | } |
472 | |
473 | static inline bool |
474 | mcp251xfd_regmap_use_crc(struct mcp251xfd_priv *priv) |
475 | { |
476 | return (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) || |
477 | (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX); |
478 | } |
479 | |
480 | static int |
481 | mcp251xfd_regmap_init_nocrc(struct mcp251xfd_priv *priv) |
482 | { |
483 | if (!priv->map_nocrc) { |
484 | struct regmap *map; |
485 | |
486 | map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_nocrc, |
487 | priv->spi, &mcp251xfd_regmap_nocrc); |
488 | if (IS_ERR(ptr: map)) |
489 | return PTR_ERR(ptr: map); |
490 | |
491 | priv->map_nocrc = map; |
492 | } |
493 | |
494 | if (!priv->map_buf_nocrc_rx) { |
495 | priv->map_buf_nocrc_rx = |
496 | devm_kzalloc(dev: &priv->spi->dev, |
497 | size: sizeof(*priv->map_buf_nocrc_rx), |
498 | GFP_KERNEL); |
499 | if (!priv->map_buf_nocrc_rx) |
500 | return -ENOMEM; |
501 | } |
502 | |
503 | if (!priv->map_buf_nocrc_tx) { |
504 | priv->map_buf_nocrc_tx = |
505 | devm_kzalloc(dev: &priv->spi->dev, |
506 | size: sizeof(*priv->map_buf_nocrc_tx), |
507 | GFP_KERNEL); |
508 | if (!priv->map_buf_nocrc_tx) |
509 | return -ENOMEM; |
510 | } |
511 | |
512 | if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) |
513 | priv->map_reg = priv->map_nocrc; |
514 | |
515 | if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX)) |
516 | priv->map_rx = priv->map_nocrc; |
517 | |
518 | return 0; |
519 | } |
520 | |
521 | static void mcp251xfd_regmap_destroy_nocrc(struct mcp251xfd_priv *priv) |
522 | { |
523 | if (priv->map_buf_nocrc_rx) { |
524 | devm_kfree(dev: &priv->spi->dev, p: priv->map_buf_nocrc_rx); |
525 | priv->map_buf_nocrc_rx = NULL; |
526 | } |
527 | if (priv->map_buf_nocrc_tx) { |
528 | devm_kfree(dev: &priv->spi->dev, p: priv->map_buf_nocrc_tx); |
529 | priv->map_buf_nocrc_tx = NULL; |
530 | } |
531 | } |
532 | |
533 | static int |
534 | mcp251xfd_regmap_init_crc(struct mcp251xfd_priv *priv) |
535 | { |
536 | if (!priv->map_crc) { |
537 | struct regmap *map; |
538 | |
539 | map = devm_regmap_init(&priv->spi->dev, &mcp251xfd_bus_crc, |
540 | priv->spi, &mcp251xfd_regmap_crc); |
541 | if (IS_ERR(ptr: map)) |
542 | return PTR_ERR(ptr: map); |
543 | |
544 | priv->map_crc = map; |
545 | } |
546 | |
547 | if (!priv->map_buf_crc_rx) { |
548 | priv->map_buf_crc_rx = |
549 | devm_kzalloc(dev: &priv->spi->dev, |
550 | size: sizeof(*priv->map_buf_crc_rx), |
551 | GFP_KERNEL); |
552 | if (!priv->map_buf_crc_rx) |
553 | return -ENOMEM; |
554 | } |
555 | |
556 | if (!priv->map_buf_crc_tx) { |
557 | priv->map_buf_crc_tx = |
558 | devm_kzalloc(dev: &priv->spi->dev, |
559 | size: sizeof(*priv->map_buf_crc_tx), |
560 | GFP_KERNEL); |
561 | if (!priv->map_buf_crc_tx) |
562 | return -ENOMEM; |
563 | } |
564 | |
565 | if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) |
566 | priv->map_reg = priv->map_crc; |
567 | |
568 | if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_RX) |
569 | priv->map_rx = priv->map_crc; |
570 | |
571 | return 0; |
572 | } |
573 | |
574 | static void mcp251xfd_regmap_destroy_crc(struct mcp251xfd_priv *priv) |
575 | { |
576 | if (priv->map_buf_crc_rx) { |
577 | devm_kfree(dev: &priv->spi->dev, p: priv->map_buf_crc_rx); |
578 | priv->map_buf_crc_rx = NULL; |
579 | } |
580 | if (priv->map_buf_crc_tx) { |
581 | devm_kfree(dev: &priv->spi->dev, p: priv->map_buf_crc_tx); |
582 | priv->map_buf_crc_tx = NULL; |
583 | } |
584 | } |
585 | |
586 | int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv) |
587 | { |
588 | int err; |
589 | |
590 | if (mcp251xfd_regmap_use_nocrc(priv)) { |
591 | err = mcp251xfd_regmap_init_nocrc(priv); |
592 | |
593 | if (err) |
594 | return err; |
595 | } else { |
596 | mcp251xfd_regmap_destroy_nocrc(priv); |
597 | } |
598 | |
599 | if (mcp251xfd_regmap_use_crc(priv)) { |
600 | err = mcp251xfd_regmap_init_crc(priv); |
601 | |
602 | if (err) |
603 | return err; |
604 | } else { |
605 | mcp251xfd_regmap_destroy_crc(priv); |
606 | } |
607 | |
608 | return 0; |
609 | } |
610 | |