Skip to contentSkip to conversation

RFC: WIP: sc16is7xx [v0.4]

PATCH In review [email protected] 3 participants 9 messages Mar 10, 2014 – Mar 11, 2014 TTY layer and serial drivers

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 RFC: WIP: sc16is7xx [v0.4]

From: Jon Ringle <[email protected]>

I started over and rewrote this driver patternized on sccnxp.c

However, I am still experiencing major latency problems with this driver at 19200 speeds.

The method that I'm testing is simply transferring a small file just over 4k in size.

On the target platform I do:

$ socat /dev/ttySC0,raw,echo=0,b19200 - > rx-file

On my development machine, I do:

$ socat /dev/ttyUSB1,echo=0,raw,time=1,min=255,b19200 FILE:./tx-file

When the socat running on the development machine returns to the prompt, it has transmitted all the bytes in tx-file. I then kill the socat running on the target platform. Success is defined as rx-file being identical to tx-file. However, I find that even at only 19200, this driver fails to receive all bytes sent.

I welcome any and all comments.

Thank you,
Jon

---
 drivers/tty/serial/Kconfig       |   7 +
 drivers/tty/serial/Makefile      |   1 +
 drivers/tty/serial/sc16is7xx.c   | 730 +++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h |   3 +
 4 files changed, 741 insertions(+)
 create mode 100644 drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/Kconfig +7 -0
index febd45c..1dfaeec 100644
@@ -1179,6 +1179,13 @@ config SERIAL_SCCNXP_CONSOLE
 	help
 	  Support for console on SCCNXP serial ports.
 
+config SERIAL_SC16IS7XX
+	tristate "SC16IS7xx RS485 serial support"
+	  select SERIAL_CORE
+	  default n
+	  help
+	  This selects support for SC16IS7xx for use as a RS485 serial port
+
 config SERIAL_BFIN_SPORT
 	tristate "Blackfin SPORT emulate UART"
 	depends on BLACKFIN
drivers/tty/serial/Makefile +1 -0
index 3068c77..c3bac45 100644
@@ -49,6 +49,7 @@ obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
 obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
 obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
 obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
+obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
 obj-$(CONFIG_SERIAL_JSM) += jsm/
 obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
 obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
drivers/tty/serial/sc16is7xx.c new file +730 -0

730 lines not on this page · raw message

include/uapi/linux/serial_core.h +3 -0
index b47dba2..a37c79a 100644
@@ -238,4 +238,7 @@
 /* Tilera TILE-Gx UART */
 #define PORT_TILEGX	106
 
+/* SC16IS74xx */
+#define PORT_SC16IS7XX   107
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
Signature · 6 lines
1.8.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#1 lore raw

Понедельник, 10 марта 2014, 2:26 -04:00 от [email protected]:

Quoted 1 line

From: Jon Ringle <[email protected]>

...

drivers/tty/serial/Kconfig config SERIAL_SCCNXP_CONSOLE · line 1187

Quoted 6 lines
drivers/tty/serial/Kconfig +6 -0
+config SERIAL_SC16IS7XX
+	tristate "SC16IS7xx RS485 serial support"
+	  select SERIAL_CORE
+	  default n
+	  help
+	  This selects support for SC16IS7xx for use as a RS485 serial port

Documentation says:
The SC16IS740/750/760 is a slave I²C-bus/SPI interface to a single-channel high performance UART.
...
The SC16IS740/750/760 also provides additional advanced features such as auto hardware and software flow control, automatic RS-485 support...

So why do you position this chip as RS485 only? Automatic direction for RS485 is just a feature as an addition for standart UART.

---

author
#2 lore raw
Quoted 17 lines · Alexander Shiyan

Понедельник, 10 марта 2014, 2:26 -04:00 от [email protected]:

Quoted 1 line

From: Jon Ringle <[email protected]>

...

drivers/tty/serial/Kconfig config SERIAL_SCCNXP_CONSOLE · line 1187

Quoted 6 lines
drivers/tty/serial/Kconfig +6 -0
+config SERIAL_SC16IS7XX
+	tristate "SC16IS7xx RS485 serial support"
+	  select SERIAL_CORE
+	  default n
+	  help
+	  This selects support for SC16IS7xx for use as a RS485 serial port

