aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/max310x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/max310x.c')
-rw-r--r--drivers/tty/serial/max310x.c176
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");