Skip to content

Commit 1bcda09

Browse files
BHESTMgregkh
authored andcommitted
serial: stm32: add support for RS485 hardware control mode
Implement Driver Enable signal (DE) to activate the transmission mode of the external transceiver. Signed-off-by: Yves Coppeaux <[email protected]> Signed-off-by: Bich Hemon <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 241672c commit 1bcda09

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

drivers/tty/serial/stm32-usart.c

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,113 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
6262
writel_relaxed(val, port->membase + reg);
6363
}
6464

65+
static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
66+
u32 delay_DDE, u32 baud)
67+
{
68+
u32 rs485_deat_dedt;
69+
u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT);
70+
bool over8;
71+
72+
*cr3 |= USART_CR3_DEM;
73+
over8 = *cr1 & USART_CR1_OVER8;
74+
75+
if (over8)
76+
rs485_deat_dedt = delay_ADE * baud * 8;
77+
else
78+
rs485_deat_dedt = delay_ADE * baud * 16;
79+
80+
rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000);
81+
rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ?
82+
rs485_deat_dedt_max : rs485_deat_dedt;
83+
rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEAT_SHIFT) &
84+
USART_CR1_DEAT_MASK;
85+
*cr1 |= rs485_deat_dedt;
86+
87+
if (over8)
88+
rs485_deat_dedt = delay_DDE * baud * 8;
89+
else
90+
rs485_deat_dedt = delay_DDE * baud * 16;
91+
92+
rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000);
93+
rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ?
94+
rs485_deat_dedt_max : rs485_deat_dedt;
95+
rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEDT_SHIFT) &
96+
USART_CR1_DEDT_MASK;
97+
*cr1 |= rs485_deat_dedt;
98+
}
99+
100+
static int stm32_config_rs485(struct uart_port *port,
101+
struct serial_rs485 *rs485conf)
102+
{
103+
struct stm32_port *stm32_port = to_stm32_port(port);
104+
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
105+
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
106+
u32 usartdiv, baud, cr1, cr3;
107+
bool over8;
108+
unsigned long flags;
109+
110+
spin_lock_irqsave(&port->lock, flags);
111+
stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
112+
113+
port->rs485 = *rs485conf;
114+
115+
rs485conf->flags |= SER_RS485_RX_DURING_TX;
116+
117+
if (rs485conf->flags & SER_RS485_ENABLED) {
118+
cr1 = readl_relaxed(port->membase + ofs->cr1);
119+
cr3 = readl_relaxed(port->membase + ofs->cr3);
120+
usartdiv = readl_relaxed(port->membase + ofs->brr);
121+
usartdiv = usartdiv & GENMASK(15, 0);
122+
over8 = cr1 & USART_CR1_OVER8;
123+
124+
if (over8)
125+
usartdiv = usartdiv | (usartdiv & GENMASK(4, 0))
126+
<< USART_BRR_04_R_SHIFT;
127+
128+
baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv);
129+
stm32_config_reg_rs485(&cr1, &cr3,
130+
rs485conf->delay_rts_before_send,
131+
rs485conf->delay_rts_after_send, baud);
132+
133+
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
134+
cr3 &= ~USART_CR3_DEP;
135+
rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND;
136+
} else {
137+
cr3 |= USART_CR3_DEP;
138+
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
139+
}
140+
141+
writel_relaxed(cr3, port->membase + ofs->cr3);
142+
writel_relaxed(cr1, port->membase + ofs->cr1);
143+
} else {
144+
stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP);
145+
stm32_clr_bits(port, ofs->cr1,
146+
USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
147+
}
148+
149+
stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
150+
spin_unlock_irqrestore(&port->lock, flags);
151+
152+
return 0;
153+
}
154+
155+
static int stm32_init_rs485(struct uart_port *port,
156+
struct platform_device *pdev)
157+
{
158+
struct serial_rs485 *rs485conf = &port->rs485;
159+
160+
rs485conf->flags = 0;
161+
rs485conf->delay_rts_before_send = 0;
162+
rs485conf->delay_rts_after_send = 0;
163+
164+
if (!pdev->dev.of_node)
165+
return -ENODEV;
166+
167+
uart_get_rs485_mode(&pdev->dev, rs485conf);
168+
169+
return 0;
170+
}
171+
65172
static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
66173
bool threaded)
67174
{
@@ -498,6 +605,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
498605
struct stm32_port *stm32_port = to_stm32_port(port);
499606
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
500607
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
608+
struct serial_rs485 *rs485conf = &port->rs485;
501609
unsigned int baud;
502610
u32 usartdiv, mantissa, fraction, oversampling;
503611
tcflag_t cflag = termios->c_cflag;
@@ -515,7 +623,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
515623
writel_relaxed(0, port->membase + ofs->cr1);
516624

517625
cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
518-
cr1 |= BIT(cfg->uart_enable_bit);
626+
519627
if (stm32_port->fifoen)
520628
cr1 |= USART_CR1_FIFOEN;
521629
cr2 = 0;
@@ -553,9 +661,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
553661
*/
554662
if (usartdiv < 16) {
555663
oversampling = 8;
664+
cr1 |= USART_CR1_OVER8;
556665
stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8);
557666
} else {
558667
oversampling = 16;
668+
cr1 &= ~USART_CR1_OVER8;
559669
stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8);
560670
}
561671

@@ -592,10 +702,28 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
592702
if (stm32_port->rx_ch)
593703
cr3 |= USART_CR3_DMAR;
594704

705+
if (rs485conf->flags & SER_RS485_ENABLED) {
706+
stm32_config_reg_rs485(&cr1, &cr3,
707+
rs485conf->delay_rts_before_send,
708+
rs485conf->delay_rts_after_send, baud);
709+
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
710+
cr3 &= ~USART_CR3_DEP;
711+
rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND;
712+
} else {
713+
cr3 |= USART_CR3_DEP;
714+
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
715+
}
716+
717+
} else {
718+
cr3 &= ~(USART_CR3_DEM | USART_CR3_DEP);
719+
cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
720+
}
721+
595722
writel_relaxed(cr3, port->membase + ofs->cr3);
596723
writel_relaxed(cr2, port->membase + ofs->cr2);
597724
writel_relaxed(cr1, port->membase + ofs->cr1);
598725

726+
stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
599727
spin_unlock_irqrestore(&port->lock, flags);
600728
}
601729

drivers/tty/serial/stm32-usart.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ struct stm32_usart_info stm32h7_info = {
135135
#define USART_BRR_DIV_F_MASK GENMASK(3, 0)
136136
#define USART_BRR_DIV_M_MASK GENMASK(15, 4)
137137
#define USART_BRR_DIV_M_SHIFT 4
138+
#define USART_BRR_04_R_SHIFT 1
138139

139140
/* USART_CR1 */
140141
#define USART_CR1_SBK BIT(0)
@@ -162,6 +163,8 @@ struct stm32_usart_info stm32h7_info = {
162163
#define USART_CR1_M1 BIT(28) /* F7 */
163164
#define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27))
164165
#define USART_CR1_FIFOEN BIT(29) /* H7 */
166+
#define USART_CR1_DEAT_SHIFT 21
167+
#define USART_CR1_DEDT_SHIFT 16
165168

166169
/* USART_CR2 */
167170
#define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */

0 commit comments

Comments
 (0)