mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
serial: sh-sci: Update the suspend/resume support
The Renesas RZ/G3S supports a power saving mode where power to most of the SoC components is turned off. When returning from this power saving mode, SoC components need to be re-configured. The SCIFs on the Renesas RZ/G3S need to be re-configured as well when returning from this power saving mode. The sh-sci code already configures the SCIF clocks, power domain and registers by calling uart_resume_port() in sci_resume(). On suspend path the SCIF UART ports are suspended accordingly (by calling uart_suspend_port() in sci_suspend()). The only missing setting is the reset signal. For this assert/de-assert the reset signal on driver suspend/resume. In case the no_console_suspend is specified by the user, the registers need to be saved on suspend path and restore on resume path. To do this the sci_console_save()/sci_console_restore() functions were added. There is no need to cache/restore the status or FIFO registers. Only the control registers. The registers that will be saved/restored on suspend/resume are specified by the struct sci_suspend_regs data structure. Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Link: https://lore.kernel.org/r/20250207113313.545432-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
1f0cfc68ad
commit
22a6984c5b
1 changed files with 69 additions and 2 deletions
|
@ -104,6 +104,15 @@ struct plat_sci_reg {
|
|||
u8 offset, size;
|
||||
};
|
||||
|
||||
struct sci_suspend_regs {
|
||||
u16 scsmr;
|
||||
u16 scscr;
|
||||
u16 scfcr;
|
||||
u16 scsptr;
|
||||
u8 scbrr;
|
||||
u8 semr;
|
||||
};
|
||||
|
||||
struct sci_port_params {
|
||||
const struct plat_sci_reg regs[SCIx_NR_REGS];
|
||||
unsigned int fifosize;
|
||||
|
@ -134,6 +143,8 @@ struct sci_port {
|
|||
struct dma_chan *chan_tx;
|
||||
struct dma_chan *chan_rx;
|
||||
|
||||
struct reset_control *rstc;
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
||||
struct dma_chan *chan_tx_saved;
|
||||
struct dma_chan *chan_rx_saved;
|
||||
|
@ -153,6 +164,7 @@ struct sci_port {
|
|||
int rx_trigger;
|
||||
struct timer_list rx_fifo_timer;
|
||||
int rx_fifo_timeout;
|
||||
struct sci_suspend_regs suspend_regs;
|
||||
u16 hscif_tot;
|
||||
|
||||
bool has_rtscts;
|
||||
|
@ -3374,6 +3386,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
|
|||
}
|
||||
|
||||
sp = &sci_ports[id];
|
||||
sp->rstc = rstc;
|
||||
*dev_id = id;
|
||||
|
||||
p->type = SCI_OF_TYPE(data);
|
||||
|
@ -3546,13 +3559,57 @@ static int sci_probe(struct platform_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void sci_console_save(struct sci_port *s)
|
||||
{
|
||||
struct sci_suspend_regs *regs = &s->suspend_regs;
|
||||
struct uart_port *port = &s->port;
|
||||
|
||||
if (sci_getreg(port, SCSMR)->size)
|
||||
regs->scsmr = sci_serial_in(port, SCSMR);
|
||||
if (sci_getreg(port, SCSCR)->size)
|
||||
regs->scscr = sci_serial_in(port, SCSCR);
|
||||
if (sci_getreg(port, SCFCR)->size)
|
||||
regs->scfcr = sci_serial_in(port, SCFCR);
|
||||
if (sci_getreg(port, SCSPTR)->size)
|
||||
regs->scsptr = sci_serial_in(port, SCSPTR);
|
||||
if (sci_getreg(port, SCBRR)->size)
|
||||
regs->scbrr = sci_serial_in(port, SCBRR);
|
||||
if (sci_getreg(port, SEMR)->size)
|
||||
regs->semr = sci_serial_in(port, SEMR);
|
||||
}
|
||||
|
||||
static void sci_console_restore(struct sci_port *s)
|
||||
{
|
||||
struct sci_suspend_regs *regs = &s->suspend_regs;
|
||||
struct uart_port *port = &s->port;
|
||||
|
||||
if (sci_getreg(port, SCSMR)->size)
|
||||
sci_serial_out(port, SCSMR, regs->scsmr);
|
||||
if (sci_getreg(port, SCSCR)->size)
|
||||
sci_serial_out(port, SCSCR, regs->scscr);
|
||||
if (sci_getreg(port, SCFCR)->size)
|
||||
sci_serial_out(port, SCFCR, regs->scfcr);
|
||||
if (sci_getreg(port, SCSPTR)->size)
|
||||
sci_serial_out(port, SCSPTR, regs->scsptr);
|
||||
if (sci_getreg(port, SCBRR)->size)
|
||||
sci_serial_out(port, SCBRR, regs->scbrr);
|
||||
if (sci_getreg(port, SEMR)->size)
|
||||
sci_serial_out(port, SEMR, regs->semr);
|
||||
}
|
||||
|
||||
static __maybe_unused int sci_suspend(struct device *dev)
|
||||
{
|
||||
struct sci_port *sport = dev_get_drvdata(dev);
|
||||
|
||||
if (sport)
|
||||
if (sport) {
|
||||
uart_suspend_port(&sci_uart_driver, &sport->port);
|
||||
|
||||
if (!console_suspend_enabled && uart_console(&sport->port))
|
||||
sci_console_save(sport);
|
||||
else
|
||||
return reset_control_assert(sport->rstc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3560,8 +3617,18 @@ static __maybe_unused int sci_resume(struct device *dev)
|
|||
{
|
||||
struct sci_port *sport = dev_get_drvdata(dev);
|
||||
|
||||
if (sport)
|
||||
if (sport) {
|
||||
if (!console_suspend_enabled && uart_console(&sport->port)) {
|
||||
sci_console_restore(sport);
|
||||
} else {
|
||||
int ret = reset_control_deassert(sport->rstc);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uart_resume_port(&sci_uart_driver, &sport->port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue