Commit 4099d4ba authored by Johan Hovold's avatar Johan Hovold
Browse files

USB: serial: xr: add support for XR21B1411



The single-port XR21B1411 is similar to the XR21B142X type but uses
12-bit registers and 16-bit register addresses, the register requests
are different and are directed at the device rather than interface, and
5 and 6-bit words are not supported.

The register layout is very similar to XR21B142X except that most
registers are offset by 0xc00 (corresponding to a channel index of 12 in
the MSB of wIndex). As the device is single-port so that the derived
channel index is 0, the current register accessors can be reused after
simply changing the address width.

Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parent 607f6718
Loading
Loading
Loading
Loading
+48 −16
Original line number Diff line number Diff line
@@ -108,18 +108,19 @@ struct xr_type {
	u8 set_reg;
	u8 get_reg;

	u8 uart_enable;
	u8 flow_control;
	u8 xon_char;
	u8 xoff_char;
	u8 tx_break;
	u8 gpio_mode;
	u8 gpio_direction;
	u8 gpio_set;
	u8 gpio_clear;
	u8 gpio_status;
	u8 custom_driver;

	u16 uart_enable;
	u16 flow_control;
	u16 xon_char;
	u16 xoff_char;
	u16 tx_break;
	u16 gpio_mode;
	u16 gpio_direction;
	u16 gpio_set;
	u16 gpio_clear;
	u16 gpio_status;
	u16 custom_driver;

	bool have_5_6_bit_mode;
	bool have_xmit_toggle;

	int (*enable)(struct usb_serial_port *port);
@@ -132,6 +133,7 @@ struct xr_type {
enum xr_type_id {
	XR21V141X,
	XR21B142X,
	XR21B1411,
	XR_TYPE_COUNT,
};

@@ -175,8 +177,27 @@ static const struct xr_type xr_types[] = {
		.gpio_status	= 0x10,
		.custom_driver	= 0x60,

		.have_5_6_bit_mode	= true,
		.have_xmit_toggle	= true,
	},
	[XR21B1411] = {
		.reg_width	= 12,
		.reg_recipient	= USB_RECIP_DEVICE,
		.set_reg	= 0x00,
		.get_reg	= 0x01,

		.uart_enable	= 0xc00,
		.flow_control	= 0xc06,
		.xon_char	= 0xc07,
		.xoff_char	= 0xc08,
		.tx_break	= 0xc0a,
		.gpio_mode	= 0xc0c,
		.gpio_direction	= 0xc0d,
		.gpio_set	= 0xc0e,
		.gpio_clear	= 0xc0f,
		.gpio_status	= 0xc10,
		.custom_driver	= 0x20d,
	},
};

struct xr_data {
@@ -184,7 +205,7 @@ struct xr_data {
	u8 channel;			/* zero-based index or interface number */
};

static int xr_set_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 val)
static int xr_set_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 val)
{
	struct xr_data *data = usb_get_serial_port_data(port);
	const struct xr_type *type = data->type;
@@ -204,7 +225,7 @@ static int xr_set_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 val)
	return 0;
}

static int xr_get_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 *val)
static int xr_get_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 *val)
{
	struct xr_data *data = usb_get_serial_port_data(port);
	const struct xr_type *type = data->type;
@@ -243,14 +264,14 @@ static int xr_get_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 *val
	return ret;
}

static int xr_set_reg_uart(struct usb_serial_port *port, u8 reg, u16 val)
static int xr_set_reg_uart(struct usb_serial_port *port, u16 reg, u16 val)
{
	struct xr_data *data = usb_get_serial_port_data(port);

	return xr_set_reg(port, data->channel, reg, val);
}

static int xr_get_reg_uart(struct usb_serial_port *port, u8 reg, u16 *val)
static int xr_get_reg_uart(struct usb_serial_port *port, u16 reg, u16 *val)
{
	struct xr_data *data = usb_get_serial_port_data(port);

@@ -646,6 +667,7 @@ static void xr21v141x_set_line_settings(struct tty_struct *tty,
static void xr_cdc_set_line_coding(struct tty_struct *tty,
		struct usb_serial_port *port, struct ktermios *old_termios)
{
	struct xr_data *data = usb_get_serial_port_data(port);
	struct usb_host_interface *alt = port->serial->interface->cur_altsetting;
	struct usb_device *udev = port->serial->dev;
	struct usb_cdc_line_coding *lc;
@@ -683,6 +705,15 @@ static void xr_cdc_set_line_coding(struct tty_struct *tty,
		lc->bParityType = USB_CDC_NO_PARITY;
	}

	if (!data->type->have_5_6_bit_mode &&
			(C_CSIZE(tty) == CS5 || C_CSIZE(tty) == CS6)) {
		tty->termios.c_cflag &= ~CSIZE;
		if (old_termios)
			tty->termios.c_cflag |= old_termios->c_cflag & CSIZE;
		else
			tty->termios.c_cflag |= CS8;
	}

	switch (C_CSIZE(tty)) {
	case CS5:
		lc->bDataBits = 5;
@@ -876,6 +907,7 @@ static void xr_port_remove(struct usb_serial_port *port)

static const struct usb_device_id id_table[] = {
	{ XR_DEVICE(0x04e2, 0x1410, XR21V141X) },
	{ XR_DEVICE(0x04e2, 0x1411, XR21B1411) },
	{ XR_DEVICE(0x04e2, 0x1412, XR21V141X) },
	{ XR_DEVICE(0x04e2, 0x1414, XR21V141X) },
	{ XR_DEVICE(0x04e2, 0x1420, XR21B142X) },