// SPDX-License-Identifier: GPL-2.0
/* Driver for Theobroma Systems UCAN devices, Protocol Version 3
*
* Copyright (C) 2018 Theobroma Systems Design und Consulting GmbH
*
*
* General Description:
*
* The USB Device uses three Endpoints:
*
* CONTROL Endpoint: Is used the setup the device (start, stop,
* info, configure).
*
* IN Endpoint: The device sends CAN Frame Messages and Device
* Information using the IN endpoint.
*
* OUT Endpoint: The driver sends configuration requests, and CAN
* Frames on the out endpoint.
*
* Error Handling:
*
* If error reporting is turned on the device encodes error into CAN
* error frames (see uapi/linux/can/error.h) and sends it using the
* IN Endpoint. The driver updates statistics and forward it.
*/
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/signal.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/usb.h>
#define UCAN_DRIVER_NAME "ucan"
#define UCAN_MAX_RX_URBS 8
/* the CAN controller needs a while to enable/disable the bus */
#define UCAN_USB_CTL_PIPE_TIMEOUT 1000
/* this driver currently supports protocol version 3 only */
#define UCAN_PROTOCOL_VERSION_MIN 3
#define UCAN_PROTOCOL_VERSION_MAX 3
/* 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 endianness
*
* INTR Endpoint: a single uint32_t storing the current space in the fifo
*
* OUT Endpoint: 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
*/
/* Device Global Commands */
enum {
UCAN_DEVICE_GET_FW_STRING = 0,
};
/* UCAN Commands */
enum {
/* start the can transceiver - val defines the operation mode */
UCAN_COMMAND_START = 0,
/* cancel pending transmissions and stop the can transceiver */
UCAN_COMMAND_STOP = 1,
/* send can transceiver into low-power sleep mode */
UCAN_COMMAND_SLEEP = 2,
/* wake up can transceiver from low-power sleep mode */
UCAN_COMMAND_WAKEUP = 3,
/* reset the can transceiver */
UCAN_COMMAND_RESET = 4,
/* get piece of info from the can transceiver - subcmd defines what
* piece
*/
UCAN_COMMAND_GET = 5,
/* clear or disable hardware filter - subcmd defines which of the two */
UCAN_COMMAND_FILTER = 6,
/* Setup bittiming */
UCAN_COMMAND_SET_BITTIMING = 7,
/* recover from bus-off state */
UCAN_COMMAND_RESTART = 8,
};
/* UCAN_COMMAND_START and UCAN_COMMAND_GET_INFO operation modes (bitmap).
* Undefined bits must be set to 0.
*/
enum {
UCAN_MODE_LOOPBACK = BIT(0),
UCAN_MODE_SILENT = BIT(1),
UCAN_MODE_3_SAMPLES = BIT(2),
UCAN_MODE_ONE_SHOT = BIT(3),
UCAN_MODE_BERR_REPORT = BIT(4),
};
/* UCAN_COMMAND_GET subcommands */
enum {
UCAN_COMMAND_GET_INFO = 0,
UCAN_COMMAND_GET_PROTOCOL_VERSION = 1,
};
/* UCAN_COMMAND_FILTER subcommands */
enum {
UCAN_FILTER_CLEAR = 0,
UCAN_FILTER_DISABLE = 1,
UCAN_FILTER_ENABLE = 2,
};
/* OUT endpoint message types */
enum {
UCAN_OUT_TX = 2, /* transmit a CAN frame */
};
/* IN endpoint message types */
enum {
UCAN_IN_TX_COMPLETE = 1, /* CAN frame transmission completed */
UCAN_IN_RX = 2, /* CAN frame received */
};
struct ucan_ctl_cmd_start {
__le16 mode; /* OR-ing any of UCAN_MODE_* */
} __packed;
struct ucan_ctl_cmd_set_bittiming {
__le32 tq; /* Time quanta (TQ) in nanoseconds */
__le16 brp; /* TQ Prescaler */
__le16 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 */
} __packed;
struct ucan_ctl_cmd_device_info {
__le32 freq; /* Clock Frequency for tq generation */
u8 tx_fifo; /* Size of the transmission fifo */
u8 sjw_max; /* can_bittiming fields... */
u8 tseg1_min;
u8 tseg1_max;
u8 tseg2_min;
u8 tseg2_max;
__le16 brp_inc;
__le32 brp_min;
__le32 brp_max; /* ...can_bittiming fields */
__le16 ctrlmodes; /* supported control modes */
__le16 hwfilter; /* Number of HW filter banks */
__le16 rxmboxes; /* Number of receive Mailboxes */
} __packed;
struct ucan_ctl_cmd_get_protocol_version {
__le32 version;
} __packed;
union ucan_ctl_payload {
/* Setup Bittiming
* bmRequest == UCAN_COMMAND_START
*/
struct ucan_ctl_cmd_start cmd_start;
/* Setup Bittiming
* bmRequest == UCAN_COMMAND_SET_BITTIMING
*/
struct ucan_ctl_cmd_set_bittiming cmd_set_bittiming;
/* Get Device Information
* bmRequest == UCAN_COMMAND_GET; wValue = UCAN_COMMAND_GET_INFO
*
|