summaryrefslogtreecommitdiff
path: root/drivers/net/can/usb/ucan.h
blob: dfe33088e405fdec61f19276795b648a81d82497 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#ifndef __UCAN_H__

/*
 * Header file for CAN driver for uCAN
 *
 * Copyright (C) 2015 Theobroma Systems Design und Consulting GmbH
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published
 * by the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.
 *
 * This driver is inspired by the 4.0.0 version of drivers/net/can/usb/ems_usb.c
 *
 */

#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/usb.h>

#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>


#define UCAN_CLASS 0xA0
#define UCAN_SUBCLASS 0x00

/* uCAN message definitions --------------------------------------------
 *
 *  uCAN_message_out_t and uCAN_message_in_t define the messages
 *  transmitted on the OUT and IN endpoint.
 *
 *  Multibyte fields are transmitted with little endianess
 *
 *  INTR Endpoint: a single uint32_t storing the current space in the fifo
 *
 *  OUT Enpoint: single message of type uCAN_message_out_t is
 *    transmitted on the out endpoint
 *
 *  IN Endpoint: multiple messages uCAN_message_in_t concateted in
 *    the following way:
 *
 *      m[n].len <=> the length if message n(including the header in bytes)
 *      m[n] is is aligned to a 4 byte boundary, hence
 *        offset(m[0])   := 0;
 *        offset(m[n+1]) := offset(m[n]) + (m[n].len + 3) & 3
 *
 *      this implies that
 *        offset(m[n]) % 4 <=> 0
 */

// UCAN Commands
enum {
	UCAN_COMMAND_START   = 0,
	UCAN_COMMAND_STOP    = 1,
	UCAN_COMMAND_SLEEP   = 2,
	UCAN_COMMAND_WAKEUP  = 3,
	UCAN_COMMAND_RESET   = 4,
	UCAN_COMMAND_GET     = 5,
  UCAN_COMMAND_GET_INFO  = 0,
	UCAN_COMMAND_FILTER  = 6,
	UCAN_FILTER_CLEAR      = 0,
	UCAN_FILTER_DISABLE    = 1,
};

enum {
	UCAN_MODE_LOOPBACK    = (1<<0),
	UCAN_MODE_SILENT      = (1<<1),
	UCAN_MODE_3_SAMPLES   = (1<<2),
	UCAN_MODE_ONE_SHOT    = (1<<3),
	UCAN_MODE_BERR_REPORT = (1<<4),
};

#define UCAN_OUT_COMMAND        0
#define UCAN_OUT_SET_BITTIMING  1
#define UCAN_OUT_TX             2
#define UCAN_OUT_ENABLE_FILTER  3

/* OUT Enpoint, outbound messages */
struct uCAN_message_out {
	u16 len;   /* Length of the content include header */
	u16 type;  /* UCAN_OUT_COMMAND and friends */
	union {
		/***************************************************
		 * Device Command
		 * (type = UCAN_OUT_SET_BITTIMING)
		 ***************************************************/
		struct {
			u8 cmd;              /* UCAN_COMMAND_START and friends */
			u8 subcmd;
			u16 val;
		} __attribute__((packed)) command;

		/***************************************************
		 * Set Bittiming
		 * (type = UCAN_OUT_SET_BITTIMING)
		 ***************************************************/
		struct {
			u32 tq;              /* Time quanta (TQ) in nanoseconds */
			u16 brp;             /* TQ Prescaler */
			u16 sample_point;    /* Samplepoint on tenth percent */
			u8 prop_seg;         /* Propagation segment in TQs */
			u8 phase_seg1;       /* Phase buffer segment 1 in TQs */
			u8 phase_seg2;       /* Phase buffer segment 2 in TQs */
			u8 sjw;              /* Synchronisation jump width in TQs */
		} __attribute__((packed)) bittiming;

		/***************************************************
		 * Transmit CAN frame
		 * (type = UCAN_TX) && ((msg.can_msg.id & CAN_RTR_FLAG) == 0)
		 ***************************************************/
		struct {  /* note DLC is computed by
			   *    msg.len - sizeof (msg.len)
			   *            - sizeof (msg.type)
			   *            - sizeof (msg.can_msg.id); */
			u32 id;
			u8 data[8];  // ensure data aligment to 4, by moving dlc after data
		} __attribute__((packed)) can_msg;

		/***************************************************
		 * Transmit RTR CAN frame
		 * (type = UCAN_TX) && ((msg.can_msg.id & CAN_RTR_FLAG) != 0)
		 ***************************************************/
		struct {
			u32 id;
			u8 dlc;
		} __attribute__((packed)) can_rtr_msg;

		/***************************************************
		 * Enable Filter
		 * (type = UCAN_OUT_ENABLE_FILTER)
		 ***************************************************/
		struct {
			u32 id;
			u32 mask;
			u16 mbox;
		} enable_filter;
	} __attribute__((aligned(0x4))) msg;
} __attribute__((packed));

#define UCAN_IN_DEVICE_INFO     0
#define UCAN_IN_RX              2

/* IN Enpoint, inbound messages */
struct uCAN_message_in {
	u16 len;    /* Length of the content include header */
	u16 type;   /* UCAN_IN_DEVICE_INFO and friends */

	union {
		/***************************************************
		 * Device Information
		 * (type = UCAN_IN_DEVICE_INFO)
		 ***************************************************/
		struct {
			u32 freq;         /* Clock Frequency for tq
					   * generation */
			u8 tx_fifo;       /* Size of the transmission
					   * fifo */
			u8 sjw_max;
			u8 tseg1_min;
			u8 tseg1_max;
			u8 tseg2_min;
			u8 tseg2_max;
			u16 brp_inc;
			u32 brp_min;
			u32 brp_max;
			u16 ctrlmodes;    /* supported control modes
					   * ors of UCAN_MODE_* */
			u16 hwfilter;     /* Number of HW filter
					   * banks */
			u16 rxmboxes;     /* Number Receive
					   * Mailboxes */
		} __attribute__((packed)) device_info;

		/***************************************************
		 * CAN RTR Frame received
		 * (type == UCAN_IN_RX) && ((msg.can_msg.id & CAN_RTR_FLAG) == 0)
		 ***************************************************/
		struct {  /* note DLC is computed by
			   *    msg.len - sizeof (msg.len)
			   *            - sizeof (msg.type)
			   *            - sizeof (msg.can_msg.id); */
			u32 id;
			u8 data[8];  // ensure data aligment to 4, by moving dlc after data
		}  __attribute__((packed)) can_msg;

		/***************************************************
		 * CAN RTR Frame received
		 * (type == UCAN_IN_RX) && ((msg.can_msg.id & CAN_RTR_FLAG) != 0)
		 ***************************************************/
		struct {
			u32 id;
			u8 dlc;
		}  __attribute__((packed)) can_rtr_msg;
	} __attribute__((aligned(0x4))) msg;
} __attribute__((packed));


/* Macros to calculate message lengths */
#define UCAN_OUT_HDR_SIZE offsetof(struct uCAN_message_out, msg)
#define UCAN_OUT_LEN(member) (UCAN_OUT_HDR_SIZE + sizeof(member) )

#define UCAN_IN_HDR_SIZE offsetof(struct uCAN_message_in, msg)
#define UCAN_IN_LEN(member) (UCAN_OUT_HDR_SIZE + sizeof(member) )

#endif