1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | /* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces. |
4 | * |
5 | * File es581_4.c: Adds support to ETAS ES581.4. |
6 | * |
7 | * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved. |
8 | * Copyright (c) 2020 ETAS K.K.. All rights reserved. |
9 | * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr> |
10 | */ |
11 | |
12 | #include <asm/unaligned.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/units.h> |
15 | |
16 | #include "es58x_core.h" |
17 | #include "es581_4.h" |
18 | |
19 | /** |
20 | * es581_4_sizeof_rx_tx_msg() - Calculate the actual length of the |
21 | * structure of a rx or tx message. |
22 | * @msg: message of variable length, must have a dlc field. |
23 | * |
24 | * Even if RTR frames have actually no payload, the ES58X devices |
25 | * still expect it. Must be a macro in order to accept several types |
26 | * (struct es581_4_tx_can_msg and struct es581_4_rx_can_msg) as an |
27 | * input. |
28 | * |
29 | * Return: length of the message. |
30 | */ |
31 | #define es581_4_sizeof_rx_tx_msg(msg) \ |
32 | offsetof(typeof(msg), data[can_cc_dlc2len((msg).dlc)]) |
33 | |
34 | static u16 es581_4_get_msg_len(const union es58x_urb_cmd *urb_cmd) |
35 | { |
36 | return get_unaligned_le16(p: &urb_cmd->es581_4_urb_cmd.msg_len); |
37 | } |
38 | |
39 | static int es581_4_echo_msg(struct es58x_device *es58x_dev, |
40 | const struct es581_4_urb_cmd *es581_4_urb_cmd) |
41 | { |
42 | struct net_device *netdev; |
43 | const struct es581_4_bulk_echo_msg *bulk_echo_msg; |
44 | const struct es581_4_echo_msg *echo_msg; |
45 | u64 *tstamps = es58x_dev->timestamps; |
46 | u16 msg_len; |
47 | u32 first_packet_idx, packet_idx; |
48 | unsigned int dropped = 0; |
49 | int i, num_element, ret; |
50 | |
51 | bulk_echo_msg = &es581_4_urb_cmd->bulk_echo_msg; |
52 | msg_len = get_unaligned_le16(p: &es581_4_urb_cmd->msg_len) - |
53 | sizeof(bulk_echo_msg->channel_no); |
54 | num_element = es58x_msg_num_element(es58x_dev->dev, |
55 | bulk_echo_msg->echo_msg, msg_len); |
56 | if (num_element <= 0) |
57 | return num_element; |
58 | |
59 | ret = es58x_get_netdev(es58x_dev, channel_no: bulk_echo_msg->channel_no, |
60 | ES581_4_CHANNEL_IDX_OFFSET, netdev: &netdev); |
61 | if (ret) |
62 | return ret; |
63 | |
64 | echo_msg = &bulk_echo_msg->echo_msg[0]; |
65 | first_packet_idx = get_unaligned_le32(p: &echo_msg->packet_idx); |
66 | packet_idx = first_packet_idx; |
67 | for (i = 0; i < num_element; i++) { |
68 | u32 tmp_idx; |
69 | |
70 | echo_msg = &bulk_echo_msg->echo_msg[i]; |
71 | tmp_idx = get_unaligned_le32(p: &echo_msg->packet_idx); |
72 | if (tmp_idx == packet_idx - 1) { |
73 | if (net_ratelimit()) |
74 | netdev_warn(dev: netdev, |
75 | format: "Received echo packet idx %u twice\n" , |
76 | packet_idx - 1); |
77 | dropped++; |
78 | continue; |
79 | } |
80 | if (tmp_idx != packet_idx) { |
81 | netdev_err(dev: netdev, format: "Echo packet idx jumped from %u to %u\n" , |
82 | packet_idx - 1, echo_msg->packet_idx); |
83 | return -EBADMSG; |
84 | } |
85 | |
86 | tstamps[i] = get_unaligned_le64(p: &echo_msg->timestamp); |
87 | packet_idx++; |
88 | } |
89 | |
90 | netdev->stats.tx_dropped += dropped; |
91 | return es58x_can_get_echo_skb(netdev, packet_idx: first_packet_idx, |
92 | tstamps, pkts: num_element - dropped); |
93 | } |
94 | |
95 | static int es581_4_rx_can_msg(struct es58x_device *es58x_dev, |
96 | const struct es581_4_urb_cmd *es581_4_urb_cmd, |
97 | u16 msg_len) |
98 | { |
99 | const struct device *dev = es58x_dev->dev; |
100 | struct net_device *netdev; |
101 | int pkts, num_element, channel_no, ret; |
102 | |
103 | num_element = es58x_msg_num_element(dev, es581_4_urb_cmd->rx_can_msg, |
104 | msg_len); |
105 | if (num_element <= 0) |
106 | return num_element; |
107 | |
108 | channel_no = es581_4_urb_cmd->rx_can_msg[0].channel_no; |
109 | ret = es58x_get_netdev(es58x_dev, channel_no, |
110 | ES581_4_CHANNEL_IDX_OFFSET, netdev: &netdev); |
111 | if (ret) |
112 | return ret; |
113 | |
114 | if (!netif_running(dev: netdev)) { |
115 | if (net_ratelimit()) |
116 | netdev_info(dev: netdev, |
117 | format: "%s: %s is down, dropping %d rx packets\n" , |
118 | __func__, netdev->name, num_element); |
119 | netdev->stats.rx_dropped += num_element; |
120 | return 0; |
121 | } |
122 | |
123 | for (pkts = 0; pkts < num_element; pkts++) { |
124 | const struct es581_4_rx_can_msg *rx_can_msg = |
125 | &es581_4_urb_cmd->rx_can_msg[pkts]; |
126 | u64 tstamp = get_unaligned_le64(p: &rx_can_msg->timestamp); |
127 | canid_t can_id = get_unaligned_le32(p: &rx_can_msg->can_id); |
128 | |
129 | if (channel_no != rx_can_msg->channel_no) |
130 | return -EBADMSG; |
131 | |
132 | ret = es58x_rx_can_msg(netdev, timestamp: tstamp, data: rx_can_msg->data, |
133 | can_id, es58x_flags: rx_can_msg->flags, |
134 | dlc: rx_can_msg->dlc); |
135 | if (ret) |
136 | break; |
137 | } |
138 | |
139 | return ret; |
140 | } |
141 | |
142 | static int es581_4_rx_err_msg(struct es58x_device *es58x_dev, |
143 | const struct es581_4_rx_err_msg *rx_err_msg) |
144 | { |
145 | struct net_device *netdev; |
146 | enum es58x_err error = get_unaligned_le32(p: &rx_err_msg->error); |
147 | int ret; |
148 | |
149 | ret = es58x_get_netdev(es58x_dev, channel_no: rx_err_msg->channel_no, |
150 | ES581_4_CHANNEL_IDX_OFFSET, netdev: &netdev); |
151 | if (ret) |
152 | return ret; |
153 | |
154 | return es58x_rx_err_msg(netdev, error, event: 0, |
155 | timestamp: get_unaligned_le64(p: &rx_err_msg->timestamp)); |
156 | } |
157 | |
158 | static int es581_4_rx_event_msg(struct es58x_device *es58x_dev, |
159 | const struct es581_4_rx_event_msg *rx_event_msg) |
160 | { |
161 | struct net_device *netdev; |
162 | enum es58x_event event = get_unaligned_le32(p: &rx_event_msg->event); |
163 | int ret; |
164 | |
165 | ret = es58x_get_netdev(es58x_dev, channel_no: rx_event_msg->channel_no, |
166 | ES581_4_CHANNEL_IDX_OFFSET, netdev: &netdev); |
167 | if (ret) |
168 | return ret; |
169 | |
170 | return es58x_rx_err_msg(netdev, error: 0, event, |
171 | timestamp: get_unaligned_le64(p: &rx_event_msg->timestamp)); |
172 | } |
173 | |
174 | static int es581_4_rx_cmd_ret_u32(struct es58x_device *es58x_dev, |
175 | const struct es581_4_urb_cmd *es581_4_urb_cmd, |
176 | enum es58x_ret_type ret_type) |
177 | { |
178 | struct net_device *netdev; |
179 | const struct es581_4_rx_cmd_ret *rx_cmd_ret; |
180 | u16 msg_len = get_unaligned_le16(p: &es581_4_urb_cmd->msg_len); |
181 | int ret; |
182 | |
183 | ret = es58x_check_msg_len(es58x_dev->dev, |
184 | es581_4_urb_cmd->rx_cmd_ret, msg_len); |
185 | if (ret) |
186 | return ret; |
187 | |
188 | rx_cmd_ret = &es581_4_urb_cmd->rx_cmd_ret; |
189 | |
190 | ret = es58x_get_netdev(es58x_dev, channel_no: rx_cmd_ret->channel_no, |
191 | ES581_4_CHANNEL_IDX_OFFSET, netdev: &netdev); |
192 | if (ret) |
193 | return ret; |
194 | |
195 | return es58x_rx_cmd_ret_u32(netdev, cmd_ret_type: ret_type, |
196 | rx_cmd_ret_u32: get_unaligned_le32(p: &rx_cmd_ret->rx_cmd_ret_le32)); |
197 | } |
198 | |
199 | static int es581_4_tx_ack_msg(struct es58x_device *es58x_dev, |
200 | const struct es581_4_urb_cmd *es581_4_urb_cmd) |
201 | { |
202 | struct net_device *netdev; |
203 | const struct es581_4_tx_ack_msg *tx_ack_msg; |
204 | u16 msg_len = get_unaligned_le16(p: &es581_4_urb_cmd->msg_len); |
205 | int ret; |
206 | |
207 | tx_ack_msg = &es581_4_urb_cmd->tx_ack_msg; |
208 | ret = es58x_check_msg_len(es58x_dev->dev, *tx_ack_msg, msg_len); |
209 | if (ret) |
210 | return ret; |
211 | |
212 | if (tx_ack_msg->rx_cmd_ret_u8 != ES58X_RET_U8_OK) |
213 | return es58x_rx_cmd_ret_u8(dev: es58x_dev->dev, |
214 | cmd_ret_type: ES58X_RET_TYPE_TX_MSG, |
215 | rx_cmd_ret_u8: tx_ack_msg->rx_cmd_ret_u8); |
216 | |
217 | ret = es58x_get_netdev(es58x_dev, channel_no: tx_ack_msg->channel_no, |
218 | ES581_4_CHANNEL_IDX_OFFSET, netdev: &netdev); |
219 | if (ret) |
220 | return ret; |
221 | |
222 | return es58x_tx_ack_msg(netdev, |
223 | tx_free_entries: get_unaligned_le16(p: &tx_ack_msg->tx_free_entries), |
224 | rx_cmd_ret_u32: ES58X_RET_U32_OK); |
225 | } |
226 | |
227 | static int es581_4_dispatch_rx_cmd(struct es58x_device *es58x_dev, |
228 | const struct es581_4_urb_cmd *es581_4_urb_cmd) |
229 | { |
230 | const struct device *dev = es58x_dev->dev; |
231 | u16 msg_len = get_unaligned_le16(p: &es581_4_urb_cmd->msg_len); |
232 | enum es581_4_rx_type rx_type = es581_4_urb_cmd->rx_can_msg[0].rx_type; |
233 | int ret = 0; |
234 | |
235 | switch (rx_type) { |
236 | case ES581_4_RX_TYPE_MESSAGE: |
237 | return es581_4_rx_can_msg(es58x_dev, es581_4_urb_cmd, msg_len); |
238 | |
239 | case ES581_4_RX_TYPE_ERROR: |
240 | ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_err_msg, |
241 | msg_len); |
242 | if (ret < 0) |
243 | return ret; |
244 | return es581_4_rx_err_msg(es58x_dev, |
245 | rx_err_msg: &es581_4_urb_cmd->rx_err_msg); |
246 | |
247 | case ES581_4_RX_TYPE_EVENT: |
248 | ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_event_msg, |
249 | msg_len); |
250 | if (ret < 0) |
251 | return ret; |
252 | return es581_4_rx_event_msg(es58x_dev, |
253 | rx_event_msg: &es581_4_urb_cmd->rx_event_msg); |
254 | |
255 | default: |
256 | dev_err(dev, "%s: Unknown rx_type 0x%02X\n" , __func__, rx_type); |
257 | return -EBADRQC; |
258 | } |
259 | } |
260 | |
261 | static int es581_4_handle_urb_cmd(struct es58x_device *es58x_dev, |
262 | const union es58x_urb_cmd *urb_cmd) |
263 | { |
264 | const struct es581_4_urb_cmd *es581_4_urb_cmd; |
265 | struct device *dev = es58x_dev->dev; |
266 | u16 msg_len = es581_4_get_msg_len(urb_cmd); |
267 | int ret; |
268 | |
269 | es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd; |
270 | |
271 | if (es581_4_urb_cmd->cmd_type != ES581_4_CAN_COMMAND_TYPE) { |
272 | dev_err(dev, "%s: Unknown command type (0x%02X)\n" , |
273 | __func__, es581_4_urb_cmd->cmd_type); |
274 | return -EBADRQC; |
275 | } |
276 | |
277 | switch ((enum es581_4_cmd_id)es581_4_urb_cmd->cmd_id) { |
278 | case ES581_4_CMD_ID_SET_BITTIMING: |
279 | return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd, |
280 | ret_type: ES58X_RET_TYPE_SET_BITTIMING); |
281 | |
282 | case ES581_4_CMD_ID_ENABLE_CHANNEL: |
283 | return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd, |
284 | ret_type: ES58X_RET_TYPE_ENABLE_CHANNEL); |
285 | |
286 | case ES581_4_CMD_ID_TX_MSG: |
287 | return es581_4_tx_ack_msg(es58x_dev, es581_4_urb_cmd); |
288 | |
289 | case ES581_4_CMD_ID_RX_MSG: |
290 | return es581_4_dispatch_rx_cmd(es58x_dev, es581_4_urb_cmd); |
291 | |
292 | case ES581_4_CMD_ID_RESET_RX: |
293 | ret = es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd, |
294 | ret_type: ES58X_RET_TYPE_RESET_RX); |
295 | return ret; |
296 | |
297 | case ES581_4_CMD_ID_RESET_TX: |
298 | ret = es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd, |
299 | ret_type: ES58X_RET_TYPE_RESET_TX); |
300 | return ret; |
301 | |
302 | case ES581_4_CMD_ID_DISABLE_CHANNEL: |
303 | return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd, |
304 | ret_type: ES58X_RET_TYPE_DISABLE_CHANNEL); |
305 | |
306 | case ES581_4_CMD_ID_TIMESTAMP: |
307 | ret = es58x_check_msg_len(dev, es581_4_urb_cmd->timestamp, |
308 | msg_len); |
309 | if (ret < 0) |
310 | return ret; |
311 | es58x_rx_timestamp(es58x_dev, |
312 | timestamp: get_unaligned_le64(p: &es581_4_urb_cmd->timestamp)); |
313 | return 0; |
314 | |
315 | case ES581_4_CMD_ID_ECHO: |
316 | return es581_4_echo_msg(es58x_dev, es581_4_urb_cmd); |
317 | |
318 | case ES581_4_CMD_ID_DEVICE_ERR: |
319 | ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_cmd_ret_u8, |
320 | msg_len); |
321 | if (ret) |
322 | return ret; |
323 | return es58x_rx_cmd_ret_u8(dev, cmd_ret_type: ES58X_RET_TYPE_DEVICE_ERR, |
324 | rx_cmd_ret_u8: es581_4_urb_cmd->rx_cmd_ret_u8); |
325 | |
326 | default: |
327 | dev_warn(dev, "%s: Unexpected command ID: 0x%02X\n" , |
328 | __func__, es581_4_urb_cmd->cmd_id); |
329 | return -EBADRQC; |
330 | } |
331 | } |
332 | |
333 | static void (union es58x_urb_cmd *urb_cmd, u8 cmd_type, |
334 | u8 cmd_id, u8 channel_idx, u16 msg_len) |
335 | { |
336 | struct es581_4_urb_cmd *es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd; |
337 | |
338 | es581_4_urb_cmd->SOF = cpu_to_le16(es581_4_param.tx_start_of_frame); |
339 | es581_4_urb_cmd->cmd_type = cmd_type; |
340 | es581_4_urb_cmd->cmd_id = cmd_id; |
341 | es581_4_urb_cmd->msg_len = cpu_to_le16(msg_len); |
342 | } |
343 | |
344 | static int es581_4_tx_can_msg(struct es58x_priv *priv, |
345 | const struct sk_buff *skb) |
346 | { |
347 | struct es58x_device *es58x_dev = priv->es58x_dev; |
348 | union es58x_urb_cmd *urb_cmd = priv->tx_urb->transfer_buffer; |
349 | struct es581_4_urb_cmd *es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd; |
350 | struct can_frame *cf = (struct can_frame *)skb->data; |
351 | struct es581_4_tx_can_msg *tx_can_msg; |
352 | u16 msg_len; |
353 | int ret; |
354 | |
355 | if (can_is_canfd_skb(skb)) |
356 | return -EMSGSIZE; |
357 | |
358 | if (priv->tx_can_msg_cnt == 0) { |
359 | msg_len = sizeof(es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg); |
360 | es581_4_fill_urb_header(urb_cmd, cmd_type: ES581_4_CAN_COMMAND_TYPE, |
361 | cmd_id: ES581_4_CMD_ID_TX_MSG, |
362 | channel_idx: priv->channel_idx, msg_len); |
363 | es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg = 0; |
364 | } else { |
365 | msg_len = es581_4_get_msg_len(urb_cmd); |
366 | } |
367 | |
368 | ret = es58x_check_msg_max_len(es58x_dev->dev, |
369 | es581_4_urb_cmd->bulk_tx_can_msg, |
370 | msg_len + sizeof(*tx_can_msg)); |
371 | if (ret) |
372 | return ret; |
373 | |
374 | /* Fill message contents. */ |
375 | tx_can_msg = (typeof(tx_can_msg))&es581_4_urb_cmd->raw_msg[msg_len]; |
376 | put_unaligned_le32(val: es58x_get_raw_can_id(cf), p: &tx_can_msg->can_id); |
377 | put_unaligned_le32(val: priv->tx_head, p: &tx_can_msg->packet_idx); |
378 | put_unaligned_le16(val: (u16)es58x_get_flags(skb), p: &tx_can_msg->flags); |
379 | tx_can_msg->channel_no = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET; |
380 | tx_can_msg->dlc = can_get_cc_dlc(cf, ctrlmode: priv->can.ctrlmode); |
381 | |
382 | memcpy(tx_can_msg->data, cf->data, cf->len); |
383 | |
384 | /* Calculate new sizes. */ |
385 | es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg++; |
386 | msg_len += es581_4_sizeof_rx_tx_msg(*tx_can_msg); |
387 | priv->tx_urb->transfer_buffer_length = es58x_get_urb_cmd_len(es58x_dev, |
388 | msg_len); |
389 | es581_4_urb_cmd->msg_len = cpu_to_le16(msg_len); |
390 | |
391 | return 0; |
392 | } |
393 | |
394 | static int es581_4_set_bittiming(struct es58x_priv *priv) |
395 | { |
396 | struct es581_4_tx_conf_msg tx_conf_msg = { 0 }; |
397 | struct can_bittiming *bt = &priv->can.bittiming; |
398 | |
399 | tx_conf_msg.bitrate = cpu_to_le32(bt->bitrate); |
400 | /* bt->sample_point is in tenth of percent. Convert it to percent. */ |
401 | tx_conf_msg.sample_point = cpu_to_le32(bt->sample_point / 10U); |
402 | tx_conf_msg.samples_per_bit = cpu_to_le32(ES58X_SAMPLES_PER_BIT_ONE); |
403 | tx_conf_msg.bit_time = cpu_to_le32(can_bit_time(bt)); |
404 | tx_conf_msg.sjw = cpu_to_le32(bt->sjw); |
405 | tx_conf_msg.sync_edge = cpu_to_le32(ES58X_SYNC_EDGE_SINGLE); |
406 | tx_conf_msg.physical_layer = |
407 | cpu_to_le32(ES58X_PHYSICAL_LAYER_HIGH_SPEED); |
408 | tx_conf_msg.echo_mode = cpu_to_le32(ES58X_ECHO_ON); |
409 | tx_conf_msg.channel_no = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET; |
410 | |
411 | return es58x_send_msg(es58x_dev: priv->es58x_dev, cmd_type: ES581_4_CAN_COMMAND_TYPE, |
412 | cmd_id: ES581_4_CMD_ID_SET_BITTIMING, msg: &tx_conf_msg, |
413 | cmd_len: sizeof(tx_conf_msg), channel_idx: priv->channel_idx); |
414 | } |
415 | |
416 | static int es581_4_enable_channel(struct es58x_priv *priv) |
417 | { |
418 | int ret; |
419 | u8 msg = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET; |
420 | |
421 | ret = es581_4_set_bittiming(priv); |
422 | if (ret) |
423 | return ret; |
424 | |
425 | return es58x_send_msg(es58x_dev: priv->es58x_dev, cmd_type: ES581_4_CAN_COMMAND_TYPE, |
426 | cmd_id: ES581_4_CMD_ID_ENABLE_CHANNEL, msg: &msg, cmd_len: sizeof(msg), |
427 | channel_idx: priv->channel_idx); |
428 | } |
429 | |
430 | static int es581_4_disable_channel(struct es58x_priv *priv) |
431 | { |
432 | u8 msg = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET; |
433 | |
434 | return es58x_send_msg(es58x_dev: priv->es58x_dev, cmd_type: ES581_4_CAN_COMMAND_TYPE, |
435 | cmd_id: ES581_4_CMD_ID_DISABLE_CHANNEL, msg: &msg, cmd_len: sizeof(msg), |
436 | channel_idx: priv->channel_idx); |
437 | } |
438 | |
439 | static int es581_4_reset_device(struct es58x_device *es58x_dev) |
440 | { |
441 | return es58x_send_msg(es58x_dev, cmd_type: ES581_4_CAN_COMMAND_TYPE, |
442 | cmd_id: ES581_4_CMD_ID_RESET_DEVICE, |
443 | ES58X_EMPTY_MSG, cmd_len: 0, ES58X_CHANNEL_IDX_NA); |
444 | } |
445 | |
446 | static int es581_4_get_timestamp(struct es58x_device *es58x_dev) |
447 | { |
448 | return es58x_send_msg(es58x_dev, cmd_type: ES581_4_CAN_COMMAND_TYPE, |
449 | cmd_id: ES581_4_CMD_ID_TIMESTAMP, |
450 | ES58X_EMPTY_MSG, cmd_len: 0, ES58X_CHANNEL_IDX_NA); |
451 | } |
452 | |
453 | /* Nominal bittiming constants for ES581.4 as specified in the |
454 | * microcontroller datasheet: "Stellaris(R) LM3S5B91 Microcontroller" |
455 | * table 17-4 "CAN Protocol Ranges" from Texas Instruments. |
456 | */ |
457 | static const struct can_bittiming_const es581_4_bittiming_const = { |
458 | .name = "ES581.4" , |
459 | .tseg1_min = 1, |
460 | .tseg1_max = 8, |
461 | .tseg2_min = 1, |
462 | .tseg2_max = 8, |
463 | .sjw_max = 4, |
464 | .brp_min = 1, |
465 | .brp_max = 128, |
466 | .brp_inc = 1 |
467 | }; |
468 | |
469 | const struct es58x_parameters es581_4_param = { |
470 | .bittiming_const = &es581_4_bittiming_const, |
471 | .data_bittiming_const = NULL, |
472 | .tdc_const = NULL, |
473 | .bitrate_max = 1 * MEGA /* BPS */, |
474 | .clock = {.freq = 50 * MEGA /* Hz */}, |
475 | .ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC, |
476 | .tx_start_of_frame = 0xAFAF, |
477 | .rx_start_of_frame = 0xFAFA, |
478 | .tx_urb_cmd_max_len = ES581_4_TX_URB_CMD_MAX_LEN, |
479 | .rx_urb_cmd_max_len = ES581_4_RX_URB_CMD_MAX_LEN, |
480 | /* Size of internal device TX queue is 330. |
481 | * |
482 | * However, we witnessed some ES58X_ERR_PROT_CRC errors from |
483 | * the device and thus, echo_skb_max was lowered to the |
484 | * empirical value of 75 which seems stable and then rounded |
485 | * down to become a power of two. |
486 | * |
487 | * Root cause of those ES58X_ERR_PROT_CRC errors is still |
488 | * unclear. |
489 | */ |
490 | .fifo_mask = 63, /* echo_skb_max = 64 */ |
491 | .dql_min_limit = CAN_FRAME_LEN_MAX * 50, /* Empirical value. */ |
492 | .tx_bulk_max = ES581_4_TX_BULK_MAX, |
493 | .urb_cmd_header_len = ES581_4_URB_CMD_HEADER_LEN, |
494 | .rx_urb_max = ES58X_RX_URBS_MAX, |
495 | .tx_urb_max = ES58X_TX_URBS_MAX |
496 | }; |
497 | |
498 | const struct es58x_operators es581_4_ops = { |
499 | .get_msg_len = es581_4_get_msg_len, |
500 | .handle_urb_cmd = es581_4_handle_urb_cmd, |
501 | .fill_urb_header = es581_4_fill_urb_header, |
502 | .tx_can_msg = es581_4_tx_can_msg, |
503 | .enable_channel = es581_4_enable_channel, |
504 | .disable_channel = es581_4_disable_channel, |
505 | .reset_device = es581_4_reset_device, |
506 | .get_timestamp = es581_4_get_timestamp |
507 | }; |
508 | |