diff options
Diffstat (limited to 'drivers/tty/serial/max310x.c')
-rw-r--r-- | drivers/tty/serial/max310x.c | 176 |
1 files changed, 110 insertions, 66 deletions
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3f6e0ab725fe..9360801df3c4 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1,7 +1,7 @@ /* * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver * - * Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru> + * Copyright (C) 2012-2016 Alexander Shiyan <shc_work@mail.ru> * * Based on max3100.c, by Christian Pellegrin <chripell@evolware.org> * Based on max3110.c, by Feng Tang <feng.tang@intel.com> @@ -32,6 +32,7 @@ #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 #define MAX310X_MINOR 209 +#define MAX310X_UART_NRMAX 16 /* MAX310X register definitions */ #define MAX310X_RHR_REG (0x00) /* RX FIFO */ @@ -155,10 +156,6 @@ #define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ #define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ #define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */ -#define MAX310X_LCR_WORD_LEN_5 (0x00) -#define MAX310X_LCR_WORD_LEN_6 (0x01) -#define MAX310X_LCR_WORD_LEN_7 (0x02) -#define MAX310X_LCR_WORD_LEN_8 (0x03) /* IRDA register bits */ #define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ @@ -262,10 +259,10 @@ struct max310x_one { struct uart_port port; struct work_struct tx_work; struct work_struct md_work; + struct work_struct rs_work; }; struct max310x_port { - struct uart_driver uart; struct max310x_devtype *devtype; struct regmap *regmap; struct mutex mutex; @@ -276,6 +273,17 @@ struct max310x_port { struct max310x_one p[0]; }; +static struct uart_driver max310x_uart = { + .owner = THIS_MODULE, + .driver_name = MAX310X_NAME, + .dev_name = "ttyMAX", + .major = MAX310X_MAJOR, + .minor = MAX310X_MINOR, + .nr = MAX310X_UART_NRMAX, +}; + +static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX); + static u8 max310x_port_read(struct uart_port *port, u8 reg) { struct max310x_port *s = dev_get_drvdata(port->dev); @@ -594,9 +602,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) unsigned int sts, ch, flag; if (unlikely(rxlen >= port->fifosize)) { - dev_warn_ratelimited(port->dev, - "Port %i: Possible RX FIFO overrun\n", - port->line); + dev_warn_ratelimited(port->dev, "Possible RX FIFO overrun\n"); port->icount.buf_overrun++; /* Ensure sanity of RX level */ rxlen = port->fifosize; @@ -715,13 +721,13 @@ static irqreturn_t max310x_ist(int irq, void *dev_id) { struct max310x_port *s = (struct max310x_port *)dev_id; - if (s->uart.nr > 1) { + if (s->devtype->nr > 1) { do { unsigned int val = ~0; WARN_ON_ONCE(regmap_read(s->regmap, MAX310X_GLOBALIRQ_REG, &val)); - val = ((1 << s->uart.nr) - 1) & ~val; + val = ((1 << s->devtype->nr) - 1) & ~val; if (!val) break; max310x_port_irq(s, fls(val) - 1); @@ -796,7 +802,7 @@ static void max310x_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - unsigned int lcr, flow = 0; + unsigned int lcr = 0, flow = 0; int baud; /* Mask termios capabilities we don't support */ @@ -805,17 +811,16 @@ static void max310x_set_termios(struct uart_port *port, /* Word size */ switch (termios->c_cflag & CSIZE) { case CS5: - lcr = MAX310X_LCR_WORD_LEN_5; break; case CS6: - lcr = MAX310X_LCR_WORD_LEN_6; + lcr = MAX310X_LCR_LENGTH0_BIT; break; case CS7: - lcr = MAX310X_LCR_WORD_LEN_7; + lcr = MAX310X_LCR_LENGTH1_BIT; break; case CS8: default: - lcr = MAX310X_LCR_WORD_LEN_8; + lcr = MAX310X_LCR_LENGTH1_BIT | MAX310X_LCR_LENGTH0_BIT; break; } @@ -877,36 +882,45 @@ static void max310x_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); } -static int max310x_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) +static void max310x_rs_proc(struct work_struct *ws) { + struct max310x_one *one = container_of(ws, struct max310x_one, rs_work); unsigned int val; - if (rs485->delay_rts_before_send > 0x0f || - rs485->delay_rts_after_send > 0x0f) - return -ERANGE; + val = (one->port.rs485.delay_rts_before_send << 4) | + one->port.rs485.delay_rts_after_send; + max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, val); - val = (rs485->delay_rts_before_send << 4) | - rs485->delay_rts_after_send; - max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val); - if (rs485->flags & SER_RS485_ENABLED) { - max310x_port_update(port, MAX310X_MODE1_REG, + if (one->port.rs485.flags & SER_RS485_ENABLED) { + max310x_port_update(&one->port, MAX310X_MODE1_REG, MAX310X_MODE1_TRNSCVCTRL_BIT, MAX310X_MODE1_TRNSCVCTRL_BIT); - max310x_port_update(port, MAX310X_MODE2_REG, + max310x_port_update(&one->port, MAX310X_MODE2_REG, MAX310X_MODE2_ECHOSUPR_BIT, MAX310X_MODE2_ECHOSUPR_BIT); } else { - max310x_port_update(port, MAX310X_MODE1_REG, + max310x_port_update(&one->port, MAX310X_MODE1_REG, MAX310X_MODE1_TRNSCVCTRL_BIT, 0); - max310x_port_update(port, MAX310X_MODE2_REG, + max310x_port_update(&one->port, MAX310X_MODE2_REG, MAX310X_MODE2_ECHOSUPR_BIT, 0); } +} + +static int max310x_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct max310x_one *one = container_of(port, struct max310x_one, port); + + if ((rs485->delay_rts_before_send > 0x0f) || + (rs485->delay_rts_after_send > 0x0f)) + return -ERANGE; rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED; memset(rs485->padding, 0, sizeof(rs485->padding)); port->rs485 = *rs485; + schedule_work(&one->rs_work); + return 0; } @@ -1009,8 +1023,8 @@ static int __maybe_unused max310x_suspend(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; - for (i = 0; i < s->uart.nr; i++) { - uart_suspend_port(&s->uart, &s->p[i].port); + for (i = 0; i < s->devtype->nr; i++) { + uart_suspend_port(&max310x_uart, &s->p[i].port); s->devtype->power(&s->p[i].port, 0); } @@ -1022,9 +1036,9 @@ static int __maybe_unused max310x_resume(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; - for (i = 0; i < s->uart.nr; i++) { + for (i = 0; i < s->devtype->nr; i++) { s->devtype->power(&s->p[i].port, 1); - uart_resume_port(&s->uart, &s->p[i].port); + uart_resume_port(&max310x_uart, &s->p[i].port); } return 0; @@ -1159,18 +1173,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); - /* Register UART driver */ - s->uart.owner = THIS_MODULE; - s->uart.dev_name = "ttyMAX"; - s->uart.major = MAX310X_MAJOR; - s->uart.minor = MAX310X_MINOR; - s->uart.nr = devtype->nr; - ret = uart_register_driver(&s->uart); - if (ret) { - dev_err(dev, "Registering UART driver failed\n"); - goto out_clk; - } - #ifdef CONFIG_GPIOLIB /* Setup GPIO cotroller */ s->gpio.owner = THIS_MODULE; @@ -1183,16 +1185,24 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->gpio.base = -1; s->gpio.ngpio = devtype->nr * 4; s->gpio.can_sleep = 1; - ret = gpiochip_add_data(&s->gpio, s); + ret = devm_gpiochip_add_data(dev, &s->gpio, s); if (ret) - goto out_uart; + goto out_clk; #endif mutex_init(&s->mutex); for (i = 0; i < devtype->nr; i++) { + unsigned int line; + + line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX); + if (line == MAX310X_UART_NRMAX) { + ret = -ERANGE; + goto out_uart; + } + /* Initialize port data */ - s->p[i].port.line = i; + s->p[i].port.line = line; s->p[i].port.dev = dev; s->p[i].port.irq = irq; s->p[i].port.type = PORT_MAX310X; @@ -1214,10 +1224,19 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, MAX310X_MODE1_IRQSEL_BIT); /* Initialize queue for start TX */ INIT_WORK(&s->p[i].tx_work, max310x_wq_proc); - /* Initialize queue for changing mode */ + /* Initialize queue for changing LOOPBACK mode */ INIT_WORK(&s->p[i].md_work, max310x_md_proc); + /* Initialize queue for changing RS485 mode */ + INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); + /* Register port */ - uart_add_one_port(&s->uart, &s->p[i].port); + ret = uart_add_one_port(&max310x_uart, &s->p[i].port); + if (ret) { + s->p[i].port.dev = NULL; + goto out_uart; + } + set_bit(line, max310x_lines); + /* Go to suspend mode */ devtype->power(&s->p[i].port, 0); } @@ -1230,14 +1249,15 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, dev_err(dev, "Unable to reguest IRQ %i\n", irq); - mutex_destroy(&s->mutex); - -#ifdef CONFIG_GPIOLIB - gpiochip_remove(&s->gpio); - out_uart: -#endif - uart_unregister_driver(&s->uart); + for (i = 0; i < devtype->nr; i++) { + if (s->p[i].port.dev) { + uart_remove_one_port(&max310x_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, max310x_lines); + } + } + + mutex_destroy(&s->mutex); out_clk: clk_disable_unprepare(s->clk); @@ -1250,19 +1270,16 @@ static int max310x_remove(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; -#ifdef CONFIG_GPIOLIB - gpiochip_remove(&s->gpio); -#endif - - for (i = 0; i < s->uart.nr; i++) { + for (i = 0; i < s->devtype->nr; i++) { cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); - uart_remove_one_port(&s->uart, &s->p[i].port); + cancel_work_sync(&s->p[i].rs_work); + uart_remove_one_port(&max310x_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, max310x_lines); s->devtype->power(&s->p[i].port, 0); } mutex_destroy(&s->mutex); - uart_unregister_driver(&s->uart); clk_disable_unprepare(s->clk); return 0; @@ -1335,7 +1352,7 @@ static const struct spi_device_id max310x_id_table[] = { }; MODULE_DEVICE_TABLE(spi, max310x_id_table); -static struct spi_driver max310x_uart_driver = { +static struct spi_driver max310x_spi_driver = { .driver = { .name = MAX310X_NAME, .of_match_table = of_match_ptr(max310x_dt_ids), @@ -1345,9 +1362,36 @@ static struct spi_driver max310x_uart_driver = { .remove = max310x_spi_remove, .id_table = max310x_id_table, }; -module_spi_driver(max310x_uart_driver); #endif +static int __init max310x_uart_init(void) +{ + int ret; + + bitmap_zero(max310x_lines, MAX310X_UART_NRMAX); + + ret = uart_register_driver(&max310x_uart); + if (ret) + return ret; + +#ifdef CONFIG_SPI_MASTER + spi_register_driver(&max310x_spi_driver); +#endif + + return 0; +} +module_init(max310x_uart_init); + +static void __exit max310x_uart_exit(void) +{ +#ifdef CONFIG_SPI_MASTER + spi_unregister_driver(&max310x_spi_driver); +#endif + + uart_unregister_driver(&max310x_uart); +} +module_exit(max310x_uart_exit); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); MODULE_DESCRIPTION("MAX310X serial driver"); |