linux/drivers/usb/serial/cp210x.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Silicon Laboratories CP210x USB to RS232 serial adaptor driver
 *
 * Copyright (C) 2005 Craig Shelley ([email protected])
 * Copyright (C) 2010-2021 Johan Hovold ([email protected])
 *
 * Support to set flow control line levels using TIOCMGET and TIOCMSET
 * thanks to Karl Hiramoto [email protected]. RTSCTS hardware flow
 * control thanks to Munir Nassar [email protected]
 *
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/gpio/driver.h>
#include <linux/bitops.h>
#include <linux/mutex.h>

#define DRIVER_DESC

/*
 * Function Prototypes
 */
static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
static void cp210x_close(struct usb_serial_port *);
static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
				const struct ktermios *);
static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
			       const struct ktermios *);
static bool cp210x_tx_empty(struct usb_serial_port *port);
static int cp210x_tiocmget(struct tty_struct *);
static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int);
static int cp210x_tiocmset_port(struct usb_serial_port *port,
		unsigned int, unsigned int);
static int cp210x_break_ctl(struct tty_struct *, int);
static int cp210x_attach(struct usb_serial *);
static void cp210x_disconnect(struct usb_serial *);
static void cp210x_release(struct usb_serial *);
static int cp210x_port_probe(struct usb_serial_port *);
static void cp210x_port_remove(struct usb_serial_port *);
static void cp210x_dtr_rts(struct usb_serial_port *port, int on);
static void cp210x_process_read_urb(struct urb *urb);
static void cp210x_enable_event_mode(struct usb_serial_port *port);
static void cp210x_disable_event_mode(struct usb_serial_port *port);

static const struct usb_device_id id_table[] =;

MODULE_DEVICE_TABLE(usb, id_table);

struct cp210x_serial_private {};

enum cp210x_event_state {};

struct cp210x_port_private {};

static struct usb_serial_driver cp210x_device =;

static struct usb_serial_driver * const serial_drivers[] =;

/* Config request types */
#define REQTYPE_HOST_TO_INTERFACE
#define REQTYPE_INTERFACE_TO_HOST
#define REQTYPE_HOST_TO_DEVICE
#define REQTYPE_DEVICE_TO_HOST

/* Config request codes */
#define CP210X_IFC_ENABLE
#define CP210X_SET_BAUDDIV
#define CP210X_GET_BAUDDIV
#define CP210X_SET_LINE_CTL
#define CP210X_GET_LINE_CTL
#define CP210X_SET_BREAK
#define CP210X_IMM_CHAR
#define CP210X_SET_MHS
#define CP210X_GET_MDMSTS
#define CP210X_SET_XON
#define CP210X_SET_XOFF
#define CP210X_SET_EVENTMASK
#define CP210X_GET_EVENTMASK
#define CP210X_SET_CHAR
#define CP210X_GET_CHARS
#define CP210X_GET_PROPS
#define CP210X_GET_COMM_STATUS
#define CP210X_RESET
#define CP210X_PURGE
#define CP210X_SET_FLOW
#define CP210X_GET_FLOW
#define CP210X_EMBED_EVENTS
#define CP210X_GET_EVENTSTATE
#define CP210X_SET_CHARS
#define CP210X_GET_BAUDRATE
#define CP210X_SET_BAUDRATE
#define CP210X_VENDOR_SPECIFIC

/* CP210X_IFC_ENABLE */
#define UART_ENABLE
#define UART_DISABLE

/* CP210X_(SET|GET)_BAUDDIV */
#define BAUD_RATE_GEN_FREQ

/* CP210X_(SET|GET)_LINE_CTL */
#define BITS_DATA_MASK
#define BITS_DATA_5
#define BITS_DATA_6
#define BITS_DATA_7
#define BITS_DATA_8
#define BITS_DATA_9

#define BITS_PARITY_MASK
#define BITS_PARITY_NONE
#define BITS_PARITY_ODD
#define BITS_PARITY_EVEN
#define BITS_PARITY_MARK
#define BITS_PARITY_SPACE

#define BITS_STOP_MASK
#define BITS_STOP_1
#define BITS_STOP_1_5
#define BITS_STOP_2

/* CP210X_SET_BREAK */
#define BREAK_ON
#define BREAK_OFF

