162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MaxLinear/Exar USB to Serial driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020 Manivannan Sadhasivam <mani@kernel.org> 662306a36Sopenharmony_ci * Copyright (c) 2021 Johan Hovold <johan@kernel.org> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on the initial driver written by Patong Yang: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * https://lore.kernel.org/r/20180404070634.nhspvmxcjwfgjkcv@advantechmxl-desktop 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Copyright (c) 2018 Patong Yang <patong.mxl@gmail.com> 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/tty.h> 1962306a36Sopenharmony_ci#include <linux/usb.h> 2062306a36Sopenharmony_ci#include <linux/usb/cdc.h> 2162306a36Sopenharmony_ci#include <linux/usb/serial.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct xr_txrx_clk_mask { 2462306a36Sopenharmony_ci u16 tx; 2562306a36Sopenharmony_ci u16 rx0; 2662306a36Sopenharmony_ci u16 rx1; 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define XR_INT_OSC_HZ 48000000U 3062306a36Sopenharmony_ci#define XR21V141X_MIN_SPEED 46U 3162306a36Sopenharmony_ci#define XR21V141X_MAX_SPEED XR_INT_OSC_HZ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* XR21V141X register blocks */ 3462306a36Sopenharmony_ci#define XR21V141X_UART_REG_BLOCK 0 3562306a36Sopenharmony_ci#define XR21V141X_UM_REG_BLOCK 4 3662306a36Sopenharmony_ci#define XR21V141X_UART_CUSTOM_BLOCK 0x66 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* XR21V141X UART registers */ 3962306a36Sopenharmony_ci#define XR21V141X_CLOCK_DIVISOR_0 0x04 4062306a36Sopenharmony_ci#define XR21V141X_CLOCK_DIVISOR_1 0x05 4162306a36Sopenharmony_ci#define XR21V141X_CLOCK_DIVISOR_2 0x06 4262306a36Sopenharmony_ci#define XR21V141X_TX_CLOCK_MASK_0 0x07 4362306a36Sopenharmony_ci#define XR21V141X_TX_CLOCK_MASK_1 0x08 4462306a36Sopenharmony_ci#define XR21V141X_RX_CLOCK_MASK_0 0x09 4562306a36Sopenharmony_ci#define XR21V141X_RX_CLOCK_MASK_1 0x0a 4662306a36Sopenharmony_ci#define XR21V141X_REG_FORMAT 0x0b 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* XR21V141X UART Manager registers */ 4962306a36Sopenharmony_ci#define XR21V141X_UM_FIFO_ENABLE_REG 0x10 5062306a36Sopenharmony_ci#define XR21V141X_UM_ENABLE_TX_FIFO 0x01 5162306a36Sopenharmony_ci#define XR21V141X_UM_ENABLE_RX_FIFO 0x02 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define XR21V141X_UM_RX_FIFO_RESET 0x18 5462306a36Sopenharmony_ci#define XR21V141X_UM_TX_FIFO_RESET 0x1c 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define XR_UART_ENABLE_TX 0x1 5762306a36Sopenharmony_ci#define XR_UART_ENABLE_RX 0x2 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define XR_GPIO_RI BIT(0) 6062306a36Sopenharmony_ci#define XR_GPIO_CD BIT(1) 6162306a36Sopenharmony_ci#define XR_GPIO_DSR BIT(2) 6262306a36Sopenharmony_ci#define XR_GPIO_DTR BIT(3) 6362306a36Sopenharmony_ci#define XR_GPIO_CTS BIT(4) 6462306a36Sopenharmony_ci#define XR_GPIO_RTS BIT(5) 6562306a36Sopenharmony_ci#define XR_GPIO_CLK BIT(6) 6662306a36Sopenharmony_ci#define XR_GPIO_XEN BIT(7) 6762306a36Sopenharmony_ci#define XR_GPIO_TXT BIT(8) 6862306a36Sopenharmony_ci#define XR_GPIO_RXT BIT(9) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define XR_UART_DATA_MASK GENMASK(3, 0) 7162306a36Sopenharmony_ci#define XR_UART_DATA_7 0x7 7262306a36Sopenharmony_ci#define XR_UART_DATA_8 0x8 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define XR_UART_PARITY_MASK GENMASK(6, 4) 7562306a36Sopenharmony_ci#define XR_UART_PARITY_SHIFT 4 7662306a36Sopenharmony_ci#define XR_UART_PARITY_NONE (0x0 << XR_UART_PARITY_SHIFT) 7762306a36Sopenharmony_ci#define XR_UART_PARITY_ODD (0x1 << XR_UART_PARITY_SHIFT) 7862306a36Sopenharmony_ci#define XR_UART_PARITY_EVEN (0x2 << XR_UART_PARITY_SHIFT) 7962306a36Sopenharmony_ci#define XR_UART_PARITY_MARK (0x3 << XR_UART_PARITY_SHIFT) 8062306a36Sopenharmony_ci#define XR_UART_PARITY_SPACE (0x4 << XR_UART_PARITY_SHIFT) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define XR_UART_STOP_MASK BIT(7) 8362306a36Sopenharmony_ci#define XR_UART_STOP_SHIFT 7 8462306a36Sopenharmony_ci#define XR_UART_STOP_1 (0x0 << XR_UART_STOP_SHIFT) 8562306a36Sopenharmony_ci#define XR_UART_STOP_2 (0x1 << XR_UART_STOP_SHIFT) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define XR_UART_FLOW_MODE_NONE 0x0 8862306a36Sopenharmony_ci#define XR_UART_FLOW_MODE_HW 0x1 8962306a36Sopenharmony_ci#define XR_UART_FLOW_MODE_SW 0x2 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define XR_GPIO_MODE_SEL_MASK GENMASK(2, 0) 9262306a36Sopenharmony_ci#define XR_GPIO_MODE_SEL_RTS_CTS 0x1 9362306a36Sopenharmony_ci#define XR_GPIO_MODE_SEL_DTR_DSR 0x2 9462306a36Sopenharmony_ci#define XR_GPIO_MODE_SEL_RS485 0x3 9562306a36Sopenharmony_ci#define XR_GPIO_MODE_SEL_RS485_ADDR 0x4 9662306a36Sopenharmony_ci#define XR_GPIO_MODE_RS485_TX_H 0x8 9762306a36Sopenharmony_ci#define XR_GPIO_MODE_TX_TOGGLE 0x100 9862306a36Sopenharmony_ci#define XR_GPIO_MODE_RX_TOGGLE 0x200 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define XR_FIFO_RESET 0x1 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci#define XR_CUSTOM_DRIVER_ACTIVE 0x1 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int xr21v141x_uart_enable(struct usb_serial_port *port); 10562306a36Sopenharmony_cistatic int xr21v141x_uart_disable(struct usb_serial_port *port); 10662306a36Sopenharmony_cistatic int xr21v141x_fifo_reset(struct usb_serial_port *port); 10762306a36Sopenharmony_cistatic void xr21v141x_set_line_settings(struct tty_struct *tty, 10862306a36Sopenharmony_ci struct usb_serial_port *port, 10962306a36Sopenharmony_ci const struct ktermios *old_termios); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct xr_type { 11262306a36Sopenharmony_ci int reg_width; 11362306a36Sopenharmony_ci u8 reg_recipient; 11462306a36Sopenharmony_ci u8 set_reg; 11562306a36Sopenharmony_ci u8 get_reg; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci u16 uart_enable; 11862306a36Sopenharmony_ci u16 flow_control; 11962306a36Sopenharmony_ci u16 xon_char; 12062306a36Sopenharmony_ci u16 xoff_char; 12162306a36Sopenharmony_ci u16 tx_break; 12262306a36Sopenharmony_ci u16 gpio_mode; 12362306a36Sopenharmony_ci u16 gpio_direction; 12462306a36Sopenharmony_ci u16 gpio_set; 12562306a36Sopenharmony_ci u16 gpio_clear; 12662306a36Sopenharmony_ci u16 gpio_status; 12762306a36Sopenharmony_ci u16 tx_fifo_reset; 12862306a36Sopenharmony_ci u16 rx_fifo_reset; 12962306a36Sopenharmony_ci u16 custom_driver; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci bool have_5_6_bit_mode; 13262306a36Sopenharmony_ci bool have_xmit_toggle; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci int (*enable)(struct usb_serial_port *port); 13562306a36Sopenharmony_ci int (*disable)(struct usb_serial_port *port); 13662306a36Sopenharmony_ci int (*fifo_reset)(struct usb_serial_port *port); 13762306a36Sopenharmony_ci void (*set_line_settings)(struct tty_struct *tty, 13862306a36Sopenharmony_ci struct usb_serial_port *port, 13962306a36Sopenharmony_ci const struct ktermios *old_termios); 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cienum xr_type_id { 14362306a36Sopenharmony_ci XR21V141X, 14462306a36Sopenharmony_ci XR21B142X, 14562306a36Sopenharmony_ci XR21B1411, 14662306a36Sopenharmony_ci XR2280X, 14762306a36Sopenharmony_ci XR_TYPE_COUNT, 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic const struct xr_type xr_types[] = { 15162306a36Sopenharmony_ci [XR21V141X] = { 15262306a36Sopenharmony_ci .reg_width = 8, 15362306a36Sopenharmony_ci .reg_recipient = USB_RECIP_DEVICE, 15462306a36Sopenharmony_ci .set_reg = 0x00, 15562306a36Sopenharmony_ci .get_reg = 0x01, 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci .uart_enable = 0x03, 15862306a36Sopenharmony_ci .flow_control = 0x0c, 15962306a36Sopenharmony_ci .xon_char = 0x10, 16062306a36Sopenharmony_ci .xoff_char = 0x11, 16162306a36Sopenharmony_ci .tx_break = 0x14, 16262306a36Sopenharmony_ci .gpio_mode = 0x1a, 16362306a36Sopenharmony_ci .gpio_direction = 0x1b, 16462306a36Sopenharmony_ci .gpio_set = 0x1d, 16562306a36Sopenharmony_ci .gpio_clear = 0x1e, 16662306a36Sopenharmony_ci .gpio_status = 0x1f, 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci .enable = xr21v141x_uart_enable, 16962306a36Sopenharmony_ci .disable = xr21v141x_uart_disable, 17062306a36Sopenharmony_ci .fifo_reset = xr21v141x_fifo_reset, 17162306a36Sopenharmony_ci .set_line_settings = xr21v141x_set_line_settings, 17262306a36Sopenharmony_ci }, 17362306a36Sopenharmony_ci [XR21B142X] = { 17462306a36Sopenharmony_ci .reg_width = 16, 17562306a36Sopenharmony_ci .reg_recipient = USB_RECIP_INTERFACE, 17662306a36Sopenharmony_ci .set_reg = 0x00, 17762306a36Sopenharmony_ci .get_reg = 0x00, 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci .uart_enable = 0x00, 18062306a36Sopenharmony_ci .flow_control = 0x06, 18162306a36Sopenharmony_ci .xon_char = 0x07, 18262306a36Sopenharmony_ci .xoff_char = 0x08, 18362306a36Sopenharmony_ci .tx_break = 0x0a, 18462306a36Sopenharmony_ci .gpio_mode = 0x0c, 18562306a36Sopenharmony_ci .gpio_direction = 0x0d, 18662306a36Sopenharmony_ci .gpio_set = 0x0e, 18762306a36Sopenharmony_ci .gpio_clear = 0x0f, 18862306a36Sopenharmony_ci .gpio_status = 0x10, 18962306a36Sopenharmony_ci .tx_fifo_reset = 0x40, 19062306a36Sopenharmony_ci .rx_fifo_reset = 0x43, 19162306a36Sopenharmony_ci .custom_driver = 0x60, 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci .have_5_6_bit_mode = true, 19462306a36Sopenharmony_ci .have_xmit_toggle = true, 19562306a36Sopenharmony_ci }, 19662306a36Sopenharmony_ci [XR21B1411] = { 19762306a36Sopenharmony_ci .reg_width = 12, 19862306a36Sopenharmony_ci .reg_recipient = USB_RECIP_DEVICE, 19962306a36Sopenharmony_ci .set_reg = 0x00, 20062306a36Sopenharmony_ci .get_reg = 0x01, 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci .uart_enable = 0xc00, 20362306a36Sopenharmony_ci .flow_control = 0xc06, 20462306a36Sopenharmony_ci .xon_char = 0xc07, 20562306a36Sopenharmony_ci .xoff_char = 0xc08, 20662306a36Sopenharmony_ci .tx_break = 0xc0a, 20762306a36Sopenharmony_ci .gpio_mode = 0xc0c, 20862306a36Sopenharmony_ci .gpio_direction = 0xc0d, 20962306a36Sopenharmony_ci .gpio_set = 0xc0e, 21062306a36Sopenharmony_ci .gpio_clear = 0xc0f, 21162306a36Sopenharmony_ci .gpio_status = 0xc10, 21262306a36Sopenharmony_ci .tx_fifo_reset = 0xc80, 21362306a36Sopenharmony_ci .rx_fifo_reset = 0xcc0, 21462306a36Sopenharmony_ci .custom_driver = 0x20d, 21562306a36Sopenharmony_ci }, 21662306a36Sopenharmony_ci [XR2280X] = { 21762306a36Sopenharmony_ci .reg_width = 16, 21862306a36Sopenharmony_ci .reg_recipient = USB_RECIP_DEVICE, 21962306a36Sopenharmony_ci .set_reg = 0x05, 22062306a36Sopenharmony_ci .get_reg = 0x05, 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci .uart_enable = 0x40, 22362306a36Sopenharmony_ci .flow_control = 0x46, 22462306a36Sopenharmony_ci .xon_char = 0x47, 22562306a36Sopenharmony_ci .xoff_char = 0x48, 22662306a36Sopenharmony_ci .tx_break = 0x4a, 22762306a36Sopenharmony_ci .gpio_mode = 0x4c, 22862306a36Sopenharmony_ci .gpio_direction = 0x4d, 22962306a36Sopenharmony_ci .gpio_set = 0x4e, 23062306a36Sopenharmony_ci .gpio_clear = 0x4f, 23162306a36Sopenharmony_ci .gpio_status = 0x50, 23262306a36Sopenharmony_ci .tx_fifo_reset = 0x60, 23362306a36Sopenharmony_ci .rx_fifo_reset = 0x63, 23462306a36Sopenharmony_ci .custom_driver = 0x81, 23562306a36Sopenharmony_ci }, 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistruct xr_data { 23962306a36Sopenharmony_ci const struct xr_type *type; 24062306a36Sopenharmony_ci u8 channel; /* zero-based index or interface number */ 24162306a36Sopenharmony_ci struct serial_rs485 rs485; 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int xr_set_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 val) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 24762306a36Sopenharmony_ci const struct xr_type *type = data->type; 24862306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 24962306a36Sopenharmony_ci int ret; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 25262306a36Sopenharmony_ci type->set_reg, 25362306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | type->reg_recipient, 25462306a36Sopenharmony_ci val, (channel << 8) | reg, NULL, 0, 25562306a36Sopenharmony_ci USB_CTRL_SET_TIMEOUT); 25662306a36Sopenharmony_ci if (ret < 0) { 25762306a36Sopenharmony_ci dev_err(&port->dev, "Failed to set reg 0x%02x: %d\n", reg, ret); 25862306a36Sopenharmony_ci return ret; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic int xr_get_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 *val) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 26762306a36Sopenharmony_ci const struct xr_type *type = data->type; 26862306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 26962306a36Sopenharmony_ci u8 *dmabuf; 27062306a36Sopenharmony_ci int ret, len; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (type->reg_width == 8) 27362306a36Sopenharmony_ci len = 1; 27462306a36Sopenharmony_ci else 27562306a36Sopenharmony_ci len = 2; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci dmabuf = kmalloc(len, GFP_KERNEL); 27862306a36Sopenharmony_ci if (!dmabuf) 27962306a36Sopenharmony_ci return -ENOMEM; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 28262306a36Sopenharmony_ci type->get_reg, 28362306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | type->reg_recipient, 28462306a36Sopenharmony_ci 0, (channel << 8) | reg, dmabuf, len, 28562306a36Sopenharmony_ci USB_CTRL_GET_TIMEOUT); 28662306a36Sopenharmony_ci if (ret == len) { 28762306a36Sopenharmony_ci if (len == 2) 28862306a36Sopenharmony_ci *val = le16_to_cpup((__le16 *)dmabuf); 28962306a36Sopenharmony_ci else 29062306a36Sopenharmony_ci *val = *dmabuf; 29162306a36Sopenharmony_ci ret = 0; 29262306a36Sopenharmony_ci } else { 29362306a36Sopenharmony_ci dev_err(&port->dev, "Failed to get reg 0x%02x: %d\n", reg, ret); 29462306a36Sopenharmony_ci if (ret >= 0) 29562306a36Sopenharmony_ci ret = -EIO; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci kfree(dmabuf); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return ret; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int xr_set_reg_uart(struct usb_serial_port *port, u16 reg, u16 val) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return xr_set_reg(port, data->channel, reg, val); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int xr_get_reg_uart(struct usb_serial_port *port, u16 reg, u16 *val) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return xr_get_reg(port, data->channel, reg, val); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int xr_set_reg_um(struct usb_serial_port *port, u8 reg_base, u8 val) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 32062306a36Sopenharmony_ci u8 reg; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci reg = reg_base + data->channel; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return xr_set_reg(port, XR21V141X_UM_REG_BLOCK, reg, val); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int __xr_uart_enable(struct usb_serial_port *port) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return xr_set_reg_uart(port, data->type->uart_enable, 33262306a36Sopenharmony_ci XR_UART_ENABLE_TX | XR_UART_ENABLE_RX); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int __xr_uart_disable(struct usb_serial_port *port) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return xr_set_reg_uart(port, data->type->uart_enable, 0); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/* 34362306a36Sopenharmony_ci * According to datasheet, below is the recommended sequence for enabling UART 34462306a36Sopenharmony_ci * module in XR21V141X: 34562306a36Sopenharmony_ci * 34662306a36Sopenharmony_ci * Enable Tx FIFO 34762306a36Sopenharmony_ci * Enable Tx and Rx 34862306a36Sopenharmony_ci * Enable Rx FIFO 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_cistatic int xr21v141x_uart_enable(struct usb_serial_port *port) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci int ret; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG, 35562306a36Sopenharmony_ci XR21V141X_UM_ENABLE_TX_FIFO); 35662306a36Sopenharmony_ci if (ret) 35762306a36Sopenharmony_ci return ret; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci ret = __xr_uart_enable(port); 36062306a36Sopenharmony_ci if (ret) 36162306a36Sopenharmony_ci return ret; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG, 36462306a36Sopenharmony_ci XR21V141X_UM_ENABLE_TX_FIFO | XR21V141X_UM_ENABLE_RX_FIFO); 36562306a36Sopenharmony_ci if (ret) 36662306a36Sopenharmony_ci __xr_uart_disable(port); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return ret; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int xr21v141x_uart_disable(struct usb_serial_port *port) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci int ret; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ret = __xr_uart_disable(port); 37662306a36Sopenharmony_ci if (ret) 37762306a36Sopenharmony_ci return ret; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG, 0); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return ret; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int xr_uart_enable(struct usb_serial_port *port) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (data->type->enable) 38962306a36Sopenharmony_ci return data->type->enable(port); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return __xr_uart_enable(port); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int xr_uart_disable(struct usb_serial_port *port) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (data->type->disable) 39962306a36Sopenharmony_ci return data->type->disable(port); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return __xr_uart_disable(port); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int xr21v141x_fifo_reset(struct usb_serial_port *port) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci int ret; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ret = xr_set_reg_um(port, XR21V141X_UM_TX_FIFO_RESET, XR_FIFO_RESET); 40962306a36Sopenharmony_ci if (ret) 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ret = xr_set_reg_um(port, XR21V141X_UM_RX_FIFO_RESET, XR_FIFO_RESET); 41362306a36Sopenharmony_ci if (ret) 41462306a36Sopenharmony_ci return ret; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic int xr_fifo_reset(struct usb_serial_port *port) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 42262306a36Sopenharmony_ci int ret; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (data->type->fifo_reset) 42562306a36Sopenharmony_ci return data->type->fifo_reset(port); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci ret = xr_set_reg_uart(port, data->type->tx_fifo_reset, XR_FIFO_RESET); 42862306a36Sopenharmony_ci if (ret) 42962306a36Sopenharmony_ci return ret; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci ret = xr_set_reg_uart(port, data->type->rx_fifo_reset, XR_FIFO_RESET); 43262306a36Sopenharmony_ci if (ret) 43362306a36Sopenharmony_ci return ret; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int xr_tiocmget(struct tty_struct *tty) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 44162306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 44262306a36Sopenharmony_ci u16 status; 44362306a36Sopenharmony_ci int ret; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci ret = xr_get_reg_uart(port, data->type->gpio_status, &status); 44662306a36Sopenharmony_ci if (ret) 44762306a36Sopenharmony_ci return ret; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Modem control pins are active low, so reading '0' means it is active 45162306a36Sopenharmony_ci * and '1' means not active. 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci ret = ((status & XR_GPIO_DTR) ? 0 : TIOCM_DTR) | 45462306a36Sopenharmony_ci ((status & XR_GPIO_RTS) ? 0 : TIOCM_RTS) | 45562306a36Sopenharmony_ci ((status & XR_GPIO_CTS) ? 0 : TIOCM_CTS) | 45662306a36Sopenharmony_ci ((status & XR_GPIO_DSR) ? 0 : TIOCM_DSR) | 45762306a36Sopenharmony_ci ((status & XR_GPIO_RI) ? 0 : TIOCM_RI) | 45862306a36Sopenharmony_ci ((status & XR_GPIO_CD) ? 0 : TIOCM_CD); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return ret; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int xr_tiocmset_port(struct usb_serial_port *port, 46462306a36Sopenharmony_ci unsigned int set, unsigned int clear) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 46762306a36Sopenharmony_ci const struct xr_type *type = data->type; 46862306a36Sopenharmony_ci u16 gpio_set = 0; 46962306a36Sopenharmony_ci u16 gpio_clr = 0; 47062306a36Sopenharmony_ci int ret = 0; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* Modem control pins are active low, so set & clr are swapped */ 47362306a36Sopenharmony_ci if (set & TIOCM_RTS) 47462306a36Sopenharmony_ci gpio_clr |= XR_GPIO_RTS; 47562306a36Sopenharmony_ci if (set & TIOCM_DTR) 47662306a36Sopenharmony_ci gpio_clr |= XR_GPIO_DTR; 47762306a36Sopenharmony_ci if (clear & TIOCM_RTS) 47862306a36Sopenharmony_ci gpio_set |= XR_GPIO_RTS; 47962306a36Sopenharmony_ci if (clear & TIOCM_DTR) 48062306a36Sopenharmony_ci gpio_set |= XR_GPIO_DTR; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Writing '0' to gpio_{set/clr} bits has no effect, so no need to do */ 48362306a36Sopenharmony_ci if (gpio_clr) 48462306a36Sopenharmony_ci ret = xr_set_reg_uart(port, type->gpio_clear, gpio_clr); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (gpio_set) 48762306a36Sopenharmony_ci ret = xr_set_reg_uart(port, type->gpio_set, gpio_set); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci return ret; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic int xr_tiocmset(struct tty_struct *tty, 49362306a36Sopenharmony_ci unsigned int set, unsigned int clear) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return xr_tiocmset_port(port, set, clear); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic void xr_dtr_rts(struct usb_serial_port *port, int on) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci if (on) 50362306a36Sopenharmony_ci xr_tiocmset_port(port, TIOCM_DTR | TIOCM_RTS, 0); 50462306a36Sopenharmony_ci else 50562306a36Sopenharmony_ci xr_tiocmset_port(port, 0, TIOCM_DTR | TIOCM_RTS); 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int xr_break_ctl(struct tty_struct *tty, int break_state) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 51162306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 51262306a36Sopenharmony_ci const struct xr_type *type = data->type; 51362306a36Sopenharmony_ci u16 state; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (break_state == 0) 51662306a36Sopenharmony_ci state = 0; 51762306a36Sopenharmony_ci else 51862306a36Sopenharmony_ci state = GENMASK(type->reg_width - 1, 0); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci dev_dbg(&port->dev, "Turning break %s\n", state == 0 ? "off" : "on"); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return xr_set_reg_uart(port, type->tx_break, state); 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci/* Tx and Rx clock mask values obtained from section 3.3.4 of datasheet */ 52662306a36Sopenharmony_cistatic const struct xr_txrx_clk_mask xr21v141x_txrx_clk_masks[] = { 52762306a36Sopenharmony_ci { 0x000, 0x000, 0x000 }, 52862306a36Sopenharmony_ci { 0x000, 0x000, 0x000 }, 52962306a36Sopenharmony_ci { 0x100, 0x000, 0x100 }, 53062306a36Sopenharmony_ci { 0x020, 0x400, 0x020 }, 53162306a36Sopenharmony_ci { 0x010, 0x100, 0x010 }, 53262306a36Sopenharmony_ci { 0x208, 0x040, 0x208 }, 53362306a36Sopenharmony_ci { 0x104, 0x820, 0x108 }, 53462306a36Sopenharmony_ci { 0x844, 0x210, 0x884 }, 53562306a36Sopenharmony_ci { 0x444, 0x110, 0x444 }, 53662306a36Sopenharmony_ci { 0x122, 0x888, 0x224 }, 53762306a36Sopenharmony_ci { 0x912, 0x448, 0x924 }, 53862306a36Sopenharmony_ci { 0x492, 0x248, 0x492 }, 53962306a36Sopenharmony_ci { 0x252, 0x928, 0x292 }, 54062306a36Sopenharmony_ci { 0x94a, 0x4a4, 0xa52 }, 54162306a36Sopenharmony_ci { 0x52a, 0xaa4, 0x54a }, 54262306a36Sopenharmony_ci { 0xaaa, 0x954, 0x4aa }, 54362306a36Sopenharmony_ci { 0xaaa, 0x554, 0xaaa }, 54462306a36Sopenharmony_ci { 0x555, 0xad4, 0x5aa }, 54562306a36Sopenharmony_ci { 0xb55, 0xab4, 0x55a }, 54662306a36Sopenharmony_ci { 0x6b5, 0x5ac, 0xb56 }, 54762306a36Sopenharmony_ci { 0x5b5, 0xd6c, 0x6d6 }, 54862306a36Sopenharmony_ci { 0xb6d, 0xb6a, 0xdb6 }, 54962306a36Sopenharmony_ci { 0x76d, 0x6da, 0xbb6 }, 55062306a36Sopenharmony_ci { 0xedd, 0xdda, 0x76e }, 55162306a36Sopenharmony_ci { 0xddd, 0xbba, 0xeee }, 55262306a36Sopenharmony_ci { 0x7bb, 0xf7a, 0xdde }, 55362306a36Sopenharmony_ci { 0xf7b, 0xef6, 0x7de }, 55462306a36Sopenharmony_ci { 0xdf7, 0xbf6, 0xf7e }, 55562306a36Sopenharmony_ci { 0x7f7, 0xfee, 0xefe }, 55662306a36Sopenharmony_ci { 0xfdf, 0xfbe, 0x7fe }, 55762306a36Sopenharmony_ci { 0xf7f, 0xefe, 0xffe }, 55862306a36Sopenharmony_ci { 0xfff, 0xffe, 0xffd }, 55962306a36Sopenharmony_ci}; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic int xr21v141x_set_baudrate(struct tty_struct *tty, struct usb_serial_port *port) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci u32 divisor, baud, idx; 56462306a36Sopenharmony_ci u16 tx_mask, rx_mask; 56562306a36Sopenharmony_ci int ret; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci baud = tty->termios.c_ospeed; 56862306a36Sopenharmony_ci if (!baud) 56962306a36Sopenharmony_ci return 0; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci baud = clamp(baud, XR21V141X_MIN_SPEED, XR21V141X_MAX_SPEED); 57262306a36Sopenharmony_ci divisor = XR_INT_OSC_HZ / baud; 57362306a36Sopenharmony_ci idx = ((32 * XR_INT_OSC_HZ) / baud) & 0x1f; 57462306a36Sopenharmony_ci tx_mask = xr21v141x_txrx_clk_masks[idx].tx; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (divisor & 0x01) 57762306a36Sopenharmony_ci rx_mask = xr21v141x_txrx_clk_masks[idx].rx1; 57862306a36Sopenharmony_ci else 57962306a36Sopenharmony_ci rx_mask = xr21v141x_txrx_clk_masks[idx].rx0; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci dev_dbg(&port->dev, "Setting baud rate: %u\n", baud); 58262306a36Sopenharmony_ci /* 58362306a36Sopenharmony_ci * XR21V141X uses fractional baud rate generator with 48MHz internal 58462306a36Sopenharmony_ci * oscillator and 19-bit programmable divisor. So theoretically it can 58562306a36Sopenharmony_ci * generate most commonly used baud rates with high accuracy. 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_ci ret = xr_set_reg_uart(port, XR21V141X_CLOCK_DIVISOR_0, 58862306a36Sopenharmony_ci divisor & 0xff); 58962306a36Sopenharmony_ci if (ret) 59062306a36Sopenharmony_ci return ret; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci ret = xr_set_reg_uart(port, XR21V141X_CLOCK_DIVISOR_1, 59362306a36Sopenharmony_ci (divisor >> 8) & 0xff); 59462306a36Sopenharmony_ci if (ret) 59562306a36Sopenharmony_ci return ret; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci ret = xr_set_reg_uart(port, XR21V141X_CLOCK_DIVISOR_2, 59862306a36Sopenharmony_ci (divisor >> 16) & 0xff); 59962306a36Sopenharmony_ci if (ret) 60062306a36Sopenharmony_ci return ret; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci ret = xr_set_reg_uart(port, XR21V141X_TX_CLOCK_MASK_0, 60362306a36Sopenharmony_ci tx_mask & 0xff); 60462306a36Sopenharmony_ci if (ret) 60562306a36Sopenharmony_ci return ret; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci ret = xr_set_reg_uart(port, XR21V141X_TX_CLOCK_MASK_1, 60862306a36Sopenharmony_ci (tx_mask >> 8) & 0xff); 60962306a36Sopenharmony_ci if (ret) 61062306a36Sopenharmony_ci return ret; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci ret = xr_set_reg_uart(port, XR21V141X_RX_CLOCK_MASK_0, 61362306a36Sopenharmony_ci rx_mask & 0xff); 61462306a36Sopenharmony_ci if (ret) 61562306a36Sopenharmony_ci return ret; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci ret = xr_set_reg_uart(port, XR21V141X_RX_CLOCK_MASK_1, 61862306a36Sopenharmony_ci (rx_mask >> 8) & 0xff); 61962306a36Sopenharmony_ci if (ret) 62062306a36Sopenharmony_ci return ret; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci tty_encode_baud_rate(tty, baud, baud); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic void xr_set_flow_mode(struct tty_struct *tty, 62862306a36Sopenharmony_ci struct usb_serial_port *port, 62962306a36Sopenharmony_ci const struct ktermios *old_termios) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 63262306a36Sopenharmony_ci const struct xr_type *type = data->type; 63362306a36Sopenharmony_ci u16 flow, gpio_mode; 63462306a36Sopenharmony_ci bool rs485_enabled; 63562306a36Sopenharmony_ci int ret; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci ret = xr_get_reg_uart(port, type->gpio_mode, &gpio_mode); 63862306a36Sopenharmony_ci if (ret) 63962306a36Sopenharmony_ci return; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* 64262306a36Sopenharmony_ci * According to the datasheets, the UART needs to be disabled while 64362306a36Sopenharmony_ci * writing to the FLOW_CONTROL register (XR21V141X), or any register 64462306a36Sopenharmony_ci * but GPIO_SET, GPIO_CLEAR, TX_BREAK and ERROR_STATUS (XR21B142X). 64562306a36Sopenharmony_ci */ 64662306a36Sopenharmony_ci xr_uart_disable(port); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* Set GPIO mode for controlling the pins manually by default. */ 64962306a36Sopenharmony_ci gpio_mode &= ~XR_GPIO_MODE_SEL_MASK; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci rs485_enabled = !!(data->rs485.flags & SER_RS485_ENABLED); 65262306a36Sopenharmony_ci if (rs485_enabled) { 65362306a36Sopenharmony_ci dev_dbg(&port->dev, "Enabling RS-485\n"); 65462306a36Sopenharmony_ci gpio_mode |= XR_GPIO_MODE_SEL_RS485; 65562306a36Sopenharmony_ci if (data->rs485.flags & SER_RS485_RTS_ON_SEND) 65662306a36Sopenharmony_ci gpio_mode &= ~XR_GPIO_MODE_RS485_TX_H; 65762306a36Sopenharmony_ci else 65862306a36Sopenharmony_ci gpio_mode |= XR_GPIO_MODE_RS485_TX_H; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (C_CRTSCTS(tty) && C_BAUD(tty) != B0 && !rs485_enabled) { 66262306a36Sopenharmony_ci dev_dbg(&port->dev, "Enabling hardware flow ctrl\n"); 66362306a36Sopenharmony_ci gpio_mode |= XR_GPIO_MODE_SEL_RTS_CTS; 66462306a36Sopenharmony_ci flow = XR_UART_FLOW_MODE_HW; 66562306a36Sopenharmony_ci } else if (I_IXON(tty)) { 66662306a36Sopenharmony_ci u8 start_char = START_CHAR(tty); 66762306a36Sopenharmony_ci u8 stop_char = STOP_CHAR(tty); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci dev_dbg(&port->dev, "Enabling sw flow ctrl\n"); 67062306a36Sopenharmony_ci flow = XR_UART_FLOW_MODE_SW; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci xr_set_reg_uart(port, type->xon_char, start_char); 67362306a36Sopenharmony_ci xr_set_reg_uart(port, type->xoff_char, stop_char); 67462306a36Sopenharmony_ci } else { 67562306a36Sopenharmony_ci dev_dbg(&port->dev, "Disabling flow ctrl\n"); 67662306a36Sopenharmony_ci flow = XR_UART_FLOW_MODE_NONE; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci xr_set_reg_uart(port, type->flow_control, flow); 68062306a36Sopenharmony_ci xr_set_reg_uart(port, type->gpio_mode, gpio_mode); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci xr_uart_enable(port); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (C_BAUD(tty) == B0) 68562306a36Sopenharmony_ci xr_dtr_rts(port, 0); 68662306a36Sopenharmony_ci else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) 68762306a36Sopenharmony_ci xr_dtr_rts(port, 1); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic void xr21v141x_set_line_settings(struct tty_struct *tty, 69162306a36Sopenharmony_ci struct usb_serial_port *port, 69262306a36Sopenharmony_ci const struct ktermios *old_termios) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct ktermios *termios = &tty->termios; 69562306a36Sopenharmony_ci u8 bits = 0; 69662306a36Sopenharmony_ci int ret; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (!old_termios || (tty->termios.c_ospeed != old_termios->c_ospeed)) 69962306a36Sopenharmony_ci xr21v141x_set_baudrate(tty, port); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci switch (C_CSIZE(tty)) { 70262306a36Sopenharmony_ci case CS5: 70362306a36Sopenharmony_ci case CS6: 70462306a36Sopenharmony_ci /* CS5 and CS6 are not supported, so just restore old setting */ 70562306a36Sopenharmony_ci termios->c_cflag &= ~CSIZE; 70662306a36Sopenharmony_ci if (old_termios) 70762306a36Sopenharmony_ci termios->c_cflag |= old_termios->c_cflag & CSIZE; 70862306a36Sopenharmony_ci else 70962306a36Sopenharmony_ci termios->c_cflag |= CS8; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (C_CSIZE(tty) == CS7) 71262306a36Sopenharmony_ci bits |= XR_UART_DATA_7; 71362306a36Sopenharmony_ci else 71462306a36Sopenharmony_ci bits |= XR_UART_DATA_8; 71562306a36Sopenharmony_ci break; 71662306a36Sopenharmony_ci case CS7: 71762306a36Sopenharmony_ci bits |= XR_UART_DATA_7; 71862306a36Sopenharmony_ci break; 71962306a36Sopenharmony_ci case CS8: 72062306a36Sopenharmony_ci default: 72162306a36Sopenharmony_ci bits |= XR_UART_DATA_8; 72262306a36Sopenharmony_ci break; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (C_PARENB(tty)) { 72662306a36Sopenharmony_ci if (C_CMSPAR(tty)) { 72762306a36Sopenharmony_ci if (C_PARODD(tty)) 72862306a36Sopenharmony_ci bits |= XR_UART_PARITY_MARK; 72962306a36Sopenharmony_ci else 73062306a36Sopenharmony_ci bits |= XR_UART_PARITY_SPACE; 73162306a36Sopenharmony_ci } else { 73262306a36Sopenharmony_ci if (C_PARODD(tty)) 73362306a36Sopenharmony_ci bits |= XR_UART_PARITY_ODD; 73462306a36Sopenharmony_ci else 73562306a36Sopenharmony_ci bits |= XR_UART_PARITY_EVEN; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (C_CSTOPB(tty)) 74062306a36Sopenharmony_ci bits |= XR_UART_STOP_2; 74162306a36Sopenharmony_ci else 74262306a36Sopenharmony_ci bits |= XR_UART_STOP_1; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci ret = xr_set_reg_uart(port, XR21V141X_REG_FORMAT, bits); 74562306a36Sopenharmony_ci if (ret) 74662306a36Sopenharmony_ci return; 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic void xr_cdc_set_line_coding(struct tty_struct *tty, 75062306a36Sopenharmony_ci struct usb_serial_port *port, 75162306a36Sopenharmony_ci const struct ktermios *old_termios) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 75462306a36Sopenharmony_ci struct usb_host_interface *alt = port->serial->interface->cur_altsetting; 75562306a36Sopenharmony_ci struct usb_device *udev = port->serial->dev; 75662306a36Sopenharmony_ci struct usb_cdc_line_coding *lc; 75762306a36Sopenharmony_ci int ret; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci lc = kzalloc(sizeof(*lc), GFP_KERNEL); 76062306a36Sopenharmony_ci if (!lc) 76162306a36Sopenharmony_ci return; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (tty->termios.c_ospeed) 76462306a36Sopenharmony_ci lc->dwDTERate = cpu_to_le32(tty->termios.c_ospeed); 76562306a36Sopenharmony_ci else 76662306a36Sopenharmony_ci lc->dwDTERate = cpu_to_le32(9600); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (C_CSTOPB(tty)) 76962306a36Sopenharmony_ci lc->bCharFormat = USB_CDC_2_STOP_BITS; 77062306a36Sopenharmony_ci else 77162306a36Sopenharmony_ci lc->bCharFormat = USB_CDC_1_STOP_BITS; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (C_PARENB(tty)) { 77462306a36Sopenharmony_ci if (C_CMSPAR(tty)) { 77562306a36Sopenharmony_ci if (C_PARODD(tty)) 77662306a36Sopenharmony_ci lc->bParityType = USB_CDC_MARK_PARITY; 77762306a36Sopenharmony_ci else 77862306a36Sopenharmony_ci lc->bParityType = USB_CDC_SPACE_PARITY; 77962306a36Sopenharmony_ci } else { 78062306a36Sopenharmony_ci if (C_PARODD(tty)) 78162306a36Sopenharmony_ci lc->bParityType = USB_CDC_ODD_PARITY; 78262306a36Sopenharmony_ci else 78362306a36Sopenharmony_ci lc->bParityType = USB_CDC_EVEN_PARITY; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci } else { 78662306a36Sopenharmony_ci lc->bParityType = USB_CDC_NO_PARITY; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (!data->type->have_5_6_bit_mode && 79062306a36Sopenharmony_ci (C_CSIZE(tty) == CS5 || C_CSIZE(tty) == CS6)) { 79162306a36Sopenharmony_ci tty->termios.c_cflag &= ~CSIZE; 79262306a36Sopenharmony_ci if (old_termios) 79362306a36Sopenharmony_ci tty->termios.c_cflag |= old_termios->c_cflag & CSIZE; 79462306a36Sopenharmony_ci else 79562306a36Sopenharmony_ci tty->termios.c_cflag |= CS8; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci switch (C_CSIZE(tty)) { 79962306a36Sopenharmony_ci case CS5: 80062306a36Sopenharmony_ci lc->bDataBits = 5; 80162306a36Sopenharmony_ci break; 80262306a36Sopenharmony_ci case CS6: 80362306a36Sopenharmony_ci lc->bDataBits = 6; 80462306a36Sopenharmony_ci break; 80562306a36Sopenharmony_ci case CS7: 80662306a36Sopenharmony_ci lc->bDataBits = 7; 80762306a36Sopenharmony_ci break; 80862306a36Sopenharmony_ci case CS8: 80962306a36Sopenharmony_ci default: 81062306a36Sopenharmony_ci lc->bDataBits = 8; 81162306a36Sopenharmony_ci break; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 81562306a36Sopenharmony_ci USB_CDC_REQ_SET_LINE_CODING, 81662306a36Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_INTERFACE, 81762306a36Sopenharmony_ci 0, alt->desc.bInterfaceNumber, 81862306a36Sopenharmony_ci lc, sizeof(*lc), USB_CTRL_SET_TIMEOUT); 81962306a36Sopenharmony_ci if (ret < 0) 82062306a36Sopenharmony_ci dev_err(&port->dev, "Failed to set line coding: %d\n", ret); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci kfree(lc); 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic void xr_sanitize_serial_rs485(struct serial_rs485 *rs485) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci if (!(rs485->flags & SER_RS485_ENABLED)) { 82862306a36Sopenharmony_ci memset(rs485, 0, sizeof(*rs485)); 82962306a36Sopenharmony_ci return; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* RTS always toggles after TX */ 83362306a36Sopenharmony_ci if (rs485->flags & SER_RS485_RTS_ON_SEND) 83462306a36Sopenharmony_ci rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; 83562306a36Sopenharmony_ci else 83662306a36Sopenharmony_ci rs485->flags |= SER_RS485_RTS_AFTER_SEND; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* Only the flags are implemented at the moment */ 83962306a36Sopenharmony_ci rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | 84062306a36Sopenharmony_ci SER_RS485_RTS_AFTER_SEND; 84162306a36Sopenharmony_ci rs485->delay_rts_before_send = 0; 84262306a36Sopenharmony_ci rs485->delay_rts_after_send = 0; 84362306a36Sopenharmony_ci memset(rs485->padding, 0, sizeof(rs485->padding)); 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int xr_get_rs485_config(struct tty_struct *tty, 84762306a36Sopenharmony_ci struct serial_rs485 __user *argp) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 85062306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci down_read(&tty->termios_rwsem); 85362306a36Sopenharmony_ci if (copy_to_user(argp, &data->rs485, sizeof(data->rs485))) { 85462306a36Sopenharmony_ci up_read(&tty->termios_rwsem); 85562306a36Sopenharmony_ci return -EFAULT; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci up_read(&tty->termios_rwsem); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci return 0; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic int xr_set_rs485_config(struct tty_struct *tty, 86362306a36Sopenharmony_ci struct serial_rs485 __user *argp) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 86662306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 86762306a36Sopenharmony_ci struct serial_rs485 rs485; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (copy_from_user(&rs485, argp, sizeof(rs485))) 87062306a36Sopenharmony_ci return -EFAULT; 87162306a36Sopenharmony_ci xr_sanitize_serial_rs485(&rs485); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci down_write(&tty->termios_rwsem); 87462306a36Sopenharmony_ci data->rs485 = rs485; 87562306a36Sopenharmony_ci xr_set_flow_mode(tty, port, NULL); 87662306a36Sopenharmony_ci up_write(&tty->termios_rwsem); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (copy_to_user(argp, &rs485, sizeof(rs485))) 87962306a36Sopenharmony_ci return -EFAULT; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci return 0; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic int xr_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci switch (cmd) { 88962306a36Sopenharmony_ci case TIOCGRS485: 89062306a36Sopenharmony_ci return xr_get_rs485_config(tty, argp); 89162306a36Sopenharmony_ci case TIOCSRS485: 89262306a36Sopenharmony_ci return xr_set_rs485_config(tty, argp); 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci return -ENOIOCTLCMD; 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic void xr_set_termios(struct tty_struct *tty, 89962306a36Sopenharmony_ci struct usb_serial_port *port, 90062306a36Sopenharmony_ci const struct ktermios *old_termios) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci /* 90562306a36Sopenharmony_ci * XR21V141X does not have a CUSTOM_DRIVER flag and always enters CDC 90662306a36Sopenharmony_ci * mode upon receiving CDC requests. 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_ci if (data->type->set_line_settings) 90962306a36Sopenharmony_ci data->type->set_line_settings(tty, port, old_termios); 91062306a36Sopenharmony_ci else 91162306a36Sopenharmony_ci xr_cdc_set_line_coding(tty, port, old_termios); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci xr_set_flow_mode(tty, port, old_termios); 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic int xr_open(struct tty_struct *tty, struct usb_serial_port *port) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci int ret; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci ret = xr_fifo_reset(port); 92162306a36Sopenharmony_ci if (ret) 92262306a36Sopenharmony_ci return ret; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ret = xr_uart_enable(port); 92562306a36Sopenharmony_ci if (ret) { 92662306a36Sopenharmony_ci dev_err(&port->dev, "Failed to enable UART\n"); 92762306a36Sopenharmony_ci return ret; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* Setup termios */ 93162306a36Sopenharmony_ci if (tty) 93262306a36Sopenharmony_ci xr_set_termios(tty, port, NULL); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci ret = usb_serial_generic_open(tty, port); 93562306a36Sopenharmony_ci if (ret) { 93662306a36Sopenharmony_ci xr_uart_disable(port); 93762306a36Sopenharmony_ci return ret; 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return 0; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic void xr_close(struct usb_serial_port *port) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci usb_serial_generic_close(port); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci xr_uart_disable(port); 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic int xr_probe(struct usb_serial *serial, const struct usb_device_id *id) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct usb_interface *control = serial->interface; 95362306a36Sopenharmony_ci struct usb_host_interface *alt = control->cur_altsetting; 95462306a36Sopenharmony_ci struct usb_cdc_parsed_header hdrs; 95562306a36Sopenharmony_ci struct usb_cdc_union_desc *desc; 95662306a36Sopenharmony_ci struct usb_interface *data; 95762306a36Sopenharmony_ci int ret; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci ret = cdc_parse_cdc_header(&hdrs, control, alt->extra, alt->extralen); 96062306a36Sopenharmony_ci if (ret < 0) 96162306a36Sopenharmony_ci return -ENODEV; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci desc = hdrs.usb_cdc_union_desc; 96462306a36Sopenharmony_ci if (!desc) 96562306a36Sopenharmony_ci return -ENODEV; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci data = usb_ifnum_to_if(serial->dev, desc->bSlaveInterface0); 96862306a36Sopenharmony_ci if (!data) 96962306a36Sopenharmony_ci return -ENODEV; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci ret = usb_serial_claim_interface(serial, data); 97262306a36Sopenharmony_ci if (ret) 97362306a36Sopenharmony_ci return ret; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci usb_set_serial_data(serial, (void *)id->driver_info); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci return 0; 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic int xr_gpio_init(struct usb_serial_port *port, const struct xr_type *type) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci u16 mask, mode; 98362306a36Sopenharmony_ci int ret; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* 98662306a36Sopenharmony_ci * Configure all pins as GPIO except for Receive and Transmit Toggle. 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_ci mode = 0; 98962306a36Sopenharmony_ci if (type->have_xmit_toggle) 99062306a36Sopenharmony_ci mode |= XR_GPIO_MODE_RX_TOGGLE | XR_GPIO_MODE_TX_TOGGLE; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci ret = xr_set_reg_uart(port, type->gpio_mode, mode); 99362306a36Sopenharmony_ci if (ret) 99462306a36Sopenharmony_ci return ret; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* 99762306a36Sopenharmony_ci * Configure DTR and RTS as outputs and make sure they are deasserted 99862306a36Sopenharmony_ci * (active low), and configure RI, CD, DSR and CTS as inputs. 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_ci mask = XR_GPIO_DTR | XR_GPIO_RTS; 100162306a36Sopenharmony_ci ret = xr_set_reg_uart(port, type->gpio_direction, mask); 100262306a36Sopenharmony_ci if (ret) 100362306a36Sopenharmony_ci return ret; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci ret = xr_set_reg_uart(port, type->gpio_set, mask); 100662306a36Sopenharmony_ci if (ret) 100762306a36Sopenharmony_ci return ret; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci return 0; 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic int xr_port_probe(struct usb_serial_port *port) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct usb_interface_descriptor *desc; 101562306a36Sopenharmony_ci const struct xr_type *type; 101662306a36Sopenharmony_ci struct xr_data *data; 101762306a36Sopenharmony_ci enum xr_type_id type_id; 101862306a36Sopenharmony_ci int ret; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci type_id = (int)(unsigned long)usb_get_serial_data(port->serial); 102162306a36Sopenharmony_ci type = &xr_types[type_id]; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 102462306a36Sopenharmony_ci if (!data) 102562306a36Sopenharmony_ci return -ENOMEM; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci data->type = type; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci desc = &port->serial->interface->cur_altsetting->desc; 103062306a36Sopenharmony_ci if (type_id == XR21V141X) 103162306a36Sopenharmony_ci data->channel = desc->bInterfaceNumber / 2; 103262306a36Sopenharmony_ci else 103362306a36Sopenharmony_ci data->channel = desc->bInterfaceNumber; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci usb_set_serial_port_data(port, data); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (type->custom_driver) { 103862306a36Sopenharmony_ci ret = xr_set_reg_uart(port, type->custom_driver, 103962306a36Sopenharmony_ci XR_CUSTOM_DRIVER_ACTIVE); 104062306a36Sopenharmony_ci if (ret) 104162306a36Sopenharmony_ci goto err_free; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci ret = xr_gpio_init(port, type); 104562306a36Sopenharmony_ci if (ret) 104662306a36Sopenharmony_ci goto err_free; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci return 0; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cierr_free: 105162306a36Sopenharmony_ci kfree(data); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci return ret; 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic void xr_port_remove(struct usb_serial_port *port) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci struct xr_data *data = usb_get_serial_port_data(port); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci kfree(data); 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci#define XR_DEVICE(vid, pid, type) \ 106462306a36Sopenharmony_ci USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_COMM), \ 106562306a36Sopenharmony_ci .driver_info = (type) 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic const struct usb_device_id id_table[] = { 106862306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1400, XR2280X) }, 106962306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1401, XR2280X) }, 107062306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1402, XR2280X) }, 107162306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1403, XR2280X) }, 107262306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1410, XR21V141X) }, 107362306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1411, XR21B1411) }, 107462306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1412, XR21V141X) }, 107562306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1414, XR21V141X) }, 107662306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1420, XR21B142X) }, 107762306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1422, XR21B142X) }, 107862306a36Sopenharmony_ci { XR_DEVICE(0x04e2, 0x1424, XR21B142X) }, 107962306a36Sopenharmony_ci { } 108062306a36Sopenharmony_ci}; 108162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic struct usb_serial_driver xr_device = { 108462306a36Sopenharmony_ci .driver = { 108562306a36Sopenharmony_ci .owner = THIS_MODULE, 108662306a36Sopenharmony_ci .name = "xr_serial", 108762306a36Sopenharmony_ci }, 108862306a36Sopenharmony_ci .id_table = id_table, 108962306a36Sopenharmony_ci .num_ports = 1, 109062306a36Sopenharmony_ci .probe = xr_probe, 109162306a36Sopenharmony_ci .port_probe = xr_port_probe, 109262306a36Sopenharmony_ci .port_remove = xr_port_remove, 109362306a36Sopenharmony_ci .open = xr_open, 109462306a36Sopenharmony_ci .close = xr_close, 109562306a36Sopenharmony_ci .break_ctl = xr_break_ctl, 109662306a36Sopenharmony_ci .set_termios = xr_set_termios, 109762306a36Sopenharmony_ci .tiocmget = xr_tiocmget, 109862306a36Sopenharmony_ci .tiocmset = xr_tiocmset, 109962306a36Sopenharmony_ci .ioctl = xr_ioctl, 110062306a36Sopenharmony_ci .dtr_rts = xr_dtr_rts 110162306a36Sopenharmony_ci}; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 110462306a36Sopenharmony_ci &xr_device, NULL 110562306a36Sopenharmony_ci}; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ciMODULE_AUTHOR("Manivannan Sadhasivam <mani@kernel.org>"); 111062306a36Sopenharmony_ciMODULE_DESCRIPTION("MaxLinear/Exar USB to Serial driver"); 111162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1112