#define XR21V141X_MIN_SPEED 46U
#define XR21V141X_MAX_SPEED XR_INT_OSC_HZ
-/* USB Requests */
+/* USB requests */
#define XR21V141X_SET_REQ 0
#define XR21V141X_GET_REQ 1
+/* XR21V141X register blocks */
+#define XR21V141X_UART_REG_BLOCK 0
+#define XR21V141X_UM_REG_BLOCK 4
+#define XR21V141X_UART_CUSTOM_BLOCK 0x66
+
+/* XR21V141X UART registers */
#define XR21V141X_CLOCK_DIVISOR_0 0x04
#define XR21V141X_CLOCK_DIVISOR_1 0x05
#define XR21V141X_CLOCK_DIVISOR_2 0x06
#define XR21V141X_TX_CLOCK_MASK_1 0x08
#define XR21V141X_RX_CLOCK_MASK_0 0x09
#define XR21V141X_RX_CLOCK_MASK_1 0x0a
+#define XR21V141X_REG_FORMAT 0x0b
-/* XR21V141X register blocks */
-#define XR21V141X_UART_REG_BLOCK 0
-#define XR21V141X_UM_REG_BLOCK 4
-#define XR21V141X_UART_CUSTOM_BLOCK 0x66
-
-/* XR21V141X UART Manager Registers */
+/* XR21V141X UART Manager registers */
#define XR21V141X_UM_FIFO_ENABLE_REG 0x10
#define XR21V141X_UM_ENABLE_TX_FIFO 0x01
#define XR21V141X_UM_ENABLE_RX_FIFO 0x02
#define XR_GPIO_MODE_RS485 0x3
#define XR_GPIO_MODE_RS485_ADDR 0x4
-#define XR21V141X_REG_ENABLE 0x03
-#define XR21V141X_REG_FORMAT 0x0b
-#define XR21V141X_REG_FLOW_CTRL 0x0c
-#define XR21V141X_REG_XON_CHAR 0x10
-#define XR21V141X_REG_XOFF_CHAR 0x11
-#define XR21V141X_REG_LOOPBACK 0x12
-#define XR21V141X_REG_TX_BREAK 0x14
-#define XR21V141X_REG_RS845_DELAY 0x15
-#define XR21V141X_REG_GPIO_MODE 0x1a
-#define XR21V141X_REG_GPIO_DIR 0x1b
-#define XR21V141X_REG_GPIO_INT_MASK 0x1c
-#define XR21V141X_REG_GPIO_SET 0x1d
-#define XR21V141X_REG_GPIO_CLR 0x1e
-#define XR21V141X_REG_GPIO_STATUS 0x1f
+struct xr_type {
+ 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;
+};
+
+enum xr_type_id {
+ XR21V141X,
+ XR_TYPE_COUNT,
+};
+
+static const struct xr_type xr_types[] = {
+ [XR21V141X] = {
+ .uart_enable = 0x03,
+ .flow_control = 0x0c,
+ .xon_char = 0x10,
+ .xoff_char = 0x11,
+ .tx_break = 0x14,
+ .gpio_mode = 0x1a,
+ .gpio_direction = 0x1b,
+ .gpio_set = 0x1d,
+ .gpio_clear = 0x1e,
+ .gpio_status = 0x1f,
+ },
+};
struct xr_data {
- u8 channel; /* zero-based index */
+ const struct xr_type *type;
+ u8 channel; /* zero-based index */
};
static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val)
*/
static int xr_uart_enable(struct usb_serial_port *port)
{
+ struct xr_data *data = usb_get_serial_port_data(port);
int ret;
ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG,
if (ret)
return ret;
- ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE,
+ ret = xr_set_reg_uart(port, data->type->uart_enable,
XR_UART_ENABLE_TX | XR_UART_ENABLE_RX);
if (ret)
return ret;
ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG,
XR21V141X_UM_ENABLE_TX_FIFO | XR21V141X_UM_ENABLE_RX_FIFO);
-
if (ret)
- xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0);
+ xr_set_reg_uart(port, data->type->uart_enable, 0);
return ret;
}
static int xr_uart_disable(struct usb_serial_port *port)
{
+ struct xr_data *data = usb_get_serial_port_data(port);
int ret;
- ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0);
+ ret = xr_set_reg_uart(port, data->type->uart_enable, 0);
if (ret)
return ret;
static int xr_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
+ struct xr_data *data = usb_get_serial_port_data(port);
u8 status;
int ret;
- ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_STATUS, &status);
+ ret = xr_get_reg_uart(port, data->type->gpio_status, &status);
if (ret)
return ret;
static int xr_tiocmset_port(struct usb_serial_port *port,
unsigned int set, unsigned int clear)
{
+ struct xr_data *data = usb_get_serial_port_data(port);
+ const struct xr_type *type = data->type;
u8 gpio_set = 0;
u8 gpio_clr = 0;
int ret = 0;
/* Writing '0' to gpio_{set/clr} bits has no effect, so no need to do */
if (gpio_clr)
- ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_CLR, gpio_clr);
+ ret = xr_set_reg_uart(port, type->gpio_clear, gpio_clr);
if (gpio_set)
- ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_SET, gpio_set);
+ ret = xr_set_reg_uart(port, type->gpio_set, gpio_set);
return ret;
}
static void xr_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
+ struct xr_data *data = usb_get_serial_port_data(port);
+ const struct xr_type *type = data->type;
u8 state;
if (break_state == 0)
dev_dbg(&port->dev, "Turning break %s\n",
state == XR21V141X_UART_BREAK_OFF ? "off" : "on");
- xr_set_reg_uart(port, XR21V141X_REG_TX_BREAK, state);
+ xr_set_reg_uart(port, type->tx_break, state);
}
/* Tx and Rx clock mask values obtained from section 3.3.4 of datasheet */
struct usb_serial_port *port,
struct ktermios *old_termios)
{
+ struct xr_data *data = usb_get_serial_port_data(port);
+ const struct xr_type *type = data->type;
u8 flow, gpio_mode;
int ret;
- ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_MODE, &gpio_mode);
+ ret = xr_get_reg_uart(port, type->gpio_mode, &gpio_mode);
if (ret)
return;
dev_dbg(&port->dev, "Enabling sw flow ctrl\n");
flow = XR_UART_FLOW_MODE_SW;
- xr_set_reg_uart(port, XR21V141X_REG_XON_CHAR, start_char);
- xr_set_reg_uart(port, XR21V141X_REG_XOFF_CHAR, stop_char);
+ xr_set_reg_uart(port, type->xon_char, start_char);
+ xr_set_reg_uart(port, type->xoff_char, stop_char);
} else {
dev_dbg(&port->dev, "Disabling flow ctrl\n");
flow = XR_UART_FLOW_MODE_NONE;
* FLOW_CONTROL register.
*/
xr_uart_disable(port);
- xr_set_reg_uart(port, XR21V141X_REG_FLOW_CTRL, flow);
+ xr_set_reg_uart(port, type->flow_control, flow);
xr_uart_enable(port);
- xr_set_reg_uart(port, XR21V141X_REG_GPIO_MODE, gpio_mode);
+ xr_set_reg_uart(port, type->gpio_mode, gpio_mode);
if (C_BAUD(tty) == B0)
xr_dtr_rts(port, 0);
if (ret)
return ret;
+ usb_set_serial_data(serial, (void *)id->driver_info);
+
return 0;
}
-static int xr_gpio_init(struct usb_serial_port *port)
+static int xr_gpio_init(struct usb_serial_port *port, const struct xr_type *type)
{
u8 mask, mode;
int ret;
/* Configure all pins as GPIO. */
mode = 0;
- ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_MODE, mode);
+ ret = xr_set_reg_uart(port, type->gpio_mode, mode);
if (ret)
return ret;
* (active low), and configure RI, CD, DSR and CTS as inputs.
*/
mask = XR_GPIO_DTR | XR_GPIO_RTS;
- ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_DIR, mask);
+ ret = xr_set_reg_uart(port, type->gpio_direction, mask);
if (ret)
return ret;
- ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_SET, mask);
+ ret = xr_set_reg_uart(port, type->gpio_set, mask);
if (ret)
return ret;
static int xr_port_probe(struct usb_serial_port *port)
{
struct usb_interface_descriptor *desc;
+ const struct xr_type *type;
struct xr_data *data;
+ enum xr_type_id type_id;
int ret;
+ type_id = (int)(unsigned long)usb_get_serial_data(port->serial);
+ type = &xr_types[type_id];
+
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ data->type = type;
+
desc = &port->serial->interface->cur_altsetting->desc;
data->channel = desc->bInterfaceNumber / 2;
usb_set_serial_port_data(port, data);
- ret = xr_gpio_init(port);
+ ret = xr_gpio_init(port, type);
if (ret)
goto err_free;
kfree(data);
}
+#define XR_DEVICE(vid, pid, type) \
+ USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_COMM), \
+ .driver_info = (type)
+
static const struct usb_device_id id_table[] = {
- { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1410, USB_CLASS_COMM) }, /* XR21V1410 */
- { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1412, USB_CLASS_COMM) }, /* XR21V1412 */
- { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1414, USB_CLASS_COMM) }, /* XR21V1414 */
+ { XR_DEVICE(0x04e2, 0x1410, XR21V141X) },
+ { XR_DEVICE(0x04e2, 0x1412, XR21V141X) },
+ { XR_DEVICE(0x04e2, 0x1414, XR21V141X) },
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);