* [PATCH 0/2] Add support for RS485 @ 2018-02-28 10:56 ` Bich HEMON 0 siblings, 0 replies; 11+ messages in thread From: Bich HEMON @ 2018-02-28 10:56 UTC (permalink / raw) To: Greg Kroah-Hartman, Rob Herring, Mark Rutland, Maxime Coquelin, Alexandre TORGUE, Jiri Slaby, linux-serial@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Bich HEMON This patchset updates existing stm32 usart driver by adding support for RS485. Bich Hemon (2): dt-bindings: serial: stm32: add RS485 optional properties serial: stm32: add support for RS485 hardware control mode .../devicetree/bindings/serial/st,stm32-usart.txt | 2 + drivers/tty/serial/stm32-usart.c | 134 ++++++++++++++++++++- drivers/tty/serial/stm32-usart.h | 3 + 3 files changed, 138 insertions(+), 1 deletion(-) -- 1.9.1 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 0/2] Add support for RS485 @ 2018-02-28 10:56 ` Bich HEMON 0 siblings, 0 replies; 11+ messages in thread From: Bich HEMON @ 2018-02-28 10:56 UTC (permalink / raw) To: linux-arm-kernel This patchset updates existing stm32 usart driver by adding support for RS485. Bich Hemon (2): dt-bindings: serial: stm32: add RS485 optional properties serial: stm32: add support for RS485 hardware control mode .../devicetree/bindings/serial/st,stm32-usart.txt | 2 + drivers/tty/serial/stm32-usart.c | 134 ++++++++++++++++++++- drivers/tty/serial/stm32-usart.h | 3 + 3 files changed, 138 insertions(+), 1 deletion(-) -- 1.9.1 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] dt-bindings: serial: stm32: add RS485 optional properties 2018-02-28 10:56 ` Bich HEMON (?) @ 2018-02-28 10:56 ` Bich HEMON -1 siblings, 0 replies; 11+ messages in thread From: Bich HEMON @ 2018-02-28 10:56 UTC (permalink / raw) To: Greg Kroah-Hartman, Rob Herring, Mark Rutland, Maxime Coquelin, Alexandre TORGUE, Jiri Slaby, linux-serial@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Bich HEMON Add options for enabling RS485 hardware control and configuring Driver Enable signal: - rs485-rts-delay - rs485-rx-during-tx - rs485-rts-active-low - linux,rs485-enabled-at-boot-time Signed-off-by: Bich Hemon <bich.hemon@st.com> --- Documentation/devicetree/bindings/serial/st,stm32-usart.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt index aaeb564..81e0011 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt +++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt @@ -16,6 +16,8 @@ Required properties: Optional properties: - pinctrl: The reference on the pins configuration - st,hw-flow-ctrl: bool flag to enable hardware flow control. +- rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low, + linux,rs485-enabled-at-boot-time: see rs485.txt. - dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt - dma-names: "rx" and/or "tx" - wakeup-source: bool flag to indicate this device has wakeup capabilities -- 1.9.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 1/2] dt-bindings: serial: stm32: add RS485 optional properties @ 2018-02-28 10:56 ` Bich HEMON 0 siblings, 0 replies; 11+ messages in thread From: Bich HEMON @ 2018-02-28 10:56 UTC (permalink / raw) To: Greg Kroah-Hartman, Rob Herring, Mark Rutland, Maxime Coquelin, Alexandre TORGUE, Jiri Slaby, linux-serial@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Bich HEMON Add options for enabling RS485 hardware control and configuring Driver Enable signal: - rs485-rts-delay - rs485-rx-during-tx - rs485-rts-active-low - linux,rs485-enabled-at-boot-time Signed-off-by: Bich Hemon <bich.hemon@st.com> Reviewed-by: Rob Herring <robh@kernel.org> --- Documentation/devicetree/bindings/serial/st,stm32-usart.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt index aaeb564..81e0011 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt +++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt @@ -16,6 +16,8 @@ Required properties: Optional properties: - pinctrl: The reference on the pins configuration - st,hw-flow-ctrl: bool flag to enable hardware flow control. +- rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low, + linux,rs485-enabled-at-boot-time: see rs485.txt. - dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt - dma-names: "rx" and/or "tx" - wakeup-source: bool flag to indicate this device has wakeup capabilities -- 1.9.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 1/2] dt-bindings: serial: stm32: add RS485 optional properties @ 2018-02-28 10:56 ` Bich HEMON 0 siblings, 0 replies; 11+ messages in thread From: Bich HEMON @ 2018-02-28 10:56 UTC (permalink / raw) To: linux-arm-kernel Add options for enabling RS485 hardware control and configuring Driver Enable signal: - rs485-rts-delay - rs485-rx-during-tx - rs485-rts-active-low - linux,rs485-enabled-at-boot-time Signed-off-by: Bich Hemon <bich.hemon@st.com> --- Documentation/devicetree/bindings/serial/st,stm32-usart.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt index aaeb564..81e0011 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt +++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt @@ -16,6 +16,8 @@ Required properties: Optional properties: - pinctrl: The reference on the pins configuration - st,hw-flow-ctrl: bool flag to enable hardware flow control. +- rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low, + linux,rs485-enabled-at-boot-time: see rs485.txt. - dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt - dma-names: "rx" and/or "tx" - wakeup-source: bool flag to indicate this device has wakeup capabilities -- 1.9.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] dt-bindings: serial: stm32: add RS485 optional properties 2018-02-28 10:56 ` Bich HEMON @ 2018-03-06 0:53 ` Rob Herring -1 siblings, 0 replies; 11+ messages in thread From: Rob Herring @ 2018-03-06 0:53 UTC (permalink / raw) To: Bich HEMON Cc: Greg Kroah-Hartman, Mark Rutland, Maxime Coquelin, Alexandre TORGUE, Jiri Slaby, linux-serial@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org On Wed, Feb 28, 2018 at 10:56:18AM +0000, Bich HEMON wrote: > Add options for enabling RS485 hardware control and configuring > Driver Enable signal: > - rs485-rts-delay > - rs485-rx-during-tx > - rs485-rts-active-low > - linux,rs485-enabled-at-boot-time > > Signed-off-by: Bich Hemon <bich.hemon@st.com> > --- > Documentation/devicetree/bindings/serial/st,stm32-usart.txt | 2 ++ > 1 file changed, 2 insertions(+) Reviewed-by: Rob Herring <robh@kernel.org> ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] dt-bindings: serial: stm32: add RS485 optional properties @ 2018-03-06 0:53 ` Rob Herring 0 siblings, 0 replies; 11+ messages in thread From: Rob Herring @ 2018-03-06 0:53 UTC (permalink / raw) To: linux-arm-kernel On Wed, Feb 28, 2018 at 10:56:18AM +0000, Bich HEMON wrote: > Add options for enabling RS485 hardware control and configuring > Driver Enable signal: > - rs485-rts-delay > - rs485-rx-during-tx > - rs485-rts-active-low > - linux,rs485-enabled-at-boot-time > > Signed-off-by: Bich Hemon <bich.hemon@st.com> > --- > Documentation/devicetree/bindings/serial/st,stm32-usart.txt | 2 ++ > 1 file changed, 2 insertions(+) Reviewed-by: Rob Herring <robh@kernel.org> ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] dt-bindings: serial: stm32: add RS485 optional properties 2018-02-28 10:56 ` Bich HEMON @ 2018-03-09 18:58 ` Greg Kroah-Hartman -1 siblings, 0 replies; 11+ messages in thread From: Greg Kroah-Hartman @ 2018-03-09 18:58 UTC (permalink / raw) To: Bich HEMON Cc: Rob Herring, Mark Rutland, Maxime Coquelin, Alexandre TORGUE, Jiri Slaby, linux-serial@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org On Wed, Feb 28, 2018 at 10:56:18AM +0000, Bich HEMON wrote: > Add options for enabling RS485 hardware control and configuring > Driver Enable signal: > - rs485-rts-delay > - rs485-rx-during-tx > - rs485-rts-active-low > - linux,rs485-enabled-at-boot-time > > Signed-off-by: Bich Hemon <bich.hemon@st.com> > Reviewed-by: Rob Herring <robh@kernel.org> > --- > Documentation/devicetree/bindings/serial/st,stm32-usart.txt | 2 ++ > 1 file changed, 2 insertions(+) This series does not apply to my tty-next tree at all. Can you rebase and resend? thanks, greg k-h ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] dt-bindings: serial: stm32: add RS485 optional properties @ 2018-03-09 18:58 ` Greg Kroah-Hartman 0 siblings, 0 replies; 11+ messages in thread From: Greg Kroah-Hartman @ 2018-03-09 18:58 UTC (permalink / raw) To: linux-arm-kernel On Wed, Feb 28, 2018 at 10:56:18AM +0000, Bich HEMON wrote: > Add options for enabling RS485 hardware control and configuring > Driver Enable signal: > - rs485-rts-delay > - rs485-rx-during-tx > - rs485-rts-active-low > - linux,rs485-enabled-at-boot-time > > Signed-off-by: Bich Hemon <bich.hemon@st.com> > Reviewed-by: Rob Herring <robh@kernel.org> > --- > Documentation/devicetree/bindings/serial/st,stm32-usart.txt | 2 ++ > 1 file changed, 2 insertions(+) This series does not apply to my tty-next tree at all. Can you rebase and resend? thanks, greg k-h ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/2] serial: stm32: add support for RS485 hardware control mode 2018-02-28 10:56 ` Bich HEMON @ 2018-02-28 10:56 ` Bich HEMON -1 siblings, 0 replies; 11+ messages in thread From: Bich HEMON @ 2018-02-28 10:56 UTC (permalink / raw) To: Greg Kroah-Hartman, Rob Herring, Mark Rutland, Maxime Coquelin, Alexandre TORGUE, Jiri Slaby, linux-serial@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Bich HEMON Implement Driver Enable signal (DE) to activate the transmission mode of the external transceiver. Signed-off-by: Yves Coppeaux <yves.coppeaux@st.com> Signed-off-by: Bich Hemon <bich.hemon@st.com> --- drivers/tty/serial/stm32-usart.c | 134 ++++++++++++++++++++++++++++++++++++++- drivers/tty/serial/stm32-usart.h | 3 + 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 5c85cbc..6d34472 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -62,6 +62,113 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } +static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, + u32 delay_DDE, u32 baud) +{ + u32 rs485_deat_dedt; + u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT); + bool over8; + + *cr3 |= USART_CR3_DEM; + over8 = *cr1 & USART_CR1_OVER8; + + if (over8) + rs485_deat_dedt = delay_ADE * baud * 8; + else + rs485_deat_dedt = delay_ADE * baud * 16; + + rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); + rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? + rs485_deat_dedt_max : rs485_deat_dedt; + rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEAT_SHIFT) & + USART_CR1_DEAT_MASK; + *cr1 |= rs485_deat_dedt; + + if (over8) + rs485_deat_dedt = delay_DDE * baud * 8; + else + rs485_deat_dedt = delay_DDE * baud * 16; + + rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); + rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? + rs485_deat_dedt_max : rs485_deat_dedt; + rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEDT_SHIFT) & + USART_CR1_DEDT_MASK; + *cr1 |= rs485_deat_dedt; +} + +static int stm32_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485conf) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; + u32 usartdiv, baud, cr1, cr3; + bool over8; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + + port->rs485 = *rs485conf; + + rs485conf->flags |= SER_RS485_RX_DURING_TX; + + if (rs485conf->flags & SER_RS485_ENABLED) { + cr1 = readl_relaxed(port->membase + ofs->cr1); + cr3 = readl_relaxed(port->membase + ofs->cr3); + usartdiv = readl_relaxed(port->membase + ofs->brr); + usartdiv = usartdiv & GENMASK(15, 0); + over8 = cr1 & USART_CR1_OVER8; + + if (over8) + usartdiv = usartdiv | (usartdiv & GENMASK(4, 0)) + << USART_BRR_04_R_SHIFT; + + baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv); + stm32_config_reg_rs485(&cr1, &cr3, + rs485conf->delay_rts_before_send, + rs485conf->delay_rts_after_send, baud); + + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + cr3 &= ~USART_CR3_DEP; + rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; + } else { + cr3 |= USART_CR3_DEP; + rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; + } + + writel_relaxed(cr3, port->membase + ofs->cr3); + writel_relaxed(cr1, port->membase + ofs->cr1); + } else { + stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP); + stm32_clr_bits(port, ofs->cr1, + USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + } + + stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static int stm32_init_rs485(struct uart_port *port, + struct platform_device *pdev) +{ + struct serial_rs485 *rs485conf = &port->rs485; + + rs485conf->flags = 0; + rs485conf->delay_rts_before_send = 0; + rs485conf->delay_rts_after_send = 0; + + if (!pdev->dev.of_node) + return -ENODEV; + + uart_get_rs485_mode(&pdev->dev, rs485conf); + + return 0; +} + static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, bool threaded) { @@ -498,6 +605,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; + struct serial_rs485 *rs485conf = &port->rs485; unsigned int baud; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; @@ -515,7 +623,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, writel_relaxed(0, port->membase + ofs->cr1); cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; - cr1 |= BIT(cfg->uart_enable_bit); + if (stm32_port->fifoen) cr1 |= USART_CR1_FIFOEN; cr2 = 0; @@ -553,9 +661,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, */ if (usartdiv < 16) { oversampling = 8; + cr1 |= USART_CR1_OVER8; stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8); } else { oversampling = 16; + cr1 &= ~USART_CR1_OVER8; stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8); } @@ -592,10 +702,28 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if (stm32_port->rx_ch) cr3 |= USART_CR3_DMAR; + if (rs485conf->flags & SER_RS485_ENABLED) { + stm32_config_reg_rs485(&cr1, &cr3, + rs485conf->delay_rts_before_send, + rs485conf->delay_rts_after_send, baud); + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + cr3 &= ~USART_CR3_DEP; + rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; + } else { + cr3 |= USART_CR3_DEP; + rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; + } + + } else { + cr3 &= ~(USART_CR3_DEM | USART_CR3_DEP); + cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + } + writel_relaxed(cr3, port->membase + ofs->cr3); writel_relaxed(cr2, port->membase + ofs->cr2); writel_relaxed(cr1, port->membase + ofs->cr1); + stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); spin_unlock_irqrestore(&port->lock, flags); } @@ -681,6 +809,10 @@ static int stm32_init_port(struct stm32_port *stm32port, port->ops = &stm32_uart_ops; port->dev = &pdev->dev; port->irq = platform_get_irq_byname(pdev, "event"); + + port->rs485_config = stm32_config_rs485; + stm32_init_rs485(port, pdev); + stm32port->wakeirq = platform_get_irq_byname(pdev, "wakeup"); stm32port->fifoen = stm32port->info->cfg.has_fifo; diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 2294d0f..6f294e2 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -135,6 +135,7 @@ struct stm32_usart_info stm32h7_info = { #define USART_BRR_DIV_F_MASK GENMASK(3, 0) #define USART_BRR_DIV_M_MASK GENMASK(15, 4) #define USART_BRR_DIV_M_SHIFT 4 +#define USART_BRR_04_R_SHIFT 1 /* USART_CR1 */ #define USART_CR1_SBK BIT(0) @@ -162,6 +163,8 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR1_M1 BIT(28) /* F7 */ #define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27)) #define USART_CR1_FIFOEN BIT(29) /* H7 */ +#define USART_CR1_DEAT_SHIFT 21 +#define USART_CR1_DEDT_SHIFT 16 /* USART_CR2 */ #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ -- 1.9.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/2] serial: stm32: add support for RS485 hardware control mode @ 2018-02-28 10:56 ` Bich HEMON 0 siblings, 0 replies; 11+ messages in thread From: Bich HEMON @ 2018-02-28 10:56 UTC (permalink / raw) To: linux-arm-kernel Implement Driver Enable signal (DE) to activate the transmission mode of the external transceiver. Signed-off-by: Yves Coppeaux <yves.coppeaux@st.com> Signed-off-by: Bich Hemon <bich.hemon@st.com> --- drivers/tty/serial/stm32-usart.c | 134 ++++++++++++++++++++++++++++++++++++++- drivers/tty/serial/stm32-usart.h | 3 + 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 5c85cbc..6d34472 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -62,6 +62,113 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } +static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, + u32 delay_DDE, u32 baud) +{ + u32 rs485_deat_dedt; + u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT); + bool over8; + + *cr3 |= USART_CR3_DEM; + over8 = *cr1 & USART_CR1_OVER8; + + if (over8) + rs485_deat_dedt = delay_ADE * baud * 8; + else + rs485_deat_dedt = delay_ADE * baud * 16; + + rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); + rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? + rs485_deat_dedt_max : rs485_deat_dedt; + rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEAT_SHIFT) & + USART_CR1_DEAT_MASK; + *cr1 |= rs485_deat_dedt; + + if (over8) + rs485_deat_dedt = delay_DDE * baud * 8; + else + rs485_deat_dedt = delay_DDE * baud * 16; + + rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); + rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? + rs485_deat_dedt_max : rs485_deat_dedt; + rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEDT_SHIFT) & + USART_CR1_DEDT_MASK; + *cr1 |= rs485_deat_dedt; +} + +static int stm32_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485conf) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; + u32 usartdiv, baud, cr1, cr3; + bool over8; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + + port->rs485 = *rs485conf; + + rs485conf->flags |= SER_RS485_RX_DURING_TX; + + if (rs485conf->flags & SER_RS485_ENABLED) { + cr1 = readl_relaxed(port->membase + ofs->cr1); + cr3 = readl_relaxed(port->membase + ofs->cr3); + usartdiv = readl_relaxed(port->membase + ofs->brr); + usartdiv = usartdiv & GENMASK(15, 0); + over8 = cr1 & USART_CR1_OVER8; + + if (over8) + usartdiv = usartdiv | (usartdiv & GENMASK(4, 0)) + << USART_BRR_04_R_SHIFT; + + baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv); + stm32_config_reg_rs485(&cr1, &cr3, + rs485conf->delay_rts_before_send, + rs485conf->delay_rts_after_send, baud); + + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + cr3 &= ~USART_CR3_DEP; + rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; + } else { + cr3 |= USART_CR3_DEP; + rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; + } + + writel_relaxed(cr3, port->membase + ofs->cr3); + writel_relaxed(cr1, port->membase + ofs->cr1); + } else { + stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP); + stm32_clr_bits(port, ofs->cr1, + USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + } + + stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static int stm32_init_rs485(struct uart_port *port, + struct platform_device *pdev) +{ + struct serial_rs485 *rs485conf = &port->rs485; + + rs485conf->flags = 0; + rs485conf->delay_rts_before_send = 0; + rs485conf->delay_rts_after_send = 0; + + if (!pdev->dev.of_node) + return -ENODEV; + + uart_get_rs485_mode(&pdev->dev, rs485conf); + + return 0; +} + static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, bool threaded) { @@ -498,6 +605,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; + struct serial_rs485 *rs485conf = &port->rs485; unsigned int baud; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; @@ -515,7 +623,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, writel_relaxed(0, port->membase + ofs->cr1); cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; - cr1 |= BIT(cfg->uart_enable_bit); + if (stm32_port->fifoen) cr1 |= USART_CR1_FIFOEN; cr2 = 0; @@ -553,9 +661,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, */ if (usartdiv < 16) { oversampling = 8; + cr1 |= USART_CR1_OVER8; stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8); } else { oversampling = 16; + cr1 &= ~USART_CR1_OVER8; stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8); } @@ -592,10 +702,28 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if (stm32_port->rx_ch) cr3 |= USART_CR3_DMAR; + if (rs485conf->flags & SER_RS485_ENABLED) { + stm32_config_reg_rs485(&cr1, &cr3, + rs485conf->delay_rts_before_send, + rs485conf->delay_rts_after_send, baud); + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + cr3 &= ~USART_CR3_DEP; + rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; + } else { + cr3 |= USART_CR3_DEP; + rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; + } + + } else { + cr3 &= ~(USART_CR3_DEM | USART_CR3_DEP); + cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + } + writel_relaxed(cr3, port->membase + ofs->cr3); writel_relaxed(cr2, port->membase + ofs->cr2); writel_relaxed(cr1, port->membase + ofs->cr1); + stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); spin_unlock_irqrestore(&port->lock, flags); } @@ -681,6 +809,10 @@ static int stm32_init_port(struct stm32_port *stm32port, port->ops = &stm32_uart_ops; port->dev = &pdev->dev; port->irq = platform_get_irq_byname(pdev, "event"); + + port->rs485_config = stm32_config_rs485; + stm32_init_rs485(port, pdev); + stm32port->wakeirq = platform_get_irq_byname(pdev, "wakeup"); stm32port->fifoen = stm32port->info->cfg.has_fifo; diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 2294d0f..6f294e2 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -135,6 +135,7 @@ struct stm32_usart_info stm32h7_info = { #define USART_BRR_DIV_F_MASK GENMASK(3, 0) #define USART_BRR_DIV_M_MASK GENMASK(15, 4) #define USART_BRR_DIV_M_SHIFT 4 +#define USART_BRR_04_R_SHIFT 1 /* USART_CR1 */ #define USART_CR1_SBK BIT(0) @@ -162,6 +163,8 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR1_M1 BIT(28) /* F7 */ #define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27)) #define USART_CR1_FIFOEN BIT(29) /* H7 */ +#define USART_CR1_DEAT_SHIFT 21 +#define USART_CR1_DEDT_SHIFT 16 /* USART_CR2 */ #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ -- 1.9.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2018-03-09 18:58 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-02-28 10:56 [PATCH 0/2] Add support for RS485 Bich HEMON 2018-02-28 10:56 ` Bich HEMON 2018-02-28 10:56 ` [PATCH 1/2] dt-bindings: serial: stm32: add RS485 optional properties Bich HEMON 2018-02-28 10:56 ` Bich HEMON 2018-02-28 10:56 ` Bich HEMON 2018-03-06 0:53 ` Rob Herring 2018-03-06 0:53 ` Rob Herring 2018-03-09 18:58 ` Greg Kroah-Hartman 2018-03-09 18:58 ` Greg Kroah-Hartman 2018-02-28 10:56 ` [PATCH 2/2] serial: stm32: add support for RS485 hardware control mode Bich HEMON 2018-02-28 10:56 ` Bich HEMON
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.