Documentation says:
The SC16IS740/750/760 is a slave I²C-bus/SPI interface to a single-channel high performance UART.
...
The SC16IS740/750/760 also provides additional advanced features such as auto hardware and software flow control, automatic RS-485 support...

Quoted 2 lines

So why do you position this chip as RS485 only? Automatic direction for RS485 is just a feature as an addition for standart UART.

You're right. This is just how we are using the chip in our board. Would a configuration flag in platform_data make sense to use the auto rs485 direction?

Any thoughts as to the latency issue I report?

Thanks.

Regards,
Jon

#3 lore raw
Quoted 20 lines · On Mon, 10 Mar 2014 07:50:12 -0400 (EDT) Jon Ringle <[email protected]> wrote:
Quoted 17 lines · Alexander Shiyan

Понедельник, 10 марта 2014, 2:26 -04:00 от [email protected]:

Quoted 1 line

From: Jon Ringle <[email protected]>

...

drivers/tty/serial/Kconfig config SERIAL_SCCNXP_CONSOLE · line 1187

Quoted 6 lines
drivers/tty/serial/Kconfig +6 -0
+config SERIAL_SC16IS7XX
+	tristate "SC16IS7xx RS485 serial support"
+	  select SERIAL_CORE
+	  default n
+	  help
+	  This selects support for SC16IS7xx for use as a RS485 serial port

Documentation says:
The SC16IS740/750/760 is a slave I²C-bus/SPI interface to a single-channel high performance UART.
...
The SC16IS740/750/760 also provides additional advanced features such as auto hardware and software flow control, automatic RS-485 support...

Quoted 6 lines
Quoted 2 lines

So why do you position this chip as RS485 only? Automatic direction for RS485 is just a feature as an addition for standart UART.

You're right. This is just how we are using the chip in our board. Would a configuration flag in platform_data make sense to use the auto rs485 direction?

We have interfaces for RS485 runtime configuration so it could be extended to set a lot of parameters that way, but I think for now it might not be a bad idea to support rs485 auto direction in/out/off in the platform data.

Alan
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#4 lore raw
In reply to Jon Ringle

Понедельник, 10 марта 2014, 7:50 -04:00 от Jon Ringle <[email protected]>:

Quoted 20 lines · Alexander Shiyan
Quoted 18 lines

Понедельник, 10 марта 2014, 2:26 -04:00 от [email protected]:

Quoted 1 line

From: Jon Ringle <[email protected]>

...

drivers/tty/serial/Kconfig config SERIAL_SCCNXP_CONSOLE · line 1187

Quoted 6 lines
drivers/tty/serial/Kconfig +6 -0
+config SERIAL_SC16IS7XX
+	tristate "SC16IS7xx RS485 serial support"
+	  select SERIAL_CORE
+	  default n
+	  help
+	  This selects support for SC16IS7xx for use as a RS485 serial port

Documentation says:
The SC16IS740/750/760 is a slave I²C-bus/SPI interface to a single-channel high performance UART.
...
The SC16IS740/750/760 also provides additional advanced features such as auto hardware and software flow control, automatic RS-485 support...

Quoted 6 lines
Quoted 2 lines

So why do you position this chip as RS485 only? Automatic direction for RS485 is just a feature as an addition for standart UART.

You're right. This is just how we are using the chip in our board. Would a configuration flag in platform_data make sense to use the auto rs485 direction?

You don't need a flag, just use IOCTLs.
https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/drivers/tty/serial/max310x.c?id=55367c620aed6bc27a82bb1763366931d7f2ee66

Quoted 1 line

Any thoughts as to the latency issue I report?

I do not understand why you chose the sccnxp driver as a template. Use as a template max310x driver from linux-next branch. I'm sure it will be better.

About latency.
I'm not exactly understand the problem, but I can say the following:
Since you're using the I2C bus, maximum UART daudrate can be predicted from the I2C bus bandwidth.
Count how many I2C clocks spent on reception and transmission of one byte through UART.

---

author
#5 lore raw
Quoted 28 lines · Alexander Shiyan

