Commit 8e9910c5 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'usb-serial-5.14-rc1' of...

Merge tag 'usb-serial-5.14-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next

Johan writes:

USB-serial updates for 5.14-rc1

Here are the USB-serial updates for 5.14-rc1, including:

 - gpio support for CP2108
 - chars_in_buffer and write_room return-value updates
 - chars_in_buffer and write_room clean ups

Included are also various clean ups.

All have been in linux-next with no reported issues.

* tag 'usb-serial-5.14-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial:
  USB: serial: cp210x: add support for GPIOs on CP2108
  USB: serial: drop irq-flags initialisations
  USB: serial: mos7840: drop buffer-callback return-value comments
  USB: serial: mos7720: drop buffer-callback sanity checks
  USB: serial: io_edgeport: drop buffer-callback sanity checks
  USB: serial: digi_acceleport: add chars_in_buffer locking
  USB: serial: digi_acceleport: reduce chars_in_buffer over-reporting
  USB: serial: make usb_serial_driver::chars_in_buffer return uint
  USB: serial: make usb_serial_driver::write_room return uint
parents 00a738b8 8051334e
Loading
Loading
Loading
Loading
+170 −19
Original line number Diff line number Diff line
@@ -247,9 +247,9 @@ struct cp210x_serial_private {
#ifdef CONFIG_GPIOLIB
	struct gpio_chip	gc;
	bool			gpio_registered;
	u8			gpio_pushpull;
	u8			gpio_altfunc;
	u8			gpio_input;
	u16			gpio_pushpull;
	u16			gpio_altfunc;
	u16			gpio_input;
#endif
	u8			partnum;
	u32			fw_version;
@@ -534,6 +534,48 @@ struct cp210x_single_port_config {
#define CP2104_GPIO1_RXLED_MODE		BIT(1)
#define CP2104_GPIO2_RS485_MODE		BIT(2)

struct cp210x_quad_port_state {
	__le16 gpio_mode_pb0;
	__le16 gpio_mode_pb1;
	__le16 gpio_mode_pb2;
	__le16 gpio_mode_pb3;
	__le16 gpio_mode_pb4;

	__le16 gpio_lowpower_pb0;
	__le16 gpio_lowpower_pb1;
	__le16 gpio_lowpower_pb2;
	__le16 gpio_lowpower_pb3;
	__le16 gpio_lowpower_pb4;

	__le16 gpio_latch_pb0;
	__le16 gpio_latch_pb1;
	__le16 gpio_latch_pb2;
	__le16 gpio_latch_pb3;
	__le16 gpio_latch_pb4;
};

/*
 * 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 {
	struct cp210x_quad_port_state reset_state;
	struct cp210x_quad_port_state suspend_state;
	u8 ipdelay_ifc[4];
	u8 enhancedfxn_ifc[4];
	u8 enhancedfxn_device;
	u8 extclkfreq[4];
} __packed;

#define CP2108_EF_IFC_GPIO_TXLED		0x01
#define CP2108_EF_IFC_GPIO_RXLED		0x02
#define CP2108_EF_IFC_GPIO_RS485		0x04
#define CP2108_EF_IFC_GPIO_RS485_LOGIC		0x08
#define CP2108_EF_IFC_GPIO_CLOCK		0x10
#define CP2108_EF_IFC_DYNAMIC_SUSPEND		0x40

/* CP2102N configuration array indices */
#define CP210X_2NCONFIG_CONFIG_VERSION_IDX	2
#define CP210X_2NCONFIG_GPIO_MODE_IDX		581
@@ -546,12 +588,24 @@ struct cp210x_single_port_config {
#define CP2102N_QFN20_GPIO1_RS485_MODE		BIT(4)
#define CP2102N_QFN20_GPIO0_CLK_MODE		BIT(6)

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

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

/*
 * Helper to get interface number when we only have struct usb_serial.
 */
@@ -1434,52 +1488,84 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
	struct usb_serial *serial = gpiochip_get_data(gc);
	struct cp210x_serial_private *priv = usb_get_serial_data(serial);
	u8 req_type = REQTYPE_DEVICE_TO_HOST;
	u8 req_type;
	u16 mask;
	int result;
	u8 buf;

	if (priv->partnum == CP210X_PARTNUM_CP2105)
		req_type = REQTYPE_INTERFACE_TO_HOST;
	int len;

	result = usb_autopm_get_interface(serial->interface);
	if (result)
		return result;

	result = cp210x_read_vendor_block(serial, req_type,
					  CP210X_READ_LATCH, &buf, sizeof(buf));
	switch (priv->partnum) {
	case CP210X_PARTNUM_CP2105:
		req_type = REQTYPE_INTERFACE_TO_HOST;
		len = 1;
		break;
	case CP210X_PARTNUM_CP2108:
		req_type = REQTYPE_INTERFACE_TO_HOST;
		len = 2;
		break;
	default:
		req_type = REQTYPE_DEVICE_TO_HOST;
		len = 1;
		break;
	}

	mask = 0;
	result = cp210x_read_vendor_block(serial, req_type, CP210X_READ_LATCH,
					  &mask, len);

	usb_autopm_put_interface(serial->interface);

	if (result < 0)
		return result;

	return !!(buf & BIT(gpio));
	le16_to_cpus(&mask);

	return !!(mask & BIT(gpio));
}

static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
	struct usb_serial *serial = gpiochip_get_data(gc);
	struct cp210x_serial_private *priv = usb_get_serial_data(serial);
	struct cp210x_gpio_write16 buf16;
	struct cp210x_gpio_write buf;
	u16 mask, state;
	u16 wIndex;
	int result;

	if (value == 1)
		buf.state = BIT(gpio);
		state = BIT(gpio);
	else
		buf.state = 0;
		state = 0;

	buf.mask = BIT(gpio);
	mask = BIT(gpio);

	result = usb_autopm_get_interface(serial->interface);
	if (result)
		goto out;

	if (priv->partnum == CP210X_PARTNUM_CP2105) {
	switch (priv->partnum) {
	case CP210X_PARTNUM_CP2105:
		buf.mask = (u8)mask;
		buf.state = (u8)state;
		result = cp210x_write_vendor_block(serial,
						   REQTYPE_HOST_TO_INTERFACE,
						   CP210X_WRITE_LATCH, &buf,
						   sizeof(buf));
	} else {
		u16 wIndex = buf.state << 8 | buf.mask;

		break;
	case CP210X_PARTNUM_CP2108:
		buf16.mask = cpu_to_le16(mask);
		buf16.state = cpu_to_le16(state);
		result = cp210x_write_vendor_block(serial,
						   REQTYPE_HOST_TO_INTERFACE,
						   CP210X_WRITE_LATCH, &buf16,
						   sizeof(buf16));
		break;
	default:
		wIndex = state << 8 | mask;
		result = usb_control_msg(serial->dev,
					 usb_sndctrlpipe(serial->dev, 0),
					 CP210X_VENDOR_SPECIFIC,
@@ -1487,6 +1573,7 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
					 CP210X_WRITE_LATCH,
					 wIndex,
					 NULL, 0, USB_CTRL_SET_TIMEOUT);
		break;
	}

	usb_autopm_put_interface(serial->interface);
@@ -1696,6 +1783,61 @@ static int cp2104_gpioconf_init(struct usb_serial *serial)
	return 0;
}

static int cp2108_gpio_init(struct usb_serial *serial)
{
	struct cp210x_serial_private *priv = usb_get_serial_data(serial);
	struct cp210x_quad_port_config config;
	u16 gpio_latch;
	int result;
	u8 i;

	result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
					  CP210X_GET_PORTCONFIG, &config,
					  sizeof(config));
	if (result < 0)
		return result;

	priv->gc.ngpio = 16;
	priv->gpio_pushpull = le16_to_cpu(config.reset_state.gpio_mode_pb1);
	gpio_latch = le16_to_cpu(config.reset_state.gpio_latch_pb1);

	/*
	 * Mark all pins which are not in GPIO mode.
	 *
	 * Refer to table 9.1 "GPIO Mode alternate Functions" in the datasheet:
	 * https://www.silabs.com/documents/public/data-sheets/cp2108-datasheet.pdf
	 *
	 * Alternate functions of GPIO0 to GPIO3 are determine by enhancedfxn_ifc[0]
	 * and the similarly for the other pins; enhancedfxn_ifc[1]: GPIO4 to GPIO7,
	 * enhancedfxn_ifc[2]: GPIO8 to GPIO11, enhancedfxn_ifc[3]: GPIO12 to GPIO15.
	 */
	for (i = 0; i < 4; i++) {
		if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_TXLED)
			priv->gpio_altfunc |= BIT(i * 4);
		if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_RXLED)
			priv->gpio_altfunc |= BIT((i * 4) + 1);
		if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_RS485)
			priv->gpio_altfunc |= BIT((i * 4) + 2);
		if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_CLOCK)
			priv->gpio_altfunc |= BIT((i * 4) + 3);
	}

	/*
	 * Like CP2102N, CP2108 has also no strict input and output pin
	 * modes. Do the same input mode emulation as CP2102N.
	 */
	for (i = 0; i < priv->gc.ngpio; ++i) {
		/*
		 * Set direction to "input" iff pin is open-drain and reset
		 * value is 1.
		 */
		if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i)))
			priv->gpio_input |= BIT(i);
	}

	return 0;
}

