serial: core: Simplify uart_get_rs485_mode()
[platform/kernel/linux-starfive.git] / drivers / tty / serial / serial_core.c
index 7bdc21d..021e096 100644 (file)
@@ -146,7 +146,7 @@ static void __uart_start(struct uart_state *state)
 
        /* Increment the runtime PM usage count for the active check below */
        err = pm_runtime_get(&port_dev->dev);
-       if (err < 0) {
+       if (err < 0 && err != -EINPROGRESS) {
                pm_runtime_put_noidle(&port_dev->dev);
                return;
        }
@@ -156,7 +156,7 @@ static void __uart_start(struct uart_state *state)
         * enabled, serial_port_runtime_resume() calls start_tx() again
         * after enabling the device.
         */
-       if (pm_runtime_active(&port_dev->dev))
+       if (!pm_runtime_enabled(port->dev) || pm_runtime_active(port->dev))
                port->ops->start_tx(port);
        pm_runtime_mark_last_busy(&port_dev->dev);
        pm_runtime_put_autosuspend(&port_dev->dev);
@@ -1370,19 +1370,27 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
                return;
        }
 
+       rs485->flags &= supported_flags;
+
        /* Pick sane settings if the user hasn't */
-       if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) &&
-           !(rs485->flags & SER_RS485_RTS_ON_SEND) ==
+       if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
            !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
-               dev_warn_ratelimited(port->dev,
-                       "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
-                       port->name, port->line);
-               rs485->flags |= SER_RS485_RTS_ON_SEND;
-               rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
-               supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND;
-       }
+               if (supported_flags & SER_RS485_RTS_ON_SEND) {
+                       rs485->flags |= SER_RS485_RTS_ON_SEND;
+                       rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
 
-       rs485->flags &= supported_flags;
+                       dev_warn_ratelimited(port->dev,
+                               "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
+                               port->name, port->line);
+               } else {
+                       rs485->flags |= SER_RS485_RTS_AFTER_SEND;
+                       rs485->flags &= ~SER_RS485_RTS_ON_SEND;
+
+                       dev_warn_ratelimited(port->dev,
+                               "%s (%d): invalid RTS setting, using RTS_AFTER_SEND instead\n",
+                               port->name, port->line);
+               }
+       }
 
        uart_sanitize_serial_rs485_delays(port, rs485);
 
@@ -1404,12 +1412,18 @@ static void uart_set_rs485_termination(struct uart_port *port,
 static int uart_rs485_config(struct uart_port *port)
 {
        struct serial_rs485 *rs485 = &port->rs485;
+       unsigned long flags;
        int ret;
 
+       if (!(rs485->flags & SER_RS485_ENABLED))
+               return 0;
+
        uart_sanitize_serial_rs485(port, rs485);
        uart_set_rs485_termination(port, rs485);
 
+       spin_lock_irqsave(&port->lock, flags);
        ret = port->rs485_config(port, NULL, rs485);
+       spin_unlock_irqrestore(&port->lock, flags);
        if (ret)
                memset(rs485, 0, sizeof(*rs485));
 
@@ -1439,7 +1453,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
        int ret;
        unsigned long flags;
 
-       if (!port->rs485_config)
+       if (!(port->rs485_supported.flags & SER_RS485_ENABLED))
                return -ENOTTY;
 
        if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user)))
@@ -2474,11 +2488,10 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
                        if (ret == 0) {
                                if (tty)
                                        uart_change_line_settings(tty, state, NULL);
+                               uart_rs485_config(uport);
                                spin_lock_irq(&uport->lock);
                                if (!(uport->rs485.flags & SER_RS485_ENABLED))
                                        ops->set_mctrl(uport, uport->mctrl);
-                               else
-                                       uart_rs485_config(uport);
                                ops->start_tx(uport);
                                spin_unlock_irq(&uport->lock);
                                tty_port_set_initialized(port, true);
@@ -2587,10 +2600,10 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
                port->mctrl &= TIOCM_DTR;
                if (!(port->rs485.flags & SER_RS485_ENABLED))
                        port->ops->set_mctrl(port, port->mctrl);
-               else
-                       uart_rs485_config(port);
                spin_unlock_irqrestore(&port->lock, flags);
 
+               uart_rs485_config(port);
+
                /*
                 * If this driver supports console, and it hasn't been
                 * successfully registered yet, try to re-register it.
@@ -3559,9 +3572,13 @@ int uart_get_rs485_mode(struct uart_port *port)
 {
        struct serial_rs485 *rs485conf = &port->rs485;
        struct device *dev = port->dev;
+       enum gpiod_flags dflags;
+       struct gpio_desc *desc;
        u32 rs485_delay[2];
        int ret;
-       int rx_during_tx_gpio_flag;
+
+       if (!(port->rs485_supported.flags & SER_RS485_ENABLED))
+               return 0;
 
        ret = device_property_read_u32_array(dev, "rs485-rts-delay",
                                             rs485_delay, 2);
@@ -3600,26 +3617,19 @@ int uart_get_rs485_mode(struct uart_port *port)
         * bus participants enable it, no communication is possible at all.
         * Works fine for short cables and users may enable for longer cables.
         */
-       port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term",
-                                                       GPIOD_OUT_LOW);
-       if (IS_ERR(port->rs485_term_gpio)) {
-               ret = PTR_ERR(port->rs485_term_gpio);
-               port->rs485_term_gpio = NULL;
-               return dev_err_probe(dev, ret, "Cannot get rs485-term-gpios\n");
-       }
+       desc = devm_gpiod_get_optional(dev, "rs485-term", GPIOD_OUT_LOW);
+       if (IS_ERR(desc))
+               return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-term-gpios\n");
+       port->rs485_term_gpio = desc;
        if (port->rs485_term_gpio)
                port->rs485_supported.flags |= SER_RS485_TERMINATE_BUS;
 
-       rx_during_tx_gpio_flag = (rs485conf->flags & SER_RS485_RX_DURING_TX) ?
-                                GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
-       port->rs485_rx_during_tx_gpio = devm_gpiod_get_optional(dev,
-                                                               "rs485-rx-during-tx",
-                                                               rx_during_tx_gpio_flag);
-       if (IS_ERR(port->rs485_rx_during_tx_gpio)) {
-               ret = PTR_ERR(port->rs485_rx_during_tx_gpio);
-               port->rs485_rx_during_tx_gpio = NULL;
-               return dev_err_probe(dev, ret, "Cannot get rs485-rx-during-tx-gpios\n");
-       }
+       dflags = (rs485conf->flags & SER_RS485_RX_DURING_TX) ?
+                GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+       desc = devm_gpiod_get_optional(dev, "rs485-rx-during-tx", dflags);
+       if (IS_ERR(desc))
+               return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-rx-during-tx-gpios\n");
+       port->rs485_rx_during_tx_gpio = desc;
 
        return 0;
 }