Понедельник, 10 марта 2014, 7:50 -04:00 от Jon Ringle <[email protected]>:

Quoted 20 lines · Alexander Shiyan
Quoted 18 lines

Понедельник, 10 марта 2014, 2:26 -04:00 от [email protected]:

Quoted 1 line

From: Jon Ringle <[email protected]>

...

drivers/tty/serial/Kconfig config SERIAL_SCCNXP_CONSOLE · line 1187

Quoted 6 lines
drivers/tty/serial/Kconfig +6 -0
+config SERIAL_SC16IS7XX
+	tristate "SC16IS7xx RS485 serial support"
+	  select SERIAL_CORE
+	  default n
+	  help
+	  This selects support for SC16IS7xx for use as a RS485 serial port

Documentation says:
The SC16IS740/750/760 is a slave I²C-bus/SPI interface to a single-channel high performance UART.
...
The SC16IS740/750/760 also provides additional advanced features such as auto hardware and software flow control, automatic RS-485 support...

Quoted 6 lines
Quoted 2 lines

So why do you position this chip as RS485 only? Automatic direction for RS485 is just a feature as an addition for standart UART.

You're right. This is just how we are using the chip in our board. Would a configuration flag in platform_data make sense to use the auto rs485 direction?

Quoted 8 lines

You don't need a flag, just use IOCTLs.
https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/drivers/tty/serial/max310x.c?id=55367c620aed6bc27a82bb1763366931d7f2ee66

Quoted 1 line

Any thoughts as to the latency issue I report?

I do not understand why you chose the sccnxp driver as a template. Use as a template max310x driver from linux-next branch. I'm sure it will be better.

I followed your advice on using max310x as a template. One thing that I'm struggling to get right is the regmap. The datasheet[1] specifies the register bits as follows:

	Table 33. Register address byte (I2C)
	Bit	Name	Function
	7 	-	not used
	6:3 	A[3:0]	UART's internal register select
	2:1	CH1,0	channel select: CH1 = 0, CH0 = 0
			Other values are reserved and should not be used.
	0	-	not used

So, I need to shift the register address by 3. Here is how I have defined the regmap stuff:

------>8 [relevant code] >8-------
/* SC16IS7XX register definitions */
#define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */
#define SC16IS7XX_THR_REG (0x00) /* TX FIFO */
#define SC16IS7XX_IER_REG (0x01) /* Interrupt enable */
#define SC16IS7XX_IIR_REG (0x02) /* Interrupt Ident */
#define SC16IS7XX_FCR_REG (0x02) /* FIFO control */
#define SC16IS7XX_LCR_REG (0x03) /* Line Control */
#define SC16IS7XX_MCR_REG (0x04) /* Modem Control */
#define SC16IS7XX_LSR_REG (0x05) /* Line Status */
#define SC16IS7XX_MSR_REG (0x06) /* Modem Status */
#define SC16IS7XX_SPR_REG (0x07) /* Scratch Pad */
#define SC16IS7XX_TXLVL_REG (0x08) /* TX FIFO level */
#define SC16IS7XX_RXLVL_REG (0x09) /* RX FIFO level */
#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Dir (750/760) */
#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State (750/760) */
#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Int Enable (750/760) */
#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control (750/760) */
#define SC16IS7XX_EFCR_REG (0x0f) /* Extra Feature Control */

/* TX/Trigger Registers: Only if ((MCR[2] == 0) && (EFR[4] == 1)) */
#define SC16IS7XX_TCR_REG (0x06) /* Transmit control */
#define SC16IS7XX_TLR_REG (0x07) /* Trigger level */

/* Special Register set: Only if ((LCR[7] == 1) && (LCR != 0xBF)) */
#define SC16IS7XX_DLL_REG (0x00) /* Divisor Latch Low */
#define SC16IS7XX_DLH_REG (0x01) /* Divisor Latch High */

/* Enhanced Register set: Only if (LCR == 0xBF) */
#define SC16IS7XX_EFR_REG (0x02) /* Enhanced Features */
#define SC16IS7XX_XON1_REG (0x04) /* Xon1 word */
#define SC16IS7XX_XON2_REG (0x05) /* Xon2 word */
#define SC16IS7XX_XOFF1_REG (0x06) /* Xoff1 word */
#define SC16IS7XX_XOFF2_REG (0x07) /* Xoff2 word */

