diff options
author | Ingo Molnar <mingo@kernel.org> | 2018-02-06 21:12:31 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2018-02-06 21:12:31 +0100 |
commit | 82845079160817cc6ac64e5321bbd935e0a47b3a (patch) | |
tree | 0886d1d52428e9db14536cae4b37db896e7c360a /drivers/tty/serial/max310x.c | |
parent | sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS (diff) | |
parent | Merge tag 'media/v4.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mc... (diff) | |
download | linux-82845079160817cc6ac64e5321bbd935e0a47b3a.tar.xz linux-82845079160817cc6ac64e5321bbd935e0a47b3a.zip |
Merge branch 'linus' into sched/urgent, to resolve conflicts
Conflicts:
arch/arm64/kernel/entry.S
arch/x86/Kconfig
include/linux/sched/mm.h
kernel/fork.c
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/tty/serial/max310x.c')
-rw-r--r-- | drivers/tty/serial/max310x.c | 267 |
1 files changed, 180 insertions, 87 deletions
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ecb6513a6505..39f635812077 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -233,6 +233,7 @@ /* Misc definitions */ #define MAX310X_FIFO_SIZE (128) #define MAX310x_REV_MASK (0xf8) +#define MAX310X_WRITE_BIT 0x80 /* MAX3107 specific */ #define MAX3107_REV_ID (0xa0) @@ -593,57 +594,118 @@ static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq, return (int)bestfreq; } -static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) +static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) { - unsigned int sts, ch, flag; + 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)); +} - if (unlikely(rxlen >= port->fifosize)) { - dev_warn_ratelimited(port->dev, "Possible RX FIFO overrun\n"); - port->icount.buf_overrun++; - /* Ensure sanity of RX level */ - rxlen = port->fifosize; - } +static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) +{ + u8 header[] = { port->iobase + MAX310X_RHR_REG }; + struct spi_transfer xfer[] = { + { + .tx_buf = &header, + .len = sizeof(header), + }, { + .rx_buf = rxbuf, + .len = len, + } + }; + spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); +} - while (rxlen--) { - ch = max310x_port_read(port, MAX310X_RHR_REG); - sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); +static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) +{ + unsigned int sts, ch, flag, i; + u8 buf[MAX310X_FIFO_SIZE]; + + if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) { + /* We are just reading, happily ignoring any error conditions. + * Break condition, parity checking, framing errors -- they + * are all ignored. That means that we can do a batch-read. + * + * There is a small opportunity for race if the RX FIFO + * overruns while we're reading the buffer; the datasheets says + * that the LSR register applies to the "current" character. + * That's also the reason why we cannot do batched reads when + * asked to check the individual statuses. + * */ - sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT | - MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT; + sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); + max310x_batch_read(port, buf, rxlen); - port->icount.rx++; + port->icount.rx += rxlen; flag = TTY_NORMAL; + sts &= port->read_status_mask; - if (unlikely(sts)) { - if (sts & MAX310X_LSR_RXBRK_BIT) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (sts & MAX310X_LSR_RXPAR_BIT) - port->icount.parity++; - else if (sts & MAX310X_LSR_FRERR_BIT) - port->icount.frame++; - else if (sts & MAX310X_LSR_RXOVR_BIT) - port->icount.overrun++; - - sts &= port->read_status_mask; - if (sts & MAX310X_LSR_RXBRK_BIT) - flag = TTY_BREAK; - else if (sts & MAX310X_LSR_RXPAR_BIT) - flag = TTY_PARITY; - else if (sts & MAX310X_LSR_FRERR_BIT) - flag = TTY_FRAME; - else if (sts & MAX310X_LSR_RXOVR_BIT) - flag = TTY_OVERRUN; + if (sts & MAX310X_LSR_RXOVR_BIT) { + dev_warn_ratelimited(port->dev, "Hardware RX FIFO overrun\n"); + port->icount.overrun++; } - if (uart_handle_sysrq_char(port, ch)) - continue; + for (i = 0; i < rxlen; ++i) { + uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, buf[i], flag); + } + + } else { + if (unlikely(rxlen >= port->fifosize)) { + dev_warn_ratelimited(port->dev, "Possible RX FIFO overrun\n"); + port->icount.buf_overrun++; + /* Ensure sanity of RX level */ + rxlen = port->fifosize; + } + + while (rxlen--) { + ch = max310x_port_read(port, MAX310X_RHR_REG); + sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); + + sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT | + MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT; + + port->icount.rx++; + flag = TTY_NORMAL; + + if (unlikely(sts)) { + if (sts & MAX310X_LSR_RXBRK_BIT) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (sts & MAX310X_LSR_RXPAR_BIT) + port->icount.parity++; + else if (sts & MAX310X_LSR_FRERR_BIT) + port->icount.frame++; + else if (sts & MAX310X_LSR_RXOVR_BIT) + port->icount.overrun++; + + sts &= port->read_status_mask; + if (sts & MAX310X_LSR_RXBRK_BIT) + flag = TTY_BREAK; + else if (sts & MAX310X_LSR_RXPAR_BIT) + flag = TTY_PARITY; + else if (sts & MAX310X_LSR_FRERR_BIT) + flag = TTY_FRAME; + else if (sts & MAX310X_LSR_RXOVR_BIT) + flag = TTY_OVERRUN; + } - if (sts & port->ignore_status_mask) - continue; + if (uart_handle_sysrq_char(port, ch)) + continue; - uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, ch, flag); + if (sts & port->ignore_status_mask) + continue; + + uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, ch, flag); + } } tty_flip_buffer_push(&port->state->port); @@ -652,7 +714,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) static void max310x_handle_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; - unsigned int txlen, to_send; + unsigned int txlen, to_send, until_end; if (unlikely(port->x_char)) { max310x_port_write(port, MAX310X_THR_REG, port->x_char); @@ -666,28 +728,43 @@ static void max310x_handle_tx(struct uart_port *port) /* Get length of data pending in circular buffer */ to_send = uart_circ_chars_pending(xmit); + until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); if (likely(to_send)) { /* Limit to size of TX FIFO */ txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG); txlen = port->fifosize - txlen; 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 */ port->icount.tx += to_send; - while (to_send--) { - max310x_port_write(port, MAX310X_THR_REG, - xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } + xmit->tail = (xmit->tail + to_send) & (UART_XMIT_SIZE - 1); } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); } -static void max310x_port_irq(struct max310x_port *s, int portno) +static void max310x_start_tx(struct uart_port *port) +{ + struct max310x_one *one = container_of(port, struct max310x_one, port); + + if (!work_pending(&one->tx_work)) + schedule_work(&one->tx_work); +} + +static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno) { struct uart_port *port = &s->p[portno].port; + irqreturn_t res = IRQ_NONE; do { unsigned int ists, lsr, rxlen; @@ -698,6 +775,8 @@ static void max310x_port_irq(struct max310x_port *s, int portno) if (!ists && !rxlen) break; + res = IRQ_HANDLED; + if (ists & MAX310X_IRQ_CTS_BIT) { lsr = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); uart_handle_cts_change(port, @@ -705,17 +784,16 @@ static void max310x_port_irq(struct max310x_port *s, int portno) } if (rxlen) max310x_handle_rx(port, rxlen); - if (ists & MAX310X_IRQ_TXEMPTY_BIT) { - mutex_lock(&s->mutex); - max310x_handle_tx(port); - mutex_unlock(&s->mutex); - } + if (ists & MAX310X_IRQ_TXEMPTY_BIT) + max310x_start_tx(port); } while (1); + return res; } static irqreturn_t max310x_ist(int irq, void *dev_id) { struct max310x_port *s = (struct max310x_port *)dev_id; + bool handled = false; if (s->devtype->nr > 1) { do { @@ -726,12 +804,15 @@ static irqreturn_t max310x_ist(int irq, void *dev_id) val = ((1 << s->devtype->nr) - 1) & ~val; if (!val) break; - max310x_port_irq(s, fls(val) - 1); + if (max310x_port_irq(s, fls(val) - 1) == IRQ_HANDLED) + handled = true; } while (1); - } else - max310x_port_irq(s, 0); + } else { + if (max310x_port_irq(s, 0) == IRQ_HANDLED) + handled = true; + } - return IRQ_HANDLED; + return IRQ_RETVAL(handled); } static void max310x_wq_proc(struct work_struct *ws) @@ -744,14 +825,6 @@ static void max310x_wq_proc(struct work_struct *ws) mutex_unlock(&s->mutex); } -static void max310x_start_tx(struct uart_port *port) -{ - struct max310x_one *one = container_of(port, struct max310x_one, port); - - if (!work_pending(&one->tx_work)) - schedule_work(&one->tx_work); -} - static unsigned int max310x_tx_empty(struct uart_port *port) { unsigned int lvl, sts; @@ -1086,10 +1159,31 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip, return 0; } + +static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + struct max310x_port *s = gpiochip_get_data(chip); + struct uart_port *port = &s->p[offset / 4].port; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + max310x_port_update(port, MAX310X_GPIOCFG_REG, + 1 << ((offset % 4) + 4), + 1 << ((offset % 4) + 4)); + return 0; + case PIN_CONFIG_DRIVE_PUSH_PULL: + max310x_port_update(port, MAX310X_GPIOCFG_REG, + 1 << ((offset % 4) + 4), 0); + return 0; + default: + return -ENOTSUPP; + } +} #endif static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, - struct regmap *regmap, int irq, unsigned long flags) + struct regmap *regmap, int irq) { int i, ret, fmin, fmax, freq, uartclk; struct clk *clk_osc, *clk_xtal; @@ -1169,23 +1263,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, uartclk = max310x_set_ref_clk(s, freq, xtal); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); -#ifdef CONFIG_GPIOLIB - /* Setup GPIO cotroller */ - s->gpio.owner = THIS_MODULE; - s->gpio.parent = dev; - s->gpio.label = dev_name(dev); - s->gpio.direction_input = max310x_gpio_direction_input; - s->gpio.get = max310x_gpio_get; - s->gpio.direction_output= max310x_gpio_direction_output; - s->gpio.set = max310x_gpio_set; - s->gpio.base = -1; - s->gpio.ngpio = devtype->nr * 4; - s->gpio.can_sleep = 1; - ret = devm_gpiochip_add_data(dev, &s->gpio, s); - if (ret) - goto out_clk; -#endif - mutex_init(&s->mutex); for (i = 0; i < devtype->nr; i++) { @@ -1237,9 +1314,27 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, devtype->power(&s->p[i].port, 0); } +#ifdef CONFIG_GPIOLIB + /* Setup GPIO cotroller */ + s->gpio.owner = THIS_MODULE; + s->gpio.parent = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = max310x_gpio_direction_input; + s->gpio.get = max310x_gpio_get; + s->gpio.direction_output= max310x_gpio_direction_output; + s->gpio.set = max310x_gpio_set; + s->gpio.set_config = max310x_gpio_set_config; + s->gpio.base = -1; + s->gpio.ngpio = devtype->nr * 4; + s->gpio.can_sleep = 1; + ret = devm_gpiochip_add_data(dev, &s->gpio, s); + if (ret) + goto out_uart; +#endif + /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, - IRQF_ONESHOT | flags, dev_name(dev), s); + IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), s); if (!ret) return 0; @@ -1293,7 +1388,7 @@ MODULE_DEVICE_TABLE(of, max310x_dt_ids); static struct regmap_config regcfg = { .reg_bits = 8, .val_bits = 8, - .write_flag_mask = 0x80, + .write_flag_mask = MAX310X_WRITE_BIT, .cache_type = REGCACHE_RBTREE, .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, @@ -1304,7 +1399,6 @@ static struct regmap_config regcfg = { static int max310x_spi_probe(struct spi_device *spi) { struct max310x_devtype *devtype; - unsigned long flags = 0; struct regmap *regmap; int ret; @@ -1327,11 +1421,10 @@ static int max310x_spi_probe(struct spi_device *spi) devtype = (struct max310x_devtype *)id_entry->driver_data; } - flags = IRQF_TRIGGER_FALLING; regcfg.max_register = devtype->nr * 0x20 - 1; regmap = devm_regmap_init_spi(spi, ®cfg); - return max310x_probe(&spi->dev, devtype, regmap, spi->irq, flags); + return max310x_probe(&spi->dev, devtype, regmap, spi->irq); } static int max310x_spi_remove(struct spi_device *spi) |