static int cp2102n_gpioconf_init(struct usb_serial *serial)
{
	struct cp210x_serial_private *priv = usb_get_serial_data(serial);
@@ -1812,6 +1954,15 @@ static int cp210x_gpio_init(struct usb_serial *serial)
	case CP210X_PARTNUM_CP2105:
		result = cp2105_gpioconf_init(serial);
		break;
	case CP210X_PARTNUM_CP2108:
		/*
		 * The GPIOs are not tied to any specific port so only register
		 * once for interface 0.
		 */
		if (cp210x_interface_num(serial) != 0)
			return 0;
		result = cp2108_gpio_init(serial);
		break;
	case CP210X_PARTNUM_CP2102N_QFN28:
	case CP210X_PARTNUM_CP2102N_QFN24:
	case CP210X_PARTNUM_CP2102N_QFN20:
+2 −2
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ static int cyberjack_open(struct tty_struct *tty,
static void cyberjack_close(struct usb_serial_port *port);
static int cyberjack_write(struct tty_struct *tty,
	struct usb_serial_port *port, const unsigned char *buf, int count);
static int cyberjack_write_room(struct tty_struct *tty);
static unsigned int cyberjack_write_room(struct tty_struct *tty);
static void cyberjack_read_int_callback(struct urb *urb);
static void cyberjack_read_bulk_callback(struct urb *urb);
static void cyberjack_write_bulk_callback(struct urb *urb);
@@ -240,7 +240,7 @@ static int cyberjack_write(struct tty_struct *tty,
	return count;
}

static int cyberjack_write_room(struct tty_struct *tty)
static unsigned int cyberjack_write_room(struct tty_struct *tty)
{
	/* FIXME: .... */
	return CYBERJACK_LOCAL_BUF_SIZE;
+8 −8
Original line number Diff line number Diff line
@@ -122,14 +122,14 @@ static void cypress_dtr_rts(struct usb_serial_port *port, int on);
static int  cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
			const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
static int  cypress_write_room(struct tty_struct *tty);
static unsigned int cypress_write_room(struct tty_struct *tty);
static void cypress_earthmate_init_termios(struct tty_struct *tty);
static void cypress_set_termios(struct tty_struct *tty,
			struct usb_serial_port *port, struct ktermios *old);
static int  cypress_tiocmget(struct tty_struct *tty);
static int  cypress_tiocmset(struct tty_struct *tty,
			unsigned int set, unsigned int clear);
static int  cypress_chars_in_buffer(struct tty_struct *tty);
static unsigned int cypress_chars_in_buffer(struct tty_struct *tty);
static void cypress_throttle(struct tty_struct *tty);
static void cypress_unthrottle(struct tty_struct *tty);
static void cypress_set_dead(struct usb_serial_port *port);
@@ -789,18 +789,18 @@ static void cypress_send(struct usb_serial_port *port)


/* returns how much space is available in the soft buffer */
static int cypress_write_room(struct tty_struct *tty)
static unsigned int cypress_write_room(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int room = 0;
	unsigned int room;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
	room = kfifo_avail(&priv->write_fifo);
	spin_unlock_irqrestore(&priv->lock, flags);

	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
	dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
	return room;
}

@@ -970,18 +970,18 @@ static void cypress_set_termios(struct tty_struct *tty,


/* returns amount of data still left in soft buffer */
static int cypress_chars_in_buffer(struct tty_struct *tty)
static unsigned int cypress_chars_in_buffer(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct cypress_private *priv = usb_get_serial_port_data(port);
	int chars = 0;
	unsigned int chars;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
	chars = kfifo_len(&priv->write_fifo);
	spin_unlock_irqrestore(&priv->lock, flags);

	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
	dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
	return chars;
}

+23 −23
Original line number Diff line number Diff line
@@ -223,8 +223,8 @@ static int digi_tiocmset(struct tty_struct *tty, unsigned int set,
static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
		const unsigned char *buf, int count);
static void digi_write_bulk_callback(struct urb *urb);
static int digi_write_room(struct tty_struct *tty);
static int digi_chars_in_buffer(struct tty_struct *tty);
static unsigned int digi_write_room(struct tty_struct *tty);
static unsigned int digi_chars_in_buffer(struct tty_struct *tty);
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port);
static void digi_close(struct usb_serial_port *port);
static void digi_dtr_rts(struct usb_serial_port *port, int on);
@@ -372,7 +372,7 @@ static int digi_write_oob_command(struct usb_serial_port *port,
	int len;
	struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
	struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
	unsigned long flags = 0;
	unsigned long flags;

	dev_dbg(&port->dev,
		"digi_write_oob_command: TOP: port=%d, count=%d\n",
@@ -430,7 +430,7 @@ static int digi_write_inb_command(struct usb_serial_port *port,
	int len;
	struct digi_port *priv = usb_get_serial_port_data(port);
	unsigned char *data = port->write_urb->transfer_buffer;
	unsigned long flags = 0;
	unsigned long flags;

	dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n",
		priv->dp_port_num, count);
@@ -511,8 +511,7 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
	struct usb_serial_port *oob_port = (struct usb_serial_port *) ((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
	struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
	unsigned char *data = oob_port->write_urb->transfer_buffer;
	unsigned long flags = 0;

	unsigned long flags;

	dev_dbg(&port->dev,
		"digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n",
@@ -577,7 +576,7 @@ static int digi_transmit_idle(struct usb_serial_port *port,
	int ret;
	unsigned char buf[2];
	struct digi_port *priv = usb_get_serial_port_data(port);
	unsigned long flags = 0;
	unsigned long flags;

	spin_lock_irqsave(&priv->dp_port_lock, flags);
	priv->dp_transmit_idle = 0;
@@ -887,7 +886,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
	int ret, data_len, new_len;
	struct digi_port *priv = usb_get_serial_port_data(port);
	unsigned char *data = port->write_urb->transfer_buffer;
	unsigned long flags = 0;
	unsigned long flags;

	dev_dbg(&port->dev, "digi_write: TOP: port=%d, count=%d\n",
		priv->dp_port_num, count);
@@ -1020,12 +1019,12 @@ static void digi_write_bulk_callback(struct urb *urb)
		tty_port_tty_wakeup(&port->port);
}

static int digi_write_room(struct tty_struct *tty)
static unsigned int digi_write_room(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct digi_port *priv = usb_get_serial_port_data(port);
	int room;
	unsigned long flags = 0;
	unsigned long flags;
	unsigned int room;

	spin_lock_irqsave(&priv->dp_port_lock, flags);

@@ -1035,27 +1034,28 @@ static int digi_write_room(struct tty_struct *tty)
		room = port->bulk_out_size - 2 - priv->dp_out_buf_len;

	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
	dev_dbg(&port->dev, "digi_write_room: port=%d, room=%d\n", priv->dp_port_num, room);
	dev_dbg(&port->dev, "digi_write_room: port=%d, room=%u\n", priv->dp_port_num, room);
	return room;

}

static int digi_chars_in_buffer(struct tty_struct *tty)
static unsigned int digi_chars_in_buffer(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct digi_port *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	unsigned int chars;

	if (priv->dp_write_urb_in_use) {
		dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n",
			priv->dp_port_num, port->bulk_out_size - 2);
		/* return(port->bulk_out_size - 2); */
		return 256;
	} else {
		dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n",
			priv->dp_port_num, priv->dp_out_buf_len);
		return priv->dp_out_buf_len;
	}
	spin_lock_irqsave(&priv->dp_port_lock, flags);
	if (priv->dp_write_urb_in_use)
		chars = port->bulk_out_size - 2;
	else
		chars = priv->dp_out_buf_len;
	spin_unlock_irqrestore(&priv->dp_port_lock, flags);

	dev_dbg(&port->dev, "%s: port=%d, chars=%d\n", __func__,
			priv->dp_port_num, chars);
	return chars;
}

static void digi_dtr_rts(struct usb_serial_port *port, int on)
+1 −1
Original line number Diff line number Diff line
@@ -1113,7 +1113,7 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
}


static int garmin_write_room(struct tty_struct *tty)
static unsigned int garmin_write_room(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	/*
Loading