#define SC16IS7XX_REG_SHIFT 3

static bool sc16is7xx_reg_writeable(struct device *dev, unsigned int reg)

{
	switch ((reg >> SC16IS7XX_REG_SHIFT) & 0xf) {
	case SC16IS7XX_LSR_REG:
	case SC16IS7XX_MSR_REG:
	case SC16IS7XX_TXLVL_REG:
	case SC16IS7XX_RXLVL_REG:
		return false;
	default:
		break;
	}

	return true;
}

static bool sc16is7xx_reg_volatile(struct device *dev, unsigned int reg)

{
	switch ((reg >> SC16IS7XX_REG_SHIFT) & 0xf) {
	case SC16IS7XX_RHR_REG:
	case SC16IS7XX_IIR_REG:
	case SC16IS7XX_LSR_REG:
	case SC16IS7XX_MSR_REG:
	case SC16IS7XX_TXLVL_REG:
	case SC16IS7XX_RXLVL_REG:
	case SC16IS7XX_IOSTATE_REG:
		return true;
	default:
		break;
	}

	return false;
}

static bool sc16is7xx_reg_precious(struct device *dev, unsigned int reg)

{
	switch ((reg >> SC16IS7XX_REG_SHIFT) & 0xf) {
	case SC16IS7XX_RHR_REG:
	case SC16IS7XX_IIR_REG:
	case SC16IS7XX_MSR_REG:
		return true;
	default:
		break;
	}

	return false;
}
static struct regmap_config regcfg = {
	.reg_bits = 8,
	.reg_stride = (1 << SC16IS7XX_REG_SHIFT),
	.val_bits = 8,
	.max_register = (0xf << SC16IS7XX_REG_SHIFT),
	.cache_type = REGCACHE_RBTREE,
	.writeable_reg = sc16is7xx_reg_writeable,
	.volatile_reg = sc16is7xx_reg_volatile,
	.precious_reg = sc16is7xx_reg_precious,
};

------------->8-----------------

I'm not sure that I have this defined correctly. I also saw in regmap_config pad_bits, which I've tried setting to SC16IS7XX_REG_SHIFT, but when I do that, I get -EINVAL failure.

Thanks,
Jon

[1] http://www.nxp.com/documents/data_sheet/SC16IS740_750_760.pdf

author
#6 lore raw

I left out some relevant functions (sc16is7xx_port_read(), sc16is7xx_port_write(), sc16is7xx_port_update()) in my previous email...

Quoted 6 lines · Alexander Shiyan

Понедельник, 10 марта 2014, 7:50 -04:00 от Jon Ringle <[email protected]>:

Quoted 2 lines · Alexander Shiyan

I do not understand why you chose the sccnxp driver as a template. Use as a template max310x driver from linux-next branch. I'm sure it will be better.

I followed your advice on using max310x as a template. One thing that I'm struggling to get right is the regmap. The datasheet[1] specifies the register bits as follows:

	Table 33. Register address byte (I2C)
	Bit	Name	Function
	7 	-	not used
	6:3 	A[3:0]	UART's internal register select
	2:1	CH1,0	channel select: CH1 = 0, CH0 = 0
			Other values are reserved and should not be used.
	0	-	not used

So, I need to shift the register address by 3. Here is how I have defined the regmap stuff:

------>8 [relevant code] >8-------
/* SC16IS7XX register definitions */
#define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */
#define SC16IS7XX_THR_REG (0x00) /* TX FIFO */
#define SC16IS7XX_IER_REG (0x01) /* Interrupt enable */
#define SC16IS7XX_IIR_REG (0x02) /* Interrupt Ident */
#define SC16IS7XX_FCR_REG (0x02) /* FIFO control */
#define SC16IS7XX_LCR_REG (0x03) /* Line Control */
#define SC16IS7XX_MCR_REG (0x04) /* Modem Control */
#define SC16IS7XX_LSR_REG (0x05) /* Line Status */
#define SC16IS7XX_MSR_REG (0x06) /* Modem Status */
#define SC16IS7XX_SPR_REG (0x07) /* Scratch Pad */
#define SC16IS7XX_TXLVL_REG (0x08) /* TX FIFO level */
#define SC16IS7XX_RXLVL_REG (0x09) /* RX FIFO level */
#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Dir (750/760) */
#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State (750/760) */
#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Int Enable (750/760) */
#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control (750/760) */
#define SC16IS7XX_EFCR_REG (0x0f) /* Extra Feature Control */