/* CP210X_(SET_MHS|GET_MDMSTS) */
#define CONTROL_DTR
#define CONTROL_RTS
#define CONTROL_CTS
#define CONTROL_DSR
#define CONTROL_RING
#define CONTROL_DCD
#define CONTROL_WRITE_DTR
#define CONTROL_WRITE_RTS

/* CP210X_(GET|SET)_CHARS */
struct cp210x_special_chars {};

/* CP210X_VENDOR_SPECIFIC values */
#define CP210X_GET_FW_VER
#define CP210X_READ_2NCONFIG
#define CP210X_GET_FW_VER_2N
#define CP210X_READ_LATCH
#define CP210X_GET_PARTNUM
#define CP210X_GET_PORTCONFIG
#define CP210X_GET_DEVICEMODE
#define CP210X_WRITE_LATCH

/* Part number definitions */
#define CP210X_PARTNUM_CP2101
#define CP210X_PARTNUM_CP2102
#define CP210X_PARTNUM_CP2103
#define CP210X_PARTNUM_CP2104
#define CP210X_PARTNUM_CP2105
#define CP210X_PARTNUM_CP2108
#define CP210X_PARTNUM_CP2102N_QFN28
#define CP210X_PARTNUM_CP2102N_QFN24
#define CP210X_PARTNUM_CP2102N_QFN20
#define CP210X_PARTNUM_UNKNOWN

/* CP210X_GET_COMM_STATUS returns these 0x13 bytes */
struct cp210x_comm_status {} __packed;

/*
 * CP210X_PURGE - 16 bits passed in wValue of USB request.
 * SiLabs app note AN571 gives a strange description of the 4 bits:
 * bit 0 or bit 2 clears the transmit queue and 1 or 3 receive.
 * writing 1 to all, however, purges cp2108 well enough to avoid the hang.
 */
#define PURGE_ALL

/* CP210X_EMBED_EVENTS */
#define CP210X_ESCCHAR

#define CP210X_LSR_OVERRUN
#define CP210X_LSR_PARITY
#define CP210X_LSR_FRAME
#define CP210X_LSR_BREAK


/* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */
struct cp210x_flow_ctl {};

/* cp210x_flow_ctl::ulControlHandshake */
#define CP210X_SERIAL_DTR_MASK
#define CP210X_SERIAL_DTR_INACTIVE
#define CP210X_SERIAL_DTR_ACTIVE
#define CP210X_SERIAL_DTR_FLOW_CTL
#define CP210X_SERIAL_CTS_HANDSHAKE
#define CP210X_SERIAL_DSR_HANDSHAKE
#define CP210X_SERIAL_DCD_HANDSHAKE
#define CP210X_SERIAL_DSR_SENSITIVITY

/* cp210x_flow_ctl::ulFlowReplace */
#define CP210X_SERIAL_AUTO_TRANSMIT
#define CP210X_SERIAL_AUTO_RECEIVE
#define CP210X_SERIAL_ERROR_CHAR
#define CP210X_SERIAL_NULL_STRIPPING
#define CP210X_SERIAL_BREAK_CHAR
#define CP210X_SERIAL_RTS_MASK
#define CP210X_SERIAL_RTS_INACTIVE
#define CP210X_SERIAL_RTS_ACTIVE
#define CP210X_SERIAL_RTS_FLOW_CTL
#define CP210X_SERIAL_XOFF_CONTINUE

/* CP210X_VENDOR_SPECIFIC, CP210X_GET_DEVICEMODE call reads these 0x2 bytes. */
struct cp210x_pin_mode {};

#define CP210X_PIN_MODE_MODEM
#define CP210X_PIN_MODE_GPIO

/*
 * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes
 * on a CP2105 chip. Structure needs padding due to unused/unspecified bytes.
 */
struct cp210x_dual_port_config {} __packed;

/*
 * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xd bytes
 * on a CP2104 chip. Structure needs padding due to unused/unspecified bytes.
 */
struct cp210x_single_port_config {} __packed;

/* GPIO modes */
#define CP210X_SCI_GPIO_MODE_OFFSET
#define CP210X_SCI_GPIO_MODE_MASK

#define CP210X_ECI_GPIO_MODE_OFFSET
#define CP210X_ECI_GPIO_MODE_MASK

