serial: max310x: use a batch write op for UART transmit
The transmit register supports batched writes. The key is simply to keep sending additional bytes up to the FIFO size in the same SPI transaction with the CS pin still being held low. This duplicates the regmap infrastructure to a certain extent. There are some provisions for multiple writes in there, but there does not appear to be any support for those writes which are destined to the *same* register (and also no standard for SPI bus transfers of these, anyway). This patch does not solve every case (if the UART xmit circular buffer wraps around, we're still doing two SPI transactions), but at least it's not one-byte-per-transaction anymore. This change does not touch the receive path at this time. Doing that in the generic case appears to be impossible in the general case, because the chips' status register contains data about the *current* byte in the HW's Rx FIFO. We cannot read these two registers in one go, unfortunately. Signed-off-by: Jan Kundrát <jan.kundrat@cesnet.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b2497c1a7d
commit
d584b65c0d
|
@ -233,6 +233,7 @@
|
||||||
/* Misc definitions */
|
/* Misc definitions */
|
||||||
#define MAX310X_FIFO_SIZE (128)
|
#define MAX310X_FIFO_SIZE (128)
|
||||||
#define MAX310x_REV_MASK (0xf8)
|
#define MAX310x_REV_MASK (0xf8)
|
||||||
|
#define MAX310X_WRITE_BIT 0x80
|
||||||
|
|
||||||
/* MAX3107 specific */
|
/* MAX3107 specific */
|
||||||
#define MAX3107_REV_ID (0xa0)
|
#define MAX3107_REV_ID (0xa0)
|
||||||
|
@ -593,6 +594,21 @@ static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq,
|
||||||
return (int)bestfreq;
|
return (int)bestfreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
|
||||||
|
{
|
||||||
|
u8 header[] = { (port->iobase + MAX310X_THR_REG) | MAX310X_WRITE_BIT };
|
||||||
|
struct spi_transfer xfer[] = {
|
||||||
|
{
|
||||||
|
.tx_buf = &header,
|
||||||
|
.len = sizeof(header),
|
||||||
|
}, {
|
||||||
|
.tx_buf = txbuf,
|
||||||
|
.len = len,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer));
|
||||||
|
}
|
||||||
|
|
||||||
static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
|
static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
|
||||||
{
|
{
|
||||||
unsigned int sts, ch, flag;
|
unsigned int sts, ch, flag;
|
||||||
|
@ -652,7 +668,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
|
||||||
static void max310x_handle_tx(struct uart_port *port)
|
static void max310x_handle_tx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct circ_buf *xmit = &port->state->xmit;
|
struct circ_buf *xmit = &port->state->xmit;
|
||||||
unsigned int txlen, to_send;
|
unsigned int txlen, to_send, until_end;
|
||||||
|
|
||||||
if (unlikely(port->x_char)) {
|
if (unlikely(port->x_char)) {
|
||||||
max310x_port_write(port, MAX310X_THR_REG, port->x_char);
|
max310x_port_write(port, MAX310X_THR_REG, port->x_char);
|
||||||
|
@ -666,19 +682,25 @@ static void max310x_handle_tx(struct uart_port *port)
|
||||||
|
|
||||||
/* Get length of data pending in circular buffer */
|
/* Get length of data pending in circular buffer */
|
||||||
to_send = uart_circ_chars_pending(xmit);
|
to_send = uart_circ_chars_pending(xmit);
|
||||||
|
until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||||
if (likely(to_send)) {
|
if (likely(to_send)) {
|
||||||
/* Limit to size of TX FIFO */
|
/* Limit to size of TX FIFO */
|
||||||
txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
|
txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
|
||||||
txlen = port->fifosize - txlen;
|
txlen = port->fifosize - txlen;
|
||||||
to_send = (to_send > txlen) ? txlen : to_send;
|
to_send = (to_send > txlen) ? txlen : to_send;
|
||||||
|
|
||||||
|
if (until_end < to_send) {
|
||||||
|
/* It's a circ buffer -- wrap around.
|
||||||
|
* We could do that in one SPI transaction, but meh. */
|
||||||
|
max310x_batch_write(port, xmit->buf + xmit->tail, until_end);
|
||||||
|
max310x_batch_write(port, xmit->buf, to_send - until_end);
|
||||||
|
} else {
|
||||||
|
max310x_batch_write(port, xmit->buf + xmit->tail, to_send);
|
||||||
|
}
|
||||||
|
|
||||||
/* Add data to send */
|
/* Add data to send */
|
||||||
port->icount.tx += to_send;
|
port->icount.tx += to_send;
|
||||||
while (to_send--) {
|
xmit->tail = (xmit->tail + to_send) & (UART_XMIT_SIZE - 1);
|
||||||
max310x_port_write(port, MAX310X_THR_REG,
|
|
||||||
xmit->buf[xmit->tail]);
|
|
||||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||||
|
@ -1301,7 +1323,7 @@ MODULE_DEVICE_TABLE(of, max310x_dt_ids);
|
||||||
static struct regmap_config regcfg = {
|
static struct regmap_config regcfg = {
|
||||||
.reg_bits = 8,
|
.reg_bits = 8,
|
||||||
.val_bits = 8,
|
.val_bits = 8,
|
||||||
.write_flag_mask = 0x80,
|
.write_flag_mask = MAX310X_WRITE_BIT,
|
||||||
.cache_type = REGCACHE_RBTREE,
|
.cache_type = REGCACHE_RBTREE,
|
||||||
.writeable_reg = max310x_reg_writeable,
|
.writeable_reg = max310x_reg_writeable,
|
||||||
.volatile_reg = max310x_reg_volatile,
|
.volatile_reg = max310x_reg_volatile,
|
||||||
|
|
Loading…
Reference in New Issue