/* TX/Trigger Registers: Only if ((MCR[2] == 0) && (EFR[4] == 1)) */
#define SC16IS7XX_TCR_REG (0x06) /* Transmit control */
#define SC16IS7XX_TLR_REG (0x07) /* Trigger level */

/* Special Register set: Only if ((LCR[7] == 1) && (LCR != 0xBF)) */
#define SC16IS7XX_DLL_REG (0x00) /* Divisor Latch Low */
#define SC16IS7XX_DLH_REG (0x01) /* Divisor Latch High */

/* Enhanced Register set: Only if (LCR == 0xBF) */
#define SC16IS7XX_EFR_REG (0x02) /* Enhanced Features */
#define SC16IS7XX_XON1_REG (0x04) /* Xon1 word */
#define SC16IS7XX_XON2_REG (0x05) /* Xon2 word */
#define SC16IS7XX_XOFF1_REG (0x06) /* Xoff1 word */
#define SC16IS7XX_XOFF2_REG (0x07) /* Xoff2 word */

#define SC16IS7XX_REG_SHIFT 3

static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)

{
	struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
	unsigned int val = 0;

	regmap_read(s->regmap, reg << SC16IS7XX_REG_SHIFT, &val);

	return val;
}

static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val)

{
	struct sc16is7xx_port *s = dev_get_drvdata(port->dev);

	regmap_write(s->regmap, reg << SC16IS7XX_REG_SHIFT, val);
}

static void sc16is7xx_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val)

{
	struct sc16is7xx_port *s = dev_get_drvdata(port->dev);

	regmap_update_bits(s->regmap, reg << SC16IS7XX_REG_SHIFT, mask, val);
}

static bool sc16is7xx_reg_writeable(struct device *dev, unsigned int reg)

{
	switch ((reg >> SC16IS7XX_REG_SHIFT) & 0xf) {
	case SC16IS7XX_LSR_REG:
	case SC16IS7XX_MSR_REG:
	case SC16IS7XX_TXLVL_REG:
	case SC16IS7XX_RXLVL_REG:
		return false;
	default:
		break;
	}

	return true;
}

static bool sc16is7xx_reg_volatile(struct device *dev, unsigned int reg)

{
	switch ((reg >> SC16IS7XX_REG_SHIFT) & 0xf) {
	case SC16IS7XX_RHR_REG:
	case SC16IS7XX_IIR_REG:
	case SC16IS7XX_LSR_REG:
	case SC16IS7XX_MSR_REG:
	case SC16IS7XX_TXLVL_REG:
	case SC16IS7XX_RXLVL_REG:
	case SC16IS7XX_IOSTATE_REG:
		return true;
	default:
		break;
	}

	return false;
}

static bool sc16is7xx_reg_precious(struct device *dev, unsigned int reg)

{
	switch ((reg >> SC16IS7XX_REG_SHIFT) & 0xf) {
	case SC16IS7XX_RHR_REG:
	case SC16IS7XX_IIR_REG:
	case SC16IS7XX_MSR_REG:
		return true;
	default:
		break;
	}

	return false;
}
static struct regmap_config regcfg = {
	.reg_bits = 8,
	.reg_stride = (1 << SC16IS7XX_REG_SHIFT),
	.val_bits = 8,
	.max_register = (0xf << SC16IS7XX_REG_SHIFT),
	.cache_type = REGCACHE_RBTREE,
	.writeable_reg = sc16is7xx_reg_writeable,
	.volatile_reg = sc16is7xx_reg_volatile,
	.precious_reg = sc16is7xx_reg_precious,
};

------------->8-----------------

I'm not sure that I have this defined correctly. I also saw in regmap_config pad_bits, which I've tried setting to SC16IS7XX_REG_SHIFT, but when I do that, I get -EINVAL failure.