#define CP210X_GPIO_MODE_OFFSET
#define CP210X_GPIO_MODE_MASK

/* CP2105 port configuration values */
#define CP2105_GPIO0_TXLED_MODE
#define CP2105_GPIO1_RXLED_MODE
#define CP2105_GPIO1_RS485_MODE

/* CP2104 port configuration values */
#define CP2104_GPIO0_TXLED_MODE
#define CP2104_GPIO1_RXLED_MODE
#define CP2104_GPIO2_RS485_MODE

struct cp210x_quad_port_state {};

/*
 * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0x49 bytes
 * on a CP2108 chip.
 *
 * See https://www.silabs.com/documents/public/application-notes/an978-cp210x-usb-to-uart-api-specification.pdf
 */
struct cp210x_quad_port_config {} __packed;

#define CP2108_EF_IFC_GPIO_TXLED
#define CP2108_EF_IFC_GPIO_RXLED
#define CP2108_EF_IFC_GPIO_RS485
#define CP2108_EF_IFC_GPIO_RS485_LOGIC
#define CP2108_EF_IFC_GPIO_CLOCK
#define CP2108_EF_IFC_DYNAMIC_SUSPEND

/* CP2102N configuration array indices */
#define CP210X_2NCONFIG_CONFIG_VERSION_IDX
#define CP210X_2NCONFIG_GPIO_MODE_IDX
#define CP210X_2NCONFIG_GPIO_RSTLATCH_IDX
#define CP210X_2NCONFIG_GPIO_CONTROL_IDX

/* CP2102N QFN20 port configuration values */
#define CP2102N_QFN20_GPIO2_TXLED_MODE
#define CP2102N_QFN20_GPIO3_RXLED_MODE
#define CP2102N_QFN20_GPIO1_RS485_MODE
#define CP2102N_QFN20_GPIO0_CLK_MODE

/*
 * CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x02 bytes
 * for CP2102N, CP2103, CP2104 and CP2105.
 */
struct cp210x_gpio_write {};

/*
 * CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x04 bytes
 * for CP2108.
 */
struct cp210x_gpio_write16 {};

/*
 * Helper to get interface number when we only have struct usb_serial.
 */
static u8 cp210x_interface_num(struct usb_serial *serial)
{}

/*
 * Reads a variable-sized block of CP210X_ registers, identified by req.
 * Returns data into buf in native USB byte order.
 */
static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
		void *buf, int bufsize)
{}

/*
 * Reads any 8-bit CP210X_ register identified by req.
 */
static int cp210x_read_u8_reg(struct usb_serial_port *port, u8 req, u8 *val)
{}

/*
 * Reads a variable-sized vendor block of CP210X_ registers, identified by val.
 * Returns data into buf in native USB byte order.
 */
static int cp210x_read_vendor_block(struct usb_serial *serial, u8 type, u16 val,
				    void *buf, int bufsize)
{}

/*
 * Writes any 16-bit CP210X_ register (req) whose value is passed
 * entirely in the wValue field of the USB request.
 */
static int cp210x_write_u16_reg(struct usb_serial_port *port, u8 req, u16 val)
{}

/*
 * Writes a variable-sized block of CP210X_ registers, identified by req.
 * Data in buf must be in native USB byte order.
 */
static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req,
		void *buf, int bufsize)
{}

/*
 * Writes any 32-bit CP210X_ register identified by req.
 */
static int cp210x_write_u32_reg(struct usb_serial_port *port, u8 req, u32 val)
{}

#ifdef CONFIG_GPIOLIB
/*
 * Writes a variable-sized vendor block of CP210X_ registers, identified by val.
 * Data in buf must be in native USB byte order.
 */
static int cp210x_write_vendor_block(struct usb_serial *serial, u8 type,
				     u16 val, void *buf, int bufsize)
{}
#endif

static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
{}

static void cp210x_close(struct usb_serial_port *port)
{}

static void cp210x_process_lsr(struct usb_serial_port *port, unsigned char lsr, char *flag)
{}

static bool cp210x_process_char(struct usb_serial_port *port, unsigned char *ch, char *flag)
{}

static void cp210x_process_read_urb(struct urb *urb)
{}

/*
 * Read how many bytes are waiting in the TX queue.
 */
static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port,
		u32 *count)
{}

