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:
Родитель
27b17ae073
Коммит
ada8618ff3
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* Inspired by st-asc.c from STMicroelectronics (c)
|
||||
|
@ -29,16 +30,74 @@
|
|||
|
||||
#define DRIVER_NAME "stm32-usart"
|
||||
|
||||
/* Register offsets */
|
||||
#define USART_SR 0x00
|
||||
#define USART_DR 0x04
|
||||
#define USART_BRR 0x08
|
||||
#define USART_CR1 0x0c
|
||||
#define USART_CR2 0x10
|
||||
#define USART_CR3 0x14
|
||||
#define USART_GTPR 0x18
|
||||
struct stm32_usart_offsets {
|
||||
u8 cr1;
|
||||
u8 cr2;
|
||||
u8 cr3;
|
||||
u8 brr;
|
||||
u8 gtpr;
|
||||
u8 rtor;
|
||||
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_FE BIT(1)
|
||||
#define USART_SR_NF BIT(2)
|
||||
|
@ -48,7 +107,16 @@
|
|||
#define USART_SR_TC BIT(6)
|
||||
#define USART_SR_TXE BIT(7)
|
||||
#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 | \
|
||||
USART_SR_FE | USART_SR_PE)
|
||||
/* Dummy bits */
|
||||
|
@ -64,7 +132,7 @@
|
|||
|
||||
/* USART_CR1 */
|
||||
#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_TE BIT(3)
|
||||
#define USART_CR1_IDLEIE BIT(4)
|
||||
|
@ -76,12 +144,20 @@
|
|||
#define USART_CR1_PCE BIT(10)
|
||||
#define USART_CR1_WAKE BIT(11)
|
||||
#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_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 */
|
||||
#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_LBDIE BIT(6)
|
||||
#define USART_CR2_LBCL BIT(8)
|
||||
|
@ -91,6 +167,15 @@
|
|||
#define USART_CR2_STOP_2B BIT(13)
|
||||
#define USART_CR2_STOP_MASK GENMASK(13, 12)
|
||||
#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 */
|
||||
#define USART_CR3_EIE BIT(0)
|
||||
|
@ -105,18 +190,47 @@
|
|||
#define USART_CR3_CTSE BIT(9)
|
||||
#define USART_CR3_CTSIE BIT(10)
|
||||
#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 */
|
||||
#define USART_GTPR_PSC_MASK GENMASK(7, 0)
|
||||
#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_MAX_PORTS 6
|
||||
|
||||
struct stm32_port {
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
struct stm32_usart_info *info;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
u32 sr;
|
||||
char flag;
|
||||
|
@ -158,9 +274,9 @@ static void stm32_receive_chars(struct uart_port *port)
|
|||
if (port->irq_wake)
|
||||
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;
|
||||
c = readl_relaxed(port->membase + USART_DR);
|
||||
c = readl_relaxed(port->membase + ofs->rdr);
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
|
||||
|
@ -170,6 +286,10 @@ static void stm32_receive_chars(struct uart_port *port)
|
|||
if (uart_handle_break(port))
|
||||
continue;
|
||||
} else if (sr & USART_SR_ORE) {
|
||||
if (ofs->icr != UNDEF_REG)
|
||||
writel_relaxed(USART_ICR_ORECF,
|
||||
port->membase +
|
||||
ofs->icr);
|
||||
port->icount.overrun++;
|
||||
} else if (sr & USART_SR_PE) {
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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->icount.tx++;
|
||||
return;
|
||||
|
@ -218,7 +340,7 @@ static void stm32_transmit_chars(struct uart_port *port)
|
|||
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);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
sr = readl_relaxed(port->membase + USART_SR);
|
||||
sr = readl_relaxed(port->membase + ofs->isr);
|
||||
|
||||
if (sr & USART_SR_RXNE)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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))
|
||||
stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
|
||||
stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE);
|
||||
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)
|
||||
|
@ -271,44 +401,56 @@ static unsigned int stm32_get_mctrl(struct uart_port *port)
|
|||
/* Transmit stop */
|
||||
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. */
|
||||
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;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
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. */
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Unthrottle the remote, the input buffer can now accept data. */
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Receive stop */
|
||||
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 */
|
||||
|
@ -318,6 +460,8 @@ static void stm32_break_ctl(struct uart_port *port, int break_state)
|
|||
|
||||
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;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
@ -327,17 +471,19 @@ static int stm32_startup(struct uart_port *port)
|
|||
return ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -346,6 +492,8 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
struct ktermios *old)
|
||||
{
|
||||
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;
|
||||
u32 usartdiv, mantissa, fraction, oversampling;
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
cr3 = 0;
|
||||
|
||||
|
@ -371,8 +520,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
|
||||
if (cflag & PARENB) {
|
||||
cr1 |= USART_CR1_PCE;
|
||||
if ((cflag & CSIZE) == CS8)
|
||||
cr1 |= USART_CR1_M;
|
||||
if ((cflag & CSIZE) == CS8) {
|
||||
if (cfg->has_7bits_data)
|
||||
cr1 |= USART_CR1_M0;
|
||||
else
|
||||
cr1 |= USART_CR1_M;
|
||||
}
|
||||
}
|
||||
|
||||
if (cflag & PARODD)
|
||||
|
@ -394,15 +547,15 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
*/
|
||||
if (usartdiv < 16) {
|
||||
oversampling = 8;
|
||||
stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
|
||||
stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8);
|
||||
} else {
|
||||
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;
|
||||
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);
|
||||
|
||||
|
@ -430,9 +583,9 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
if ((termios->c_cflag & CREAD) == 0)
|
||||
port->ignore_status_mask |= USART_SR_DUMMY_RX;
|
||||
|
||||
writel_relaxed(cr3, port->membase + USART_CR3);
|
||||
writel_relaxed(cr2, port->membase + USART_CR2);
|
||||
writel_relaxed(cr1, port->membase + USART_CR1);
|
||||
writel_relaxed(cr3, port->membase + ofs->cr3);
|
||||
writel_relaxed(cr2, port->membase + ofs->cr2);
|
||||
writel_relaxed(cr1, port->membase + ofs->cr1);
|
||||
|
||||
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, port);
|
||||
struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
|
||||
struct stm32_usart_config *cfg = &stm32port->info->cfg;
|
||||
unsigned long flags = 0;
|
||||
|
||||
switch (state) {
|
||||
|
@ -477,7 +632,7 @@ static void stm32_pm(struct uart_port *port, unsigned int state,
|
|||
break;
|
||||
case UART_PM_STATE_OFF:
|
||||
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);
|
||||
clk_disable_unprepare(stm32port->clk);
|
||||
break;
|
||||
|
@ -567,8 +722,10 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
|
|||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id stm32_match[] = {
|
||||
{ .compatible = "st,stm32-usart", },
|
||||
{ .compatible = "st,stm32-uart", },
|
||||
{ .compatible = "st,stm32-usart", .data = &stm32f4_info},
|
||||
{ .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)
|
||||
{
|
||||
int ret;
|
||||
const struct of_device_id *match;
|
||||
struct stm32_port *stm32port;
|
||||
int ret;
|
||||
|
||||
stm32port = stm32_of_get_stm32_port(pdev);
|
||||
if (!stm32port)
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -608,15 +772,20 @@ static int stm32_serial_remove(struct platform_device *pdev)
|
|||
#ifdef CONFIG_SERIAL_STM32_CONSOLE
|
||||
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();
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
u32 old_cr1, new_cr1;
|
||||
int locked = 1;
|
||||
|
@ -630,14 +799,14 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
|
|||
spin_lock(&port->lock);
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
|
||||
/* Restore interrupt state */
|
||||
writel_relaxed(old_cr1, port->membase + USART_CR1);
|
||||
writel_relaxed(old_cr1, port->membase + ofs->cr1);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&port->lock);
|
||||
|
|
Загрузка…
Ссылка в новой задаче