serial: stm32: adding support for stm32f7

Register offset management rework to support both
stm32f4 (default) and stm32f7. Driver rework to
ensure same functional level on both stm32f4 and
stm32f7: no new feature in this version yet.

Signed-off-by: Gerald Baeza <gerald.baeza@st.com>
Signed-off-by: Alexandre TORGUE <alexandre.torgue@st.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Alexandre TORGUE 2016-09-15 18:42:33 +02:00 committed by Greg Kroah-Hartman
parent 27b17ae073
commit ada8618ff3

View file

@ -1,6 +1,7 @@
/* /*
* Copyright (C) Maxime Coquelin 2015 * Copyright (C) Maxime Coquelin 2015
* Author: Maxime Coquelin <mcoquelin.stm32@gmail.com> * Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com>
* Gerald Baeza <gerald.baeza@st.com>
* License terms: GNU General Public License (GPL), version 2 * License terms: GNU General Public License (GPL), version 2
* *
* Inspired by st-asc.c from STMicroelectronics (c) * Inspired by st-asc.c from STMicroelectronics (c)
@ -29,16 +30,74 @@
#define DRIVER_NAME "stm32-usart" #define DRIVER_NAME "stm32-usart"
/* Register offsets */ struct stm32_usart_offsets {
#define USART_SR 0x00 u8 cr1;
#define USART_DR 0x04 u8 cr2;
#define USART_BRR 0x08 u8 cr3;
#define USART_CR1 0x0c u8 brr;
#define USART_CR2 0x10 u8 gtpr;
#define USART_CR3 0x14 u8 rtor;
#define USART_GTPR 0x18 u8 rqr;
u8 isr;
u8 icr;
u8 rdr;
u8 tdr;
};
/* USART_SR */ struct stm32_usart_config {
u8 uart_enable_bit; /* USART_CR1_UE */
bool has_7bits_data;
};
struct stm32_usart_info {
struct stm32_usart_offsets ofs;
struct stm32_usart_config cfg;
};
#define UNDEF_REG ~0
/* Register offsets */
struct stm32_usart_info stm32f4_info = {
.ofs = {
.isr = 0x00,
.rdr = 0x04,
.tdr = 0x04,
.brr = 0x08,
.cr1 = 0x0c,
.cr2 = 0x10,
.cr3 = 0x14,
.gtpr = 0x18,
.rtor = UNDEF_REG,
.rqr = UNDEF_REG,
.icr = UNDEF_REG,
},
.cfg = {
.uart_enable_bit = 13,
.has_7bits_data = false,
}
};
struct stm32_usart_info stm32f7_info = {
.ofs = {
.cr1 = 0x00,
.cr2 = 0x04,
.cr3 = 0x08,
.brr = 0x0c,
.gtpr = 0x10,
.rtor = 0x14,
.rqr = 0x18,
.isr = 0x1c,
.icr = 0x20,
.rdr = 0x24,
.tdr = 0x28,
},
.cfg = {
.uart_enable_bit = 0,
.has_7bits_data = true,
}
};
/* USART_SR (F4) / USART_ISR (F7) */
#define USART_SR_PE BIT(0) #define USART_SR_PE BIT(0)
#define USART_SR_FE BIT(1) #define USART_SR_FE BIT(1)
#define USART_SR_NF BIT(2) #define USART_SR_NF BIT(2)
@ -48,7 +107,16 @@
#define USART_SR_TC BIT(6) #define USART_SR_TC BIT(6)
#define USART_SR_TXE BIT(7) #define USART_SR_TXE BIT(7)
#define USART_SR_LBD BIT(8) #define USART_SR_LBD BIT(8)
#define USART_SR_CTS BIT(9) #define USART_SR_CTSIF BIT(9)
#define USART_SR_CTS BIT(10) /* F7 */
#define USART_SR_RTOF BIT(11) /* F7 */
#define USART_SR_EOBF BIT(12) /* F7 */
#define USART_SR_ABRE BIT(14) /* F7 */
#define USART_SR_ABRF BIT(15) /* F7 */
#define USART_SR_BUSY BIT(16) /* F7 */
#define USART_SR_CMF BIT(17) /* F7 */
#define USART_SR_SBKF BIT(18) /* F7 */
#define USART_SR_TEACK BIT(21) /* F7 */
#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ #define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
USART_SR_FE | USART_SR_PE) USART_SR_FE | USART_SR_PE)
/* Dummy bits */ /* Dummy bits */
@ -64,7 +132,7 @@
/* USART_CR1 */ /* USART_CR1 */
#define USART_CR1_SBK BIT(0) #define USART_CR1_SBK BIT(0)
#define USART_CR1_RWU BIT(1) #define USART_CR1_RWU BIT(1) /* F4 */
#define USART_CR1_RE BIT(2) #define USART_CR1_RE BIT(2)
#define USART_CR1_TE BIT(3) #define USART_CR1_TE BIT(3)
#define USART_CR1_IDLEIE BIT(4) #define USART_CR1_IDLEIE BIT(4)
@ -76,12 +144,20 @@
#define USART_CR1_PCE BIT(10) #define USART_CR1_PCE BIT(10)
#define USART_CR1_WAKE BIT(11) #define USART_CR1_WAKE BIT(11)
#define USART_CR1_M BIT(12) #define USART_CR1_M BIT(12)
#define USART_CR1_UE BIT(13) #define USART_CR1_M0 BIT(12) /* F7 */
#define USART_CR1_MME BIT(13) /* F7 */
#define USART_CR1_CMIE BIT(14) /* F7 */
#define USART_CR1_OVER8 BIT(15) #define USART_CR1_OVER8 BIT(15)
#define USART_CR1_IE_MASK GENMASK(8, 4) #define USART_CR1_DEDT_MASK GENMASK(20, 16) /* F7 */
#define USART_CR1_DEAT_MASK GENMASK(25, 21) /* F7 */
#define USART_CR1_RTOIE BIT(26) /* F7 */
#define USART_CR1_EOBIE BIT(27) /* F7 */
#define USART_CR1_M1 BIT(28) /* F7 */
#define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27))
/* USART_CR2 */ /* USART_CR2 */
#define USART_CR2_ADD_MASK GENMASK(3, 0) #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */
#define USART_CR2_ADDM7 BIT(4) /* F7 */
#define USART_CR2_LBDL BIT(5) #define USART_CR2_LBDL BIT(5)
#define USART_CR2_LBDIE BIT(6) #define USART_CR2_LBDIE BIT(6)
#define USART_CR2_LBCL BIT(8) #define USART_CR2_LBCL BIT(8)
@ -91,6 +167,15 @@
#define USART_CR2_STOP_2B BIT(13) #define USART_CR2_STOP_2B BIT(13)
#define USART_CR2_STOP_MASK GENMASK(13, 12) #define USART_CR2_STOP_MASK GENMASK(13, 12)
#define USART_CR2_LINEN BIT(14) #define USART_CR2_LINEN BIT(14)
#define USART_CR2_SWAP BIT(15) /* F7 */
#define USART_CR2_RXINV BIT(16) /* F7 */
#define USART_CR2_TXINV BIT(17) /* F7 */
#define USART_CR2_DATAINV BIT(18) /* F7 */
#define USART_CR2_MSBFIRST BIT(19) /* F7 */
#define USART_CR2_ABREN BIT(20) /* F7 */
#define USART_CR2_ABRMOD_MASK GENMASK(22, 21) /* F7 */
#define USART_CR2_RTOEN BIT(23) /* F7 */
#define USART_CR2_ADD_F7_MASK GENMASK(31, 24) /* F7 */
/* USART_CR3 */ /* USART_CR3 */
#define USART_CR3_EIE BIT(0) #define USART_CR3_EIE BIT(0)
@ -105,18 +190,47 @@
#define USART_CR3_CTSE BIT(9) #define USART_CR3_CTSE BIT(9)
#define USART_CR3_CTSIE BIT(10) #define USART_CR3_CTSIE BIT(10)
#define USART_CR3_ONEBIT BIT(11) #define USART_CR3_ONEBIT BIT(11)
#define USART_CR3_OVRDIS BIT(12) /* F7 */
#define USART_CR3_DDRE BIT(13) /* F7 */
#define USART_CR3_DEM BIT(14) /* F7 */
#define USART_CR3_DEP BIT(15) /* F7 */
#define USART_CR3_SCARCNT_MASK GENMASK(19, 17) /* F7 */
/* USART_GTPR */ /* USART_GTPR */
#define USART_GTPR_PSC_MASK GENMASK(7, 0) #define USART_GTPR_PSC_MASK GENMASK(7, 0)
#define USART_GTPR_GT_MASK GENMASK(15, 8) #define USART_GTPR_GT_MASK GENMASK(15, 8)
#define DRIVER_NAME "stm32-usart" /* USART_RTOR */
#define USART_RTOR_RTO_MASK GENMASK(23, 0) /* F7 */
#define USART_RTOR_BLEN_MASK GENMASK(31, 24) /* F7 */
/* USART_RQR */
#define USART_RQR_ABRRQ BIT(0) /* F7 */
#define USART_RQR_SBKRQ BIT(1) /* F7 */
#define USART_RQR_MMRQ BIT(2) /* F7 */
#define USART_RQR_RXFRQ BIT(3) /* F7 */
#define USART_RQR_TXFRQ BIT(4) /* F7 */
/* USART_ICR */
#define USART_ICR_PECF BIT(0) /* F7 */
#define USART_ICR_FFECF BIT(1) /* F7 */
#define USART_ICR_NCF BIT(2) /* F7 */
#define USART_ICR_ORECF BIT(3) /* F7 */
#define USART_ICR_IDLECF BIT(4) /* F7 */
#define USART_ICR_TCCF BIT(6) /* F7 */
#define USART_ICR_LBDCF BIT(8) /* F7 */
#define USART_ICR_CTSCF BIT(9) /* F7 */
#define USART_ICR_RTOCF BIT(11) /* F7 */
#define USART_ICR_EOBCF BIT(12) /* F7 */
#define USART_ICR_CMCF BIT(17) /* F7 */
#define STM32_SERIAL_NAME "ttyS" #define STM32_SERIAL_NAME "ttyS"
#define STM32_MAX_PORTS 6 #define STM32_MAX_PORTS 6
struct stm32_port { struct stm32_port {
struct uart_port port; struct uart_port port;
struct clk *clk; struct clk *clk;
struct stm32_usart_info *info;
bool hw_flow_control; bool hw_flow_control;
}; };
@ -151,6 +265,8 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
static void stm32_receive_chars(struct uart_port *port) static void stm32_receive_chars(struct uart_port *port)
{ {
struct tty_port *tport = &port->state->port; struct tty_port *tport = &port->state->port;
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
unsigned long c; unsigned long c;
u32 sr; u32 sr;
char flag; char flag;
@ -158,9 +274,9 @@ static void stm32_receive_chars(struct uart_port *port)
if (port->irq_wake) if (port->irq_wake)
pm_wakeup_event(tport->tty->dev, 0); pm_wakeup_event(tport->tty->dev, 0);
while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) { while ((sr = readl_relaxed(port->membase + ofs->isr)) & USART_SR_RXNE) {
sr |= USART_SR_DUMMY_RX; sr |= USART_SR_DUMMY_RX;
c = readl_relaxed(port->membase + USART_DR); c = readl_relaxed(port->membase + ofs->rdr);
flag = TTY_NORMAL; flag = TTY_NORMAL;
port->icount.rx++; port->icount.rx++;
@ -170,6 +286,10 @@ static void stm32_receive_chars(struct uart_port *port)
if (uart_handle_break(port)) if (uart_handle_break(port))
continue; continue;
} else if (sr & USART_SR_ORE) { } else if (sr & USART_SR_ORE) {
if (ofs->icr != UNDEF_REG)
writel_relaxed(USART_ICR_ORECF,
port->membase +
ofs->icr);
port->icount.overrun++; port->icount.overrun++;
} else if (sr & USART_SR_PE) { } else if (sr & USART_SR_PE) {
port->icount.parity++; port->icount.parity++;
@ -199,10 +319,12 @@ static void stm32_receive_chars(struct uart_port *port)
static void stm32_transmit_chars(struct uart_port *port) static void stm32_transmit_chars(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct circ_buf *xmit = &port->state->xmit; struct circ_buf *xmit = &port->state->xmit;
if (port->x_char) { if (port->x_char) {
writel_relaxed(port->x_char, port->membase + USART_DR); writel_relaxed(port->x_char, port->membase + ofs->tdr);
port->x_char = 0; port->x_char = 0;
port->icount.tx++; port->icount.tx++;
return; return;
@ -218,7 +340,7 @@ static void stm32_transmit_chars(struct uart_port *port)
return; return;
} }
writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR); writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++; port->icount.tx++;
@ -232,11 +354,13 @@ static void stm32_transmit_chars(struct uart_port *port)
static irqreturn_t stm32_interrupt(int irq, void *ptr) static irqreturn_t stm32_interrupt(int irq, void *ptr)
{ {
struct uart_port *port = ptr; struct uart_port *port = ptr;
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
u32 sr; u32 sr;
spin_lock(&port->lock); spin_lock(&port->lock);
sr = readl_relaxed(port->membase + USART_SR); sr = readl_relaxed(port->membase + ofs->isr);
if (sr & USART_SR_RXNE) if (sr & USART_SR_RXNE)
stm32_receive_chars(port); stm32_receive_chars(port);
@ -251,15 +375,21 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr)
static unsigned int stm32_tx_empty(struct uart_port *port) static unsigned int stm32_tx_empty(struct uart_port *port)
{ {
return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE; struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE;
} }
static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
stm32_set_bits(port, USART_CR3, USART_CR3_RTSE); stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE);
else else
stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE); stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE);
} }
static unsigned int stm32_get_mctrl(struct uart_port *port) static unsigned int stm32_get_mctrl(struct uart_port *port)
@ -271,44 +401,56 @@ static unsigned int stm32_get_mctrl(struct uart_port *port)
/* Transmit stop */ /* Transmit stop */
static void stm32_stop_tx(struct uart_port *port) static void stm32_stop_tx(struct uart_port *port)
{ {
stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE); struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
} }
/* There are probably characters waiting to be transmitted. */ /* There are probably characters waiting to be transmitted. */
static void stm32_start_tx(struct uart_port *port) static void stm32_start_tx(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct circ_buf *xmit = &port->state->xmit; struct circ_buf *xmit = &port->state->xmit;
if (uart_circ_empty(xmit)) if (uart_circ_empty(xmit))
return; return;
stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE); stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE | USART_CR1_TE);
} }
/* Throttle the remote when input buffer is about to overflow. */ /* Throttle the remote when input buffer is about to overflow. */
static void stm32_throttle(struct uart_port *port) static void stm32_throttle(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
/* Unthrottle the remote, the input buffer can now accept data. */ /* Unthrottle the remote, the input buffer can now accept data. */
static void stm32_unthrottle(struct uart_port *port) static void stm32_unthrottle(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE); stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
/* Receive stop */ /* Receive stop */
static void stm32_stop_rx(struct uart_port *port) static void stm32_stop_rx(struct uart_port *port)
{ {
stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
} }
/* Handle breaks - ignored by us */ /* Handle breaks - ignored by us */
@ -318,6 +460,8 @@ static void stm32_break_ctl(struct uart_port *port, int break_state)
static int stm32_startup(struct uart_port *port) static int stm32_startup(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
const char *name = to_platform_device(port->dev)->name; const char *name = to_platform_device(port->dev)->name;
u32 val; u32 val;
int ret; int ret;
@ -327,17 +471,19 @@ static int stm32_startup(struct uart_port *port)
return ret; return ret;
val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
stm32_set_bits(port, USART_CR1, val); stm32_set_bits(port, ofs->cr1, val);
return 0; return 0;
} }
static void stm32_shutdown(struct uart_port *port) static void stm32_shutdown(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
u32 val; u32 val;
val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
stm32_set_bits(port, USART_CR1, val); stm32_set_bits(port, ofs->cr1, val);
free_irq(port->irq, port); free_irq(port->irq, port);
} }
@ -346,6 +492,8 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old) struct ktermios *old)
{ {
struct stm32_port *stm32_port = to_stm32_port(port); 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;
unsigned int baud; unsigned int baud;
u32 usartdiv, mantissa, fraction, oversampling; u32 usartdiv, mantissa, fraction, oversampling;
tcflag_t cflag = termios->c_cflag; tcflag_t cflag = termios->c_cflag;
@ -360,9 +508,10 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
/* Stop serial port and reset value */ /* Stop serial port and reset value */
writel_relaxed(0, port->membase + USART_CR1); writel_relaxed(0, port->membase + ofs->cr1);
cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE; cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
cr1 |= BIT(cfg->uart_enable_bit);
cr2 = 0; cr2 = 0;
cr3 = 0; cr3 = 0;
@ -371,8 +520,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
if (cflag & PARENB) { if (cflag & PARENB) {
cr1 |= USART_CR1_PCE; cr1 |= USART_CR1_PCE;
if ((cflag & CSIZE) == CS8) if ((cflag & CSIZE) == CS8) {
cr1 |= USART_CR1_M; if (cfg->has_7bits_data)
cr1 |= USART_CR1_M0;
else
cr1 |= USART_CR1_M;
}
} }
if (cflag & PARODD) if (cflag & PARODD)
@ -394,15 +547,15 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
*/ */
if (usartdiv < 16) { if (usartdiv < 16) {
oversampling = 8; oversampling = 8;
stm32_set_bits(port, USART_CR1, USART_CR1_OVER8); stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8);
} else { } else {
oversampling = 16; oversampling = 16;
stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8); stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8);
} }
mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
fraction = usartdiv % oversampling; fraction = usartdiv % oversampling;
writel_relaxed(mantissa | fraction, port->membase + USART_BRR); writel_relaxed(mantissa | fraction, port->membase + ofs->brr);
uart_update_timeout(port, cflag, baud); uart_update_timeout(port, cflag, baud);
@ -430,9 +583,9 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
if ((termios->c_cflag & CREAD) == 0) if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= USART_SR_DUMMY_RX; port->ignore_status_mask |= USART_SR_DUMMY_RX;
writel_relaxed(cr3, port->membase + USART_CR3); writel_relaxed(cr3, port->membase + ofs->cr3);
writel_relaxed(cr2, port->membase + USART_CR2); writel_relaxed(cr2, port->membase + ofs->cr2);
writel_relaxed(cr1, port->membase + USART_CR1); writel_relaxed(cr1, port->membase + ofs->cr1);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
@ -469,6 +622,8 @@ static void stm32_pm(struct uart_port *port, unsigned int state,
{ {
struct stm32_port *stm32port = container_of(port, struct stm32_port *stm32port = container_of(port,
struct stm32_port, port); struct stm32_port, port);
struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
struct stm32_usart_config *cfg = &stm32port->info->cfg;
unsigned long flags = 0; unsigned long flags = 0;
switch (state) { switch (state) {
@ -477,7 +632,7 @@ static void stm32_pm(struct uart_port *port, unsigned int state,
break; break;
case UART_PM_STATE_OFF: case UART_PM_STATE_OFF:
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
stm32_clr_bits(port, USART_CR1, USART_CR1_UE); stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
clk_disable_unprepare(stm32port->clk); clk_disable_unprepare(stm32port->clk);
break; break;
@ -567,8 +722,10 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id stm32_match[] = { static const struct of_device_id stm32_match[] = {
{ .compatible = "st,stm32-usart", }, { .compatible = "st,stm32-usart", .data = &stm32f4_info},
{ .compatible = "st,stm32-uart", }, { .compatible = "st,stm32-uart", .data = &stm32f4_info},
{ .compatible = "st,stm32f7-usart", .data = &stm32f7_info},
{ .compatible = "st,stm32f7-uart", .data = &stm32f7_info},
{}, {},
}; };
@ -577,13 +734,20 @@ MODULE_DEVICE_TABLE(of, stm32_match);
static int stm32_serial_probe(struct platform_device *pdev) static int stm32_serial_probe(struct platform_device *pdev)
{ {
int ret; const struct of_device_id *match;
struct stm32_port *stm32port; struct stm32_port *stm32port;
int ret;
stm32port = stm32_of_get_stm32_port(pdev); stm32port = stm32_of_get_stm32_port(pdev);
if (!stm32port) if (!stm32port)
return -ENODEV; return -ENODEV;
match = of_match_device(stm32_match, &pdev->dev);
if (match && match->data)
stm32port->info = (struct stm32_usart_info *)match->data;
else
return -EINVAL;
ret = stm32_init_port(stm32port, pdev); ret = stm32_init_port(stm32port, pdev);
if (ret) if (ret)
return ret; return ret;
@ -608,15 +772,20 @@ static int stm32_serial_remove(struct platform_device *pdev)
#ifdef CONFIG_SERIAL_STM32_CONSOLE #ifdef CONFIG_SERIAL_STM32_CONSOLE
static void stm32_console_putchar(struct uart_port *port, int ch) static void stm32_console_putchar(struct uart_port *port, int ch)
{ {
while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE)) struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
while (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
cpu_relax(); cpu_relax();
writel_relaxed(ch, port->membase + USART_DR); writel_relaxed(ch, port->membase + ofs->tdr);
} }
static void stm32_console_write(struct console *co, const char *s, unsigned cnt) static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
{ {
struct uart_port *port = &stm32_ports[co->index].port; struct uart_port *port = &stm32_ports[co->index].port;
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
unsigned long flags; unsigned long flags;
u32 old_cr1, new_cr1; u32 old_cr1, new_cr1;
int locked = 1; int locked = 1;
@ -630,14 +799,14 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
spin_lock(&port->lock); spin_lock(&port->lock);
/* Save and disable interrupts */ /* Save and disable interrupts */
old_cr1 = readl_relaxed(port->membase + USART_CR1); old_cr1 = readl_relaxed(port->membase + ofs->cr1);
new_cr1 = old_cr1 & ~USART_CR1_IE_MASK; new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
writel_relaxed(new_cr1, port->membase + USART_CR1); writel_relaxed(new_cr1, port->membase + ofs->cr1);
uart_console_write(port, s, cnt, stm32_console_putchar); uart_console_write(port, s, cnt, stm32_console_putchar);
/* Restore interrupt state */ /* Restore interrupt state */
writel_relaxed(old_cr1, port->membase + USART_CR1); writel_relaxed(old_cr1, port->membase + ofs->cr1);
if (locked) if (locked)
spin_unlock(&port->lock); spin_unlock(&port->lock);