mbox series

[0/4] rs485 bus termination GPIO

Message ID cover.1588505407.git.lukas@wunner.de
Headers show
Series rs485 bus termination GPIO | expand

Message

Lukas Wunner May 5, 2020, 2:42 p.m. UTC
Commit e8759ad17d41 ("serial: uapi: Add support for bus termination"),
allowed user space to change rs485 bus termination through a flag in
struct serial_rs485.  But so far only a single driver, 8250_exar.c,
supports the flag:  It hardcodes a GPIO specific to Siemens IOT2040
products.

Provide for a more generic solution:  Define a device tree binding
for an rs485 bus termination GPIO (patch [3/4]), amend the serial core
to retrieve the GPIO from the device tree and amend the default
->rs485_config() callback for 8250 drivers to change the GPIO on
request from user space (patch [4/4]).

Retrieving the GPIO from the device tree may fail, so allow
uart_get_rs485_mode() to return an errno and change all callers
to check for failure (patch [2/4]).

Testing has exposed a bug in the 8250 core if retrieval of the GPIO
initially fails with -EPROBE_DEFER and is later retried.  That bug
is fixed by patch [1/4].


Lukas Wunner (4):
  serial: 8250: Avoid error message on reprobe
  serial: Allow uart_get_rs485_mode() to return errno
  dt-bindings: serial: Add binding for rs485 bus termination GPIO
  serial: 8250: Support rs485 bus termination GPIO

 .../devicetree/bindings/serial/rs485.yaml     |  4 +++
 drivers/tty/serial/8250/8250_core.c           | 16 +++++++---
 drivers/tty/serial/8250/8250_port.c           |  4 +++
 drivers/tty/serial/ar933x_uart.c              |  6 ++--
 drivers/tty/serial/atmel_serial.c             |  6 ++--
 drivers/tty/serial/fsl_lpuart.c               |  5 +++-
 drivers/tty/serial/imx.c                      |  6 +++-
 drivers/tty/serial/omap-serial.c              |  4 ++-
 drivers/tty/serial/serial_core.c              | 30 ++++++++++++++++++-
 drivers/tty/serial/stm32-usart.c              |  8 ++---
 include/linux/serial_core.h                   |  4 ++-
 11 files changed, 76 insertions(+), 17 deletions(-)

Comments

Andy Shevchenko May 5, 2020, 4:10 p.m. UTC | #1
On Tue, May 05, 2020 at 04:42:04PM +0200, Lukas Wunner wrote:
> Commit e8759ad17d41 ("serial: uapi: Add support for bus termination")
> introduced the ability to enable rs485 bus termination from user space.
> So far the feature is only used by a single driver, 8250_exar.c, using a
> hardcoded GPIO pin specific to Siemens IOT2040 products.
> 
> Provide for a more generic solution by allowing specification of an
> rs485 bus termination GPIO pin in the device tree:  Amend the serial
> core to retrieve the GPIO from the device tree (or ACPI table) and amend
> the default ->rs485_config() callback for 8250 drivers to change the
> GPIO on request from user space.

...

> @@ -3331,6 +3332,29 @@ int uart_get_rs485_mode(struct uart_port *port)

> +		devm_gpiod_put(dev, port->rs485_term_gpio);

> +	port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term",

Using devm_*() in uart_get_rs485_mode() seems not right.
Why do you need this?

> +		GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT);

Parameter has a specific macro GPIOD_OUT_HIGH.
Lukas Wunner May 6, 2020, 6:29 a.m. UTC | #2
On Tue, May 05, 2020 at 07:10:35PM +0300, Andy Shevchenko wrote:
> On Tue, May 05, 2020 at 04:42:04PM +0200, Lukas Wunner wrote:
> > Commit e8759ad17d41 ("serial: uapi: Add support for bus termination")
> > introduced the ability to enable rs485 bus termination from user space.
> > So far the feature is only used by a single driver, 8250_exar.c, using a
> > hardcoded GPIO pin specific to Siemens IOT2040 products.
> > 
> > Provide for a more generic solution by allowing specification of an
> > rs485 bus termination GPIO pin in the device tree:  Amend the serial
> > core to retrieve the GPIO from the device tree (or ACPI table) and amend
> > the default ->rs485_config() callback for 8250 drivers to change the
> > GPIO on request from user space.
> 
> ...
> 
> > @@ -3331,6 +3332,29 @@ int uart_get_rs485_mode(struct uart_port *port)
> 
> > +		devm_gpiod_put(dev, port->rs485_term_gpio);
> 
> > +	port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term",
> 
> Using devm_*() in uart_get_rs485_mode() seems not right.
> Why do you need this?

uart_get_rs485_mode() is called from a driver's ->probe() hook and we
do not have a corresponding function that is called from a ->remove()
hook where we'd be able to relinquish rs485 resources we've acquired
on probe.

Of course I could add that but it would be more heavy-weight compared
to simply using devm_*().  Do you disagree?

devm_gpiod_put() isn't strictly necessary here.  It is only necessary
if one of the drivers would invoke uart_get_rs485_mode() multiple
times, which none of them does AFAICS.  It's just a safety measure.
I can drop it if that is preferred.


> > +		GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT);
> 
> Parameter has a specific macro GPIOD_OUT_HIGH.

Good point.  It's also occurred to me now that reading the GPIO's
value after changing its direction to output is nonsense.  If anything
it ought to be read *before* changing the direction to output.
That would make sense in case the board has a pullup or pulldown on
the Termination Enable pin.  In other cases the pin may just float
and the value will be unpredictable.  However if I do not read the
pin, I'd have to choose either high or low as initial state.  Hm.
Let me check back with our hardware engineers today and see what they
recommend.

Thanks,

Lukas
Andy Shevchenko May 6, 2020, 10:06 a.m. UTC | #3
On Wed, May 06, 2020 at 08:29:43AM +0200, Lukas Wunner wrote:
> On Tue, May 05, 2020 at 07:10:35PM +0300, Andy Shevchenko wrote:
> > On Tue, May 05, 2020 at 04:42:04PM +0200, Lukas Wunner wrote:

...

> > > +		devm_gpiod_put(dev, port->rs485_term_gpio);
> > 
> > > +	port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term",
> > 
> > Using devm_*() in uart_get_rs485_mode() seems not right.
> > Why do you need this?
> 
> uart_get_rs485_mode() is called from a driver's ->probe() hook and we
> do not have a corresponding function that is called from a ->remove()
> hook where we'd be able to relinquish rs485 resources we've acquired
> on probe.
> 
> Of course I could add that but it would be more heavy-weight compared
> to simply using devm_*().  Do you disagree?
> 
> devm_gpiod_put() isn't strictly necessary here.  It is only necessary
> if one of the drivers would invoke uart_get_rs485_mode() multiple
> times, which none of them does AFAICS.  It's just a safety measure.
> I can drop it if that is preferred.

I think putting and re-requesting here is also racy. Somebody can request the
very same GPIO in between (for example crazy user space tool).

Setting the same value many times won't hurt.

> > > +		GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT);
> > 
> > Parameter has a specific macro GPIOD_OUT_HIGH.
> 
> Good point.  It's also occurred to me now that reading the GPIO's
> value after changing its direction to output is nonsense.  If anything
> it ought to be read *before* changing the direction to output.

It's not a complete nonsense, depends what you actually want to achieve here.

> That would make sense in case the board has a pullup or pulldown on
> the Termination Enable pin.  In other cases the pin may just float
> and the value will be unpredictable.  However if I do not read the
> pin, I'd have to choose either high or low as initial state.  Hm.
> Let me check back with our hardware engineers today and see what they
> recommend.