Thanks,
Jon

[1] http://www.nxp.com/documents/data_sheet/SC16IS740_750_760.pdf

#7 lore raw

Вторник, 11 марта 2014, 14:44 -04:00 от Jon Ringle <[email protected]>:

Quoted 12 lines

I left out some relevant functions (sc16is7xx_port_read(), sc16is7xx_port_write(), sc16is7xx_port_update()) in my previous email...

Quoted 6 lines · Alexander Shiyan

Понедельник, 10 марта 2014, 7:50 -04:00 от Jon Ringle <[email protected]>:

Quoted 2 lines · Alexander Shiyan

I do not understand why you chose the sccnxp driver as a template. Use as a template max310x driver from linux-next branch. I'm sure it will be better.

Here are the approximate changes:

Quoted 1 line

#define SC16IS7XX_REG_SHIFT 3

#define SC16IS7XX_REG_SHIFT 2

Quoted 6 lines

static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)

{
	struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
	unsigned int val = 0;

	regmap_read(s->regmap, reg << SC16IS7XX_REG_SHIFT, &val);

regmap_read(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | port->index, &val);

Same for "write" and "update".

Quoted 2 lines
static struct regmap_config regcfg = {
	.reg_bits = 8,

.reg_bits = 7,

Quoted 1 line
	.reg_stride = (1 << SC16IS7XX_REG_SHIFT),

Kill this line (.reg_stride), but add:
.pad_bits = 1,

---

#8 lore raw
In reply to [email protected]

drivers/tty/serial/sc16is7xx.c line 54

Quoted 4 lines
drivers/tty/serial/sc16is7xx.c new file +4 -0
+#define DRV_NAME	"sc16is7xx"
+#define DRV_VERSION	"0.4"
+#define SC16IS7XX_MAJOR	204
+#define SC16IS7XX_MINOR	8

Use dynamic minors for any new device

Quoted 1 line

+static inline u8 sc16is7xx_read(struct uart_port *port, u8 reg)

I wouldn't inline this - the compiler will figure it out for you and you've got a fair bit code there.

Quoted 1 line

+static void sc16is7xx_handle_rx(struct uart_port *port)

This gets called from handle_events which gets called from the ist handler with IRQs disabled. I'm surprised it works at all but you definitely don't want to be doing all this work with interrupts blocked. That may be part of your problem.

Quoted 1 line

+static void sc16is7xx_handle_tx(struct uart_port *port)

Ditto

Quoted 24 lines
drivers/tty/serial/sc16is7xx.c new file +24 -0
+static void sc16is7xx_set_termios(struct uart_port *port,
+				  struct ktermios *termios, struct ktermios *old)
+{
+	struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+	unsigned long flags;
+	u8 cval;
+	u8 fcr;
+	int baud;
+
+	spin_lock_irqsave(&s->lock, flags);
+
+	/* Mask termios capabilities we don't support */
+	termios->c_cflag &= ~CMSPAR;
+
+	/* Disable RX & TX, reset break condition, status and FIFOs */
+	fcr = sc16is7xx_read(port, UART_FCR);
+	fcr |= UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
+	fcr &= ~UART_FCR_ENABLE_FIFO;
+	sc16is7xx_write(port, UART_FCR, fcr);
+
+	/* Word size */
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		cval = UART_LCR_WLEN5;

drivers/tty/serial/sc16is7xx.c line 431

Quoted 10 lines
drivers/tty/serial/sc16is7xx.c new file +10 -0
+		break;
+	case CS6:
+		cval = UART_LCR_WLEN6;
+		break;
+	case CS7:
+		cval = UART_LCR_WLEN7;
+		break;
+	case CS8:
+	default:
+		cval = UART_LCR_WLEN8;

(for the unknown case you also need to do

		termios->c_cflag &= ~CSIZE;
		termios->c_cflag |= CS8;

so the caller gets informed they didn't get their requested feature

Likewise btw for unsupported features. In this case CMSPAR appears not to be supported ?)

Reading drivers/tty/serial/max310x.c may be helpful with regards to the locking. It is SPI based so also has to defer some of the processing from the IRQ handler. The threaded IRQ support we now have may also help you.

Alan