static bool cp210x_tx_empty(struct usb_serial_port *port)
{}

struct cp210x_rate {};

static const struct cp210x_rate cp210x_an205_table1[] =;

/*
 * Quantises the baud rate as per AN205 Table 1
 */
static speed_t cp210x_get_an205_rate(speed_t baud)
{}

static speed_t cp210x_get_actual_rate(speed_t baud)
{}

/*
 * CP2101 supports the following baud rates:
 *
 *	300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800,
 *	38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600
 *
 * CP2102 and CP2103 support the following additional rates:
 *
 *	4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000,
 *	576000
 *
 * The device will map a requested rate to a supported one, but the result
 * of requests for rates greater than 1053257 is undefined (see AN205).
 *
 * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud,
 * respectively, with an error less than 1%. The actual rates are determined
 * by
 *
 *	div = round(freq / (2 x prescale x request))
 *	actual = freq / (2 x prescale x div)
 *
 * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps
 * or 1 otherwise.
 * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1
 * otherwise.
 */
static void cp210x_change_speed(struct tty_struct *tty,
				struct usb_serial_port *port,
				const struct ktermios *old_termios)
{}

static void cp210x_enable_event_mode(struct usb_serial_port *port)
{}

static void cp210x_disable_event_mode(struct usb_serial_port *port)
{}

static bool cp210x_termios_change(const struct ktermios *a, const struct ktermios *b)
{}

static void cp210x_set_flow_control(struct tty_struct *tty,
				    struct usb_serial_port *port,
				    const struct ktermios *old_termios)
{}

static void cp210x_set_termios(struct tty_struct *tty,
		               struct usb_serial_port *port,
		               const struct ktermios *old_termios)
{}

static int cp210x_tiocmset(struct tty_struct *tty,
		unsigned int set, unsigned int clear)
{}

static int cp210x_tiocmset_port(struct usb_serial_port *port,
		unsigned int set, unsigned int clear)
{}

static void cp210x_dtr_rts(struct usb_serial_port *port, int on)
{}

static int cp210x_tiocmget(struct tty_struct *tty)
{}

static int cp210x_break_ctl(struct tty_struct *tty, int break_state)
{}

#ifdef CONFIG_GPIOLIB
static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{}

static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
{}

static int cp210x_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio)
{}

static int cp210x_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
{}

static int cp210x_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
					int value)
{}

static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
				  unsigned long config)
{}

static int cp210x_gpio_init_valid_mask(struct gpio_chip *gc,
		unsigned long *valid_mask, unsigned int ngpios)
{}

/*
 * This function is for configuring GPIO using shared pins, where other signals
 * are made unavailable by configuring the use of GPIO. This is believed to be
 * only applicable to the cp2105 at this point, the other devices supported by
 * this driver that provide GPIO do so in a way that does not impact other
 * signals and are thus expected to have very different initialisation.
 */
static int cp2105_gpioconf_init(struct usb_serial *serial)
{}

static int cp2104_gpioconf_init(struct usb_serial *serial)
{}

static int cp2108_gpio_init(struct usb_serial *serial)
{}

static int cp2102n_gpioconf_init(struct usb_serial *serial)
{}

static int cp210x_gpio_init(struct usb_serial *serial)
{}

static void cp210x_gpio_remove(struct usb_serial *serial)
{}

#else

static int cp210x_gpio_init(struct usb_serial *serial)
{
	return 0;
}

static void cp210x_gpio_remove(struct usb_serial *serial)
{
	/* Nothing to do */
}

#endif

static int cp210x_port_probe(struct usb_serial_port *port)
{}

static void cp210x_port_remove(struct usb_serial_port *port)
{}

static void cp210x_init_max_speed(struct usb_serial *serial)
{}

static void cp2102_determine_quirks(struct usb_serial *serial)
{}

static int cp210x_get_fw_version(struct usb_serial *serial, u16 value)
{}

static void cp210x_determine_type(struct usb_serial *serial)
{}

static int cp210x_attach(struct usb_serial *serial)
{}

static void cp210x_disconnect(struct usb_serial *serial)
{}

static void cp210x_release(struct usb_serial *serial)
{}

module_usb_serial_driver();

MODULE_DESCRIPTION();
MODULE_LICENSE();